devfs_rule.c revision 150501
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: head/sys/fs/devfs/devfs_rule.c 150501 2005-09-24 07:03:09Z phk $ 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/ioccom.h> 74#include <sys/lock.h> 75#include <sys/sx.h> 76 77#include <fs/devfs/devfs.h> 78#include <fs/devfs/devfs_int.h> 79 80/* 81 * Kernel version of devfs_rule. 82 */ 83struct devfs_krule { 84 TAILQ_ENTRY(devfs_krule) dk_list; 85 struct devfs_ruleset *dk_ruleset; 86 struct devfs_rule dk_rule; 87}; 88 89TAILQ_HEAD(rulehead, devfs_krule); 90static MALLOC_DEFINE(M_DEVFSRULE, "DEVFS_RULE", "DEVFS rule storage"); 91 92/* 93 * Structure to describe a ruleset. 94 */ 95struct devfs_ruleset { 96 TAILQ_ENTRY(devfs_ruleset) ds_list; 97 struct rulehead ds_rules; 98 devfs_rsnum ds_number; 99 int ds_refcount; 100}; 101 102static devfs_rid devfs_rid_input(devfs_rid rid, struct devfs_mount *dm); 103 104static void devfs_rule_applyde_recursive(struct devfs_krule *dk, 105 struct devfs_dirent *de); 106static void devfs_rule_applydm(struct devfs_krule *dk, struct devfs_mount *dm); 107static int devfs_rule_autonumber(struct devfs_ruleset *ds, devfs_rnum *rnp); 108static struct devfs_krule *devfs_rule_byid(devfs_rid rid); 109static int devfs_rule_delete(struct devfs_krule *dkp); 110static struct cdev *devfs_rule_getdev(struct devfs_dirent *de); 111static int devfs_rule_input(struct devfs_rule *dr, struct devfs_mount *dm); 112static int devfs_rule_insert(struct devfs_rule *dr); 113static int devfs_rule_match(struct devfs_krule *dk, struct devfs_dirent *de); 114static int devfs_rule_matchpath(struct devfs_krule *dk, 115 struct devfs_dirent *de); 116static void devfs_rule_run(struct devfs_krule *dk, struct devfs_dirent *de, unsigned depth); 117 118static void devfs_ruleset_applyde(struct devfs_ruleset *ds, 119 struct devfs_dirent *de, unsigned depth); 120static void devfs_ruleset_applydm(struct devfs_ruleset *ds, 121 struct devfs_mount *dm); 122static struct devfs_ruleset *devfs_ruleset_bynum(devfs_rsnum rsnum); 123static struct devfs_ruleset *devfs_ruleset_create(devfs_rsnum rsnum); 124static void devfs_ruleset_reap(struct devfs_ruleset *dsp); 125static int devfs_ruleset_use(devfs_rsnum rsnum, struct devfs_mount *dm); 126 127static struct sx sx_rules; 128SX_SYSINIT(sx_rules, &sx_rules, "DEVFS ruleset lock"); 129 130static TAILQ_HEAD(, devfs_ruleset) devfs_rulesets = 131 TAILQ_HEAD_INITIALIZER(devfs_rulesets); 132 133/* 134 * Called to apply the proper rules for 'de' before it can be 135 * exposed to the userland. This should be called with an exclusive 136 * lock on dm in case we need to run anything. 137 */ 138void 139devfs_rules_apply(struct devfs_mount *dm, struct devfs_dirent *de) 140{ 141 struct devfs_ruleset *ds; 142 143 if (dm->dm_ruleset == 0) 144 return; 145 sx_slock(&sx_rules); 146 ds = devfs_ruleset_bynum(dm->dm_ruleset); 147 KASSERT(ds != NULL, ("mount-point has NULL ruleset")); 148 devfs_ruleset_applyde(ds, de, devfs_rule_depth); 149 sx_sunlock(&sx_rules); 150} 151 152/* 153 * Rule subsystem ioctl hook. 154 */ 155int 156devfs_rules_ioctl(struct devfs_mount *dm, u_long cmd, caddr_t data, struct thread *td) 157{ 158 struct devfs_ruleset *ds; 159 struct devfs_krule *dk; 160 struct devfs_rule *dr; 161 devfs_rsnum rsnum; 162 devfs_rnum rnum; 163 devfs_rid rid; 164 int error; 165 166 sx_assert(&dm->dm_lock, SX_XLOCKED); 167 168 /* 169 * XXX: This returns an error regardless of whether we 170 * actually support the cmd or not. 171 */ 172 error = suser(td); 173 if (error != 0) 174 return (error); 175 176 sx_xlock(&sx_rules); 177 178 switch (cmd) { 179 case DEVFSIO_RADD: 180 dr = (struct devfs_rule *)data; 181 error = devfs_rule_input(dr, dm); 182 if (error != 0) 183 break; 184 dk = devfs_rule_byid(dr->dr_id); 185 if (dk != NULL) { 186 error = EEXIST; 187 break; 188 } 189 if (rid2rsn(dr->dr_id) == 0) 190 return (EIO); 191 error = devfs_rule_insert(dr); 192 break; 193 case DEVFSIO_RAPPLY: 194 dr = (struct devfs_rule *)data; 195 error = devfs_rule_input(dr, dm); 196 if (error != 0) 197 break; 198 199 /* 200 * This is one of many possible hackish 201 * implementations. The primary contender is an 202 * implementation where the rule we read in is 203 * temporarily inserted into some ruleset, perhaps 204 * with a hypothetical DRO_NOAUTO flag so that it 205 * doesn't get used where it isn't intended, and 206 * applied in the normal way. This can be done in the 207 * userland (DEVFSIO_ADD, DEVFSIO_APPLYID, 208 * DEVFSIO_DEL) or in the kernel; either way it breaks 209 * some corner case assumptions in other parts of the 210 * code (not that this implementation doesn't do 211 * that). 212 */ 213 if (dr->dr_iacts & DRA_INCSET && 214 devfs_ruleset_bynum(dr->dr_incset) == NULL) { 215 error = ESRCH; 216 break; 217 } 218 dk = malloc(sizeof(*dk), M_TEMP, M_WAITOK | M_ZERO); 219 memcpy(&dk->dk_rule, dr, sizeof(*dr)); 220 devfs_rule_applydm(dk, dm); 221 free(dk, M_TEMP); 222 break; 223 case DEVFSIO_RAPPLYID: 224 rid = *(devfs_rid *)data; 225 rid = devfs_rid_input(rid, dm); 226 dk = devfs_rule_byid(rid); 227 if (dk == NULL) { 228 error = ENOENT; 229 break; 230 } 231 devfs_rule_applydm(dk, dm); 232 break; 233 case DEVFSIO_RDEL: 234 rid = *(devfs_rid *)data; 235 rid = devfs_rid_input(rid, dm); 236 dk = devfs_rule_byid(rid); 237 if (dk == NULL) { 238 error = ENOENT; 239 break; 240 } 241 ds = dk->dk_ruleset; 242 error = devfs_rule_delete(dk); 243 break; 244 case DEVFSIO_RGETNEXT: 245 dr = (struct devfs_rule *)data; 246 error = devfs_rule_input(dr, dm); 247 if (error != 0) 248 break; 249 /* 250 * We can't use devfs_rule_byid() here since that 251 * requires the rule specified to exist, but we want 252 * getnext(N) to work whether there is a rule N or not 253 * (specifically, getnext(0) must work, but we should 254 * never have a rule 0 since the add command 255 * interprets 0 to mean "auto-number"). 256 */ 257 ds = devfs_ruleset_bynum(rid2rsn(dr->dr_id)); 258 if (ds == NULL) { 259 error = ENOENT; 260 break; 261 } 262 rnum = rid2rn(dr->dr_id); 263 TAILQ_FOREACH(dk, &ds->ds_rules, dk_list) { 264 if (rid2rn(dk->dk_rule.dr_id) > rnum) 265 break; 266 } 267 if (dk == NULL) { 268 error = ENOENT; 269 break; 270 } 271 memcpy(dr, &dk->dk_rule, sizeof(*dr)); 272 break; 273 case DEVFSIO_SUSE: 274 rsnum = *(devfs_rsnum *)data; 275 error = devfs_ruleset_use(rsnum, dm); 276 break; 277 case DEVFSIO_SAPPLY: 278 rsnum = *(devfs_rsnum *)data; 279 rsnum = rid2rsn(devfs_rid_input(mkrid(rsnum, 0), dm)); 280 ds = devfs_ruleset_bynum(rsnum); 281 if (ds == NULL) { 282 error = ESRCH; 283 break; 284 } 285 devfs_ruleset_applydm(ds, dm); 286 break; 287 case DEVFSIO_SGETNEXT: 288 rsnum = *(devfs_rsnum *)data; 289 TAILQ_FOREACH(ds, &devfs_rulesets, ds_list) { 290 if (ds->ds_number > rsnum) 291 break; 292 } 293 if (ds == NULL) { 294 error = ENOENT; 295 break; 296 } 297 *(devfs_rsnum *)data = ds->ds_number; 298 break; 299 default: 300 error = ENOIOCTL; 301 break; 302 } 303 304 sx_xunlock(&sx_rules); 305 return (error); 306} 307 308/* 309 * Adjust the rule identifier to use the ruleset of dm if one isn't 310 * explicitly specified. 311 * 312 * Note that after this operation, rid2rsn(rid) might still be 0, and 313 * that's okay; ruleset 0 is a valid ruleset, but when it's read in 314 * from the userland, it means "current ruleset for this mount-point". 315 */ 316static devfs_rid 317devfs_rid_input(devfs_rid rid, struct devfs_mount *dm) 318{ 319 320 if (rid2rsn(rid) == 0) 321 return (mkrid(dm->dm_ruleset, rid2rn(rid))); 322 else 323 return (rid); 324} 325 326/* 327 * Apply dk to de and everything under de. 328 * 329 * XXX: This method needs a function call for every nested 330 * subdirectory in a devfs mount. If we plan to have many of these, 331 * we might eventually run out of kernel stack space. 332 * XXX: a linear search could be done through the cdev list instead. 333 */ 334static void 335devfs_rule_applyde_recursive(struct devfs_krule *dk, struct devfs_dirent *de) 336{ 337 struct devfs_dirent *de2; 338 339 TAILQ_FOREACH(de2, &de->de_dlist, de_list) 340 devfs_rule_applyde_recursive(dk, de2); 341 devfs_rule_run(dk, de, devfs_rule_depth); 342} 343 344/* 345 * Apply dk to all entires in dm. 346 */ 347static void 348devfs_rule_applydm(struct devfs_krule *dk, struct devfs_mount *dm) 349{ 350 351 devfs_rule_applyde_recursive(dk, dm->dm_rootdir); 352} 353 354/* 355 * Automatically select a number for a new rule in ds, and write the 356 * result into rnump. 357 */ 358static int 359devfs_rule_autonumber(struct devfs_ruleset *ds, devfs_rnum *rnump) 360{ 361 struct devfs_krule *dk; 362 363 /* Find the last rule. */ 364 dk = TAILQ_LAST(&ds->ds_rules, rulehead); 365 if (dk == NULL) 366 *rnump = 100; 367 else { 368 *rnump = rid2rn(dk->dk_rule.dr_id) + 100; 369 /* Detect overflow. */ 370 if (*rnump < rid2rn(dk->dk_rule.dr_id)) 371 return (ERANGE); 372 } 373 KASSERT(devfs_rule_byid(mkrid(ds->ds_number, *rnump)) == NULL, 374 ("autonumbering resulted in an already existing rule")); 375 return (0); 376} 377 378/* 379 * Find a krule by id. 380 */ 381static struct devfs_krule * 382devfs_rule_byid(devfs_rid rid) 383{ 384 struct devfs_ruleset *ds; 385 struct devfs_krule *dk; 386 devfs_rnum rn; 387 388 rn = rid2rn(rid); 389 ds = devfs_ruleset_bynum(rid2rsn(rid)); 390 if (ds == NULL) 391 return (NULL); 392 TAILQ_FOREACH(dk, &ds->ds_rules, dk_list) { 393 if (rid2rn(dk->dk_rule.dr_id) == rn) 394 return (dk); 395 else if (rid2rn(dk->dk_rule.dr_id) > rn) 396 break; 397 } 398 return (NULL); 399} 400 401/* 402 * Remove dkp from any lists it may be on and remove memory associated 403 * with it. 404 */ 405static int 406devfs_rule_delete(struct devfs_krule *dk) 407{ 408 struct devfs_ruleset *ds; 409 410 if (dk->dk_rule.dr_iacts & DRA_INCSET) { 411 ds = devfs_ruleset_bynum(dk->dk_rule.dr_incset); 412 KASSERT(ds != NULL, ("DRA_INCSET but bad dr_incset")); 413 --ds->ds_refcount; 414 devfs_ruleset_reap(ds); 415 } 416 ds = dk->dk_ruleset; 417 TAILQ_REMOVE(&ds->ds_rules, dk, dk_list); 418 devfs_ruleset_reap(ds); 419 free(dk, M_DEVFSRULE); 420 return (0); 421} 422 423/* 424 * Get a struct cdev *corresponding to de so we can try to match rules based 425 * on it. If this routine returns NULL, there is no struct cdev *associated 426 * with the dirent (symlinks and directories don't have dev_ts), and 427 * the caller should assume that any critera dependent on a dev_t 428 * don't match. 429 */ 430static struct cdev * 431devfs_rule_getdev(struct devfs_dirent *de) 432{ 433 434 if (de->de_cdp == NULL) 435 return (NULL); 436 if (de->de_cdp->cdp_flags & CDP_ACTIVE) 437 return (&de->de_cdp->cdp_c); 438 else 439 return (NULL); 440} 441 442/* 443 * Do what we need to do to a rule that we just loaded from the 444 * userland. In particular, we need to check the magic, and adjust 445 * the ruleset appropriate if desired. 446 */ 447static int 448devfs_rule_input(struct devfs_rule *dr, struct devfs_mount *dm) 449{ 450 451 if (dr->dr_magic != DEVFS_MAGIC) 452 return (ERPCMISMATCH); 453 dr->dr_id = devfs_rid_input(dr->dr_id, dm); 454 return (0); 455} 456 457/* 458 * Import dr into the appropriate place in the kernel (i.e., make a 459 * krule). The value of dr is copied, so the pointer may be destroyed 460 * after this call completes. 461 */ 462static int 463devfs_rule_insert(struct devfs_rule *dr) 464{ 465 struct devfs_ruleset *ds, *dsi; 466 struct devfs_krule *k1; 467 struct devfs_krule *dk; 468 devfs_rsnum rsnum; 469 devfs_rnum dkrn; 470 int error; 471 472 /* 473 * This stuff seems out of place here, but we want to do it as 474 * soon as possible so that if it fails, we don't have to roll 475 * back any changes we already made (e.g., ruleset creation). 476 */ 477 if (dr->dr_iacts & DRA_INCSET) { 478 dsi = devfs_ruleset_bynum(dr->dr_incset); 479 if (dsi == NULL) 480 return (ESRCH); 481 } else 482 dsi = NULL; 483 484 rsnum = rid2rsn(dr->dr_id); 485 KASSERT(rsnum != 0, ("Inserting into ruleset zero")); 486 487 ds = devfs_ruleset_bynum(rsnum); 488 if (ds == NULL) 489 ds = devfs_ruleset_create(rsnum); 490 dkrn = rid2rn(dr->dr_id); 491 if (dkrn == 0) { 492 error = devfs_rule_autonumber(ds, &dkrn); 493 if (error != 0) { 494 devfs_ruleset_reap(ds); 495 return (error); 496 } 497 } 498 499 dk = malloc(sizeof(*dk), M_DEVFSRULE, M_WAITOK | M_ZERO); 500 dk->dk_ruleset = ds; 501 if (dsi != NULL) 502 ++dsi->ds_refcount; 503 /* XXX: Inspect dr? */ 504 memcpy(&dk->dk_rule, dr, sizeof(*dr)); 505 dk->dk_rule.dr_id = mkrid(rid2rsn(dk->dk_rule.dr_id), dkrn); 506 507 TAILQ_FOREACH(k1, &ds->ds_rules, dk_list) { 508 if (rid2rn(k1->dk_rule.dr_id) > dkrn) { 509 TAILQ_INSERT_BEFORE(k1, dk, dk_list); 510 break; 511 } 512 } 513 if (k1 == NULL) 514 TAILQ_INSERT_TAIL(&ds->ds_rules, dk, dk_list); 515 return (0); 516} 517 518/* 519 * Determine whether dk matches de. Returns 1 if dk should be run on 520 * de; 0, otherwise. 521 */ 522static int 523devfs_rule_match(struct devfs_krule *dk, struct devfs_dirent *de) 524{ 525 struct devfs_rule *dr = &dk->dk_rule; 526 struct cdev *dev; 527 528 dev = devfs_rule_getdev(de); 529 /* 530 * At this point, if dev is NULL, we should assume that any 531 * criteria that depend on it don't match. We should *not* 532 * just ignore them (i.e., act like they weren't specified), 533 * since that makes a rule that only has criteria dependent on 534 * the struct cdev *match all symlinks and directories. 535 * 536 * Note also that the following tests are somewhat reversed: 537 * They're actually testing to see whether the condition does 538 * *not* match, since the default is to assume the rule should 539 * be run (such as if there are no conditions). 540 * 541 * XXX: lacks threadref on dev 542 */ 543 if (dr->dr_icond & DRC_DSWFLAGS) 544 if (dev == NULL || 545 (dev->si_devsw->d_flags & dr->dr_dswflags) == 0) 546 return (0); 547 if (dr->dr_icond & DRC_PATHPTRN) 548 if (!devfs_rule_matchpath(dk, de)) 549 return (0); 550 551 return (1); 552} 553 554/* 555 * Determine whether dk matches de on account of dr_pathptrn. 556 */ 557static int 558devfs_rule_matchpath(struct devfs_krule *dk, struct devfs_dirent *de) 559{ 560 struct devfs_rule *dr = &dk->dk_rule; 561 char *pname; 562 struct cdev *dev; 563 564 dev = devfs_rule_getdev(de); 565 if (dev != NULL) 566 pname = dev->si_name; 567 else if (de->de_dirent->d_type == DT_LNK || 568 de->de_dirent->d_type == DT_DIR) 569 pname = de->de_dirent->d_name; 570 else 571 return (0); 572 KASSERT(pname != NULL, ("devfs_rule_matchpath: NULL pname")); 573 574 return (fnmatch(dr->dr_pathptrn, pname, 0) == 0); 575} 576 577/* 578 * Run dk on de. 579 */ 580static void 581devfs_rule_run(struct devfs_krule *dk, struct devfs_dirent *de, unsigned depth) 582{ 583 struct devfs_rule *dr = &dk->dk_rule; 584 struct devfs_ruleset *ds; 585 586 if (!devfs_rule_match(dk, de)) 587 return; 588 if (dr->dr_iacts & DRA_BACTS) { 589 if (dr->dr_bacts & DRB_HIDE) 590 de->de_flags |= DE_WHITEOUT; 591 if (dr->dr_bacts & DRB_UNHIDE) 592 de->de_flags &= ~DE_WHITEOUT; 593 } 594 if (dr->dr_iacts & DRA_UID) 595 de->de_uid = dr->dr_uid; 596 if (dr->dr_iacts & DRA_GID) 597 de->de_gid = dr->dr_gid; 598 if (dr->dr_iacts & DRA_MODE) 599 de->de_mode = dr->dr_mode; 600 if (dr->dr_iacts & DRA_INCSET) { 601 /* 602 * XXX: we should tell the user if the depth is exceeded here 603 * XXX: but it is not obvious how to. A return value will 604 * XXX: not work as this is called when devices are created 605 * XXX: long time after the rules were instantiated. 606 * XXX: a printf() would probably give too much noise, or 607 * XXX: DoS the machine. I guess a a rate-limited message 608 * XXX: might work. 609 */ 610 if (depth > 0) { 611 ds = devfs_ruleset_bynum(dk->dk_rule.dr_incset); 612 KASSERT(ds != NULL, ("DRA_INCSET but bad dr_incset")); 613 devfs_ruleset_applyde(ds, de, depth - 1); 614 } 615 } 616} 617 618/* 619 * Apply all the rules in ds to de. 620 */ 621static void 622devfs_ruleset_applyde(struct devfs_ruleset *ds, struct devfs_dirent *de, unsigned depth) 623{ 624 struct devfs_krule *dk; 625 626 TAILQ_FOREACH(dk, &ds->ds_rules, dk_list) 627 devfs_rule_run(dk, de, depth); 628} 629 630/* 631 * Apply all the rules in ds to all the entires in dm. 632 */ 633static void 634devfs_ruleset_applydm(struct devfs_ruleset *ds, struct devfs_mount *dm) 635{ 636 struct devfs_krule *dk; 637 638 /* 639 * XXX: Does it matter whether we do 640 * 641 * foreach(dk in ds) 642 * foreach(de in dm) 643 * apply(dk to de) 644 * 645 * as opposed to 646 * 647 * foreach(de in dm) 648 * foreach(dk in ds) 649 * apply(dk to de) 650 * 651 * The end result is obviously the same, but does the order 652 * matter? 653 */ 654 TAILQ_FOREACH(dk, &ds->ds_rules, dk_list) 655 devfs_rule_applydm(dk, dm); 656} 657 658/* 659 * Find a ruleset by number. 660 */ 661static struct devfs_ruleset * 662devfs_ruleset_bynum(devfs_rsnum rsnum) 663{ 664 struct devfs_ruleset *ds; 665 666 TAILQ_FOREACH(ds, &devfs_rulesets, ds_list) { 667 if (ds->ds_number == rsnum) 668 return (ds); 669 } 670 return (NULL); 671} 672 673/* 674 * Create a new ruleset. 675 */ 676static struct devfs_ruleset * 677devfs_ruleset_create(devfs_rsnum rsnum) 678{ 679 struct devfs_ruleset *s1; 680 struct devfs_ruleset *ds; 681 682 KASSERT(rsnum != 0, ("creating ruleset zero")); 683 684 KASSERT(devfs_ruleset_bynum(rsnum) == NULL, 685 ("creating already existent ruleset %d", rsnum)); 686 687 ds = malloc(sizeof(*ds), M_DEVFSRULE, M_WAITOK | M_ZERO); 688 ds->ds_number = rsnum; 689 TAILQ_INIT(&ds->ds_rules); 690 691 TAILQ_FOREACH(s1, &devfs_rulesets, ds_list) { 692 if (s1->ds_number > rsnum) { 693 TAILQ_INSERT_BEFORE(s1, ds, ds_list); 694 break; 695 } 696 } 697 if (s1 == NULL) 698 TAILQ_INSERT_TAIL(&devfs_rulesets, ds, ds_list); 699 return (ds); 700} 701 702/* 703 * Remove a ruleset from the system if it's empty and not used 704 * anywhere. This should be called after every time a rule is deleted 705 * from this ruleset or the reference count is decremented. 706 */ 707static void 708devfs_ruleset_reap(struct devfs_ruleset *ds) 709{ 710 711 KASSERT(ds->ds_number != 0, ("reaping ruleset zero ")); 712 713 if (!TAILQ_EMPTY(&ds->ds_rules) || ds->ds_refcount != 0) 714 return; 715 716 TAILQ_REMOVE(&devfs_rulesets, ds, ds_list); 717 free(ds, M_DEVFSRULE); 718} 719 720/* 721 * Make rsnum the active ruleset for dm. 722 */ 723static int 724devfs_ruleset_use(devfs_rsnum rsnum, struct devfs_mount *dm) 725{ 726 struct devfs_ruleset *cds, *ds; 727 728 ds = devfs_ruleset_bynum(rsnum); 729 if (ds == NULL) 730 ds = devfs_ruleset_create(rsnum); 731 if (dm->dm_ruleset != 0) { 732 cds = devfs_ruleset_bynum(dm->dm_ruleset); 733 --cds->ds_refcount; 734 devfs_ruleset_reap(cds); 735 } 736 737 /* These should probably be made atomic somehow. */ 738 ++ds->ds_refcount; 739 dm->dm_ruleset = rsnum; 740 741 return (0); 742} 743 744void 745devfs_rules_cleanup(struct devfs_mount *dm) 746{ 747 struct devfs_ruleset *ds; 748 749 sx_assert(&dm->dm_lock, SX_XLOCKED); 750 if (dm->dm_ruleset != 0) { 751 ds = devfs_ruleset_bynum(dm->dm_ruleset); 752 --ds->ds_refcount; 753 devfs_ruleset_reap(ds); 754 } 755} 756