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