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_rule.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) 2002 Dima Dorfman.
    3  * 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. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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  * $FreeBSD$
   27  */
   28 
   29 /*
   30  * DEVFS ruleset implementation.
   31  *
   32  * A note on terminology: To "run" a rule on a dirent is to take the
   33  * prescribed action; to "apply" a rule is to check whether it matches
   34  * a dirent and run if if it does.
   35  *
   36  * A note on locking: Only foreign entry points (non-static functions)
   37  * should deal with locking.  Everything else assumes we already hold
   38  * the required kind of lock.
   39  *
   40  * A note on namespace: devfs_rules_* are the non-static functions for
   41  * the entire "ruleset" subsystem, devfs_rule_* are the static
   42  * functions that operate on rules, and devfs_ruleset_* are the static
   43  * functions that operate on rulesets.  The line between the last two
   44  * isn't always clear, but the guideline is still useful.
   45  *
   46  * A note on "special" identifiers: Ruleset 0 is the NULL, or empty,
   47  * ruleset; it cannot be deleted or changed in any way.  This may be
   48  * assumed inside the code; e.g., a ruleset of 0 may be interpeted to
   49  * mean "no ruleset".  The interpretation of rule 0 is
   50  * command-dependent, but in no case is there a real rule with number
   51  * 0.
   52  *
   53  * A note on errno codes: To make it easier for the userland to tell
   54  * what went wrong, we sometimes use errno codes that are not entirely
   55  * appropriate for the error but that would be less ambiguous than the
   56  * appropriate "generic" code.  For example, when we can't find a
   57  * ruleset, we return ESRCH instead of ENOENT (except in
   58  * DEVFSIO_{R,S}GETNEXT, where a nonexistent ruleset means "end of
   59  * list", and the userland expects ENOENT to be this indicator); this
   60  * way, when an operation fails, it's clear that what couldn't be
   61  * found is a ruleset and not a rule (well, it's clear to those who
   62  * know the convention).
   63  */
   64 
   65 #include "opt_devfs.h"
   66 
   67 #include <sys/param.h>
   68 #include <sys/systm.h>
   69 #include <sys/conf.h>
   70 #include <sys/kernel.h>
   71 #include <sys/malloc.h>
   72 #include <sys/dirent.h>
   73 #include <sys/vnode.h>
   74 #include <sys/mount.h>
   75 #include <sys/ioccom.h>
   76 
   77 #include <fs/devfs/devfs.h>
   78 
   79 
   80 /*
   81  * Kernel version of devfs_rule.
   82  */
   83 struct devfs_krule {
   84         SLIST_ENTRY(devfs_krule) dk_list;
   85         struct devfs_ruleset *dk_ruleset;
   86         struct devfs_rule dk_rule;
   87 };
   88 
   89 /*
   90  * Structure to describe a ruleset.
   91  */
   92 struct devfs_ruleset {
   93         SLIST_ENTRY(devfs_ruleset) ds_list;
   94         devfs_rsnum ds_number;
   95         SLIST_HEAD(, devfs_krule) ds_rules;
   96         int     ds_refcount;
   97         int     ds_flags;
   98 #define DS_IMMUTABLE    0x001
   99         int     ds_running;
  100 };
  101 
  102 static devfs_rid devfs_rid_input(devfs_rid rid, struct devfs_mount *dm);
  103 
  104 static void devfs_rule_applyde(struct devfs_krule *dk,struct devfs_dirent *de);
  105 static void devfs_rule_applyde_recursive(struct devfs_krule *dk,
  106                 struct devfs_dirent *de);
  107 static void devfs_rule_applydm(struct devfs_krule *dk, struct devfs_mount *dm);
  108 static int  devfs_rule_autonumber(struct devfs_ruleset *ds, devfs_rnum *rnp);
  109 static struct devfs_krule *devfs_rule_byid(devfs_rid rid);
  110 static int  devfs_rule_delete(struct devfs_krule **dkp);
  111 static struct cdev *devfs_rule_getdev(struct devfs_dirent *de);
  112 static int  devfs_rule_input(struct devfs_rule *dr, struct devfs_mount *dm);
  113 static int  devfs_rule_insert(struct devfs_rule *dr);
  114 static int  devfs_rule_match(struct devfs_krule *dk, struct devfs_dirent *de);
  115 static int  devfs_rule_matchpath(struct devfs_krule *dk,
  116                 struct devfs_dirent *de);
  117 static void devfs_rule_run(struct devfs_krule *dk, struct devfs_dirent *de);
  118 
  119 static void devfs_ruleset_applyde(struct devfs_ruleset *ds,
  120                 struct devfs_dirent *de);
  121 static void devfs_ruleset_applydm(struct devfs_ruleset *ds,
  122                 struct devfs_mount *dm);
  123 static struct devfs_ruleset *devfs_ruleset_bynum(devfs_rsnum rsnum);
  124 static struct devfs_ruleset *devfs_ruleset_create(devfs_rsnum rsnum);
  125 static void devfs_ruleset_destroy(struct devfs_ruleset **dsp);
  126 static void devfs_ruleset_reap(struct devfs_ruleset **dsp);
  127 static int  devfs_ruleset_use(devfs_rsnum rsnum, struct devfs_mount *dm);
  128 
  129 static SLIST_HEAD(, devfs_ruleset) devfs_rulesets;
  130 
  131 /*
  132  * Called to apply the proper rules for de before the latter can be
  133  * exposed to the userland.  This should be called with an exclusive
  134  * lock on dm in case we need to run anything.
  135  */
  136 void
  137 devfs_rules_apply(struct devfs_mount *dm, struct devfs_dirent *de)
  138 {
  139         struct devfs_ruleset *ds;
  140 
  141         ds = devfs_ruleset_bynum(dm->dm_ruleset);
  142         KASSERT(ds != NULL, ("mount-point has NULL ruleset"));
  143         devfs_ruleset_applyde(ds, de);
  144 }
  145 
  146 /*
  147  * Rule subsystem SYSINIT hook.
  148  */
  149 static void
  150 devfs_rules_init(void *junk __unused)
  151 {
  152         struct devfs_ruleset *ds;
  153 
  154         SLIST_INIT(&devfs_rulesets);
  155 
  156         ds = devfs_ruleset_create(0);
  157         ds->ds_flags |= DS_IMMUTABLE;
  158         ds->ds_refcount = 1;            /* Prevent reaping. */
  159 }
  160 
  161 SYSINIT(devfs_rules, SI_SUB_DEVFS, SI_ORDER_FIRST, devfs_rules_init, NULL);
  162 
  163 /*
  164  * Rule subsystem ioctl hook.
  165  */
  166 int
  167 devfs_rules_ioctl(struct mount *mp, u_long cmd, caddr_t data, struct thread *td)
  168 {
  169         struct devfs_mount *dm = VFSTODEVFS(mp);
  170         struct devfs_ruleset *ds;
  171         struct devfs_krule *dk;
  172         struct devfs_rule *dr;
  173         devfs_rsnum rsnum;
  174         devfs_rnum rnum;
  175         devfs_rid rid;
  176         int error;
  177 
  178         /*
  179          * XXX: This returns an error regardless of whether we
  180          * actually support the cmd or not.
  181          */
  182         error = suser(td);
  183         if (error != 0)
  184                 return (error);
  185 
  186         lockmgr(&dm->dm_lock, LK_SHARED, 0, td);
  187 
  188         switch (cmd) {
  189         case DEVFSIO_RADD:
  190                 dr = (struct devfs_rule *)data;
  191                 error = devfs_rule_input(dr, dm);
  192                 if (error != 0)
  193                         goto out;
  194                 dk = devfs_rule_byid(dr->dr_id);
  195                 if (dk != NULL) {
  196                         error = EEXIST;
  197                         goto out;
  198                 }
  199                 lockmgr(&dm->dm_lock, LK_UPGRADE, 0, td);
  200                 error = devfs_rule_insert(dr);
  201                 break;
  202         case DEVFSIO_RAPPLY:
  203                 dr = (struct devfs_rule *)data;
  204                 error = devfs_rule_input(dr, dm);
  205                 if (error != 0)
  206                         goto out;
  207 
  208                 /*
  209                  * This is one of many possible hackish
  210                  * implementations.  The primary contender is an
  211                  * implementation where the rule we read in is
  212                  * temporarily inserted into some ruleset, perhaps
  213                  * with a hypothetical DRO_NOAUTO flag so that it
  214                  * doesn't get used where it isn't intended, and
  215                  * applied in the normal way.  This can be done in the
  216                  * userland (DEVFSIO_ADD, DEVFSIO_APPLYID,
  217                  * DEVFSIO_DEL) or in the kernel; either way it breaks
  218                  * some corner case assumptions in other parts of the
  219                  * code (not that this implementation doesn't do
  220                  * that).
  221                  */
  222                 if (dr->dr_iacts & DRA_INCSET &&
  223                     devfs_ruleset_bynum(dr->dr_incset) == NULL) {
  224                         error = ESRCH;
  225                         goto out;
  226                 }
  227                 dk = malloc(sizeof(*dk), M_TEMP, M_WAITOK | M_ZERO);
  228                 memcpy(&dk->dk_rule, dr, sizeof(*dr));
  229                 lockmgr(&dm->dm_lock, LK_UPGRADE, 0, td);
  230                 devfs_rule_applydm(dk, dm);
  231                 lockmgr(&dm->dm_lock, LK_DOWNGRADE, 0, td);
  232                 free(dk, M_TEMP);
  233                 error = 0;
  234                 break;
  235         case DEVFSIO_RAPPLYID:
  236                 rid = *(devfs_rid *)data;
  237                 rid = devfs_rid_input(rid, dm);
  238                 dk = devfs_rule_byid(rid);
  239                 if (dk == NULL) {
  240                         error = ENOENT;
  241                         goto out;
  242                 }
  243                 lockmgr(&dm->dm_lock, LK_UPGRADE, 0, td);
  244                 devfs_rule_applydm(dk, dm);
  245                 error = 0;
  246                 break;
  247         case DEVFSIO_RDEL:
  248                 rid = *(devfs_rid *)data;
  249                 rid = devfs_rid_input(rid, dm);
  250                 dk = devfs_rule_byid(rid);
  251                 if (dk == NULL) {
  252                         error = ENOENT;
  253                         goto out;
  254                 }
  255                 ds = dk->dk_ruleset;
  256                 lockmgr(&dm->dm_lock, LK_UPGRADE, 0, td);
  257                 error = devfs_rule_delete(&dk);
  258                 devfs_ruleset_reap(&ds);
  259                 break;
  260         case DEVFSIO_RGETNEXT:
  261                 dr = (struct devfs_rule *)data;
  262                 error = devfs_rule_input(dr, dm);
  263                 if (error != 0)
  264                         goto out;
  265                 /*
  266                  * We can't use devfs_rule_byid() here since that
  267                  * requires the rule specified to exist, but we want
  268                  * getnext(N) to work whether there is a rule N or not
  269                  * (specifically, getnext(0) must work, but we should
  270                  * never have a rule 0 since the add command
  271                  * interprets 0 to mean "auto-number").
  272                  */
  273                 ds = devfs_ruleset_bynum(rid2rsn(dr->dr_id));
  274                 if (ds == NULL) {
  275                         error = ENOENT;
  276                         goto out;
  277                 }
  278                 rnum = rid2rn(dr->dr_id);
  279                 SLIST_FOREACH(dk, &ds->ds_rules, dk_list) {
  280                         if (rid2rn(dk->dk_rule.dr_id) > rnum)
  281                                 break;
  282                 }
  283                 if (dk == NULL) {
  284                         error = ENOENT;
  285                         goto out;
  286                 }
  287                 memcpy(dr, &dk->dk_rule, sizeof(*dr));
  288                 error = 0;
  289                 break;
  290         case DEVFSIO_SUSE:
  291                 rsnum = *(devfs_rsnum *)data;
  292                 lockmgr(&dm->dm_lock, LK_UPGRADE, 0, td);
  293                 error = devfs_ruleset_use(rsnum, dm);
  294                 break;
  295         case DEVFSIO_SAPPLY:
  296                 rsnum = *(devfs_rsnum *)data;
  297                 rsnum = rid2rsn(devfs_rid_input(mkrid(rsnum, 0), dm));
  298                 ds = devfs_ruleset_bynum(rsnum);
  299                 if (ds == NULL) {
  300                         error = ESRCH;
  301                         goto out;
  302                 }
  303                 lockmgr(&dm->dm_lock, LK_UPGRADE, 0, td);
  304                 devfs_ruleset_applydm(ds, dm);
  305                 error = 0;
  306                 break;
  307         case DEVFSIO_SGETNEXT:
  308                 rsnum = *(devfs_rsnum *)data;
  309                 SLIST_FOREACH(ds, &devfs_rulesets, ds_list) {
  310                         if (ds->ds_number > rsnum)
  311                                 break;
  312                 }
  313                 if (ds == NULL)
  314                         error = ENOENT;
  315                 else {
  316                         *(devfs_rsnum *)data = ds->ds_number;
  317                         error = 0;
  318                 }
  319                 break;
  320         default:
  321                 error = ENOIOCTL;
  322                 break;
  323         }
  324 
  325 out:
  326         lockmgr(&dm->dm_lock, LK_RELEASE, 0, td);
  327         return (error);
  328 }
  329 
  330 /*
  331  * Called to initialize dm_ruleset when there is a new mount-point.
  332  */
  333 void
  334 devfs_rules_newmount(struct devfs_mount *dm, struct thread *td)
  335 {
  336         struct devfs_ruleset *ds;
  337 
  338         lockmgr(&dm->dm_lock, LK_EXCLUSIVE, 0, td);
  339         /*
  340          * We can't use devfs_ruleset_use() since it will try to
  341          * decrement the refcount for the old ruleset, and there is no
  342          * old ruleset.  Making some value of ds_ruleset "special" to
  343          * mean "don't decrement refcount" is uglier than this.
  344          */
  345         ds = devfs_ruleset_bynum(0);
  346         KASSERT(ds != NULL, ("no ruleset 0"));
  347         ++ds->ds_refcount;
  348         dm->dm_ruleset = 0;
  349         lockmgr(&dm->dm_lock, LK_RELEASE, 0, td);
  350 }
  351 
  352 /*
  353  * Adjust the rule identifier to use the ruleset of dm if one isn't
  354  * explicitly specified.
  355  *
  356  * Note that after this operation, rid2rsn(rid) might still be 0, and
  357  * that's okay; ruleset 0 is a valid ruleset, but when it's read in
  358  * from the userland, it means "current ruleset for this mount-point".
  359  */
  360 static devfs_rid
  361 devfs_rid_input(devfs_rid rid, struct devfs_mount *dm)
  362 {
  363 
  364         if (rid2rsn(rid) == 0)
  365                 return (mkrid(dm->dm_ruleset, rid2rn(rid)));
  366         else
  367                 return (rid);
  368 }
  369 
  370 /*
  371  * Apply dk to de.
  372  */
  373 static void
  374 devfs_rule_applyde(struct devfs_krule *dk, struct devfs_dirent *de)
  375 {
  376 
  377         if (devfs_rule_match(dk, de))
  378                 devfs_rule_run(dk, de);
  379 }
  380 
  381 /*
  382  * Apply dk to de and everything under de.
  383  *
  384  * XXX: This method needs a function call for every nested
  385  * subdirectory in a devfs mount.  If we plan to have many of these,
  386  * we might eventually run out of kernel stack space.
  387  */
  388 static void
  389 devfs_rule_applyde_recursive(struct devfs_krule *dk, struct devfs_dirent *de)
  390 {
  391         struct devfs_dirent *de2;
  392 
  393         /* XXX: Should we apply to ourselves first or last?  Does it matter? */
  394         TAILQ_FOREACH(de2, &de->de_dlist, de_list) {
  395                 devfs_rule_applyde_recursive(dk, de2);
  396         }
  397         devfs_rule_applyde(dk, de);
  398 }
  399 
  400 /*
  401  * Apply dk to all entires in dm.
  402  */
  403 static void
  404 devfs_rule_applydm(struct devfs_krule *dk, struct devfs_mount *dm)
  405 {
  406 
  407         devfs_rule_applyde_recursive(dk, dm->dm_basedir);
  408 }
  409 
  410 /*
  411  * Automatically select a number for a new rule in ds, and write the
  412  * result into rnump.
  413  */
  414 static int
  415 devfs_rule_autonumber(struct devfs_ruleset *ds, devfs_rnum *rnump)
  416 {
  417         struct devfs_krule *dk;
  418 
  419         /* Find the last rule. */
  420         SLIST_FOREACH(dk, &ds->ds_rules, dk_list) {
  421                 if (SLIST_NEXT(dk, dk_list) == NULL)
  422                         break;
  423         }
  424         if (dk == NULL)
  425                 *rnump = 100;
  426         else {
  427                 *rnump = rid2rn(dk->dk_rule.dr_id) + 100;
  428                 /* Detect overflow. */
  429                 if (*rnump < rid2rn(dk->dk_rule.dr_id))
  430                         return (ERANGE);
  431         }
  432         KASSERT(devfs_rule_byid(mkrid(ds->ds_number, *rnump)) == NULL,
  433             ("autonumbering resulted in an already existing rule"));
  434         return (0);
  435 }
  436 
  437 /*
  438  * Find a krule by id.
  439  */
  440 static struct devfs_krule *
  441 devfs_rule_byid(devfs_rid rid)
  442 {
  443         struct devfs_ruleset *ds;
  444         struct devfs_krule *dk;
  445         devfs_rnum rn;
  446 
  447         rn = rid2rn(rid);
  448         ds = devfs_ruleset_bynum(rid2rsn(rid));
  449         if (ds == NULL)
  450                 return (NULL);
  451         SLIST_FOREACH(dk, &ds->ds_rules, dk_list) {
  452                 if (rid2rn(dk->dk_rule.dr_id) == rn)
  453                         return (dk);
  454                 else if (rid2rn(dk->dk_rule.dr_id) > rn)
  455                         break;
  456         }
  457         return (NULL);
  458 }
  459 
  460 /*
  461  * Remove dkp from any lists it may be on and remove memory associated
  462  * with it.
  463  */
  464 static int
  465 devfs_rule_delete(struct devfs_krule **dkp)
  466 {
  467         struct devfs_krule *dk = *dkp;
  468         struct devfs_ruleset *ds;
  469 
  470         if (dk->dk_rule.dr_iacts & DRA_INCSET) {
  471                 ds = devfs_ruleset_bynum(dk->dk_rule.dr_incset);
  472                 KASSERT(ds != NULL, ("DRA_INCSET but bad dr_incset"));
  473                 --ds->ds_refcount;
  474                 devfs_ruleset_reap(&ds);
  475         }
  476         SLIST_REMOVE(&dk->dk_ruleset->ds_rules, dk, devfs_krule, dk_list);
  477         free(dk, M_DEVFS);
  478         *dkp = NULL;
  479         return (0);
  480 }
  481 
  482 /*
  483  * Get a struct cdev *corresponding to de so we can try to match rules based
  484  * on it.  If this routine returns NULL, there is no struct cdev *associated
  485  * with the dirent (symlinks and directories don't have dev_ts), and
  486  * the caller should assume that any critera dependent on a dev_t
  487  * don't match.
  488  */
  489 static struct cdev *
  490 devfs_rule_getdev(struct devfs_dirent *de)
  491 {
  492         struct cdev **devp, *dev;
  493 
  494         devp = devfs_itod(de->de_inode);
  495         if (devp != NULL)
  496                 dev = *devp;
  497         else
  498                 dev = NULL;
  499         /* If we think this dirent should have a struct cdev *, alert the user. */
  500         if (dev == NULL && de->de_dirent->d_type != DT_LNK &&
  501             de->de_dirent->d_type != DT_DIR)
  502                 printf("Warning: no struct cdev *for %s\n", de->de_dirent->d_name);
  503         return (dev);
  504 }
  505 
  506 /*
  507  * Do what we need to do to a rule that we just loaded from the
  508  * userland.  In particular, we need to check the magic, and adjust
  509  * the ruleset appropriate if desired.
  510  */
  511 static int
  512 devfs_rule_input(struct devfs_rule *dr, struct devfs_mount *dm)
  513 {
  514 
  515         if (dr->dr_magic != DEVFS_MAGIC)
  516                 return (ERPCMISMATCH);
  517         dr->dr_id = devfs_rid_input(dr->dr_id, dm);
  518         return (0);
  519 }
  520 
  521 /*
  522  * Import dr into the appropriate place in the kernel (i.e., make a
  523  * krule).  The value of dr is copied, so the pointer may be destroyed
  524  * after this call completes.
  525  */
  526 static int
  527 devfs_rule_insert(struct devfs_rule *dr)
  528 {
  529         struct devfs_ruleset *ds, *dsi;
  530         struct devfs_krule *k1, *k2;
  531         struct devfs_krule *dk;
  532         devfs_rsnum rsnum;
  533         devfs_rnum dkrn;
  534         int error;
  535 
  536         /*
  537          * This stuff seems out of place here, but we want to do it as
  538          * soon as possible so that if it fails, we don't have to roll
  539          * back any changes we already made (e.g., ruleset creation).
  540          */
  541         if (dr->dr_iacts & DRA_INCSET) {
  542                 dsi = devfs_ruleset_bynum(dr->dr_incset);
  543                 if (dsi == NULL)
  544                         return (ESRCH);
  545         } else
  546                 dsi = NULL;
  547 
  548         rsnum = rid2rsn(dr->dr_id);
  549         ds = devfs_ruleset_bynum(rsnum);
  550         if (ds == NULL)
  551                 ds = devfs_ruleset_create(rsnum);
  552         if (ds->ds_flags & DS_IMMUTABLE)
  553                 return (EIO);
  554         dkrn = rid2rn(dr->dr_id);
  555         if (dkrn == 0) {
  556                 error = devfs_rule_autonumber(ds, &dkrn);
  557                 if (error != 0)
  558                         return (error);
  559         }
  560 
  561         dk = malloc(sizeof(*dk), M_DEVFS, M_WAITOK);
  562         dk->dk_ruleset = ds;
  563         if (dsi != NULL)
  564                 ++dsi->ds_refcount;
  565         /* XXX: Inspect dr? */
  566         memcpy(&dk->dk_rule, dr, sizeof(*dr));
  567         dk->dk_rule.dr_id = mkrid(rid2rsn(dk->dk_rule.dr_id), dkrn);
  568 
  569         k1 = SLIST_FIRST(&ds->ds_rules);
  570         if (k1 == NULL || rid2rn(k1->dk_rule.dr_id) > dkrn)
  571                 SLIST_INSERT_HEAD(&ds->ds_rules, dk, dk_list);
  572         else {
  573                 SLIST_FOREACH(k1, &ds->ds_rules, dk_list) {
  574                         k2 = SLIST_NEXT(k1, dk_list);
  575                         if (k2 == NULL || rid2rn(k2->dk_rule.dr_id) > dkrn) {
  576                                 SLIST_INSERT_AFTER(k1, dk, dk_list);
  577                                 break;
  578                         }
  579                 }
  580         }
  581 
  582         return (0);
  583 }
  584 
  585 /*
  586  * Determine whether dk matches de.  Returns 1 if dk should be run on
  587  * de; 0, otherwise.
  588  */
  589 static int
  590 devfs_rule_match(struct devfs_krule *dk, struct devfs_dirent *de)
  591 {
  592         struct devfs_rule *dr = &dk->dk_rule;
  593         struct cdev *dev;
  594 
  595         dev = devfs_rule_getdev(de);
  596         /*
  597          * At this point, if dev is NULL, we should assume that any
  598          * criteria that depend on it don't match.  We should *not*
  599          * just ignore them (i.e., act like they weren't specified),
  600          * since that makes a rule that only has criteria dependent on
  601          * the struct cdev *match all symlinks and directories.
  602          *
  603          * Note also that the following tests are somewhat reversed:
  604          * They're actually testing to see whether the condition does
  605          * *not* match, since the default is to assume the rule should
  606          * be run (such as if there are no conditions).
  607          */
  608         if (dr->dr_icond & DRC_DSWFLAGS)
  609                 if (dev == NULL ||
  610                     (dev->si_devsw->d_flags & dr->dr_dswflags) == 0)
  611                         goto nomatch;
  612         if (dr->dr_icond & DRC_PATHPTRN)
  613                 if (!devfs_rule_matchpath(dk, de))
  614                         goto nomatch;
  615         if (dr->dr_icond & DRC_MAJOR)
  616                 if (dev == NULL || major(dev) != dr->dr_major)
  617                         goto nomatch;
  618 
  619         return (1);
  620 
  621 nomatch:
  622         return (0);
  623 }
  624 
  625 /*
  626  * Determine whether dk matches de on account of dr_pathptrn.
  627  */
  628 static int
  629 devfs_rule_matchpath(struct devfs_krule *dk, struct devfs_dirent *de)
  630 {
  631         struct devfs_rule *dr = &dk->dk_rule;
  632         char *pname;
  633         struct cdev *dev;
  634 
  635         dev = devfs_rule_getdev(de);
  636         if (dev != NULL)
  637                 pname = dev->si_name;
  638         else if (de->de_dirent->d_type == DT_LNK ||
  639             de->de_dirent->d_type == DT_DIR)
  640                 pname = de->de_dirent->d_name;
  641         else
  642                 return (0);
  643         KASSERT(pname != NULL, ("devfs_rule_matchpath: NULL pname"));
  644 
  645         return (fnmatch(dr->dr_pathptrn, pname, 0) == 0);
  646 }
  647 
  648 /*
  649  * Run dk on de.
  650  */
  651 static void
  652 devfs_rule_run(struct devfs_krule *dk, struct devfs_dirent *de)
  653 {
  654         struct devfs_rule *dr = &dk->dk_rule;
  655         struct devfs_ruleset *ds;
  656 
  657         if (dr->dr_iacts & DRA_BACTS) {
  658                 if (dr->dr_bacts & DRB_HIDE)
  659                         de->de_flags |= DE_WHITEOUT;
  660                 if (dr->dr_bacts & DRB_UNHIDE)
  661                         de->de_flags &= ~DE_WHITEOUT;
  662         }
  663         if (dr->dr_iacts & DRA_UID)
  664                 de->de_uid = dr->dr_uid;
  665         if (dr->dr_iacts & DRA_GID)
  666                 de->de_gid = dr->dr_gid;
  667         if (dr->dr_iacts & DRA_MODE)
  668                 de->de_mode = dr->dr_mode;
  669         if (dr->dr_iacts & DRA_INCSET) {
  670                 ds = devfs_ruleset_bynum(dk->dk_rule.dr_incset);
  671                 KASSERT(ds != NULL, ("DRA_INCSET but bad dr_incset"));
  672                 if (ds->ds_running)
  673                         printf("Warning: avoiding loop through ruleset %d\n",
  674                             ds->ds_number);
  675                 else
  676                         devfs_ruleset_applyde(ds, de);
  677         }
  678 }
  679 
  680 /*
  681  * Apply all the rules in ds to de.
  682  */
  683 static void
  684 devfs_ruleset_applyde(struct devfs_ruleset *ds, struct devfs_dirent *de)
  685 {
  686         struct devfs_krule *dk;
  687 
  688         KASSERT(!ds->ds_running,("ruleset %d already running", ds->ds_number));
  689         ds->ds_running = 1;
  690         SLIST_FOREACH(dk, &ds->ds_rules, dk_list) {
  691                 devfs_rule_applyde(dk, de);
  692         }
  693         ds->ds_running = 0;
  694 }
  695 
  696 /*
  697  * Apply all the rules in ds to all the entires in dm.
  698  */
  699 static void
  700 devfs_ruleset_applydm(struct devfs_ruleset *ds, struct devfs_mount *dm)
  701 {
  702         struct devfs_krule *dk;
  703 
  704         KASSERT(!ds->ds_running,("ruleset %d already running", ds->ds_number));
  705         ds->ds_running = 1;
  706         /*
  707          * XXX: Does it matter whether we do
  708          *
  709          *      foreach(dk in ds)
  710          *              foreach(de in dm)
  711          *                      apply(dk to de)
  712          *
  713          * as opposed to
  714          *
  715          *      foreach(de in dm)
  716          *              foreach(dk in ds)
  717          *                      apply(dk to de)
  718          *
  719          * The end result is obviously the same, but does the order
  720          * matter?
  721          */
  722         SLIST_FOREACH(dk, &ds->ds_rules, dk_list) {
  723                 devfs_rule_applydm(dk, dm);
  724         }
  725         ds->ds_running = 0;
  726 }
  727 
  728 /*
  729  * Find a ruleset by number.
  730  */
  731 static struct devfs_ruleset *
  732 devfs_ruleset_bynum(devfs_rsnum rsnum)
  733 {
  734         struct devfs_ruleset *ds;
  735 
  736         SLIST_FOREACH(ds, &devfs_rulesets, ds_list) {
  737                 if (ds->ds_number == rsnum)
  738                         return (ds);
  739         }
  740         return (NULL);
  741 }
  742 
  743 /*
  744  * Create a new ruleset.
  745  */
  746 static struct devfs_ruleset *
  747 devfs_ruleset_create(devfs_rsnum rsnum)
  748 {
  749         struct devfs_ruleset *s1, *s2;
  750         struct devfs_ruleset *ds;
  751 
  752         KASSERT(devfs_ruleset_bynum(rsnum) == NULL,
  753             ("creating already existent ruleset %d", rsnum));
  754 
  755         ds = malloc(sizeof(*ds), M_DEVFS, M_WAITOK | M_ZERO);
  756         ds->ds_number = rsnum;
  757         ds->ds_refcount = ds->ds_flags = 0;
  758         SLIST_INIT(&ds->ds_rules);
  759 
  760         s1 = SLIST_FIRST(&devfs_rulesets);
  761         if (s1 == NULL || s1->ds_number > rsnum)
  762                 SLIST_INSERT_HEAD(&devfs_rulesets, ds, ds_list);
  763         else {
  764                 SLIST_FOREACH(s1, &devfs_rulesets, ds_list) {
  765                         s2 = SLIST_NEXT(s1, ds_list);
  766                         if (s2 == NULL || s2->ds_number > rsnum) {
  767                                 SLIST_INSERT_AFTER(s1, ds, ds_list);
  768                                 break;
  769                         }
  770                 }
  771         }
  772 
  773         return (ds);
  774 }
  775 
  776 /*
  777  * Remove a ruleset form the system.  The ruleset specified must be
  778  * empty and not in use.
  779  */
  780 static void
  781 devfs_ruleset_destroy(struct devfs_ruleset **dsp)
  782 {
  783         struct devfs_ruleset *ds = *dsp;
  784 
  785         KASSERT(SLIST_EMPTY(&ds->ds_rules), ("destroying non-empty ruleset"));
  786         KASSERT(ds->ds_refcount == 0, ("destroying busy ruleset"));
  787         KASSERT((ds->ds_flags & DS_IMMUTABLE) == 0,
  788             ("destroying immutable ruleset"));
  789 
  790         SLIST_REMOVE(&devfs_rulesets, ds, devfs_ruleset, ds_list);
  791         free(ds, M_DEVFS);
  792         *dsp = NULL;
  793 }
  794 
  795 /*
  796  * Remove a ruleset from the system if it's empty and not used
  797  * anywhere.  This should be called after every time a rule is deleted
  798  * from this ruleset or the reference count is decremented.
  799  */
  800 static void
  801 devfs_ruleset_reap(struct devfs_ruleset **dsp)
  802 {
  803         struct devfs_ruleset *ds = *dsp;
  804 
  805         if (SLIST_EMPTY(&ds->ds_rules) && ds->ds_refcount == 0) {
  806                 devfs_ruleset_destroy(&ds);
  807                 *dsp = ds;
  808         }
  809 }
  810 
  811 /*
  812  * Make rsnum the active ruleset for dm.
  813  */
  814 static int
  815 devfs_ruleset_use(devfs_rsnum rsnum, struct devfs_mount *dm)
  816 {
  817         struct devfs_ruleset *cds, *ds;
  818 
  819         ds = devfs_ruleset_bynum(rsnum);
  820         if (ds == NULL)
  821                 ds = devfs_ruleset_create(rsnum);
  822         cds = devfs_ruleset_bynum(dm->dm_ruleset);
  823         KASSERT(cds != NULL, ("mount-point has NULL ruleset"));
  824 
  825         /* These should probably be made atomic somehow. */
  826         --cds->ds_refcount;
  827         ++ds->ds_refcount;
  828         dm->dm_ruleset = rsnum;
  829 
  830         devfs_ruleset_reap(&cds);
  831         return (0);
  832 }
  833 

Cache object: 1d72d5e6e4f911a227413c639d1a658e


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