xref: /dragonfly/sys/kern/kern_conf.c (revision cecb9aae)
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 $
34  * $DragonFly: src/sys/kern/kern_conf.c,v 1.23 2007/05/09 00:53:34 dillon Exp $
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>
46 #include <sys/device.h>
47 #include <sys/disk.h>
48 #include <machine/stdarg.h>
49 
50 #include <sys/sysref2.h>
51 
52 #include <sys/devfs.h>
53 
54 MALLOC_DEFINE(M_DEVT, "cdev_t", "dev_t storage");
55 
56 int dev_ref_debug = 0;
57 SYSCTL_INT(_debug, OID_AUTO, dev_refs, CTLFLAG_RW, &dev_ref_debug, 0,
58     "Toggle device reference debug output");
59 
60 /*
61  * cdev_t and u_dev_t primitives.  Note that the major number is always
62  * extracted from si_umajor, not from si_devsw, because si_devsw is replaced
63  * when a device is destroyed.
64  */
65 int
66 major(cdev_t dev)
67 {
68 	if (dev == NULL)
69 		return NOUDEV;
70 	return(dev->si_umajor);
71 }
72 
73 int
74 minor(cdev_t dev)
75 {
76 	if (dev == NULL)
77 		return NOUDEV;
78 	return(dev->si_uminor);
79 }
80 
81 /*
82  * Compatibility function with old udev_t format to convert the
83  * non-consecutive minor space into a consecutive minor space.
84  */
85 int
86 lminor(cdev_t dev)
87 {
88 	int y;
89 
90 	if (dev == NULL)
91 		return NOUDEV;
92 	y = dev->si_uminor;
93 	if (y & 0x0000ff00)
94 		return NOUDEV;
95 	return ((y & 0xff) | (y >> 8));
96 }
97 
98 /*
99  * Convert a device pointer to an old style device number.  Return NOUDEV
100  * if the device is invalid or if the device (maj,min) cannot be converted
101  * to an old style udev_t.
102  */
103 udev_t
104 dev2udev(cdev_t dev)
105 {
106 	if (dev == NULL)
107 		return NOUDEV;
108 
109 	return (udev_t)dev->si_inode;
110 }
111 
112 /*
113  * Convert a device number to a device pointer.  The device is referenced
114  * ad-hoc, meaning that the caller should call reference_dev() if it wishes
115  * to keep ahold of the returned structure long term.
116  *
117  * The returned device is associated with the currently installed cdevsw
118  * for the requested major number.  NULL is returned if the major number
119  * has not been registered.
120  */
121 cdev_t
122 udev2dev(udev_t x, int b)
123 {
124 	if (x == NOUDEV || b != 0)
125 		return(NULL);
126 
127 	return devfs_find_device_by_udev(x);
128 }
129 
130 int
131 dev_is_good(cdev_t dev)
132 {
133 	if (dev != NULL && dev->si_ops != &dead_dev_ops)
134 		return(1);
135 	return(0);
136 }
137 
138 /*
139  * Various user device number extraction and conversion routines
140  */
141 int
142 uminor(udev_t dev)
143 {
144 	if (dev == NOUDEV)
145 		return(-1);
146 	return(dev & 0xffff00ff);
147 }
148 
149 int
150 umajor(udev_t dev)
151 {
152 	if (dev == NOUDEV)
153 		return(-1);
154 	return((dev & 0xff00) >> 8);
155 }
156 
157 udev_t
158 makeudev(int x, int y)
159 {
160 	if ((x & 0xffffff00) || (y & 0x0000ff00))
161 		return NOUDEV;
162 	return ((x << 8) | y);
163 }
164 
165 /*
166  * Create an internal or external device.
167  *
168  * This routine creates and returns an unreferenced ad-hoc entry for the
169  * device which will remain intact until the device is destroyed.  If the
170  * caller intends to store the device pointer it must call reference_dev()
171  * to retain a real reference to the device.
172  *
173  * If an entry already exists, this function will set (or override)
174  * its cred requirements and name (XXX DEVFS interface).
175  */
176 cdev_t
177 make_dev(struct dev_ops *ops, int minor, uid_t uid, gid_t gid,
178 	int perms, const char *fmt, ...)
179 {
180 	cdev_t	devfs_dev;
181 	__va_list ap;
182 
183 	/*
184 	 * compile the cdevsw and install the device
185 	 */
186 	compile_dev_ops(ops);
187 
188 	devfs_dev = devfs_new_cdev(ops, minor, NULL);
189 	__va_start(ap, fmt);
190 	kvsnrprintf(devfs_dev->si_name, sizeof(devfs_dev->si_name),
191 		    32, fmt, ap);
192 	__va_end(ap);
193 
194 	devfs_debug(DEVFS_DEBUG_INFO,
195 		    "make_dev called for %s\n",
196 		    devfs_dev->si_name);
197 	devfs_create_dev(devfs_dev, uid, gid, perms);
198 
199 	return (devfs_dev);
200 }
201 
202 /*
203  * make_dev_covering has equivalent functionality to make_dev, except that it
204  * also takes the cdev of the underlying device. Hence this function should
205  * only be used by systems and drivers which create devices covering others
206  */
207 cdev_t
208 make_dev_covering(struct dev_ops *ops, struct dev_ops *bops, int minor,
209 	    uid_t uid, gid_t gid, int perms, const char *fmt, ...)
210 {
211 	cdev_t	devfs_dev;
212 	__va_list ap;
213 
214 	/*
215 	 * compile the cdevsw and install the device
216 	 */
217 	compile_dev_ops(ops);
218 
219 	devfs_dev = devfs_new_cdev(ops, minor, bops);
220 	__va_start(ap, fmt);
221 	kvsnrprintf(devfs_dev->si_name, sizeof(devfs_dev->si_name),
222 		    32, fmt, ap);
223 	__va_end(ap);
224 
225 	devfs_debug(DEVFS_DEBUG_INFO,
226 		    "make_dev called for %s\n",
227 		    devfs_dev->si_name);
228 	devfs_create_dev(devfs_dev, uid, gid, perms);
229 
230 	return (devfs_dev);
231 }
232 
233 
234 
235 cdev_t
236 make_only_devfs_dev(struct dev_ops *ops, int minor, uid_t uid, gid_t gid,
237 	int perms, const char *fmt, ...)
238 {
239 	cdev_t	devfs_dev;
240 	__va_list ap;
241 
242 	/*
243 	 * compile the cdevsw and install the device
244 	 */
245 	compile_dev_ops(ops);
246 	devfs_dev = devfs_new_cdev(ops, minor, NULL);
247 
248 	/*
249 	 * Set additional fields (XXX DEVFS interface goes here)
250 	 */
251 	__va_start(ap, fmt);
252 	kvsnrprintf(devfs_dev->si_name, sizeof(devfs_dev->si_name),
253 		    32, fmt, ap);
254 	__va_end(ap);
255 
256 	devfs_create_dev(devfs_dev, uid, gid, perms);
257 
258 	return (devfs_dev);
259 }
260 
261 cdev_t
262 make_only_dev(struct dev_ops *ops, int minor, uid_t uid, gid_t gid,
263 	int perms, const char *fmt, ...)
264 {
265 	cdev_t	devfs_dev;
266 	__va_list ap;
267 
268 	/*
269 	 * compile the cdevsw and install the device
270 	 */
271 	compile_dev_ops(ops);
272 	devfs_dev = devfs_new_cdev(ops, minor, NULL);
273 	devfs_dev->si_perms = perms;
274 	devfs_dev->si_uid = uid;
275 	devfs_dev->si_gid = gid;
276 
277 	/*
278 	 * Set additional fields (XXX DEVFS interface goes here)
279 	 */
280 	__va_start(ap, fmt);
281 	kvsnrprintf(devfs_dev->si_name, sizeof(devfs_dev->si_name),
282 		    32, fmt, ap);
283 	__va_end(ap);
284 
285 	reference_dev(devfs_dev);
286 
287 	return (devfs_dev);
288 }
289 
290 cdev_t
291 make_only_dev_covering(struct dev_ops *ops, struct dev_ops *bops, int minor,
292 	uid_t uid, gid_t gid, int perms, const char *fmt, ...)
293 {
294 	cdev_t	devfs_dev;
295 	__va_list ap;
296 
297 	/*
298 	 * compile the cdevsw and install the device
299 	 */
300 	compile_dev_ops(ops);
301 	devfs_dev = devfs_new_cdev(ops, minor, bops);
302 	devfs_dev->si_perms = perms;
303 	devfs_dev->si_uid = uid;
304 	devfs_dev->si_gid = gid;
305 
306 	/*
307 	 * Set additional fields (XXX DEVFS interface goes here)
308 	 */
309 	__va_start(ap, fmt);
310 	kvsnrprintf(devfs_dev->si_name, sizeof(devfs_dev->si_name),
311 		    32, fmt, ap);
312 	__va_end(ap);
313 
314 	reference_dev(devfs_dev);
315 
316 	return (devfs_dev);
317 }
318 
319 void
320 destroy_only_dev(cdev_t dev)
321 {
322 	release_dev(dev);
323 	release_dev(dev);
324 	release_dev(dev);
325 }
326 
327 /*
328  * destroy_dev() removes the adhoc association for a device and revectors
329  * its ops to &dead_dev_ops.
330  *
331  * This routine releases the reference count associated with the ADHOC
332  * entry, plus releases the reference count held by the caller.  What this
333  * means is that you should not call destroy_dev(make_dev(...)), because
334  * make_dev() does not bump the reference count (beyond what it needs to
335  * create the ad-hoc association).  Any procedure that intends to destroy
336  * a device must have its own reference to it first.
337  */
338 void
339 destroy_dev(cdev_t dev)
340 {
341 	if (dev) {
342 		devfs_debug(DEVFS_DEBUG_DEBUG,
343 			    "destroy_dev called for %s\n",
344 			    dev->si_name);
345 		devfs_destroy_dev(dev);
346 	}
347 }
348 
349 /*
350  * Make sure all asynchronous disk and devfs related operations have
351  * completed.
352  *
353  * Typically called prior to mountroot to ensure that all disks have
354  * been completely probed and on module unload to ensure that ops
355  * structures have been dereferenced.
356  */
357 void
358 sync_devs(void)
359 {
360 	disk_config(NULL);
361 	devfs_config();
362 	disk_config(NULL);
363 	devfs_config();
364 }
365 
366 int
367 make_dev_alias(cdev_t target, const char *fmt, ...)
368 {
369 	__va_list ap;
370 	char *name;
371 
372 	__va_start(ap, fmt);
373 	kvasnrprintf(&name, PATH_MAX, 32, fmt, ap);
374 	__va_end(ap);
375 
376 	devfs_make_alias(name, target);
377 	kvasfree(&name);
378 
379 	return 0;
380 }
381 
382 int
383 destroy_dev_alias(cdev_t target, const char *fmt, ...)
384 {
385 	__va_list ap;
386 	char *name;
387 
388 	__va_start(ap, fmt);
389 	kvasnrprintf(&name, PATH_MAX, 32, fmt, ap);
390 	__va_end(ap);
391 
392 	devfs_destroy_alias(name, target);
393 	kvasfree(&name);
394 
395 	return 0;
396 }
397 
398 extern struct dev_ops default_dev_ops;
399 
400 cdev_t
401 make_autoclone_dev(struct dev_ops *ops, struct devfs_bitmap *bitmap,
402 		d_clone_t *nhandler, uid_t uid, gid_t gid, int perms, const char *fmt, ...)
403 {
404 	__va_list ap;
405 	cdev_t dev;
406 	char *name;
407 
408 	__va_start(ap, fmt);
409 	kvasnrprintf(&name, PATH_MAX, 32, fmt, ap);
410 	__va_end(ap);
411 
412 	if (bitmap != NULL)
413 		devfs_clone_bitmap_init(bitmap);
414 
415 	devfs_clone_handler_add(name, nhandler);
416 	dev = make_dev_covering(&default_dev_ops, ops, 0xffff00ff,
417 		       uid, gid, perms, "%s", name);
418 	kvasfree(&name);
419 	return dev;
420 }
421 
422 void
423 destroy_autoclone_dev(cdev_t dev, struct devfs_bitmap *bitmap)
424 {
425 	if (dev == NULL)
426 		return;
427 
428 	devfs_clone_handler_del(dev->si_name);
429 
430 	if (bitmap != NULL)
431 		devfs_clone_bitmap_uninit(bitmap);
432 
433 	destroy_dev(dev);
434 }
435 
436 
437 /*
438  * Add a reference to a device.  Callers generally add their own references
439  * when they are going to store a device node in a variable for long periods
440  * of time, to prevent a disassociation from free()ing the node.
441  *
442  * Also note that a caller that intends to call destroy_dev() must first
443  * obtain a reference on the device.  The ad-hoc reference you get with
444  * make_dev() and friends is NOT sufficient to be able to call destroy_dev().
445  */
446 cdev_t
447 reference_dev(cdev_t dev)
448 {
449 	//kprintf("reference_dev\n");
450 
451 	if (dev != NULL) {
452 		sysref_get(&dev->si_sysref);
453 		if (dev_ref_debug & 2) {
454 			kprintf("reference dev %p %s(minor=%08x) refs=%d\n",
455 			    dev, devtoname(dev), dev->si_uminor,
456 			    dev->si_sysref.refcnt);
457 		}
458 	}
459 	return(dev);
460 }
461 
462 /*
463  * release a reference on a device.  The device will be terminated when the
464  * last reference has been released.
465  *
466  * NOTE: we must use si_umajor to figure out the original major number,
467  * because si_ops could already be pointing at dead_dev_ops.
468  */
469 void
470 release_dev(cdev_t dev)
471 {
472 	//kprintf("release_dev\n");
473 
474 	if (dev == NULL)
475 		return;
476 	sysref_put(&dev->si_sysref);
477 }
478 
479 const char *
480 devtoname(cdev_t dev)
481 {
482 	int mynor;
483 	int len;
484 	char *p;
485 	const char *dname;
486 
487 	if (dev == NULL)
488 		return("#nodev");
489 	if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') {
490 		p = dev->si_name;
491 		len = sizeof(dev->si_name);
492 		if ((dname = dev_dname(dev)) != NULL)
493 			ksnprintf(p, len, "#%s/", dname);
494 		else
495 			ksnprintf(p, len, "#%d/", major(dev));
496 		len -= strlen(p);
497 		p += strlen(p);
498 		mynor = minor(dev);
499 		if (mynor < 0 || mynor > 255)
500 			ksnprintf(p, len, "%#x", (u_int)mynor);
501 		else
502 			ksnprintf(p, len, "%d", mynor);
503 	}
504 	return (dev->si_name);
505 }
506 
507