Replace NOCDEV with NULL. NOCDEV was ((void *)-1) and as inherited
[games.git] / sys / kern / kern_conf.c
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.22 2007/05/08 02:31:42 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 <machine/stdarg.h>
48
49 #include <sys/sysref2.h>
50
51 #define cdevsw_ALLOCSTART       (NUMCDEVSW/2)
52
53 static void cdev_terminate(struct cdev *dev);
54
55 MALLOC_DEFINE(M_DEVT, "cdev_t", "dev_t storage");
56
57 /*
58  * SYSREF Integration - reference counting, allocation,
59  * sysid and syslink integration.
60  */
61 static struct sysref_class     cdev_sysref_class = {
62         .name =         "cdev",
63         .mtype =        M_DEVT,
64         .proto =        SYSREF_PROTO_DEV,
65         .offset =       offsetof(struct cdev, si_sysref),
66         .objsize =      sizeof(struct cdev),
67         .mag_capacity = 32,
68         .flags =        0,
69         .ops =  {
70                 .terminate = (sysref_terminate_func_t)cdev_terminate
71         }
72 };
73
74 /*
75  * This is the number of hash-buckets.  Experiements with 'real-life'
76  * udev_t's show that a prime halfway between two powers of two works
77  * best.
78  */
79 #define DEVT_HASH 83
80 static LIST_HEAD(, cdev) dev_hash[DEVT_HASH];
81
82 static int free_devt;
83 SYSCTL_INT(_debug, OID_AUTO, free_devt, CTLFLAG_RW, &free_devt, 0, "");
84 int dev_ref_debug = 0;
85 SYSCTL_INT(_debug, OID_AUTO, dev_refs, CTLFLAG_RW, &dev_ref_debug, 0, "");
86
87 /*
88  * cdev_t and u_dev_t primitives.  Note that the major number is always
89  * extracted from si_udev, not from si_devsw, because si_devsw is replaced
90  * when a device is destroyed.
91  */
92 int
93 major(cdev_t dev)
94 {
95         if (dev == NULL)
96                 return NOUDEV;
97         return((dev->si_udev >> 8) & 0xff);
98 }
99
100 int
101 minor(cdev_t dev)
102 {
103         if (dev == NULL)
104                 return NOUDEV;
105         return(dev->si_udev & 0xffff00ff);
106 }
107
108 int
109 lminor(cdev_t dev)
110 {
111         int i;
112
113         if (dev == NULL)
114                 return NOUDEV;
115         i = minor(dev);
116         return ((i & 0xff) | (i >> 8));
117 }
118
119 /*
120  * This is a bit complex because devices are always created relative to
121  * a particular cdevsw, including 'hidden' cdevsw's (such as the raw device
122  * backing a disk subsystem overlay), so we have to compare both the
123  * devsw and udev fields to locate the correct device.
124  *
125  * The device is created if it does not already exist.  If SI_ADHOC is not
126  * set the device will be referenced (once) and SI_ADHOC will be set.
127  * The caller must explicitly add additional references to the device if
128  * the caller wishes to track additional references.
129  *
130  * NOTE: The passed ops vector must normally match the device.  This is
131  * because the kernel may create shadow devices that are INVISIBLE TO
132  * USERLAND.  For example, the block device backing a disk is created
133  * as a shadow underneath the user-visible disklabel management device.
134  * Sometimes a device ops vector can be overridden, such as by /dev/console.
135  * In this case and this case only we allow a match when the ops vector
136  * otherwise would not match.
137  */
138 static
139 cdev_t
140 hashdev(struct dev_ops *ops, int x, int y, int allow_intercept)
141 {
142         struct cdev *si;
143         udev_t  udev;
144         int hash;
145
146         udev = makeudev(x, y);
147         hash = udev % DEVT_HASH;
148         LIST_FOREACH(si, &dev_hash[hash], si_hash) {
149                 if (si->si_udev == udev) {
150                         if (si->si_ops == ops)
151                                 return (si);
152                         if (allow_intercept && (si->si_flags & SI_INTERCEPTED))
153                                 return (si);
154                 }
155         }
156         si = sysref_alloc(&cdev_sysref_class);
157         si->si_ops = ops;
158         si->si_flags |= SI_HASHED | SI_ADHOC;
159         si->si_udev = udev;
160         LIST_INSERT_HEAD(&dev_hash[hash], si, si_hash);
161         sysref_activate(&si->si_sysref);
162
163         dev_dclone(si);
164         if (ops != &dead_dev_ops)
165                 ++ops->head.refs;
166         if (dev_ref_debug) {
167                 kprintf("create    dev %p %s(minor=%08x) refs=%d\n", 
168                         si, devtoname(si), uminor(si->si_udev),
169                         si->si_sysref.refcnt);
170         }
171         return (si);
172 }
173
174 /*
175  * Convert a device pointer to a device number
176  */
177 udev_t
178 dev2udev(cdev_t dev)
179 {
180         if (dev == NULL)
181                 return NOUDEV;
182         return (dev->si_udev);
183 }
184
185 /*
186  * Convert a device number to a device pointer.  The device is referenced
187  * ad-hoc, meaning that the caller should call reference_dev() if it wishes
188  * to keep ahold of the returned structure long term.
189  *
190  * The returned device is associated with the currently installed cdevsw
191  * for the requested major number.  NULL is returned if the major number
192  * has not been registered.
193  */
194 cdev_t
195 udev2dev(udev_t x, int b)
196 {
197         cdev_t dev;
198         struct dev_ops *ops;
199
200         if (x == NOUDEV || b != 0)
201                 return(NULL);
202         ops = dev_ops_get(umajor(x), uminor(x));
203         if (ops == NULL)
204                 return(NULL);
205         dev = hashdev(ops, umajor(x), uminor(x), TRUE);
206         return(dev);
207 }
208
209 int
210 dev_is_good(cdev_t dev)
211 {
212         if (dev != NULL && dev->si_ops != &dead_dev_ops)
213                 return(1);
214         return(0);
215 }
216
217 /*
218  * Various user device number extraction and conversion routines
219  */
220 int
221 uminor(udev_t dev)
222 {
223         return(dev & 0xffff00ff);
224 }
225
226 int
227 umajor(udev_t dev)
228 {
229         return((dev & 0xff00) >> 8);
230 }
231
232 udev_t
233 makeudev(int x, int y)
234 {
235         return ((x << 8) | y);
236 }
237
238 /*
239  * Create an internal or external device.
240  *
241  * Device majors can be overloaded and used directly by the kernel without
242  * conflict, but userland will only see the particular device major that
243  * has been installed with dev_ops_add().
244  *
245  * This routine creates and returns an unreferenced ad-hoc entry for the
246  * device which will remain intact until the device is destroyed.  If the
247  * caller intends to store the device pointer it must call reference_dev()
248  * to retain a real reference to the device.
249  *
250  * If an entry already exists, this function will set (or override)
251  * its cred requirements and name (XXX DEVFS interface).
252  */
253 cdev_t
254 make_dev(struct dev_ops *ops, int minor, uid_t uid, gid_t gid, 
255         int perms, const char *fmt, ...)
256 {
257         cdev_t  dev;
258         __va_list ap;
259         int i;
260
261         /*
262          * compile the cdevsw and install the device
263          */
264         compile_dev_ops(ops);
265         dev = hashdev(ops, ops->head.maj, minor, FALSE);
266
267         /*
268          * Set additional fields (XXX DEVFS interface goes here)
269          */
270         __va_start(ap, fmt);
271         i = kvcprintf(fmt, NULL, dev->si_name, 32, ap);
272         dev->si_name[i] = '\0';
273         __va_end(ap);
274
275         return (dev);
276 }
277
278 /*
279  * This function is similar to make_dev() but no cred information or name
280  * need be specified.
281  */
282 cdev_t
283 make_adhoc_dev(struct dev_ops *ops, int minor)
284 {
285         cdev_t dev;
286
287         dev = hashdev(ops, ops->head.maj, minor, FALSE);
288         return(dev);
289 }
290
291 /*
292  * This function is similar to make_dev() except the new device is created
293  * using an old device as a template.
294  */
295 cdev_t
296 make_sub_dev(cdev_t odev, int minor)
297 {
298         cdev_t  dev;
299
300         dev = hashdev(odev->si_ops, umajor(odev->si_udev), minor, FALSE);
301
302         /*
303          * Copy cred requirements and name info XXX DEVFS.
304          */
305         if (dev->si_name[0] == 0 && odev->si_name[0])
306                 bcopy(odev->si_name, dev->si_name, sizeof(dev->si_name));
307         return (dev);
308 }
309
310 /*
311  * destroy_dev() removes the adhoc association for a device and revectors
312  * its ops to &dead_dev_ops.
313  *
314  * This routine releases the reference count associated with the ADHOC
315  * entry, plus releases the reference count held by the caller.  What this
316  * means is that you should not call destroy_dev(make_dev(...)), because
317  * make_dev() does not bump the reference count (beyond what it needs to
318  * create the ad-hoc association).  Any procedure that intends to destroy
319  * a device must have its own reference to it first.
320  */
321 void
322 destroy_dev(cdev_t dev)
323 {
324         int hash;
325
326         if (dev == NULL)
327                 return;
328         if ((dev->si_flags & SI_ADHOC) == 0) {
329                 release_dev(dev);
330                 return;
331         }
332         if (dev_ref_debug) {
333                 kprintf("destroy   dev %p %s(minor=%08x) refs=%d\n", 
334                         dev, devtoname(dev), uminor(dev->si_udev),
335                         dev->si_sysref.refcnt);
336         }
337         if (dev->si_sysref.refcnt < 2) {
338                 kprintf("destroy_dev(): too few references on device! "
339                         "%p %s(minor=%08x) refs=%d\n",
340                     dev, devtoname(dev), uminor(dev->si_udev),
341                     dev->si_sysref.refcnt);
342         }
343         dev->si_flags &= ~SI_ADHOC;
344         if (dev->si_flags & SI_HASHED) {
345                 hash = dev->si_udev % DEVT_HASH;
346                 LIST_REMOVE(dev, si_hash);
347                 dev->si_flags &= ~SI_HASHED;
348         }
349
350         /*
351          * We have to release the ops reference before we replace the
352          * device switch with dead_dev_ops.
353          */
354         if (dead_dev_ops.d_strategy == NULL)
355                 compile_dev_ops(&dead_dev_ops);
356         if (dev->si_ops && dev->si_ops != &dead_dev_ops)
357                 dev_ops_release(dev->si_ops);
358         dev->si_drv1 = NULL;
359         dev->si_drv2 = NULL;
360         dev->si_ops = &dead_dev_ops;
361         sysref_put(&dev->si_sysref);    /* release adhoc association */
362         release_dev(dev);               /* release callers reference */
363 }
364
365 /*
366  * Destroy all ad-hoc device associations associated with a domain within a
367  * device switch.  Only the minor numbers are included in the mask/match
368  * values. 
369  *
370  * Unlike the ops functions whos link structures do not contain
371  * any major bits, this function scans through the dev list via si_udev
372  * which is a 32 bit field that contains both major and minor bits.
373  * Because of this, we must mask the minor bits in the passed mask variable
374  * to allow -1 to be specified generically.
375  *
376  * The caller must not include any major bits in the match value.
377  */
378 void
379 destroy_all_devs(struct dev_ops *ops, u_int mask, u_int match)
380 {
381         int i;
382         cdev_t dev;
383         cdev_t ndev;
384
385         mask = uminor(mask);
386         for (i = 0; i < DEVT_HASH; ++i) {
387                 ndev = LIST_FIRST(&dev_hash[i]);
388                 while ((dev = ndev) != NULL) {
389                     ndev = LIST_NEXT(dev, si_hash);
390                     KKASSERT(dev->si_flags & SI_ADHOC);
391                     if (dev->si_ops == ops && 
392                         (dev->si_udev & mask) == match
393                     ) {
394                         reference_dev(dev);
395                         destroy_dev(dev);
396                     }
397                 }
398         }
399 }
400
401 /*
402  * Add a reference to a device.  Callers generally add their own references
403  * when they are going to store a device node in a variable for long periods
404  * of time, to prevent a disassociation from free()ing the node.
405  *
406  * Also note that a caller that intends to call destroy_dev() must first
407  * obtain a reference on the device.  The ad-hoc reference you get with
408  * make_dev() and friends is NOT sufficient to be able to call destroy_dev().
409  */
410 cdev_t
411 reference_dev(cdev_t dev)
412 {
413         if (dev != NULL) {
414                 sysref_get(&dev->si_sysref);
415                 if (dev_ref_debug) {
416                         kprintf("reference dev %p %s(minor=%08x) refs=%d\n", 
417                             dev, devtoname(dev), uminor(dev->si_udev),
418                             dev->si_sysref.refcnt);
419                 }
420         }
421         return(dev);
422 }
423
424 /*
425  * release a reference on a device.  The device will be terminated when the
426  * last reference has been released.
427  *
428  * NOTE: we must use si_udev to figure out the original (major, minor),
429  * because si_ops could already be pointing at dead_dev_ops.
430  */
431 void
432 release_dev(cdev_t dev)
433 {
434         if (dev == NULL)
435                 return;
436         sysref_put(&dev->si_sysref);
437 }
438
439 static
440 void
441 cdev_terminate(struct cdev *dev)
442 {
443         int messedup = 0;
444
445         if (dev_ref_debug) {
446                 kprintf("release   dev %p %s(minor=%08x) refs=%d\n", 
447                         dev, devtoname(dev), uminor(dev->si_udev),
448                         dev->si_sysref.refcnt);
449         }
450         if (dev->si_flags & SI_ADHOC) {
451                 kprintf("Warning: illegal final release on ADHOC"
452                         " device %p(%s), the device was never"
453                         " destroyed!\n",
454                         dev, devtoname(dev));
455                 messedup = 1;
456         }
457         if (dev->si_flags & SI_HASHED) {
458                 kprintf("Warning: last release on device, no call"
459                         " to destroy_dev() was made! dev %p(%s)\n",
460                         dev, devtoname(dev));
461                 reference_dev(dev);
462                 destroy_dev(dev);
463                 messedup = 1;
464         }
465         if (SLIST_FIRST(&dev->si_hlist) != NULL) {
466                 kprintf("Warning: last release on device, vnode"
467                         " associations still exist! dev %p(%s)\n",
468                         dev, devtoname(dev));
469                 messedup = 1;
470         }
471         if (dev->si_ops && dev->si_ops != &dead_dev_ops) {
472                 dev_ops_release(dev->si_ops);
473                 dev->si_ops = NULL;
474         }
475         if (messedup == 0) 
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