kernel - Provide descriptions for lwkt.* and debug.* sysctl's
[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
e4c9c0c8 56int dev_ref_debug = 0;
0c52fa62
SG
57SYSCTL_INT(_debug, OID_AUTO, dev_refs, CTLFLAG_RW, &dev_ref_debug, 0,
58 "Toggle device reference debug output");
984263bc 59
984263bc 60/*
b13267a5 61 * cdev_t and u_dev_t primitives. Note that the major number is always
0e9b9130 62 * extracted from si_umajor, not from si_devsw, because si_devsw is replaced
e4c9c0c8 63 * when a device is destroyed.
984263bc 64 */
984263bc 65int
028066b1 66major(cdev_t dev)
984263bc 67{
028066b1 68 if (dev == NULL)
984263bc 69 return NOUDEV;
0e9b9130 70 return(dev->si_umajor);
984263bc
MD
71}
72
73int
028066b1 74minor(cdev_t dev)
984263bc 75{
028066b1 76 if (dev == NULL)
984263bc 77 return NOUDEV;
0e9b9130 78 return(dev->si_uminor);
984263bc
MD
79}
80
0e9b9130
MD
81/*
82 * Compatibility function with old udev_t format to convert the
83 * non-consecutive minor space into a consecutive minor space.
84 */
984263bc 85int
028066b1 86lminor(cdev_t dev)
984263bc 87{
0e9b9130 88 int y;
984263bc 89
028066b1 90 if (dev == NULL)
984263bc 91 return NOUDEV;
0e9b9130
MD
92 y = dev->si_uminor;
93 if (y & 0x0000ff00)
94 return NOUDEV;
95 return ((y & 0xff) | (y >> 8));
984263bc
MD
96}
97
e4c9c0c8 98/*
0e9b9130
MD
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.
e4c9c0c8 102 */
984263bc 103udev_t
028066b1 104dev2udev(cdev_t dev)
984263bc 105{
028066b1 106 if (dev == NULL)
984263bc 107 return NOUDEV;
cd29885a
MD
108
109 return (udev_t)dev->si_inode;
984263bc
MD
110}
111
e4c9c0c8
MD
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
028066b1 118 * for the requested major number. NULL is returned if the major number
e4c9c0c8
MD
119 * has not been registered.
120 */
b13267a5 121cdev_t
984263bc
MD
122udev2dev(udev_t x, int b)
123{
e4c9c0c8 124 if (x == NOUDEV || b != 0)
028066b1 125 return(NULL);
cd29885a
MD
126
127 return devfs_find_device_by_udev(x);
984263bc
MD
128}
129
130int
b13267a5 131dev_is_good(cdev_t dev)
e4c9c0c8 132{
028066b1 133 if (dev != NULL && dev->si_ops != &dead_dev_ops)
e4c9c0c8
MD
134 return(1);
135 return(0);
136}
137
138/*
139 * Various user device number extraction and conversion routines
140 */
141int
984263bc
MD
142uminor(udev_t dev)
143{
0e9b9130
MD
144 if (dev == NOUDEV)
145 return(-1);
984263bc
MD
146 return(dev & 0xffff00ff);
147}
148
149int
150umajor(udev_t dev)
151{
0e9b9130
MD
152 if (dev == NOUDEV)
153 return(-1);
984263bc
MD
154 return((dev & 0xff00) >> 8);
155}
156
157udev_t
158makeudev(int x, int y)
159{
0e9b9130
MD
160 if ((x & 0xffffff00) || (y & 0x0000ff00))
161 return NOUDEV;
7cbab9da 162 return ((x << 8) | y);
984263bc
MD
163}
164
e4c9c0c8
MD
165/*
166 * Create an internal or external device.
167 *
32beb3ff
MD
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)
e4c9c0c8
MD
174 * its cred requirements and name (XXX DEVFS interface).
175 */
b13267a5 176cdev_t
07dfa375 177make_dev(struct dev_ops *ops, int minor, uid_t uid, gid_t gid,
e4c9c0c8 178 int perms, const char *fmt, ...)
984263bc 179{
cd29885a 180 cdev_t devfs_dev;
e2565a42 181 __va_list ap;
984263bc 182
e4c9c0c8
MD
183 /*
184 * compile the cdevsw and install the device
185 */
fef8985e 186 compile_dev_ops(ops);
e4c9c0c8 187
47ae500f 188 devfs_dev = devfs_new_cdev(ops, minor, NULL);
e2565a42 189 __va_start(ap, fmt);
da655383
MD
190 kvsnrprintf(devfs_dev->si_name, sizeof(devfs_dev->si_name),
191 32, fmt, ap);
e2565a42 192 __va_end(ap);
984263bc 193
aec8eea4
MD
194 devfs_debug(DEVFS_DEBUG_INFO,
195 "make_dev called for %s\n",
196 devfs_dev->si_name);
cd29885a
MD
197 devfs_create_dev(devfs_dev, uid, gid, perms);
198
199 return (devfs_dev);
984263bc
MD
200}
201
47ae500f
AH
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 */
207cdev_t
8f960aa9
AH
208make_dev_covering(struct dev_ops *ops, struct dev_ops *bops, int minor,
209 uid_t uid, gid_t gid, int perms, const char *fmt, ...)
47ae500f
AH
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
8f960aa9 219 devfs_dev = devfs_new_cdev(ops, minor, bops);
47ae500f
AH
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
cd29885a
MD
234
235cdev_t
236make_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;
cd29885a
MD
241
242 /*
243 * compile the cdevsw and install the device
244 */
245 compile_dev_ops(ops);
47ae500f 246 devfs_dev = devfs_new_cdev(ops, minor, NULL);
cd29885a
MD
247
248 /*
249 * Set additional fields (XXX DEVFS interface goes here)
250 */
251 __va_start(ap, fmt);
da655383
MD
252 kvsnrprintf(devfs_dev->si_name, sizeof(devfs_dev->si_name),
253 32, fmt, ap);
cd29885a
MD
254 __va_end(ap);
255
cd29885a
MD
256 devfs_create_dev(devfs_dev, uid, gid, perms);
257
258 return (devfs_dev);
259}
260
cd29885a
MD
261cdev_t
262make_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;
cd29885a
MD
267
268 /*
269 * compile the cdevsw and install the device
270 */
271 compile_dev_ops(ops);
47ae500f 272 devfs_dev = devfs_new_cdev(ops, minor, NULL);
cd29885a
MD
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);
da655383
MD
281 kvsnrprintf(devfs_dev->si_name, sizeof(devfs_dev->si_name),
282 32, fmt, ap);
cd29885a
MD
283 __va_end(ap);
284
285 reference_dev(devfs_dev);
286
287 return (devfs_dev);
288}
289
cc754c81
AH
290cdev_t
291make_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
cd29885a
MD
319void
320destroy_only_dev(cdev_t dev)
321{
aec8eea4
MD
322 release_dev(dev);
323 release_dev(dev);
324 release_dev(dev);
cd29885a
MD
325}
326
e4c9c0c8
MD
327/*
328 * destroy_dev() removes the adhoc association for a device and revectors
fef8985e 329 * its ops to &dead_dev_ops.
e4c9c0c8
MD
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.
217ff971 337 */
984263bc 338void
b13267a5 339destroy_dev(cdev_t dev)
984263bc 340{
3e82b46c
MD
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);
e4c9c0c8 346 }
e4c9c0c8
MD
347}
348
2a32d680
MD
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 */
357void
358sync_devs(void)
359{
360 disk_config(NULL);
361 devfs_config();
362 disk_config(NULL);
363 devfs_config();
364}
365
cd29885a
MD
366int
367make_dev_alias(cdev_t target, const char *fmt, ...)
368{
cd29885a 369 __va_list ap;
da655383 370 char *name;
cd29885a
MD
371
372 __va_start(ap, fmt);
da655383 373 kvasnrprintf(&name, PATH_MAX, 32, fmt, ap);
cd29885a
MD
374 __va_end(ap);
375
376 devfs_make_alias(name, target);
da655383 377 kvasfree(&name);
cd29885a
MD
378
379 return 0;
380}
381
8312ca30
AH
382int
383destroy_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
07dfa375
AH
398extern struct dev_ops default_dev_ops;
399
b96f3782
AH
400cdev_t
401make_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{
b96f3782 404 __va_list ap;
da655383
MD
405 cdev_t dev;
406 char *name;
b96f3782
AH
407
408 __va_start(ap, fmt);
da655383 409 kvasnrprintf(&name, PATH_MAX, 32, fmt, ap);
b96f3782
AH
410 __va_end(ap);
411
07dfa375
AH
412 if (bitmap != NULL)
413 devfs_clone_bitmap_init(bitmap);
414
b96f3782 415 devfs_clone_handler_add(name, nhandler);
8f960aa9 416 dev = make_dev_covering(&default_dev_ops, ops, 0xffff00ff,
da655383
MD
417 uid, gid, perms, "%s", name);
418 kvasfree(&name);
b96f3782
AH
419 return dev;
420}
421
07dfa375
AH
422void
423destroy_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
cd29885a 436
e4c9c0c8
MD
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 */
b13267a5
MD
446cdev_t
447reference_dev(cdev_t dev)
e4c9c0c8 448{
cd29885a
MD
449 //kprintf("reference_dev\n");
450
028066b1
MD
451 if (dev != NULL) {
452 sysref_get(&dev->si_sysref);
aec8eea4 453 if (dev_ref_debug & 2) {
07dfa375 454 kprintf("reference dev %p %s(minor=%08x) refs=%d\n",
0e9b9130 455 dev, devtoname(dev), dev->si_uminor,
028066b1 456 dev->si_sysref.refcnt);
e4c9c0c8
MD
457 }
458 }
459 return(dev);
460}
461
462/*
028066b1
MD
463 * release a reference on a device. The device will be terminated when the
464 * last reference has been released.
e4c9c0c8 465 *
0e9b9130 466 * NOTE: we must use si_umajor to figure out the original major number,
fef8985e 467 * because si_ops could already be pointing at dead_dev_ops.
e4c9c0c8
MD
468 */
469void
b13267a5 470release_dev(cdev_t dev)
e4c9c0c8 471{
cd29885a
MD
472 //kprintf("release_dev\n");
473
028066b1 474 if (dev == NULL)
e4c9c0c8 475 return;
028066b1
MD
476 sysref_put(&dev->si_sysref);
477}
478
984263bc 479const char *
b13267a5 480devtoname(cdev_t dev)
984263bc 481{
984263bc 482 int mynor;
335dda38
MD
483 int len;
484 char *p;
485 const char *dname;
984263bc 486
028066b1 487 if (dev == NULL)
e4c9c0c8 488 return("#nodev");
984263bc
MD
489 if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') {
490 p = dev->si_name;
335dda38
MD
491 len = sizeof(dev->si_name);
492 if ((dname = dev_dname(dev)) != NULL)
f8c7a42d 493 ksnprintf(p, len, "#%s/", dname);
984263bc 494 else
f8c7a42d 495 ksnprintf(p, len, "#%d/", major(dev));
335dda38 496 len -= strlen(p);
984263bc
MD
497 p += strlen(p);
498 mynor = minor(dev);
499 if (mynor < 0 || mynor > 255)
f8c7a42d 500 ksnprintf(p, len, "%#x", (u_int)mynor);
984263bc 501 else
f8c7a42d 502 ksnprintf(p, len, "%d", mynor);
984263bc
MD
503 }
504 return (dev->si_name);
505}
e4c9c0c8 506