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/fs/devfs/devfs_devs.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  * Copyright (c) 2000,2004
    3  *      Poul-Henning Kamp.  All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Neither the name of the University nor the names of its contributors
   11  *    may be used to endorse or promote products derived from this software
   12  *    without specific prior written permission.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  *
   26  * From: FreeBSD: src/sys/miscfs/kernfs/kernfs_vfsops.c 1.36
   27  *
   28  * $FreeBSD: releng/5.3/sys/fs/devfs/devfs_devs.c 130678 2004-06-18 08:08:47Z phk $
   29  */
   30 
   31 #include "opt_devfs.h"
   32 #include "opt_mac.h"
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/conf.h>
   37 #include <sys/dirent.h>
   38 #include <sys/kernel.h>
   39 #include <sys/lock.h>
   40 #include <sys/mac.h>
   41 #include <sys/malloc.h>
   42 #include <sys/proc.h>
   43 #include <sys/sysctl.h>
   44 #include <sys/vnode.h>
   45 
   46 #include <machine/atomic.h>
   47 
   48 #include <fs/devfs/devfs.h>
   49 
   50 static struct cdev *devfs_inot[NDEVFSINO];
   51 static struct cdev **devfs_overflow;
   52 static int devfs_ref[NDEVFSINO];
   53 static int *devfs_refoverflow;
   54 static int devfs_nextino = 3;
   55 static int devfs_numino;
   56 static int devfs_topino;
   57 static int devfs_noverflowwant = NDEVFSOVERFLOW;
   58 static int devfs_noverflow;
   59 static unsigned devfs_generation;
   60 
   61 static struct devfs_dirent *devfs_find (struct devfs_dirent *dd, const char *name, int namelen);
   62 
   63 SYSCTL_NODE(_vfs, OID_AUTO, devfs, CTLFLAG_RW, 0, "DEVFS filesystem");
   64 SYSCTL_UINT(_vfs_devfs, OID_AUTO, noverflow, CTLFLAG_RW,
   65         &devfs_noverflowwant, 0, "Size of DEVFS overflow table");
   66 SYSCTL_UINT(_vfs_devfs, OID_AUTO, generation, CTLFLAG_RD,
   67         &devfs_generation, 0, "DEVFS generation number");
   68 SYSCTL_UINT(_vfs_devfs, OID_AUTO, inodes, CTLFLAG_RD,
   69         &devfs_numino, 0, "DEVFS inodes");
   70 SYSCTL_UINT(_vfs_devfs, OID_AUTO, topinode, CTLFLAG_RD,
   71         &devfs_topino, 0, "DEVFS highest inode#");
   72 
   73 static int *
   74 devfs_itor(int inode)
   75 {
   76         if (inode < NDEVFSINO)
   77                 return (&devfs_ref[inode]);
   78         else if (inode < NDEVFSINO + devfs_noverflow)
   79                 return (&devfs_refoverflow[inode - NDEVFSINO]);
   80         else
   81                 panic ("YRK!");
   82 }
   83 
   84 static void
   85 devfs_dropref(int inode)
   86 {
   87         int *ip;
   88 
   89         ip = devfs_itor(inode);
   90         atomic_add_int(ip, -1);
   91 }
   92 
   93 static int
   94 devfs_getref(int inode)
   95 {
   96         int *ip, i, j;
   97         struct cdev **dp;
   98 
   99         ip = devfs_itor(inode);
  100         dp = devfs_itod(inode);
  101         for (;;) {
  102                 i = *ip;
  103                 j = i + 1;
  104                 if (!atomic_cmpset_int(ip, i, j))
  105                         continue;
  106                 if (*dp != NULL)
  107                         return (1);
  108                 atomic_add_int(ip, -1);
  109                 return(0);
  110         }
  111 }
  112 
  113 struct devfs_dirent **
  114 devfs_itode (struct devfs_mount *dm, int inode)
  115 {
  116 
  117         if (inode < NDEVFSINO)
  118                 return (&dm->dm_dirent[inode]);
  119         if (devfs_overflow == NULL)
  120                 return (NULL);
  121         if (inode < NDEVFSINO + devfs_noverflow)
  122                 return (&dm->dm_overflow[inode - NDEVFSINO]);
  123         return (NULL);
  124 }
  125 
  126 struct cdev **
  127 devfs_itod (int inode)
  128 {
  129 
  130         if (inode < NDEVFSINO)
  131                 return (&devfs_inot[inode]);
  132         if (devfs_overflow == NULL)
  133                 return (NULL);
  134         if (inode < NDEVFSINO + devfs_noverflow)
  135                 return (&devfs_overflow[inode - NDEVFSINO]);
  136         return (NULL);
  137 }
  138 
  139 static struct devfs_dirent *
  140 devfs_find(struct devfs_dirent *dd, const char *name, int namelen)
  141 {
  142         struct devfs_dirent *de;
  143 
  144         TAILQ_FOREACH(de, &dd->de_dlist, de_list) {
  145                 if (namelen != de->de_dirent->d_namlen)
  146                         continue;
  147                 if (bcmp(name, de->de_dirent->d_name, namelen) != 0)
  148                         continue;
  149                 break;
  150         }
  151         return (de);
  152 }
  153 
  154 struct devfs_dirent *
  155 devfs_newdirent(char *name, int namelen)
  156 {
  157         int i;
  158         struct devfs_dirent *de;
  159         struct dirent d;
  160 
  161         d.d_namlen = namelen;
  162         i = sizeof (*de) + GENERIC_DIRSIZ(&d);
  163         MALLOC(de, struct devfs_dirent *, i, M_DEVFS, M_WAITOK | M_ZERO);
  164         de->de_dirent = (struct dirent *)(de + 1);
  165         de->de_dirent->d_namlen = namelen;
  166         de->de_dirent->d_reclen = GENERIC_DIRSIZ(&d);
  167         bcopy(name, de->de_dirent->d_name, namelen);
  168         de->de_dirent->d_name[namelen] = '\0';
  169         vfs_timestamp(&de->de_ctime);
  170         de->de_mtime = de->de_atime = de->de_ctime;
  171         de->de_links = 1;
  172 #ifdef MAC
  173         mac_init_devfsdirent(de);
  174 #endif
  175         return (de);
  176 }
  177 
  178 struct devfs_dirent *
  179 devfs_vmkdir(char *name, int namelen, struct devfs_dirent *dotdot)
  180 {
  181         struct devfs_dirent *dd;
  182         struct devfs_dirent *de;
  183 
  184         dd = devfs_newdirent(name, namelen);
  185 
  186         TAILQ_INIT(&dd->de_dlist);
  187 
  188         dd->de_dirent->d_type = DT_DIR;
  189         dd->de_mode = 0555;
  190         dd->de_links = 2;
  191         dd->de_dir = dd;
  192 
  193         de = devfs_newdirent(".", 1);
  194         de->de_dirent->d_type = DT_DIR;
  195         de->de_dir = dd;
  196         de->de_flags |= DE_DOT;
  197         TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
  198 
  199         de = devfs_newdirent("..", 2);
  200         de->de_dirent->d_type = DT_DIR;
  201         if (dotdot == NULL)
  202                 de->de_dir = dd;
  203         else
  204                 de->de_dir = dotdot;
  205         de->de_flags |= DE_DOTDOT;
  206         TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
  207 
  208         return (dd);
  209 }
  210 
  211 static void
  212 devfs_delete(struct devfs_dirent *dd, struct devfs_dirent *de)
  213 {
  214 
  215         if (de->de_symlink) {
  216                 FREE(de->de_symlink, M_DEVFS);
  217                 de->de_symlink = NULL;
  218         }
  219         if (de->de_vnode)
  220                 de->de_vnode->v_data = NULL;
  221         TAILQ_REMOVE(&dd->de_dlist, de, de_list);
  222 #ifdef MAC
  223         mac_destroy_devfsdirent(de);
  224 #endif
  225         FREE(de, M_DEVFS);
  226 }
  227 
  228 void
  229 devfs_purge(struct devfs_dirent *dd)
  230 {
  231         struct devfs_dirent *de;
  232 
  233         for (;;) {
  234                 de = TAILQ_FIRST(&dd->de_dlist);
  235                 if (de == NULL)
  236                         break;
  237                 devfs_delete(dd, de);
  238         }
  239         FREE(dd, M_DEVFS);
  240 }
  241 
  242 
  243 int
  244 devfs_populate(struct devfs_mount *dm)
  245 {
  246         int i, j;
  247         struct cdev *dev, *pdev;
  248         struct devfs_dirent *dd;
  249         struct devfs_dirent *de, **dep;
  250         char *q, *s;
  251 
  252         if (dm->dm_generation == devfs_generation)
  253                 return (0);
  254         lockmgr(&dm->dm_lock, LK_UPGRADE, 0, curthread);
  255         if (devfs_noverflow && dm->dm_overflow == NULL) {
  256                 i = devfs_noverflow * sizeof (struct devfs_dirent *);
  257                 MALLOC(dm->dm_overflow, struct devfs_dirent **, i,
  258                         M_DEVFS, M_WAITOK | M_ZERO);
  259         }
  260         while (dm->dm_generation != devfs_generation) {
  261                 dm->dm_generation = devfs_generation;
  262                 for (i = 0; i <= devfs_topino; i++) {
  263                         dev = *devfs_itod(i);
  264                         dep = devfs_itode(dm, i);
  265                         de = *dep;
  266                         if (dev == NULL && de == DE_DELETED) {
  267                                 *dep = NULL;
  268                                 continue;
  269                         }
  270                         if (dev == NULL && de != NULL) {
  271                                 dd = de->de_dir;
  272                                 *dep = NULL;
  273                                 TAILQ_REMOVE(&dd->de_dlist, de, de_list);
  274                                 if (de->de_vnode)
  275                                         de->de_vnode->v_data = NULL;
  276                                 FREE(de, M_DEVFS);
  277                                 devfs_dropref(i);
  278                                 continue;
  279                         }
  280                         if (dev == NULL)
  281                                 continue;
  282                         if (de != NULL)
  283                                 continue;
  284                         if (!devfs_getref(i))
  285                                 continue;
  286                         dd = dm->dm_basedir;
  287                         s = dev->si_name;
  288                         for (;;) {
  289                                 for (q = s; *q != '/' && *q != '\0'; q++)
  290                                         continue;
  291                                 if (*q != '/')
  292                                         break;
  293                                 de = devfs_find(dd, s, q - s);
  294                                 if (de == NULL) {
  295                                         de = devfs_vmkdir(s, q - s, dd);
  296 #ifdef MAC
  297                                         mac_create_devfs_directory(
  298                                             dm->dm_mount, s, q - s, de);
  299 #endif
  300                                         de->de_inode = dm->dm_inode++;
  301                                         TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
  302                                         dd->de_links++;
  303                                 }
  304                                 s = q + 1;
  305                                 dd = de;
  306                         }
  307                         de = devfs_newdirent(s, q - s);
  308                         if (dev->si_flags & SI_ALIAS) {
  309                                 de->de_inode = dm->dm_inode++;
  310                                 de->de_uid = 0;
  311                                 de->de_gid = 0;
  312                                 de->de_mode = 0755;
  313                                 de->de_dirent->d_type = DT_LNK;
  314                                 pdev = dev->si_parent;
  315                                 j = strlen(pdev->si_name) + 1;
  316                                 MALLOC(de->de_symlink, char *, j, M_DEVFS, M_WAITOK);
  317                                 bcopy(pdev->si_name, de->de_symlink, j);
  318                         } else {
  319                                 de->de_inode = i;
  320                                 de->de_uid = dev->si_uid;
  321                                 de->de_gid = dev->si_gid;
  322                                 de->de_mode = dev->si_mode;
  323                                 de->de_dirent->d_type = DT_CHR;
  324                         }
  325 #ifdef MAC
  326                         mac_create_devfs_device(dm->dm_mount, dev, de);
  327 #endif
  328                         *dep = de;
  329                         de->de_dir = dd;
  330                         devfs_rules_apply(dm, de);
  331                         TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
  332                 }
  333         }
  334         lockmgr(&dm->dm_lock, LK_DOWNGRADE, 0, curthread);
  335         return (0);
  336 }
  337 
  338 /*
  339  * devfs_create() and devfs_destroy() are called from kern_conf.c and
  340  * in both cases the devlock() mutex is held, so no further locking
  341  * is necesary and no sleeping allowed.
  342  */
  343 
  344 void
  345 devfs_create(struct cdev *dev)
  346 {
  347         int ino, i, *ip;
  348         struct cdev **dp;
  349         struct cdev **ot;
  350         int *or;
  351         int n;
  352 
  353         for (;;) {
  354                 /* Grab the next inode number */
  355                 ino = devfs_nextino;
  356                 i = ino + 1;
  357                 /* wrap around when we reach the end */
  358                 if (i >= NDEVFSINO + devfs_noverflow)
  359                         i = 3;
  360                 devfs_nextino = i;
  361 
  362                 /* see if it was occupied */
  363                 dp = devfs_itod(ino);
  364                 KASSERT(dp != NULL, ("DEVFS: No devptr inode %d", ino));
  365                 if (*dp != NULL)
  366                         continue;
  367                 ip = devfs_itor(ino);
  368                 KASSERT(ip != NULL, ("DEVFS: No iptr inode %d", ino));
  369                 if (*ip != 0)
  370                         continue;
  371                 break;
  372         }
  373 
  374         *dp = dev;
  375         dev->si_inode = ino;
  376         if (i > devfs_topino)
  377                 devfs_topino = i;
  378 
  379         devfs_numino++;
  380         devfs_generation++;
  381 
  382         if (devfs_overflow != NULL || devfs_numino + 100 < NDEVFSINO)
  383                 return;
  384 
  385         /*
  386          * Try to allocate overflow table
  387          * XXX: we can probably be less panicy these days and a linked
  388          * XXX: list of PAGESIZE/PTRSIZE entries might be a better idea.
  389          *
  390          * XXX: we may be into witness unlove here.
  391          */
  392         n = devfs_noverflowwant;
  393         ot = malloc(sizeof(*ot) * n, M_DEVFS, M_NOWAIT | M_ZERO);
  394         if (ot == NULL)
  395                 return;
  396         or = malloc(sizeof(*or) * n, M_DEVFS, M_NOWAIT | M_ZERO);
  397         if (or == NULL) {
  398                 free(ot, M_DEVFS);
  399                 return;
  400         }
  401         devfs_overflow = ot;
  402         devfs_refoverflow = or;
  403         devfs_noverflow = n;
  404         printf("DEVFS Overflow table with %d entries allocated\n", n);
  405         return;
  406 }
  407 
  408 void
  409 devfs_destroy(struct cdev *dev)
  410 {
  411         int ino;
  412         struct cdev **dp;
  413 
  414         ino = dev->si_inode;
  415         dev->si_inode = 0;
  416         if (ino == 0)
  417                 return;
  418         dp = devfs_itod(ino);
  419         KASSERT(*dp == dev,
  420             ("DEVFS: destroying wrong cdev ino %d", ino));
  421         *dp = NULL;
  422         devfs_numino--;
  423         devfs_generation++;
  424         if (ino < devfs_nextino)
  425                 devfs_nextino = ino;
  426 }

Cache object: 9bdc7385c4921d85fb32b9f45839918f


[ 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.