The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_conf.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 97a16c0cdc7cd304d19e989d6462fdfc


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.