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