summaryrefslogtreecommitdiffstats
path: root/sys/fs/devfs
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>2005-09-24 07:03:09 +0000
committerphk <phk@FreeBSD.org>2005-09-24 07:03:09 +0000
commita951e327e625708d60d649c19b21d217d9325f91 (patch)
treed0b4460b68d3350b91dc217d61ac6168b4077b02 /sys/fs/devfs
parent07adfc3d98d69f8a0bc6828588bde6785f3d08b4 (diff)
downloadFreeBSD-src-a951e327e625708d60d649c19b21d217d9325f91.zip
FreeBSD-src-a951e327e625708d60d649c19b21d217d9325f91.tar.gz
Make rule zero really magical, that way we don't have to do anything
when we mount and get zero cost if no rules are used in a mountpoint. Add code to deref rules on unmount. Switch from SLIST to TAILQ. Drop SYSINIT, use SX_SYSINIT and static initializer of TAILQ instead. Drop goto, a break will do. Reduce double pointers to single pointers. Combine reaping and destroying rulesets. Avoid memory leaks in a some error cases.
Diffstat (limited to 'sys/fs/devfs')
-rw-r--r--sys/fs/devfs/devfs.h2
-rw-r--r--sys/fs/devfs/devfs_rule.c248
-rw-r--r--sys/fs/devfs/devfs_vfsops.c2
3 files changed, 99 insertions, 153 deletions
diff --git a/sys/fs/devfs/devfs.h b/sys/fs/devfs/devfs.h
index 18061b9..37136be0 100644
--- a/sys/fs/devfs/devfs.h
+++ b/sys/fs/devfs/devfs.h
@@ -161,8 +161,8 @@ extern unsigned devfs_rule_depth;
#define VFSTODEVFS(mp) ((struct devfs_mount *)((mp)->mnt_data))
void devfs_rules_apply(struct devfs_mount *dm, struct devfs_dirent *de);
+void devfs_rules_cleanup (struct devfs_mount *dm);
int devfs_rules_ioctl(struct devfs_mount *dm, u_long cmd, caddr_t data, struct thread *td);
-void devfs_rules_newmount(struct devfs_mount *dm, struct thread *td);
int devfs_allocv (struct devfs_dirent *de, struct mount *mp, struct vnode **vpp, struct thread *td);
struct cdev **devfs_itod (int inode);
struct devfs_dirent **devfs_itode (struct devfs_mount *dm, int inode);
diff --git a/sys/fs/devfs/devfs_rule.c b/sys/fs/devfs/devfs_rule.c
index c1edfd3..840f9f9 100644
--- a/sys/fs/devfs/devfs_rule.c
+++ b/sys/fs/devfs/devfs_rule.c
@@ -81,21 +81,22 @@
* Kernel version of devfs_rule.
*/
struct devfs_krule {
- SLIST_ENTRY(devfs_krule) dk_list;
- struct devfs_ruleset *dk_ruleset;
- struct devfs_rule dk_rule;
+ TAILQ_ENTRY(devfs_krule) dk_list;
+ struct devfs_ruleset *dk_ruleset;
+ struct devfs_rule dk_rule;
};
+TAILQ_HEAD(rulehead, devfs_krule);
+static MALLOC_DEFINE(M_DEVFSRULE, "DEVFS_RULE", "DEVFS rule storage");
+
/*
* Structure to describe a ruleset.
*/
struct devfs_ruleset {
- SLIST_ENTRY(devfs_ruleset) ds_list;
- devfs_rsnum ds_number;
- SLIST_HEAD(, devfs_krule) ds_rules;
- int ds_refcount;
- int ds_flags;
-#define DS_IMMUTABLE 0x001
+ TAILQ_ENTRY(devfs_ruleset) ds_list;
+ struct rulehead ds_rules;
+ devfs_rsnum ds_number;
+ int ds_refcount;
};
static devfs_rid devfs_rid_input(devfs_rid rid, struct devfs_mount *dm);
@@ -105,7 +106,7 @@ static void devfs_rule_applyde_recursive(struct devfs_krule *dk,
static void devfs_rule_applydm(struct devfs_krule *dk, struct devfs_mount *dm);
static int devfs_rule_autonumber(struct devfs_ruleset *ds, devfs_rnum *rnp);
static struct devfs_krule *devfs_rule_byid(devfs_rid rid);
-static int devfs_rule_delete(struct devfs_krule **dkp);
+static int devfs_rule_delete(struct devfs_krule *dkp);
static struct cdev *devfs_rule_getdev(struct devfs_dirent *de);
static int devfs_rule_input(struct devfs_rule *dr, struct devfs_mount *dm);
static int devfs_rule_insert(struct devfs_rule *dr);
@@ -120,12 +121,14 @@ static void devfs_ruleset_applydm(struct devfs_ruleset *ds,
struct devfs_mount *dm);
static struct devfs_ruleset *devfs_ruleset_bynum(devfs_rsnum rsnum);
static struct devfs_ruleset *devfs_ruleset_create(devfs_rsnum rsnum);
-static void devfs_ruleset_destroy(struct devfs_ruleset **dsp);
-static void devfs_ruleset_reap(struct devfs_ruleset **dsp);
+static void devfs_ruleset_reap(struct devfs_ruleset *dsp);
static int devfs_ruleset_use(devfs_rsnum rsnum, struct devfs_mount *dm);
static struct sx sx_rules;
-static SLIST_HEAD(, devfs_ruleset) devfs_rulesets;
+SX_SYSINIT(sx_rules, &sx_rules, "DEVFS ruleset lock");
+
+static TAILQ_HEAD(, devfs_ruleset) devfs_rulesets =
+ TAILQ_HEAD_INITIALIZER(devfs_rulesets);
/*
* Called to apply the proper rules for 'de' before it can be
@@ -137,6 +140,8 @@ devfs_rules_apply(struct devfs_mount *dm, struct devfs_dirent *de)
{
struct devfs_ruleset *ds;
+ if (dm->dm_ruleset == 0)
+ return;
sx_slock(&sx_rules);
ds = devfs_ruleset_bynum(dm->dm_ruleset);
KASSERT(ds != NULL, ("mount-point has NULL ruleset"));
@@ -145,24 +150,6 @@ devfs_rules_apply(struct devfs_mount *dm, struct devfs_dirent *de)
}
/*
- * Rule subsystem SYSINIT hook.
- */
-static void
-devfs_rules_init(void *junk __unused)
-{
- struct devfs_ruleset *ds;
-
- sx_init(&sx_rules, "devfsrules");
- SLIST_INIT(&devfs_rulesets);
-
- ds = devfs_ruleset_create(0);
- ds->ds_flags |= DS_IMMUTABLE;
- ds->ds_refcount = 1; /* Prevent reaping. */
-}
-
-SYSINIT(devfs_rules, SI_SUB_DEVFS, SI_ORDER_FIRST, devfs_rules_init, NULL);
-
-/*
* Rule subsystem ioctl hook.
*/
int
@@ -193,19 +180,21 @@ devfs_rules_ioctl(struct devfs_mount *dm, u_long cmd, caddr_t data, struct threa
dr = (struct devfs_rule *)data;
error = devfs_rule_input(dr, dm);
if (error != 0)
- goto out;
+ break;
dk = devfs_rule_byid(dr->dr_id);
if (dk != NULL) {
error = EEXIST;
- goto out;
+ break;
}
+ if (rid2rsn(dr->dr_id) == 0)
+ return (EIO);
error = devfs_rule_insert(dr);
break;
case DEVFSIO_RAPPLY:
dr = (struct devfs_rule *)data;
error = devfs_rule_input(dr, dm);
if (error != 0)
- goto out;
+ break;
/*
* This is one of many possible hackish
@@ -224,13 +213,12 @@ devfs_rules_ioctl(struct devfs_mount *dm, u_long cmd, caddr_t data, struct threa
if (dr->dr_iacts & DRA_INCSET &&
devfs_ruleset_bynum(dr->dr_incset) == NULL) {
error = ESRCH;
- goto out;
+ break;
}
dk = malloc(sizeof(*dk), M_TEMP, M_WAITOK | M_ZERO);
memcpy(&dk->dk_rule, dr, sizeof(*dr));
devfs_rule_applydm(dk, dm);
free(dk, M_TEMP);
- error = 0;
break;
case DEVFSIO_RAPPLYID:
rid = *(devfs_rid *)data;
@@ -238,10 +226,9 @@ devfs_rules_ioctl(struct devfs_mount *dm, u_long cmd, caddr_t data, struct threa
dk = devfs_rule_byid(rid);
if (dk == NULL) {
error = ENOENT;
- goto out;
+ break;
}
devfs_rule_applydm(dk, dm);
- error = 0;
break;
case DEVFSIO_RDEL:
rid = *(devfs_rid *)data;
@@ -249,17 +236,16 @@ devfs_rules_ioctl(struct devfs_mount *dm, u_long cmd, caddr_t data, struct threa
dk = devfs_rule_byid(rid);
if (dk == NULL) {
error = ENOENT;
- goto out;
+ break;
}
ds = dk->dk_ruleset;
- error = devfs_rule_delete(&dk);
- devfs_ruleset_reap(&ds);
+ error = devfs_rule_delete(dk);
break;
case DEVFSIO_RGETNEXT:
dr = (struct devfs_rule *)data;
error = devfs_rule_input(dr, dm);
if (error != 0)
- goto out;
+ break;
/*
* We can't use devfs_rule_byid() here since that
* requires the rule specified to exist, but we want
@@ -271,19 +257,18 @@ devfs_rules_ioctl(struct devfs_mount *dm, u_long cmd, caddr_t data, struct threa
ds = devfs_ruleset_bynum(rid2rsn(dr->dr_id));
if (ds == NULL) {
error = ENOENT;
- goto out;
+ break;
}
rnum = rid2rn(dr->dr_id);
- SLIST_FOREACH(dk, &ds->ds_rules, dk_list) {
+ TAILQ_FOREACH(dk, &ds->ds_rules, dk_list) {
if (rid2rn(dk->dk_rule.dr_id) > rnum)
break;
}
if (dk == NULL) {
error = ENOENT;
- goto out;
+ break;
}
memcpy(dr, &dk->dk_rule, sizeof(*dr));
- error = 0;
break;
case DEVFSIO_SUSE:
rsnum = *(devfs_rsnum *)data;
@@ -295,57 +280,32 @@ devfs_rules_ioctl(struct devfs_mount *dm, u_long cmd, caddr_t data, struct threa
ds = devfs_ruleset_bynum(rsnum);
if (ds == NULL) {
error = ESRCH;
- goto out;
+ break;
}
devfs_ruleset_applydm(ds, dm);
- error = 0;
break;
case DEVFSIO_SGETNEXT:
rsnum = *(devfs_rsnum *)data;
- SLIST_FOREACH(ds, &devfs_rulesets, ds_list) {
+ TAILQ_FOREACH(ds, &devfs_rulesets, ds_list) {
if (ds->ds_number > rsnum)
break;
}
- if (ds == NULL)
+ if (ds == NULL) {
error = ENOENT;
- else {
- *(devfs_rsnum *)data = ds->ds_number;
- error = 0;
+ break;
}
+ *(devfs_rsnum *)data = ds->ds_number;
break;
default:
error = ENOIOCTL;
break;
}
-out:
sx_xunlock(&sx_rules);
return (error);
}
/*
- * Called to initialize dm_ruleset when there is a new mount-point.
- */
-void
-devfs_rules_newmount(struct devfs_mount *dm, struct thread *td)
-{
- struct devfs_ruleset *ds;
-
- /*
- * We can't use devfs_ruleset_use() since it will try to
- * decrement the refcount for the old ruleset, and there is no
- * old ruleset. Making some value of ds_ruleset "special" to
- * mean "don't decrement refcount" is uglier than this.
- */
- sx_slock(&sx_rules);
- ds = devfs_ruleset_bynum(0);
- KASSERT(ds != NULL, ("no ruleset 0"));
- ++ds->ds_refcount;
- dm->dm_ruleset = 0;
- sx_sunlock(&sx_rules);
-}
-
-/*
* Adjust the rule identifier to use the ruleset of dm if one isn't
* explicitly specified.
*
@@ -401,10 +361,7 @@ devfs_rule_autonumber(struct devfs_ruleset *ds, devfs_rnum *rnump)
struct devfs_krule *dk;
/* Find the last rule. */
- SLIST_FOREACH(dk, &ds->ds_rules, dk_list) {
- if (SLIST_NEXT(dk, dk_list) == NULL)
- break;
- }
+ dk = TAILQ_LAST(&ds->ds_rules, rulehead);
if (dk == NULL)
*rnump = 100;
else {
@@ -432,7 +389,7 @@ devfs_rule_byid(devfs_rid rid)
ds = devfs_ruleset_bynum(rid2rsn(rid));
if (ds == NULL)
return (NULL);
- SLIST_FOREACH(dk, &ds->ds_rules, dk_list) {
+ TAILQ_FOREACH(dk, &ds->ds_rules, dk_list) {
if (rid2rn(dk->dk_rule.dr_id) == rn)
return (dk);
else if (rid2rn(dk->dk_rule.dr_id) > rn)
@@ -446,20 +403,20 @@ devfs_rule_byid(devfs_rid rid)
* with it.
*/
static int
-devfs_rule_delete(struct devfs_krule **dkp)
+devfs_rule_delete(struct devfs_krule *dk)
{
- struct devfs_krule *dk = *dkp;
struct devfs_ruleset *ds;
if (dk->dk_rule.dr_iacts & DRA_INCSET) {
ds = devfs_ruleset_bynum(dk->dk_rule.dr_incset);
KASSERT(ds != NULL, ("DRA_INCSET but bad dr_incset"));
--ds->ds_refcount;
- devfs_ruleset_reap(&ds);
+ devfs_ruleset_reap(ds);
}
- SLIST_REMOVE(&dk->dk_ruleset->ds_rules, dk, devfs_krule, dk_list);
- free(dk, M_DEVFS);
- *dkp = NULL;
+ ds = dk->dk_ruleset;
+ TAILQ_REMOVE(&ds->ds_rules, dk, dk_list);
+ devfs_ruleset_reap(ds);
+ free(dk, M_DEVFSRULE);
return (0);
}
@@ -506,7 +463,7 @@ static int
devfs_rule_insert(struct devfs_rule *dr)
{
struct devfs_ruleset *ds, *dsi;
- struct devfs_krule *k1, *k2;
+ struct devfs_krule *k1;
struct devfs_krule *dk;
devfs_rsnum rsnum;
devfs_rnum dkrn;
@@ -525,19 +482,21 @@ devfs_rule_insert(struct devfs_rule *dr)
dsi = NULL;
rsnum = rid2rsn(dr->dr_id);
+ KASSERT(rsnum != 0, ("Inserting into ruleset zero"));
+
ds = devfs_ruleset_bynum(rsnum);
if (ds == NULL)
ds = devfs_ruleset_create(rsnum);
- if (ds->ds_flags & DS_IMMUTABLE)
- return (EIO);
dkrn = rid2rn(dr->dr_id);
if (dkrn == 0) {
error = devfs_rule_autonumber(ds, &dkrn);
- if (error != 0)
+ if (error != 0) {
+ devfs_ruleset_reap(ds);
return (error);
+ }
}
- dk = malloc(sizeof(*dk), M_DEVFS, M_WAITOK);
+ dk = malloc(sizeof(*dk), M_DEVFSRULE, M_WAITOK | M_ZERO);
dk->dk_ruleset = ds;
if (dsi != NULL)
++dsi->ds_refcount;
@@ -545,19 +504,14 @@ devfs_rule_insert(struct devfs_rule *dr)
memcpy(&dk->dk_rule, dr, sizeof(*dr));
dk->dk_rule.dr_id = mkrid(rid2rsn(dk->dk_rule.dr_id), dkrn);
- k1 = SLIST_FIRST(&ds->ds_rules);
- if (k1 == NULL || rid2rn(k1->dk_rule.dr_id) > dkrn)
- SLIST_INSERT_HEAD(&ds->ds_rules, dk, dk_list);
- else {
- SLIST_FOREACH(k1, &ds->ds_rules, dk_list) {
- k2 = SLIST_NEXT(k1, dk_list);
- if (k2 == NULL || rid2rn(k2->dk_rule.dr_id) > dkrn) {
- SLIST_INSERT_AFTER(k1, dk, dk_list);
- break;
- }
+ TAILQ_FOREACH(k1, &ds->ds_rules, dk_list) {
+ if (rid2rn(k1->dk_rule.dr_id) > dkrn) {
+ TAILQ_INSERT_BEFORE(k1, dk, dk_list);
+ break;
}
}
-
+ if (k1 == NULL)
+ TAILQ_INSERT_TAIL(&ds->ds_rules, dk, dk_list);
return (0);
}
@@ -669,7 +623,7 @@ devfs_ruleset_applyde(struct devfs_ruleset *ds, struct devfs_dirent *de, unsigne
{
struct devfs_krule *dk;
- SLIST_FOREACH(dk, &ds->ds_rules, dk_list)
+ TAILQ_FOREACH(dk, &ds->ds_rules, dk_list)
devfs_rule_run(dk, de, depth);
}
@@ -697,9 +651,8 @@ devfs_ruleset_applydm(struct devfs_ruleset *ds, struct devfs_mount *dm)
* The end result is obviously the same, but does the order
* matter?
*/
- SLIST_FOREACH(dk, &ds->ds_rules, dk_list) {
+ TAILQ_FOREACH(dk, &ds->ds_rules, dk_list)
devfs_rule_applydm(dk, dm);
- }
}
/*
@@ -710,7 +663,7 @@ devfs_ruleset_bynum(devfs_rsnum rsnum)
{
struct devfs_ruleset *ds;
- SLIST_FOREACH(ds, &devfs_rulesets, ds_list) {
+ TAILQ_FOREACH(ds, &devfs_rulesets, ds_list) {
if (ds->ds_number == rsnum)
return (ds);
}
@@ -723,66 +676,45 @@ devfs_ruleset_bynum(devfs_rsnum rsnum)
static struct devfs_ruleset *
devfs_ruleset_create(devfs_rsnum rsnum)
{
- struct devfs_ruleset *s1, *s2;
+ struct devfs_ruleset *s1;
struct devfs_ruleset *ds;
+ KASSERT(rsnum != 0, ("creating ruleset zero"));
+
KASSERT(devfs_ruleset_bynum(rsnum) == NULL,
("creating already existent ruleset %d", rsnum));
- ds = malloc(sizeof(*ds), M_DEVFS, M_WAITOK | M_ZERO);
+ ds = malloc(sizeof(*ds), M_DEVFSRULE, M_WAITOK | M_ZERO);
ds->ds_number = rsnum;
- ds->ds_refcount = ds->ds_flags = 0;
- SLIST_INIT(&ds->ds_rules);
+ TAILQ_INIT(&ds->ds_rules);
- s1 = SLIST_FIRST(&devfs_rulesets);
- if (s1 == NULL || s1->ds_number > rsnum)
- SLIST_INSERT_HEAD(&devfs_rulesets, ds, ds_list);
- else {
- SLIST_FOREACH(s1, &devfs_rulesets, ds_list) {
- s2 = SLIST_NEXT(s1, ds_list);
- if (s2 == NULL || s2->ds_number > rsnum) {
- SLIST_INSERT_AFTER(s1, ds, ds_list);
- break;
- }
+ TAILQ_FOREACH(s1, &devfs_rulesets, ds_list) {
+ if (s1->ds_number > rsnum) {
+ TAILQ_INSERT_BEFORE(s1, ds, ds_list);
+ break;
}
}
-
+ if (s1 == NULL)
+ TAILQ_INSERT_TAIL(&devfs_rulesets, ds, ds_list);
return (ds);
}
/*
- * Remove a ruleset form the system. The ruleset specified must be
- * empty and not in use.
- */
-static void
-devfs_ruleset_destroy(struct devfs_ruleset **dsp)
-{
- struct devfs_ruleset *ds = *dsp;
-
- KASSERT(SLIST_EMPTY(&ds->ds_rules), ("destroying non-empty ruleset"));
- KASSERT(ds->ds_refcount == 0, ("destroying busy ruleset"));
- KASSERT((ds->ds_flags & DS_IMMUTABLE) == 0,
- ("destroying immutable ruleset"));
-
- SLIST_REMOVE(&devfs_rulesets, ds, devfs_ruleset, ds_list);
- free(ds, M_DEVFS);
- *dsp = NULL;
-}
-
-/*
* Remove a ruleset from the system if it's empty and not used
* anywhere. This should be called after every time a rule is deleted
* from this ruleset or the reference count is decremented.
*/
static void
-devfs_ruleset_reap(struct devfs_ruleset **dsp)
+devfs_ruleset_reap(struct devfs_ruleset *ds)
{
- struct devfs_ruleset *ds = *dsp;
- if (SLIST_EMPTY(&ds->ds_rules) && ds->ds_refcount == 0) {
- devfs_ruleset_destroy(&ds);
- *dsp = ds;
- }
+ KASSERT(ds->ds_number != 0, ("reaping ruleset zero "));
+
+ if (!TAILQ_EMPTY(&ds->ds_rules) || ds->ds_refcount != 0)
+ return;
+
+ TAILQ_REMOVE(&devfs_rulesets, ds, ds_list);
+ free(ds, M_DEVFSRULE);
}
/*
@@ -796,14 +728,28 @@ devfs_ruleset_use(devfs_rsnum rsnum, struct devfs_mount *dm)
ds = devfs_ruleset_bynum(rsnum);
if (ds == NULL)
ds = devfs_ruleset_create(rsnum);
- cds = devfs_ruleset_bynum(dm->dm_ruleset);
- KASSERT(cds != NULL, ("mount-point has NULL ruleset"));
+ if (dm->dm_ruleset != 0) {
+ cds = devfs_ruleset_bynum(dm->dm_ruleset);
+ --cds->ds_refcount;
+ devfs_ruleset_reap(cds);
+ }
/* These should probably be made atomic somehow. */
- --cds->ds_refcount;
++ds->ds_refcount;
dm->dm_ruleset = rsnum;
- devfs_ruleset_reap(&cds);
return (0);
}
+
+void
+devfs_rules_cleanup(struct devfs_mount *dm)
+{
+ struct devfs_ruleset *ds;
+
+ sx_assert(&dm->dm_lock, SX_XLOCKED);
+ if (dm->dm_ruleset != 0) {
+ ds = devfs_ruleset_bynum(dm->dm_ruleset);
+ --ds->ds_refcount;
+ devfs_ruleset_reap(ds);
+ }
+}
diff --git a/sys/fs/devfs/devfs_vfsops.c b/sys/fs/devfs/devfs_vfsops.c
index 6aad2b0..bb34586 100644
--- a/sys/fs/devfs/devfs_vfsops.c
+++ b/sys/fs/devfs/devfs_vfsops.c
@@ -92,7 +92,6 @@ devfs_mount(struct mount *mp, struct thread *td)
vfs_getnewfsid(mp);
fmp->dm_rootdir = devfs_vmkdir(fmp, NULL, 0, NULL, DEVFS_ROOTINO);
- devfs_rules_newmount(fmp, td);
error = devfs_root(mp, LK_EXCLUSIVE, &rvp, td);
if (error) {
@@ -123,6 +122,7 @@ devfs_unmount(struct mount *mp, int mntflags, struct thread *td)
return (error);
sx_xlock(&fmp->dm_lock);
devfs_cleanup(fmp);
+ devfs_rules_cleanup(fmp);
sx_xunlock(&fmp->dm_lock);
mp->mnt_data = NULL;
sx_destroy(&fmp->dm_lock);
OpenPOWER on IntegriCloud