devfs - Change make_dev_covering to use dev_ops
[dragonfly.git] / sys / kern / kern_conf.c
CommitLineData
984263bc
MD
1/*-
2 * Parts Copyright (c) 1995 Terrence R. Lambert
3 * Copyright (c) 1995 Julian R. Elischer
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Terrence R. Lambert.
17 * 4. The name Terrence R. Lambert may not be used to endorse or promote
18 * products derived from this software without specific prior written
19 * permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY Julian R. Elischer ``AS IS'' AND ANY
22 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * $FreeBSD: src/sys/kern/kern_conf.c,v 1.73.2.3 2003/03/10 02:18:25 imp Exp $
0e9b9130 34 * $DragonFly: src/sys/kern/kern_conf.c,v 1.23 2007/05/09 00:53:34 dillon Exp $
984263bc
MD
35 */
36
37#include <sys/param.h>
38#include <sys/kernel.h>
39#include <sys/sysctl.h>
40#include <sys/systm.h>
41#include <sys/module.h>
42#include <sys/malloc.h>
43#include <sys/conf.h>
44#include <sys/vnode.h>
45#include <sys/queue.h>
335dda38 46#include <sys/device.h>
2a32d680 47#include <sys/disk.h>
984263bc
MD
48#include <machine/stdarg.h>
49
028066b1
MD
50#include <sys/sysref2.h>
51
2c1e28dd 52#include <sys/devfs.h>
cd29885a 53
b13267a5 54MALLOC_DEFINE(M_DEVT, "cdev_t", "dev_t storage");
984263bc 55
984263bc
MD
56static int free_devt;
57SYSCTL_INT(_debug, OID_AUTO, free_devt, CTLFLAG_RW, &free_devt, 0, "");
e4c9c0c8
MD
58int dev_ref_debug = 0;
59SYSCTL_INT(_debug, OID_AUTO, dev_refs, CTLFLAG_RW, &dev_ref_debug, 0, "");
984263bc 60
984263bc 61/*
b13267a5 62 * cdev_t and u_dev_t primitives. Note that the major number is always
0e9b9130 63 * extracted from si_umajor, not from si_devsw, because si_devsw is replaced
e4c9c0c8 64 * when a device is destroyed.
984263bc 65 */
984263bc 66int
028066b1 67major(cdev_t dev)
984263bc 68{
028066b1 69 if (dev == NULL)
984263bc 70 return NOUDEV;
0e9b9130 71 return(dev->si_umajor);
984263bc
MD
72}
73
74int
028066b1 75minor(cdev_t dev)
984263bc 76{
028066b1 77 if (dev == NULL)
984263bc 78 return NOUDEV;
0e9b9130 79 return(dev->si_uminor);
984263bc
MD
80}
81
0e9b9130
MD
82/*
83 * Compatibility function with old udev_t format to convert the
84 * non-consecutive minor space into a consecutive minor space.
85 */
984263bc 86int
028066b1 87lminor(cdev_t dev)
984263bc 88{
0e9b9130 89 int y;
984263bc 90
028066b1 91 if (dev == NULL)
984263bc 92 return NOUDEV;
0e9b9130
MD
93 y = dev->si_uminor;
94 if (y & 0x0000ff00)
95 return NOUDEV;
96 return ((y & 0xff) | (y >> 8));
984263bc
MD
97}
98
e4c9c0c8 99/*
0e9b9130
MD
100 * Convert a device pointer to an old style device number. Return NOUDEV
101 * if the device is invalid or if the device (maj,min) cannot be converted
102 * to an old style udev_t.
e4c9c0c8 103 */
984263bc 104udev_t
028066b1 105dev2udev(cdev_t dev)
984263bc 106{
028066b1 107 if (dev == NULL)
984263bc 108 return NOUDEV;
cd29885a
MD
109
110 return (udev_t)dev->si_inode;
984263bc
MD
111}
112
e4c9c0c8
MD
113/*
114 * Convert a device number to a device pointer. The device is referenced
115 * ad-hoc, meaning that the caller should call reference_dev() if it wishes
116 * to keep ahold of the returned structure long term.
117 *
118 * The returned device is associated with the currently installed cdevsw
028066b1 119 * for the requested major number. NULL is returned if the major number
e4c9c0c8
MD
120 * has not been registered.
121 */
b13267a5 122cdev_t
984263bc
MD
123udev2dev(udev_t x, int b)
124{
e4c9c0c8 125 if (x == NOUDEV || b != 0)
028066b1 126 return(NULL);
cd29885a
MD
127
128 return devfs_find_device_by_udev(x);
984263bc
MD
129}
130
131int
b13267a5 132dev_is_good(cdev_t dev)
e4c9c0c8 133{
028066b1 134 if (dev != NULL && dev->si_ops != &dead_dev_ops)
e4c9c0c8
MD
135 return(1);
136 return(0);
137}
138
139/*
140 * Various user device number extraction and conversion routines
141 */
142int
984263bc
MD
143uminor(udev_t dev)
144{
0e9b9130
MD
145 if (dev == NOUDEV)
146 return(-1);
984263bc
MD
147 return(dev & 0xffff00ff);
148}
149
150int
151umajor(udev_t dev)
152{
0e9b9130
MD
153 if (dev == NOUDEV)
154 return(-1);
984263bc
MD
155 return((dev & 0xff00) >> 8);
156}
157
158udev_t
159makeudev(int x, int y)
160{
0e9b9130
MD
161 if ((x & 0xffffff00) || (y & 0x0000ff00))
162 return NOUDEV;
7cbab9da 163 return ((x << 8) | y);
984263bc
MD
164}
165
e4c9c0c8
MD
166/*
167 * Create an internal or external device.
168 *
32beb3ff
MD
169 * This routine creates and returns an unreferenced ad-hoc entry for the
170 * device which will remain intact until the device is destroyed. If the
171 * caller intends to store the device pointer it must call reference_dev()
172 * to retain a real reference to the device.
173 *
174 * If an entry already exists, this function will set (or override)
e4c9c0c8
MD
175 * its cred requirements and name (XXX DEVFS interface).
176 */
b13267a5 177cdev_t
07dfa375 178make_dev(struct dev_ops *ops, int minor, uid_t uid, gid_t gid,
e4c9c0c8 179 int perms, const char *fmt, ...)
984263bc 180{
cd29885a 181 cdev_t devfs_dev;
e2565a42 182 __va_list ap;
984263bc 183
e4c9c0c8
MD
184 /*
185 * compile the cdevsw and install the device
186 */
fef8985e 187 compile_dev_ops(ops);
e4c9c0c8 188
47ae500f 189 devfs_dev = devfs_new_cdev(ops, minor, NULL);
e2565a42 190 __va_start(ap, fmt);
da655383
MD
191 kvsnrprintf(devfs_dev->si_name, sizeof(devfs_dev->si_name),
192 32, fmt, ap);
e2565a42 193 __va_end(ap);
984263bc 194
aec8eea4
MD
195 devfs_debug(DEVFS_DEBUG_INFO,
196 "make_dev called for %s\n",
197 devfs_dev->si_name);
cd29885a
MD
198 devfs_create_dev(devfs_dev, uid, gid, perms);
199
200 return (devfs_dev);
984263bc
MD
201}
202
47ae500f
AH
203/*
204 * make_dev_covering has equivalent functionality to make_dev, except that it
205 * also takes the cdev of the underlying device. Hence this function should
206 * only be used by systems and drivers which create devices covering others
207 */
208cdev_t
b17f0c0d
AH
209make_dev_covering(struct dev_ops *ops, struct dev_ops *bops, int minor,
210 uid_t uid, gid_t gid, int perms, const char *fmt, ...)
47ae500f
AH
211{
212 cdev_t devfs_dev;
213 __va_list ap;
214
215 /*
216 * compile the cdevsw and install the device
217 */
218 compile_dev_ops(ops);
219
b17f0c0d 220 devfs_dev = devfs_new_cdev(ops, minor, bops);
47ae500f
AH
221 __va_start(ap, fmt);
222 kvsnrprintf(devfs_dev->si_name, sizeof(devfs_dev->si_name),
223 32, fmt, ap);
224 __va_end(ap);
225
226 devfs_debug(DEVFS_DEBUG_INFO,
227 "make_dev called for %s\n",
228 devfs_dev->si_name);
229 devfs_create_dev(devfs_dev, uid, gid, perms);
230
231 return (devfs_dev);
232}
233
234
cd29885a
MD
235
236cdev_t
237make_only_devfs_dev(struct dev_ops *ops, int minor, uid_t uid, gid_t gid,
238 int perms, const char *fmt, ...)
239{
240 cdev_t devfs_dev;
241 __va_list ap;
cd29885a
MD
242
243 /*
244 * compile the cdevsw and install the device
245 */
246 compile_dev_ops(ops);
47ae500f 247 devfs_dev = devfs_new_cdev(ops, minor, NULL);
cd29885a
MD
248
249 /*
250 * Set additional fields (XXX DEVFS interface goes here)
251 */
252 __va_start(ap, fmt);
da655383
MD
253 kvsnrprintf(devfs_dev->si_name, sizeof(devfs_dev->si_name),
254 32, fmt, ap);
cd29885a
MD
255 __va_end(ap);
256
cd29885a
MD
257 devfs_create_dev(devfs_dev, uid, gid, perms);
258
259 return (devfs_dev);
260}
261
262
263cdev_t
264make_only_dev(struct dev_ops *ops, int minor, uid_t uid, gid_t gid,
265 int perms, const char *fmt, ...)
266{
267 cdev_t devfs_dev;
268 __va_list ap;
cd29885a
MD
269
270 /*
271 * compile the cdevsw and install the device
272 */
273 compile_dev_ops(ops);
47ae500f 274 devfs_dev = devfs_new_cdev(ops, minor, NULL);
cd29885a
MD
275 devfs_dev->si_perms = perms;
276 devfs_dev->si_uid = uid;
277 devfs_dev->si_gid = gid;
278
279 /*
280 * Set additional fields (XXX DEVFS interface goes here)
281 */
282 __va_start(ap, fmt);
da655383
MD
283 kvsnrprintf(devfs_dev->si_name, sizeof(devfs_dev->si_name),
284 32, fmt, ap);
cd29885a
MD
285 __va_end(ap);
286
287 reference_dev(devfs_dev);
288
289 return (devfs_dev);
290}
291
292void
293destroy_only_dev(cdev_t dev)
294{
aec8eea4
MD
295 release_dev(dev);
296 release_dev(dev);
297 release_dev(dev);
cd29885a
MD
298}
299
e4c9c0c8
MD
300/*
301 * destroy_dev() removes the adhoc association for a device and revectors
fef8985e 302 * its ops to &dead_dev_ops.
e4c9c0c8
MD
303 *
304 * This routine releases the reference count associated with the ADHOC
305 * entry, plus releases the reference count held by the caller. What this
306 * means is that you should not call destroy_dev(make_dev(...)), because
307 * make_dev() does not bump the reference count (beyond what it needs to
308 * create the ad-hoc association). Any procedure that intends to destroy
309 * a device must have its own reference to it first.
217ff971 310 */
984263bc 311void
b13267a5 312destroy_dev(cdev_t dev)
984263bc 313{
3e82b46c
MD
314 if (dev) {
315 devfs_debug(DEVFS_DEBUG_DEBUG,
316 "destroy_dev called for %s\n",
317 dev->si_name);
318 devfs_destroy_dev(dev);
e4c9c0c8 319 }
e4c9c0c8
MD
320}
321
2a32d680
MD
322/*
323 * Make sure all asynchronous disk and devfs related operations have
324 * completed.
325 *
326 * Typically called prior to mountroot to ensure that all disks have
327 * been completely probed and on module unload to ensure that ops
328 * structures have been dereferenced.
329 */
330void
331sync_devs(void)
332{
333 disk_config(NULL);
334 devfs_config();
335 disk_config(NULL);
336 devfs_config();
337}
338
cd29885a
MD
339int
340make_dev_alias(cdev_t target, const char *fmt, ...)
341{
cd29885a 342 __va_list ap;
da655383 343 char *name;
cd29885a
MD
344
345 __va_start(ap, fmt);
da655383 346 kvasnrprintf(&name, PATH_MAX, 32, fmt, ap);
cd29885a
MD
347 __va_end(ap);
348
349 devfs_make_alias(name, target);
da655383 350 kvasfree(&name);
cd29885a
MD
351
352 return 0;
353}
354
07dfa375
AH
355extern struct dev_ops default_dev_ops;
356
b96f3782
AH
357cdev_t
358make_autoclone_dev(struct dev_ops *ops, struct devfs_bitmap *bitmap,
359 d_clone_t *nhandler, uid_t uid, gid_t gid, int perms, const char *fmt, ...)
360{
b96f3782 361 __va_list ap;
da655383
MD
362 cdev_t dev;
363 char *name;
b96f3782
AH
364
365 __va_start(ap, fmt);
da655383 366 kvasnrprintf(&name, PATH_MAX, 32, fmt, ap);
b96f3782
AH
367 __va_end(ap);
368
07dfa375
AH
369 if (bitmap != NULL)
370 devfs_clone_bitmap_init(bitmap);
371
b96f3782 372 devfs_clone_handler_add(name, nhandler);
b17f0c0d 373 dev = make_dev_covering(&default_dev_ops, ops, 0xffff00ff,
da655383
MD
374 uid, gid, perms, "%s", name);
375 kvasfree(&name);
b96f3782
AH
376 return dev;
377}
378
07dfa375
AH
379void
380destroy_autoclone_dev(cdev_t dev, struct devfs_bitmap *bitmap)
381{
382 if (dev == NULL)
383 return;
384
385 devfs_clone_handler_del(dev->si_name);
386
387 if (bitmap != NULL)
388 devfs_clone_bitmap_uninit(bitmap);
389
390 destroy_dev(dev);
391}
392
cd29885a 393
e4c9c0c8
MD
394/*
395 * Add a reference to a device. Callers generally add their own references
396 * when they are going to store a device node in a variable for long periods
397 * of time, to prevent a disassociation from free()ing the node.
398 *
399 * Also note that a caller that intends to call destroy_dev() must first
400 * obtain a reference on the device. The ad-hoc reference you get with
401 * make_dev() and friends is NOT sufficient to be able to call destroy_dev().
402 */
b13267a5
MD
403cdev_t
404reference_dev(cdev_t dev)
e4c9c0c8 405{
cd29885a
MD
406 //kprintf("reference_dev\n");
407
028066b1
MD
408 if (dev != NULL) {
409 sysref_get(&dev->si_sysref);
aec8eea4 410 if (dev_ref_debug & 2) {
07dfa375 411 kprintf("reference dev %p %s(minor=%08x) refs=%d\n",
0e9b9130 412 dev, devtoname(dev), dev->si_uminor,
028066b1 413 dev->si_sysref.refcnt);
e4c9c0c8
MD
414 }
415 }
416 return(dev);
417}
418
419/*
028066b1
MD
420 * release a reference on a device. The device will be terminated when the
421 * last reference has been released.
e4c9c0c8 422 *
0e9b9130 423 * NOTE: we must use si_umajor to figure out the original major number,
fef8985e 424 * because si_ops could already be pointing at dead_dev_ops.
e4c9c0c8
MD
425 */
426void
b13267a5 427release_dev(cdev_t dev)
e4c9c0c8 428{
cd29885a
MD
429 //kprintf("release_dev\n");
430
028066b1 431 if (dev == NULL)
e4c9c0c8 432 return;
028066b1
MD
433 sysref_put(&dev->si_sysref);
434}
435
984263bc 436const char *
b13267a5 437devtoname(cdev_t dev)
984263bc 438{
984263bc 439 int mynor;
335dda38
MD
440 int len;
441 char *p;
442 const char *dname;
984263bc 443
028066b1 444 if (dev == NULL)
e4c9c0c8 445 return("#nodev");
984263bc
MD
446 if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') {
447 p = dev->si_name;
335dda38
MD
448 len = sizeof(dev->si_name);
449 if ((dname = dev_dname(dev)) != NULL)
f8c7a42d 450 ksnprintf(p, len, "#%s/", dname);
984263bc 451 else
f8c7a42d 452 ksnprintf(p, len, "#%d/", major(dev));
335dda38 453 len -= strlen(p);
984263bc
MD
454 p += strlen(p);
455 mynor = minor(dev);
456 if (mynor < 0 || mynor > 255)
f8c7a42d 457 ksnprintf(p, len, "%#x", (u_int)mynor);
984263bc 458 else
f8c7a42d 459 ksnprintf(p, len, "%d", mynor);
984263bc
MD
460 }
461 return (dev->si_name);
462}
e4c9c0c8 463