summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPoul-Henning Kamp <phk@FreeBSD.org>2005-09-26 14:36:54 +0000
committerPoul-Henning Kamp <phk@FreeBSD.org>2005-09-26 14:36:54 +0000
commit02eb92cc0eb8efadf6e5fc5ac65a45a8b92d15bc (patch)
tree9fb4509eaa194b800fd8212c7887890cd6f7884e
parentda7684092a47a3ece76b7fd0e41ef2d51f674ba4 (diff)
Notes
-rw-r--r--sys/fs/devfs/devfs.h44
-rw-r--r--sys/fs/devfs/devfs_devs.c546
-rw-r--r--sys/fs/devfs/devfs_int.h22
-rw-r--r--sys/fs/devfs/devfs_rule.c271
-rw-r--r--sys/fs/devfs/devfs_vfsops.c60
-rw-r--r--sys/fs/devfs/devfs_vnops.c192
-rw-r--r--sys/kern/kern_conf.c66
-rw-r--r--sys/security/mac_biba/mac_biba.c1
-rw-r--r--sys/security/mac_lomac/mac_lomac.c1
-rw-r--r--sys/security/mac_mls/mac_mls.c1
-rw-r--r--sys/security/mac_none/mac_none.c1
-rw-r--r--sys/security/mac_partition/mac_partition.c1
-rw-r--r--sys/security/mac_stub/mac_stub.c1
-rw-r--r--sys/security/mac_test/mac_test.c1
-rw-r--r--sys/sys/conf.h3
15 files changed, 571 insertions, 640 deletions
diff --git a/sys/fs/devfs/devfs.h b/sys/fs/devfs/devfs.h
index 07912a9a0dcf..37136be02f23 100644
--- a/sys/fs/devfs/devfs.h
+++ b/sys/fs/devfs/devfs.h
@@ -118,32 +118,12 @@ struct devfs_rule {
#ifdef _KERNEL
-/*
- * These are default sizes for the DEVFS inode table and the overflow
- * table. If the default table overflows we allocate the overflow
- * table, the size of which can also be set with a sysctl. If the
- * overflow table fills you're toast.
- */
-#ifndef NDEVFSINO
-#define NDEVFSINO 1024
-#endif
-
-#ifndef NDEVFSOVERFLOW
-#define NDEVFSOVERFLOW 32768
-#endif
-
-/*
- * This is the first "per mount" inode, these are used for directories
- * and symlinks and the like. Must be larger than the number of "true"
- * device nodes and symlinks. It is.
- */
-#define DEVFSINOMOUNT 0x2000000
-
#ifdef MALLOC_DECLARE
MALLOC_DECLARE(M_DEVFS);
#endif
struct devfs_dirent {
+ struct cdev_priv *de_cdp;
int de_inode;
int de_flags;
#define DE_WHITEOUT 0x1
@@ -152,7 +132,6 @@ struct devfs_dirent {
struct dirent *de_dirent;
TAILQ_ENTRY(devfs_dirent) de_list;
TAILQ_HEAD(, devfs_dirent) de_dlist;
- LIST_ENTRY(devfs_dirent) de_alias;
struct devfs_dirent *de_dir;
int de_links;
mode_t de_mode;
@@ -167,35 +146,32 @@ struct devfs_dirent {
};
struct devfs_mount {
+ u_int dm_idx;
struct mount *dm_mount;
struct devfs_dirent *dm_rootdir;
unsigned dm_generation;
- struct devfs_dirent **dm_dirent;
- struct devfs_dirent **dm_overflow;
- int dm_inode;
- struct lock dm_lock;
+ struct sx dm_lock;
devfs_rsnum dm_ruleset;
};
-extern unsigned devfs_rule_depth;
+#define DEVFS_ROOTINO 2
-/*
- * This is what we fill in dm_dirent[N] for a deleted entry.
- */
-#define DE_DELETED ((struct devfs_dirent *)sizeof(struct devfs_dirent))
+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);
+void devfs_delete(struct devfs_mount *dm, struct devfs_dirent *de);
void devfs_populate (struct devfs_mount *dm);
+void devfs_cleanup (struct devfs_mount *dm);
struct devfs_dirent *devfs_newdirent (char *name, int namelen);
-void devfs_purge (struct devfs_dirent *dd);
-struct devfs_dirent *devfs_vmkdir (char *name, int namelen, struct devfs_dirent *dotdot);
+struct devfs_dirent *devfs_vmkdir (struct devfs_mount *, char *name, int namelen, struct devfs_dirent *dotdot, u_int inode);
+struct devfs_dirent *devfs_find (struct devfs_dirent *dd, const char *name, int namelen);
#endif /* _KERNEL */
diff --git a/sys/fs/devfs/devfs_devs.c b/sys/fs/devfs/devfs_devs.c
index 77a514083e3b..5b06b8cc24ca 100644
--- a/sys/fs/devfs/devfs_devs.c
+++ b/sys/fs/devfs/devfs_devs.c
@@ -36,44 +36,42 @@
#include <sys/conf.h>
#include <sys/dirent.h>
#include <sys/kernel.h>
+#include <sys/limits.h>
#include <sys/lock.h>
#include <sys/mac.h>
#include <sys/malloc.h>
#include <sys/proc.h>
+#include <sys/sx.h>
#include <sys/sysctl.h>
#include <sys/vnode.h>
-#include <machine/atomic.h>
+#include <sys/kdb.h>
#include <fs/devfs/devfs.h>
#include <fs/devfs/devfs_int.h>
-static struct cdev *devfs_inot[NDEVFSINO];
-static struct cdev **devfs_overflow;
-static int devfs_ref[NDEVFSINO];
-static int *devfs_refoverflow;
-static int devfs_nextino = 3;
-static int devfs_numino;
-static int devfs_topino;
-static int devfs_noverflowwant = NDEVFSOVERFLOW;
-static int devfs_noverflow;
-static unsigned devfs_generation;
+/*
+ * The one true (but secret) list of active devices in the system.
+ * Locked by dev_lock()/devmtx
+ */
+static TAILQ_HEAD(,cdev_priv) cdevp_list = TAILQ_HEAD_INITIALIZER(cdevp_list);
+
+struct unrhdr *devfs_inos;
-static struct devfs_dirent *devfs_find (struct devfs_dirent *dd, const char *name, int namelen);
+
+static MALLOC_DEFINE(M_DEVFS2, "DEVFS2", "DEVFS data 2");
+static MALLOC_DEFINE(M_DEVFS3, "DEVFS3", "DEVFS data 3");
+static MALLOC_DEFINE(M_CDEVP, "DEVFS1", "DEVFS cdev_priv storage");
static SYSCTL_NODE(_vfs, OID_AUTO, devfs, CTLFLAG_RW, 0, "DEVFS filesystem");
-SYSCTL_UINT(_vfs_devfs, OID_AUTO, noverflow, CTLFLAG_RW,
- &devfs_noverflowwant, 0, "Size of DEVFS overflow table");
+
+static unsigned devfs_generation;
SYSCTL_UINT(_vfs_devfs, OID_AUTO, generation, CTLFLAG_RD,
&devfs_generation, 0, "DEVFS generation number");
-SYSCTL_UINT(_vfs_devfs, OID_AUTO, inodes, CTLFLAG_RD,
- &devfs_numino, 0, "DEVFS inodes");
-SYSCTL_UINT(_vfs_devfs, OID_AUTO, topinode, CTLFLAG_RD,
- &devfs_topino, 0, "DEVFS highest inode#");
unsigned devfs_rule_depth = 1;
SYSCTL_UINT(_vfs_devfs, OID_AUTO, rule_depth, CTLFLAG_RW,
- &devfs_rule_depth, 0, "Max depth of ruleset include");
+ &devfs_rule_depth, 0, "Max depth of ruleset include");
/*
* Helper sysctl for devname(3). We're given a struct cdev * and return
@@ -84,20 +82,24 @@ sysctl_devname(SYSCTL_HANDLER_ARGS)
{
int error;
dev_t ud;
- struct cdev *dev, **dp;
+ struct cdev_priv *cdp;
error = SYSCTL_IN(req, &ud, sizeof (ud));
if (error)
return (error);
if (ud == NODEV)
return(EINVAL);
- dp = devfs_itod(ud);
- if (dp == NULL)
- return(ENOENT);
- dev = *dp;
- if (dev == NULL)
+/*
+ ud ^ devfs_random();
+*/
+ dev_lock();
+ TAILQ_FOREACH(cdp, &cdevp_list, cdp_list)
+ if (cdp->cdp_inode == ud)
+ break;
+ dev_unlock();
+ if (cdp == NULL)
return(ENOENT);
- return(SYSCTL_OUT(req, dev->si_name, strlen(dev->si_name) + 1));
+ return(SYSCTL_OUT(req, cdp->cdp_c.si_name, strlen(cdp->cdp_c.si_name) + 1));
return (error);
}
@@ -107,77 +109,45 @@ SYSCTL_PROC(_kern, OID_AUTO, devname, CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_ANYBODY,
SYSCTL_INT(_debug_sizeof, OID_AUTO, cdev, CTLFLAG_RD,
0, sizeof(struct cdev), "sizeof(struct cdev)");
-static int *
-devfs_itor(int inode)
-{
- if (inode < NDEVFSINO)
- return (&devfs_ref[inode]);
- else if (inode < NDEVFSINO + devfs_noverflow)
- return (&devfs_refoverflow[inode - NDEVFSINO]);
- else
- panic ("YRK!");
-}
+SYSCTL_INT(_debug_sizeof, OID_AUTO, cdev_priv, CTLFLAG_RD,
+ 0, sizeof(struct cdev_priv), "sizeof(struct cdev_priv)");
-static void
-devfs_dropref(int inode)
+struct cdev *
+devfs_alloc(void)
{
- int *ip;
+ struct cdev_priv *cdp;
+ struct cdev *cdev;
- ip = devfs_itor(inode);
- atomic_add_int(ip, -1);
-}
+ cdp = malloc(sizeof *cdp, M_CDEVP, M_USE_RESERVE | M_ZERO | M_WAITOK);
-static int
-devfs_getref(int inode)
-{
- int *ip, i, j;
- struct cdev **dp;
-
- ip = devfs_itor(inode);
- dp = devfs_itod(inode);
- for (;;) {
- i = *ip;
- j = i + 1;
- if (!atomic_cmpset_int(ip, i, j))
- continue;
- if (*dp != NULL)
- return (1);
- atomic_add_int(ip, -1);
- return(0);
- }
-}
+ cdp->cdp_dirents = &cdp->cdp_dirent0;
+ cdp->cdp_dirent0 = NULL;
+ cdp->cdp_maxdirent = 0;
-struct devfs_dirent **
-devfs_itode (struct devfs_mount *dm, int inode)
-{
+ cdev = &cdp->cdp_c;
+ cdev->si_priv = cdp;
- if (inode < 0)
- return (NULL);
- if (inode < NDEVFSINO)
- return (&dm->dm_dirent[inode]);
- if (devfs_overflow == NULL)
- return (NULL);
- if (inode < NDEVFSINO + devfs_noverflow)
- return (&dm->dm_overflow[inode - NDEVFSINO]);
- return (NULL);
+ cdev->si_name = cdev->__si_namebuf;
+ LIST_INIT(&cdev->si_children);
+ return (cdev);
}
-struct cdev **
-devfs_itod (int inode)
+void
+devfs_free(struct cdev *cdev)
{
-
- if (inode < 0)
- return (NULL);
- if (inode < NDEVFSINO)
- return (&devfs_inot[inode]);
- if (devfs_overflow == NULL)
- return (NULL);
- if (inode < NDEVFSINO + devfs_noverflow)
- return (&devfs_overflow[inode - NDEVFSINO]);
- return (NULL);
+ struct cdev_priv *cdp;
+
+ cdp = cdev->si_priv;
+ if (cdev->si_cred != NULL)
+ crfree(cdev->si_cred);
+ if (cdp->cdp_inode > 0)
+ free_unr(devfs_inos, cdp->cdp_inode);
+ if (cdp->cdp_maxdirent > 0)
+ free(cdp->cdp_dirents, M_DEVFS2);
+ free(cdp, M_CDEVP);
}
-static struct devfs_dirent *
+struct devfs_dirent *
devfs_find(struct devfs_dirent *dd, const char *name, int namelen)
{
struct devfs_dirent *de;
@@ -200,8 +170,8 @@ devfs_newdirent(char *name, int namelen)
struct dirent d;
d.d_namlen = namelen;
- i = sizeof (*de) + GENERIC_DIRSIZ(&d);
- de = malloc(i, M_DEVFS, M_WAITOK | M_ZERO);
+ i = sizeof (*de) + GENERIC_DIRSIZ(&d);
+ de = malloc(i, M_DEVFS3, M_WAITOK | M_ZERO);
de->de_dirent = (struct dirent *)(de + 1);
de->de_dirent->d_namlen = namelen;
de->de_dirent->d_reclen = GENERIC_DIRSIZ(&d);
@@ -217,158 +187,274 @@ devfs_newdirent(char *name, int namelen)
}
struct devfs_dirent *
-devfs_vmkdir(char *name, int namelen, struct devfs_dirent *dotdot)
+devfs_vmkdir(struct devfs_mount *dmp, char *name, int namelen, struct devfs_dirent *dotdot, u_int inode)
{
struct devfs_dirent *dd;
struct devfs_dirent *de;
+ /* Create the new directory */
dd = devfs_newdirent(name, namelen);
-
TAILQ_INIT(&dd->de_dlist);
-
dd->de_dirent->d_type = DT_DIR;
dd->de_mode = 0555;
dd->de_links = 2;
dd->de_dir = dd;
+ if (inode != 0)
+ dd->de_inode = inode;
+ else
+ dd->de_inode = alloc_unr(devfs_inos);
+ /* Create the "." entry in the new directory */
de = devfs_newdirent(".", 1);
de->de_dirent->d_type = DT_DIR;
- de->de_dir = dd;
de->de_flags |= DE_DOT;
TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
+ de->de_dir = dd;
+ /* Create the ".." entry in the new directory */
de = devfs_newdirent("..", 2);
de->de_dirent->d_type = DT_DIR;
- if (dotdot == NULL)
- de->de_dir = dd;
- else
- de->de_dir = dotdot;
de->de_flags |= DE_DOTDOT;
TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
+ if (dotdot == NULL) {
+ de->de_dir = dd;
+ } else {
+ de->de_dir = dotdot;
+ TAILQ_INSERT_TAIL(&dotdot->de_dlist, dd, de_list);
+ dotdot->de_links++;
+ }
+#ifdef MAC
+ mac_create_devfs_directory(dmp->dm_mount, name, namelen, dd);
+#endif
return (dd);
}
-static void
-devfs_delete(struct devfs_dirent *dd, struct devfs_dirent *de)
+void
+devfs_delete(struct devfs_mount *dm, struct devfs_dirent *de)
{
if (de->de_symlink) {
free(de->de_symlink, M_DEVFS);
de->de_symlink = NULL;
}
- if (de->de_vnode)
+ if (de->de_vnode != NULL) {
de->de_vnode->v_data = NULL;
- TAILQ_REMOVE(&dd->de_dlist, de, de_list);
+ vgone(de->de_vnode);
+ de->de_vnode = NULL;
+ }
#ifdef MAC
mac_destroy_devfsdirent(de);
#endif
- free(de, M_DEVFS);
+ if (de->de_inode > DEVFS_ROOTINO) {
+ free_unr(devfs_inos, de->de_inode);
+ de->de_inode = 0;
+ }
+ free(de, M_DEVFS3);
}
-void
-devfs_purge(struct devfs_dirent *dd)
+/*
+ * Called on unmount.
+ * Recursively removes the entire tree
+ */
+
+static void
+devfs_purge(struct devfs_mount *dm, struct devfs_dirent *dd)
{
struct devfs_dirent *de;
+ sx_assert(&dm->dm_lock, SX_XLOCKED);
for (;;) {
de = TAILQ_FIRST(&dd->de_dlist);
if (de == NULL)
break;
- devfs_delete(dd, de);
+ TAILQ_REMOVE(&dd->de_dlist, de, de_list);
+ if (de->de_flags & (DE_DOT|DE_DOTDOT))
+ devfs_delete(dm, de);
+ else if (de->de_dirent->d_type == DT_DIR)
+ devfs_purge(dm, de);
+ else
+ devfs_delete(dm, de);
}
- FREE(dd, M_DEVFS);
+ devfs_delete(dm, dd);
}
+/*
+ * Each cdev_priv has an array of pointers to devfs_dirent which is indexed
+ * by the mount points dm_idx.
+ * This function extends the array when necessary, taking into account that
+ * the default array is 1 element and not malloc'ed.
+ */
+static void
+devfs_metoo(struct cdev_priv *cdp, struct devfs_mount *dm)
+{
+ struct devfs_dirent **dep;
+ int siz;
+
+ siz = (dm->dm_idx + 1) * sizeof *dep;
+ dep = malloc(siz, M_DEVFS2, M_WAITOK | M_ZERO);
+ dev_lock();
+ if (dm->dm_idx <= cdp->cdp_maxdirent) {
+ /* We got raced */
+ dev_unlock();
+ free(dep, M_DEVFS2);
+ return;
+ }
+ memcpy(dep, cdp->cdp_dirents, (cdp->cdp_maxdirent + 1) * sizeof *dep);
+ if (cdp->cdp_maxdirent > 0)
+ free(cdp->cdp_dirents, M_DEVFS2);
+ cdp->cdp_dirents = dep;
+ /*
+ * XXX: if malloc told us how much we actually got this could
+ * XXX: be optimized.
+ */
+ cdp->cdp_maxdirent = dm->dm_idx;
+ dev_unlock();
+}
-void
-devfs_populate(struct devfs_mount *dm)
+static int
+devfs_populate_loop(struct devfs_mount *dm, int cleanup)
{
- int i, j;
- struct cdev *dev, *pdev;
+ struct cdev_priv *cdp;
+ struct devfs_dirent *de;
struct devfs_dirent *dd;
- struct devfs_dirent *de, **dep;
+ struct cdev *pdev;
+ int j;
char *q, *s;
- if (dm->dm_generation == devfs_generation)
- return;
- if (devfs_noverflow && dm->dm_overflow == NULL) {
- i = devfs_noverflow * sizeof (struct devfs_dirent *);
- MALLOC(dm->dm_overflow, struct devfs_dirent **, i,
- M_DEVFS, M_WAITOK | M_ZERO);
- }
- while (dm->dm_generation != devfs_generation) {
- dm->dm_generation = devfs_generation;
- for (i = 0; i <= devfs_topino; i++) {
- dev = *devfs_itod(i);
- dep = devfs_itode(dm, i);
- de = *dep;
- if (dev == NULL && de == DE_DELETED) {
- *dep = NULL;
- continue;
- }
- if (dev == NULL && de != NULL) {
- dd = de->de_dir;
- *dep = NULL;
- devfs_delete(dd, de);
- devfs_dropref(i);
- continue;
- }
- if (dev == NULL)
- continue;
- if (de != NULL)
+ sx_assert(&dm->dm_lock, SX_XLOCKED);
+ dev_lock();
+ TAILQ_FOREACH(cdp, &cdevp_list, cdp_list) {
+
+ KASSERT(cdp->cdp_dirents != NULL, ("NULL cdp_dirents"));
+
+ /*
+ * If we are unmounting, or the device has been destroyed,
+ * clean up our dirent.
+ */
+ if ((cleanup || !(cdp->cdp_flags & CDP_ACTIVE)) &&
+ dm->dm_idx <= cdp->cdp_maxdirent &&
+ cdp->cdp_dirents[dm->dm_idx] != NULL) {
+ de = cdp->cdp_dirents[dm->dm_idx];
+ cdp->cdp_dirents[dm->dm_idx] = NULL;
+ cdp->cdp_inuse--;
+ KASSERT(cdp == de->de_cdp,
+ ("%s %d %s %p %p", __func__, __LINE__,
+ cdp->cdp_c.si_name, cdp, de->de_cdp));
+ KASSERT(de->de_dir != NULL, ("Null de->de_dir"));
+ dev_unlock();
+
+ TAILQ_REMOVE(&de->de_dir->de_dlist, de, de_list);
+ de->de_cdp = NULL;
+ de->de_inode = 0;
+ devfs_delete(dm, de);
+ return (1);
+ }
+ /*
+ * GC any lingering devices
+ */
+ if (!(cdp->cdp_flags & CDP_ACTIVE)) {
+ if (cdp->cdp_inuse > 0)
continue;
- if (!devfs_getref(i))
+ TAILQ_REMOVE(&cdevp_list, cdp, cdp_list);
+ dev_unlock();
+ dev_rel(&cdp->cdp_c);
+ return (1);
+ }
+ /*
+ * Don't create any new dirents if we are unmounting
+ */
+ if (cleanup)
+ continue;
+ KASSERT((cdp->cdp_flags & CDP_ACTIVE), ("Bogons, I tell ya'!"));
+
+ if (dm->dm_idx <= cdp->cdp_maxdirent &&
+ cdp->cdp_dirents[dm->dm_idx] != NULL) {
+ de = cdp->cdp_dirents[dm->dm_idx];
+ KASSERT(cdp == de->de_cdp, ("inconsistent cdp"));
+ continue;
+ }
+
+
+ cdp->cdp_inuse++;
+ dev_unlock();
+
+ if (dm->dm_idx > cdp->cdp_maxdirent)
+ devfs_metoo(cdp, dm);
+
+ dd = dm->dm_rootdir;
+ s = cdp->cdp_c.si_name;
+ for (;;) {
+ for (q = s; *q != '/' && *q != '\0'; q++)
continue;
- dd = dm->dm_rootdir;
- s = dev->si_name;
- for (;;) {
- for (q = s; *q != '/' && *q != '\0'; q++)
- continue;
- if (*q != '/')
- break;
- de = devfs_find(dd, s, q - s);
- if (de == NULL) {
- de = devfs_vmkdir(s, q - s, dd);
-#ifdef MAC
- mac_create_devfs_directory(
- dm->dm_mount, s, q - s, de);
-#endif
- de->de_inode = dm->dm_inode++;
- TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
- dd->de_links++;
- }
- s = q + 1;
- dd = de;
- }
- de = devfs_newdirent(s, q - s);
- if (dev->si_flags & SI_ALIAS) {
- de->de_inode = dm->dm_inode++;
- de->de_uid = 0;
- de->de_gid = 0;
- de->de_mode = 0755;
- de->de_dirent->d_type = DT_LNK;
- pdev = dev->si_parent;
- j = strlen(pdev->si_name) + 1;
- MALLOC(de->de_symlink, char *, j, M_DEVFS, M_WAITOK);
- bcopy(pdev->si_name, de->de_symlink, j);
- } else {
- de->de_inode = i;
- de->de_uid = dev->si_uid;
- de->de_gid = dev->si_gid;
- de->de_mode = dev->si_mode;
- de->de_dirent->d_type = DT_CHR;
- }
+ if (*q != '/')
+ break;
+ de = devfs_find(dd, s, q - s);
+ if (de == NULL)
+ de = devfs_vmkdir(dm, s, q - s, dd, 0);
+ s = q + 1;
+ dd = de;
+ }
+
+ de = devfs_newdirent(s, q - s);
+ if (cdp->cdp_c.si_flags & SI_ALIAS) {
+ de->de_uid = 0;
+ de->de_gid = 0;
+ de->de_mode = 0755;
+ de->de_dirent->d_type = DT_LNK;
+ pdev = cdp->cdp_c.si_parent;
+ j = strlen(pdev->si_name) + 1;
+ de->de_symlink = malloc(j, M_DEVFS, M_WAITOK);
+ bcopy(pdev->si_name, de->de_symlink, j);
+ } else {
+ de->de_uid = cdp->cdp_c.si_uid;
+ de->de_gid = cdp->cdp_c.si_gid;
+ de->de_mode = cdp->cdp_c.si_mode;
+ de->de_dirent->d_type = DT_CHR;
+ }
+ de->de_inode = cdp->cdp_inode;
+ de->de_cdp = cdp;
#ifdef MAC
- mac_create_devfs_device(dev->si_cred, dm->dm_mount,
- dev, de);
+ mac_create_devfs_device(cdp->cdp_c.si_cred, dm->dm_mount,
+ &cdp->cdp_c, de);
#endif
- *dep = de;
- de->de_dir = dd;
- devfs_rules_apply(dm, de);
- TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
- }
+ de->de_dir = dd;
+ TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
+ devfs_rules_apply(dm, de);
+ dev_lock();
+ /* XXX: could check that cdp is still active here */
+ KASSERT(cdp->cdp_dirents[dm->dm_idx] == NULL,
+ ("%s %d\n", __func__, __LINE__));
+ cdp->cdp_dirents[dm->dm_idx] = de;
+ KASSERT(de->de_cdp != (void *)0xdeadc0de,
+ ("%s %d\n", __func__, __LINE__));
+ dev_unlock();
+ return (1);
}
+ dev_unlock();
+ return (0);
+}
+
+void
+devfs_populate(struct devfs_mount *dm)
+{
+
+ sx_assert(&dm->dm_lock, SX_XLOCKED);
+ if (dm->dm_generation == devfs_generation)
+ return;
+ while (devfs_populate_loop(dm, 0))
+ continue;
+ dm->dm_generation = devfs_generation;
+}
+
+void
+devfs_cleanup(struct devfs_mount *dm)
+{
+
+ sx_assert(&dm->dm_lock, SX_XLOCKED);
+ while (devfs_populate_loop(dm, 1))
+ continue;
+ devfs_purge(dm, dm->dm_rootdir);
}
/*
@@ -380,83 +466,33 @@ devfs_populate(struct devfs_mount *dm)
void
devfs_create(struct cdev *dev)
{
- int ino, i, *ip;
- struct cdev **dp;
- struct cdev **ot;
- int *or;
- int n;
-
- for (;;) {
- /* Grab the next inode number */
- ino = devfs_nextino;
- i = ino + 1;
- /* wrap around when we reach the end */
- if (i >= NDEVFSINO + devfs_noverflow)
- i = 3;
- devfs_nextino = i;
-
- /* see if it was occupied */
- dp = devfs_itod(ino);
- KASSERT(dp != NULL, ("DEVFS: No devptr inode %d", ino));
- if (*dp != NULL)
- continue;
- ip = devfs_itor(ino);
- KASSERT(ip != NULL, ("DEVFS: No iptr inode %d", ino));
- if (*ip != 0)
- continue;
- break;
- }
-
- *dp = dev;
- dev->si_inode = ino;
- if (i > devfs_topino)
- devfs_topino = i;
-
- devfs_numino++;
+ struct cdev_priv *cdp;
+
+ mtx_assert(&devmtx, MA_OWNED);
+ cdp = dev->si_priv;
+ cdp->cdp_flags |= CDP_ACTIVE;
+ cdp->cdp_inode = alloc_unrl(devfs_inos);
+ dev_refl(dev);
+ TAILQ_INSERT_TAIL(&cdevp_list, cdp, cdp_list);
devfs_generation++;
-
- if (devfs_overflow != NULL || devfs_numino + 100 < NDEVFSINO)
- return;
-
- /*
- * Try to allocate overflow table
- * XXX: we can probably be less panicy these days and a linked
- * XXX: list of PAGESIZE/PTRSIZE entries might be a better idea.
- *
- * XXX: we may be into witness unlove here.
- */
- n = devfs_noverflowwant;
- ot = malloc(sizeof(*ot) * n, M_DEVFS, M_NOWAIT | M_ZERO);
- if (ot == NULL)
- return;
- or = malloc(sizeof(*or) * n, M_DEVFS, M_NOWAIT | M_ZERO);
- if (or == NULL) {
- free(ot, M_DEVFS);
- return;
- }
- devfs_overflow = ot;
- devfs_refoverflow = or;
- devfs_noverflow = n;
- printf("DEVFS Overflow table with %d entries allocated\n", n);
- return;
}
void
devfs_destroy(struct cdev *dev)
{
- int ino;
- struct cdev **dp;
+ struct cdev_priv *cdp;
- ino = dev->si_inode;
- dev->si_inode = 0;
- if (ino == 0)
- return;
- dp = devfs_itod(ino);
- KASSERT(*dp == dev,
- ("DEVFS: destroying wrong cdev ino %d", ino));
- *dp = NULL;
- devfs_numino--;
+ mtx_assert(&devmtx, MA_OWNED);
+ cdp = dev->si_priv;
+ cdp->cdp_flags &= ~CDP_ACTIVE;
devfs_generation++;
- if (ino < devfs_nextino)
- devfs_nextino = ino;
}
+
+static void
+devfs_devs_init(void *junk __unused)
+{
+
+ devfs_inos = new_unrhdr(DEVFS_ROOTINO + 1, INT_MAX, &devmtx);
+}
+
+SYSINIT(devfs_devs, SI_SUB_DEVFS, SI_ORDER_FIRST, devfs_devs_init, NULL);
diff --git a/sys/fs/devfs/devfs_int.h b/sys/fs/devfs/devfs_int.h
index 9c4c5f939b47..41cc0c2553a5 100644
--- a/sys/fs/devfs/devfs_int.h
+++ b/sys/fs/devfs/devfs_int.h
@@ -37,9 +37,31 @@
#ifdef _KERNEL
+struct devfs_dirent;
+
+struct cdev_priv {
+ struct cdev cdp_c;
+ TAILQ_ENTRY(cdev_priv) cdp_list;
+
+ u_int cdp_inode;
+
+ u_int cdp_flags;
+#define CDP_ACTIVE (1 << 0)
+
+ u_int cdp_inuse;
+ u_int cdp_maxdirent;
+ struct devfs_dirent **cdp_dirents;
+ struct devfs_dirent *cdp_dirent0;
+};
+
+struct cdev *devfs_alloc(void);
+void devfs_free(struct cdev *);
void devfs_create(struct cdev *dev);
void devfs_destroy(struct cdev *dev);
+extern struct unrhdr *devfs_inos;
+extern struct mtx devmtx;
+
#endif /* _KERNEL */
#endif /* !_FS_DEVFS_DEVFS_INT_H_ */
diff --git a/sys/fs/devfs/devfs_rule.c b/sys/fs/devfs/devfs_rule.c
index 5e25f4eaeadf..840f9f970e74 100644
--- a/sys/fs/devfs/devfs_rule.c
+++ b/sys/fs/devfs/devfs_rule.c
@@ -70,32 +70,33 @@
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/dirent.h>
-#include <sys/vnode.h>
#include <sys/ioccom.h>
+#include <sys/lock.h>
#include <sys/sx.h>
#include <fs/devfs/devfs.h>
-
+#include <fs/devfs/devfs_int.h>
/*
* 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
@@ -176,6 +163,8 @@ devfs_rules_ioctl(struct devfs_mount *dm, u_long cmd, caddr_t data, struct threa
devfs_rid rid;
int error;
+ sx_assert(&dm->dm_lock, SX_XLOCKED);
+
/*
* XXX: This returns an error regardless of whether we
* actually support the cmd or not.
@@ -185,24 +174,27 @@ devfs_rules_ioctl(struct devfs_mount *dm, u_long cmd, caddr_t data, struct threa
return (error);
sx_xlock(&sx_rules);
+
switch (cmd) {
case DEVFSIO_RADD:
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
@@ -221,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;
@@ -235,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;
@@ -246,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
@@ -268,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;
@@ -292,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.
*
@@ -366,6 +329,7 @@ devfs_rid_input(devfs_rid rid, struct devfs_mount *dm)
* XXX: This method needs a function call for every nested
* subdirectory in a devfs mount. If we plan to have many of these,
* we might eventually run out of kernel stack space.
+ * XXX: a linear search could be done through the cdev list instead.
*/
static void
devfs_rule_applyde_recursive(struct devfs_krule *dk, struct devfs_dirent *de)
@@ -397,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 {
@@ -428,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)
@@ -442,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);
}
@@ -469,18 +430,13 @@ devfs_rule_delete(struct devfs_krule **dkp)
static struct cdev *
devfs_rule_getdev(struct devfs_dirent *de)
{
- struct cdev **devp, *dev;
- devp = devfs_itod(de->de_inode);
- if (devp != NULL)
- dev = *devp;
+ if (de->de_cdp == NULL)
+ return (NULL);
+ if (de->de_cdp->cdp_flags & CDP_ACTIVE)
+ return (&de->de_cdp->cdp_c);
else
- dev = NULL;
- /* If we think this dirent should have a struct cdev *, alert the user. */
- if (dev == NULL && de->de_dirent->d_type != DT_LNK &&
- de->de_dirent->d_type != DT_DIR)
- printf("Warning: no struct cdev *for %s\n", de->de_dirent->d_name);
- return (dev);
+ return (NULL);
}
/*
@@ -507,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;
@@ -526,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;
@@ -546,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);
}
@@ -670,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);
}
@@ -698,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);
- }
}
/*
@@ -711,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);
}
@@ -724,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);
}
/*
@@ -797,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 307b4a28ceaf..bb3458646ea2 100644
--- a/sys/fs/devfs/devfs_vfsops.c
+++ b/sys/fs/devfs/devfs_vfsops.c
@@ -45,10 +45,14 @@
#include <sys/malloc.h>
#include <sys/mount.h>
#include <sys/proc.h>
+#include <sys/sx.h>
#include <sys/vnode.h>
+#include <sys/limits.h>
#include <fs/devfs/devfs.h>
+static struct unrhdr *devfs_unr;
+
MALLOC_DEFINE(M_DEVFS, "DEVFS", "DEVFS data");
static vfs_mount_t devfs_mount;
@@ -66,39 +70,34 @@ devfs_mount(struct mount *mp, struct thread *td)
struct devfs_mount *fmp;
struct vnode *rvp;
+ if (devfs_unr == NULL)
+ devfs_unr = new_unrhdr(0, INT_MAX, NULL);
+
error = 0;
if (mp->mnt_flag & (MNT_UPDATE | MNT_ROOTFS))
return (EOPNOTSUPP);
- MALLOC(fmp, struct devfs_mount *, sizeof(struct devfs_mount),
- M_DEVFS, M_WAITOK | M_ZERO);
- MALLOC(fmp->dm_dirent, struct devfs_dirent **,
- sizeof(struct devfs_dirent *) * NDEVFSINO,
- M_DEVFS, M_WAITOK | M_ZERO);
- lockinit(&fmp->dm_lock, PVFS, "devfs", 0, 0);
+ fmp = malloc(sizeof *fmp, M_DEVFS, M_WAITOK | M_ZERO);
+ fmp->dm_idx = alloc_unr(devfs_unr);
+ sx_init(&fmp->dm_lock, "devfsmount");
mp->mnt_flag |= MNT_LOCAL;
+ mp->mnt_kern_flag |= MNTK_MPSAFE;
#ifdef MAC
mp->mnt_flag |= MNT_MULTILABEL;
#endif
fmp->dm_mount = mp;
- mp->mnt_data = (qaddr_t) fmp;
+ mp->mnt_data = (void *) fmp;
vfs_getnewfsid(mp);
- fmp->dm_inode = DEVFSINOMOUNT;
-
- fmp->dm_rootdir = devfs_vmkdir("(root)", 6, NULL);
- fmp->dm_rootdir->de_inode = 2;
-#ifdef MAC
- mac_create_devfs_directory(mp, "", 0, fmp->dm_rootdir);
-#endif
- devfs_rules_newmount(fmp, td);
+ fmp->dm_rootdir = devfs_vmkdir(fmp, NULL, 0, NULL, DEVFS_ROOTINO);
error = devfs_root(mp, LK_EXCLUSIVE, &rvp, td);
if (error) {
- lockdestroy(&fmp->dm_lock);
- FREE(fmp, M_DEVFS);
+ sx_destroy(&fmp->dm_lock);
+ free_unr(devfs_unr, fmp->dm_idx);
+ free(fmp, M_DEVFS);
return (error);
}
@@ -110,10 +109,7 @@ devfs_mount(struct mount *mp, struct thread *td)
}
static int
-devfs_unmount(mp, mntflags, td)
- struct mount *mp;
- int mntflags;
- struct thread *td;
+devfs_unmount(struct mount *mp, int mntflags, struct thread *td)
{
int error;
int flags = 0;
@@ -124,10 +120,13 @@ devfs_unmount(mp, mntflags, td)
error = vflush(mp, 1, flags, td);
if (error)
return (error);
- devfs_purge(fmp->dm_rootdir);
- mp->mnt_data = 0;
- lockdestroy(&fmp->dm_lock);
- free(fmp->dm_dirent, M_DEVFS);
+ 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);
+ free_unr(devfs_unr, fmp->dm_idx);
free(fmp, M_DEVFS);
return 0;
}
@@ -135,11 +134,7 @@ devfs_unmount(mp, mntflags, td)
/* Return locked reference to root. */
static int
-devfs_root(mp, flags, vpp, td)
- struct mount *mp;
- int flags;
- struct vnode **vpp;
- struct thread *td;
+devfs_root(struct mount *mp, int flags, struct vnode **vpp, struct thread *td)
{
int error;
struct vnode *vp;
@@ -155,10 +150,7 @@ devfs_root(mp, flags, vpp, td)
}
static int
-devfs_statfs(mp, sbp, td)
- struct mount *mp;
- struct statfs *sbp;
- struct thread *td;
+devfs_statfs(struct mount *mp, struct statfs *sbp, struct thread *td)
{
sbp->f_flags = 0;
diff --git a/sys/fs/devfs/devfs_vnops.c b/sys/fs/devfs/devfs_vnops.c
index 6cf2f49b888d..f14f480c6c11 100644
--- a/sys/fs/devfs/devfs_vnops.c
+++ b/sys/fs/devfs/devfs_vnops.c
@@ -37,7 +37,6 @@
/*
* TODO:
* remove empty directories
- * mknod: hunt down DE_DELETED, compare name, reinstantiate.
* mkdir: want it ?
*/
@@ -71,6 +70,8 @@ static struct vop_vector devfs_specops;
static struct fileops devfs_ops_f;
#include <fs/devfs/devfs.h>
+#include <fs/devfs/devfs_int.h>
+
static int
devfs_fp_check(struct file *fp, struct cdev **devp, struct cdevsw **dswp)
{
@@ -139,9 +140,9 @@ loop:
return (0);
}
if (de->de_dirent->d_type == DT_CHR) {
- dev = *devfs_itod(de->de_inode);
- if (dev == NULL)
+ if (!(de->de_cdp->cdp_flags & CDP_ACTIVE))
return (ENOENT);
+ dev = &de->de_cdp->cdp_c;
} else {
dev = NULL;
}
@@ -157,7 +158,8 @@ loop:
dev_lock();
dev_refl(dev);
vp->v_rdev = dev;
- LIST_INSERT_HEAD(&dev->si_alist, de, de_alias);
+ KASSERT(vp->v_usecount == 1,
+ ("%s %d (%d)\n", __func__, __LINE__, vp->v_usecount));
dev->si_usecount += vp->v_usecount;
dev_unlock();
VI_UNLOCK(vp);
@@ -204,9 +206,6 @@ devfs_access(struct vop_access_args *ap)
return (error);
}
-/*
- * Special device advisory byte-level locks.
- */
/* ARGSUSED */
static int
devfs_advlock(struct vop_advlock_args *ap)
@@ -215,9 +214,6 @@ devfs_advlock(struct vop_advlock_args *ap)
return (ap->a_flags & F_FLOCK ? EOPNOTSUPP : EINVAL);
}
-/*
- * Device close routine
- */
/* ARGSUSED */
static int
devfs_close(struct vop_close_args *ap)
@@ -301,9 +297,6 @@ devfs_close_f(struct file *fp, struct thread *td)
return (vnops.fo_close(fp, td));
}
-/*
- * Synch buffers associated with a block device
- */
/* ARGSUSED */
static int
devfs_fsync(struct vop_fsync_args *ap)
@@ -370,7 +363,7 @@ devfs_getattr(struct vop_getattr_args *ap)
fix(dev->si_ctime);
vap->va_ctime = dev->si_ctime;
- vap->va_rdev = dev->si_inode;
+ vap->va_rdev = dev->si_priv->cdp_inode;
}
vap->va_gen = 0;
vap->va_flags = 0;
@@ -380,9 +373,6 @@ devfs_getattr(struct vop_getattr_args *ap)
return (error);
}
-/*
- * Device ioctl operation.
- */
/* ARGSUSED */
static int
devfs_ioctl_f(struct file *fp, u_long com, void *data, struct ucred *cred, struct thread *td)
@@ -446,7 +436,6 @@ devfs_ioctl_f(struct file *fp, u_long com, void *data, struct ucred *cred, struc
return (error);
}
-
/* ARGSUSED */
static int
devfs_kqfilter_f(struct file *fp, struct knote *kn)
@@ -520,65 +509,47 @@ devfs_lookupx(struct vop_lookup_args *ap)
return (error);
}
- lockmgr(&dmp->dm_lock, LK_UPGRADE, 0, curthread);
devfs_populate(dmp);
- lockmgr(&dmp->dm_lock, LK_DOWNGRADE, 0, curthread);
dd = dvp->v_data;
- TAILQ_FOREACH(de, &dd->de_dlist, de_list) {
- if (cnp->cn_namelen != de->de_dirent->d_namlen)
- continue;
- if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name,
- de->de_dirent->d_namlen) != 0)
- continue;
- if (de->de_flags & DE_WHITEOUT)
- goto notfound;
- goto found;
- }
-
- if (nameiop == DELETE)
- goto notfound;
-
- /*
- * OK, we didn't have an entry for the name we were asked for
- * so we try to see if anybody can create it on demand.
- */
- pname = devfs_fqpn(specname, dvp, cnp);
- if (pname == NULL)
- goto notfound;
+ de = devfs_find(dd, cnp->cn_nameptr, cnp->cn_namelen);
+ while (de == NULL) { /* While(...) so we can use break */
- cdev = NULL;
- EVENTHANDLER_INVOKE(dev_clone, td->td_ucred, pname, strlen(pname),
- &cdev);
- if (cdev == NULL)
- goto notfound;
-
- lockmgr(&dmp->dm_lock, LK_UPGRADE, 0, curthread);
- devfs_populate(dmp);
- lockmgr(&dmp->dm_lock, LK_DOWNGRADE, 0, curthread);
-
- dde = devfs_itode(dmp, cdev->si_inode);
- dev_rel(cdev);
-
- if (dde == NULL || *dde == NULL || *dde == DE_DELETED)
- goto notfound;
+ if (nameiop == DELETE)
+ return (ENOENT);
- if ((*dde)->de_flags & DE_WHITEOUT)
- goto notfound;
+ /*
+ * OK, we didn't have an entry for the name we were asked for
+ * so we try to see if anybody can create it on demand.
+ */
+ pname = devfs_fqpn(specname, dvp, cnp);
+ if (pname == NULL)
+ break;
- de = *dde;
- goto found;
+ cdev = NULL;
+ EVENTHANDLER_INVOKE(dev_clone,
+ td->td_ucred, pname, strlen(pname), &cdev);
+ if (cdev == NULL)
+ break;
-notfound:
+ devfs_populate(dmp);
- if ((nameiop == CREATE || nameiop == RENAME) &&
- (flags & (LOCKPARENT | WANTPARENT)) && (flags & ISLASTCN)) {
- cnp->cn_flags |= SAVENAME;
- return (EJUSTRETURN);
+ dev_lock();
+ dde = &cdev->si_priv->cdp_dirents[dmp->dm_idx];
+ if (dde != NULL && *dde != NULL)
+ de = *dde;
+ dev_unlock();
+ dev_rel(cdev);
+ break;
}
- return (ENOENT);
-
-found:
+ if (de == NULL || de->de_flags & DE_WHITEOUT) {
+ if ((nameiop == CREATE || nameiop == RENAME) &&
+ (flags & (LOCKPARENT | WANTPARENT)) && (flags & ISLASTCN)) {
+ cnp->cn_flags |= SAVENAME;
+ return (EJUSTRETURN);
+ }
+ return (ENOENT);
+ }
if ((cnp->cn_nameiop == DELETE) && (flags & ISLASTCN)) {
error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td);
@@ -589,10 +560,6 @@ found:
*vpp = dvp;
return (0);
}
- error = devfs_allocv(de, dvp->v_mount, vpp, td);
- if (error)
- return (error);
- return (0);
}
error = devfs_allocv(de, dvp->v_mount, vpp, td);
return (error);
@@ -605,9 +572,9 @@ devfs_lookup(struct vop_lookup_args *ap)
struct devfs_mount *dmp;
dmp = VFSTODEVFS(ap->a_dvp->v_mount);
- lockmgr(&dmp->dm_lock, LK_SHARED, 0, curthread);
+ sx_xlock(&dmp->dm_lock);
j = devfs_lookupx(ap);
- lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread);
+ sx_xunlock(&dmp->dm_lock);
return (j);
}
@@ -629,7 +596,7 @@ devfs_mknod(struct vop_mknod_args *ap)
return (EOPNOTSUPP);
dvp = ap->a_dvp;
dmp = VFSTODEVFS(dvp->v_mount);
- lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread);
+ sx_xlock(&dmp->dm_lock);
cnp = ap->a_cnp;
vpp = ap->a_vpp;
@@ -652,13 +619,10 @@ devfs_mknod(struct vop_mknod_args *ap)
de->de_flags &= ~DE_WHITEOUT;
error = devfs_allocv(de, dvp->v_mount, vpp, td);
notfound:
- lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread);
+ sx_xunlock(&dmp->dm_lock);
return (error);
}
-/*
- * Open a special file.
- */
/* ARGSUSED */
static int
devfs_open(struct vop_open_args *ap)
@@ -793,9 +757,6 @@ devfs_print(struct vop_print_args *ap)
return (0);
}
-/*
- * Vnode op for read
- */
/* ARGSUSED */
static int
devfs_read_f(struct file *fp, struct uio *uio, struct ucred *cred, int flags, struct thread *td)
@@ -845,18 +806,14 @@ devfs_readdir(struct vop_readdir_args *ap)
return (EINVAL);
dmp = VFSTODEVFS(ap->a_vp->v_mount);
- lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread);
+ sx_xlock(&dmp->dm_lock);
devfs_populate(dmp);
- lockmgr(&dmp->dm_lock, LK_DOWNGRADE, 0, curthread);
error = 0;
de = ap->a_vp->v_data;
off = 0;
oldoff = uio->uio_offset;
- if (ap->a_ncookies != NULL) {
- *ap->a_ncookies = 0;
- *ap->a_cookies = NULL;
- }
TAILQ_FOREACH(dd, &de->de_dlist, de_list) {
+ KASSERT(dd->de_cdp != (void *)0xdeadc0de, ("%s %d\n", __func__, __LINE__));
if (dd->de_flags & DE_WHITEOUT)
continue;
if (dd->de_dirent->d_type == DT_DIR)
@@ -874,7 +831,7 @@ devfs_readdir(struct vop_readdir_args *ap)
}
off += dp->d_reclen;
}
- lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread);
+ sx_xunlock(&dmp->dm_lock);
uio->uio_offset = off;
return (error);
}
@@ -908,8 +865,6 @@ devfs_reclaim(struct vop_reclaim_args *ap)
return (0);
dev_lock();
- if (de != NULL)
- LIST_REMOVE(de, de_alias);
dev->si_usecount -= vp->v_usecount;
dev_unlock();
dev_rel(dev);
@@ -924,21 +879,16 @@ devfs_remove(struct vop_remove_args *ap)
struct devfs_dirent *de;
struct devfs_mount *dmp = VFSTODEVFS(vp->v_mount);
- lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread);
+ sx_xlock(&dmp->dm_lock);
dd = ap->a_dvp->v_data;
de = vp->v_data;
if (de->de_dirent->d_type == DT_LNK) {
TAILQ_REMOVE(&dd->de_dlist, de, de_list);
- if (de->de_vnode)
- de->de_vnode->v_data = NULL;
-#ifdef MAC
- mac_destroy_devfsdirent(de);
-#endif
- free(de, M_DEVFS);
+ devfs_delete(dmp, de);
} else {
de->de_flags |= DE_WHITEOUT;
}
- lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread);
+ sx_xunlock(&dmp->dm_lock);
return (0);
}
@@ -946,24 +896,43 @@ devfs_remove(struct vop_remove_args *ap)
* Revoke is called on a tty when a terminal session ends. The vnode
* is orphaned by setting v_op to deadfs so we need to let go of it
* as well so that we create a new one next time around.
+ *
+ * XXX: locking :-(
+ * XXX: We mess around with other mountpoints without holding their sxlock.
+ * XXX: We hold the devlock() when we zero their vnode pointer, but is that
+ * XXX: enough ?
*/
static int
devfs_revoke(struct vop_revoke_args *ap)
{
- struct vnode *vp = ap->a_vp;
+ struct vnode *vp = ap->a_vp, *vp2;
struct cdev *dev;
+ struct cdev_priv *cdp;
struct devfs_dirent *de;
+ int i;
KASSERT((ap->a_flags & REVOKEALL) != 0, ("devfs_revoke !REVOKEALL"));
dev = vp->v_rdev;
+ cdp = dev->si_priv;
for (;;) {
dev_lock();
- de = LIST_FIRST(&dev->si_alist);
+ vp2 = NULL;
+ for (i = 0; i <= cdp->cdp_maxdirent; i++) {
+ de = cdp->cdp_dirents[i];
+ if (de == NULL)
+ continue;
+ vp2 = de->de_vnode;
+ de->de_vnode = NULL;
+ if (vp2 != NULL)
+ break;
+ }
dev_unlock();
- if (de == NULL)
- break;
- vgone(de->de_vnode);
+ if (vp2 != NULL) {
+ vgone(vp2);
+ continue;
+ }
+ break;
}
return (0);
}
@@ -975,10 +944,10 @@ devfs_rioctl(struct vop_ioctl_args *ap)
struct devfs_mount *dmp;
dmp = VFSTODEVFS(ap->a_vp->v_mount);
- lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread);
+ sx_xlock(&dmp->dm_lock);
devfs_populate(dmp);
error = devfs_rules_ioctl(dmp, ap->a_command, ap->a_data, ap->a_td);
- lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread);
+ sx_xunlock(&dmp->dm_lock);
return (error);
}
@@ -1120,24 +1089,21 @@ devfs_symlink(struct vop_symlink_args *ap)
de->de_uid = 0;
de->de_gid = 0;
de->de_mode = 0755;
- de->de_inode = dmp->dm_inode++;
+ de->de_inode = alloc_unr(devfs_inos);
de->de_dirent->d_type = DT_LNK;
i = strlen(ap->a_target) + 1;
de->de_symlink = malloc(i, M_DEVFS, M_WAITOK);
bcopy(ap->a_target, de->de_symlink, i);
- lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, td);
+ sx_xlock(&dmp->dm_lock);
#ifdef MAC
mac_create_devfs_symlink(ap->a_cnp->cn_cred, dmp->dm_mount, dd, de);
#endif
TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
devfs_allocv(de, ap->a_dvp->v_mount, ap->a_vpp, td);
- lockmgr(&dmp->dm_lock, LK_RELEASE, 0, td);
+ sx_xunlock(&dmp->dm_lock);
return (0);
}
-/*
- * Vnode op for write
- */
/* ARGSUSED */
static int
devfs_write_f(struct file *fp, struct uio *uio, struct ucred *cred, int flags, struct thread *td)
@@ -1176,7 +1142,7 @@ dev2udev(struct cdev *x)
{
if (x == NULL)
return (NODEV);
- return (x->si_inode);
+ return (x->si_priv->cdp_inode);
}
static struct fileops devfs_ops_f = {
diff --git a/sys/kern/kern_conf.c b/sys/kern/kern_conf.c
index a6fcf83ab144..4e8e0337ba06 100644
--- a/sys/kern/kern_conf.c
+++ b/sys/kern/kern_conf.c
@@ -33,7 +33,6 @@ __FBSDID("$FreeBSD$");
#include <sys/bio.h>
#include <sys/lock.h>
#include <sys/mutex.h>
-#include <sys/sysctl.h>
#include <sys/module.h>
#include <sys/malloc.h>
#include <sys/conf.h>
@@ -49,8 +48,7 @@ __FBSDID("$FreeBSD$");
static MALLOC_DEFINE(M_DEVT, "cdev", "cdev storage");
-static struct mtx devmtx;
-static void freedev(struct cdev *dev);
+struct mtx devmtx;
static void destroy_devl(struct cdev *dev);
static struct cdev *make_dev_credv(struct cdevsw *devsw, int minornr,
struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt,
@@ -99,15 +97,19 @@ dev_rel(struct cdev *dev)
dev->si_refcount--;
KASSERT(dev->si_refcount >= 0,
("dev_rel(%s) gave negative count", devtoname(dev)));
+#if 0
if (dev->si_usecount == 0 &&
(dev->si_flags & SI_CHEAPCLONE) && (dev->si_flags & SI_NAMED))
- if (dev->si_devsw == NULL && dev->si_refcount == 0) {
+ ;
+ else
+#endif
+if (dev->si_devsw == NULL && dev->si_refcount == 0) {
LIST_REMOVE(dev, si_list);
flag = 1;
}
dev_unlock();
if (flag)
- freedev(dev);
+ devfs_free(dev);
}
struct cdevsw *
@@ -389,18 +391,6 @@ unit2minor(int unit)
}
static struct cdev *
-allocdev(void)
-{
- struct cdev *si;
-
- si = malloc(sizeof *si, M_DEVT, M_USE_RESERVE | M_ZERO | M_WAITOK);
- si->si_name = si->__si_namebuf;
- LIST_INIT(&si->si_children);
- LIST_INIT(&si->si_alist);
- return (si);
-}
-
-static struct cdev *
newdev(struct cdevsw *csw, int y, struct cdev *si)
{
struct cdev *si2;
@@ -410,24 +400,16 @@ newdev(struct cdevsw *csw, int y, struct cdev *si)
udev = y;
LIST_FOREACH(si2, &csw->d_devs, si_list) {
if (si2->si_drv0 == udev) {
- freedev(si);
+ devfs_free(si);
return (si2);
}
}
si->si_drv0 = udev;
+ si->si_devsw = csw;
LIST_INSERT_HEAD(&csw->d_devs, si, si_list);
return (si);
}
-static void
-freedev(struct cdev *dev)
-{
-
- if (dev->si_cred != NULL)
- crfree(dev->si_cred);
- free(dev, M_DEVT);
-}
-
int
uminor(dev_t dev)
{
@@ -538,12 +520,11 @@ make_dev_credv(struct cdevsw *devsw, int minornr, struct ucred *cr, uid_t uid,
if (!(devsw->d_flags & D_INIT))
prep_cdevsw(devsw);
- dev = allocdev();
+ dev = devfs_alloc();
dev_lock();
dev = newdev(devsw, minornr, dev);
if (dev->si_flags & SI_CHEAPCLONE &&
- dev->si_flags & SI_NAMED &&
- dev->si_devsw == devsw) {
+ dev->si_flags & SI_NAMED) {
/*
* This is allowed as it removes races and generally
* simplifies cloning devices.
@@ -562,7 +543,6 @@ make_dev_credv(struct cdevsw *devsw, int minornr, struct ucred *cr, uid_t uid,
dev->__si_namebuf);
}
- dev->si_devsw = devsw;
dev->si_flags |= SI_NAMED;
if (cr != NULL)
dev->si_cred = crhold(cr);
@@ -604,14 +584,22 @@ make_dev_cred(struct cdevsw *devsw, int minornr, struct ucred *cr, uid_t uid,
return (dev);
}
-void
-dev_depends(struct cdev *pdev, struct cdev *cdev)
+static void
+dev_dependsl(struct cdev *pdev, struct cdev *cdev)
{
- dev_lock();
cdev->si_parent = pdev;
cdev->si_flags |= SI_CHILD;
LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings);
+}
+
+
+void
+dev_depends(struct cdev *pdev, struct cdev *cdev)
+{
+
+ dev_lock();
+ dev_dependsl(pdev, cdev);
dev_unlock();
}
@@ -622,7 +610,7 @@ make_dev_alias(struct cdev *pdev, const char *fmt, ...)
va_list ap;
int i;
- dev = allocdev();
+ dev = devfs_alloc();
dev_lock();
dev->si_flags |= SI_ALIAS;
dev->si_flags |= SI_NAMED;
@@ -689,7 +677,7 @@ destroy_devl(struct cdev *dev)
/* Remove from cdevsw list */
LIST_REMOVE(dev, si_list);
- /* If cdevsw has no struct cdev *'s, clean it */
+ /* If cdevsw has no more struct cdev *'s, clean it */
if (LIST_EMPTY(&csw->d_devs))
fini_cdevsw(csw);
}
@@ -698,7 +686,7 @@ destroy_devl(struct cdev *dev)
if (dev->si_refcount > 0) {
LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list);
} else {
- freedev(dev);
+ devfs_free(dev);
}
}
@@ -817,7 +805,7 @@ clone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up, struct cdev **
* the end of the list.
*/
unit = *up;
- ndev = allocdev();
+ ndev = devfs_alloc();
dev_lock();
low = extra;
de = dl = NULL;
@@ -828,7 +816,7 @@ clone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up, struct cdev **
u = dev2unit(dev);
if (u == (unit | extra)) {
*dp = dev;
- freedev(ndev);
+ devfs_free(ndev);
dev_unlock();
return (0);
}
diff --git a/sys/security/mac_biba/mac_biba.c b/sys/security/mac_biba/mac_biba.c
index 8d5e9db8da36..93b7eabd130c 100644
--- a/sys/security/mac_biba/mac_biba.c
+++ b/sys/security/mac_biba/mac_biba.c
@@ -60,6 +60,7 @@
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/pipe.h>
+#include <sys/sx.h>
#include <sys/sysctl.h>
#include <sys/msg.h>
#include <sys/sem.h>
diff --git a/sys/security/mac_lomac/mac_lomac.c b/sys/security/mac_lomac/mac_lomac.c
index cb2ebdfc421b..3dd36339726d 100644
--- a/sys/security/mac_lomac/mac_lomac.c
+++ b/sys/security/mac_lomac/mac_lomac.c
@@ -59,6 +59,7 @@
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
+#include <sys/sx.h>
#include <sys/pipe.h>
#include <sys/sysctl.h>
#include <sys/syslog.h>
diff --git a/sys/security/mac_mls/mac_mls.c b/sys/security/mac_mls/mac_mls.c
index 1599cc0a4c58..bc69a77942a1 100644
--- a/sys/security/mac_mls/mac_mls.c
+++ b/sys/security/mac_mls/mac_mls.c
@@ -60,6 +60,7 @@
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/pipe.h>
+#include <sys/sx.h>
#include <sys/sysctl.h>
#include <sys/msg.h>
#include <sys/sem.h>
diff --git a/sys/security/mac_none/mac_none.c b/sys/security/mac_none/mac_none.c
index 11910a6b4f8d..d36d4296f223 100644
--- a/sys/security/mac_none/mac_none.c
+++ b/sys/security/mac_none/mac_none.c
@@ -59,6 +59,7 @@
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/pipe.h>
+#include <sys/sx.h>
#include <sys/sysctl.h>
#include <fs/devfs/devfs.h>
diff --git a/sys/security/mac_partition/mac_partition.c b/sys/security/mac_partition/mac_partition.c
index 397e44abb59c..fe3d8e81677d 100644
--- a/sys/security/mac_partition/mac_partition.c
+++ b/sys/security/mac_partition/mac_partition.c
@@ -54,6 +54,7 @@
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
+#include <sys/sx.h>
#include <sys/sysctl.h>
#include <fs/devfs/devfs.h>
diff --git a/sys/security/mac_stub/mac_stub.c b/sys/security/mac_stub/mac_stub.c
index 8ab11e976bd6..fc667ce42008 100644
--- a/sys/security/mac_stub/mac_stub.c
+++ b/sys/security/mac_stub/mac_stub.c
@@ -62,6 +62,7 @@
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/pipe.h>
+#include <sys/sx.h>
#include <sys/sysctl.h>
#include <sys/msg.h>
#include <sys/sem.h>
diff --git a/sys/security/mac_test/mac_test.c b/sys/security/mac_test/mac_test.c
index 3c51215518e4..cdc5c798f468 100644
--- a/sys/security/mac_test/mac_test.c
+++ b/sys/security/mac_test/mac_test.c
@@ -57,6 +57,7 @@
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
+#include <sys/sx.h>
#include <sys/sysctl.h>
#include <sys/msg.h>
#include <sys/sem.h>
diff --git a/sys/sys/conf.h b/sys/sys/conf.h
index 1ceadc0eb206..cecd71a51c6c 100644
--- a/sys/sys/conf.h
+++ b/sys/sys/conf.h
@@ -52,6 +52,7 @@ struct devfs_dirent;
struct cdevsw;
struct cdev {
+ struct cdev_priv *si_priv;
u_int si_flags;
#define SI_ALIAS 0x0002 /* carrier of alias name */
#define SI_NAMED 0x0004 /* make_dev{_alias} has been called */
@@ -73,11 +74,9 @@ struct cdev {
int si_refcount;
LIST_ENTRY(cdev) si_list;
LIST_ENTRY(cdev) si_clone;
- LIST_HEAD(,devfs_dirent)si_alist;
LIST_HEAD(, cdev) si_children;
LIST_ENTRY(cdev) si_siblings;
struct cdev *si_parent;
- u_int si_inode;
char *si_name;
void *si_drv1, *si_drv2;
struct cdevsw *si_devsw;