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