diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/kern/kern_conf.c | 67 | ||||
-rw-r--r-- | sys/kern/vfs_export.c | 3 | ||||
-rw-r--r-- | sys/kern/vfs_subr.c | 3 | ||||
-rw-r--r-- | sys/sys/conf.h | 8 | ||||
-rw-r--r-- | sys/sys/linedisc.h | 8 |
5 files changed, 74 insertions, 15 deletions
diff --git a/sys/kern/kern_conf.c b/sys/kern/kern_conf.c index 3f49464..325c7ef 100644 --- a/sys/kern/kern_conf.c +++ b/sys/kern/kern_conf.c @@ -35,6 +35,7 @@ #include <sys/param.h> #include <sys/kernel.h> +#include <sys/sysctl.h> #include <sys/systm.h> #include <sys/module.h> #include <sys/malloc.h> @@ -63,9 +64,15 @@ MALLOC_DEFINE(M_DEVT, "dev_t", "dev_t storage"); static struct specinfo devt_stash[DEVT_STASH]; -static SLIST_HEAD(devt_hash_head, specinfo) dev_hash[DEVT_HASH]; +static LIST_HEAD(, specinfo) dev_hash[DEVT_HASH]; + +static LIST_HEAD(, specinfo) dev_free; devfs_create_t *devfs_create_hook; +devfs_remove_t *devfs_remove_hook; + +static int free_devt; +SYSCTL_INT(_debug, OID_AUTO, free_devt, CTLFLAG_RW, &free_devt, 0, ""); /* * Routine to convert from character to block device number. @@ -230,26 +237,47 @@ makedev(int x, int y) udev = (x << 8) | y; hash = udev % DEVT_HASH; - SLIST_FOREACH(si, &dev_hash[hash], si_hash) { + LIST_FOREACH(si, &dev_hash[hash], si_hash) { if (si->si_udev == udev) return (si); } if (stashed >= DEVT_STASH) { MALLOC(si, struct specinfo *, sizeof(*si), M_DEVT, M_USE_RESERVE); + bzero(si, sizeof(*si)); + } else if (LIST_FIRST(&dev_free)) { + si = LIST_FIRST(&dev_free); + LIST_REMOVE(si, si_hash); } else { si = devt_stash + stashed++; + si->si_flags |= SI_STASHED; } - bzero(si, sizeof(*si)); si->si_udev = udev; - if (y > 256) - sprintf(si->si_name, "#%d/0x%x", x, y); - else - sprintf(si->si_name, "#%d/%d", x, y); - SLIST_INSERT_HEAD(&dev_hash[hash], si, si_hash); + LIST_INSERT_HEAD(&dev_hash[hash], si, si_hash); return (si); } +void +freedev(dev_t dev) +{ + int hash; + + if (!free_devt) + return; + if (SLIST_FIRST(&dev->si_hlist)) + return; + if (dev->si_devsw || dev->si_drv1 || dev->si_drv2) + return; + hash = dev->si_udev % DEVT_HASH; + LIST_REMOVE(dev, si_hash); + if (dev->si_flags & SI_STASHED) { + bzero(dev, sizeof(*dev)); + LIST_INSERT_HEAD(&dev_free, dev, si_hash); + } else { + FREE(dev, M_DEVT); + } +} + udev_t dev2udev(dev_t x) { @@ -318,10 +346,31 @@ make_dev(struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms, char return (dev); } +void +remove_dev(dev_t dev) +{ + if (devfs_remove_hook) + devfs_remove_hook(dev); + dev->si_drv1 = 0; + dev->si_drv2 = 0; + dev->si_devsw = 0; + freedev(dev); +} + char * devtoname(dev_t dev) { - + char *p; + + if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') { + p = dev->si_name; + if (devsw(dev)) + sprintf(p, "#%s/", devsw(dev)->d_name); + else + sprintf(p, "#%d/", major(dev)); + p += strlen(p); + sprintf(p, minor(dev) > 255 ? "0x%x" : "%d", minor(dev)); + } return (dev->si_name); } diff --git a/sys/kern/vfs_export.c b/sys/kern/vfs_export.c index c6ce788..b452cc1 100644 --- a/sys/kern/vfs_export.c +++ b/sys/kern/vfs_export.c @@ -1692,7 +1692,7 @@ vclean(vp, flags, p) if (VSHOULDFREE(vp)) vfree(vp); - + /* * Done with purge, notify sleepers of the grim news. */ @@ -1821,6 +1821,7 @@ vgonel(vp, p) if ((vp->v_type == VBLK || vp->v_type == VCHR) && vp->v_rdev != NULL) { simple_lock(&spechash_slock); SLIST_REMOVE(&vp->v_hashchain, vp, vnode, v_specnext); + freedev(vp->v_rdev); simple_unlock(&spechash_slock); vp->v_rdev = NULL; } diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index c6ce788..b452cc1 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -1692,7 +1692,7 @@ vclean(vp, flags, p) if (VSHOULDFREE(vp)) vfree(vp); - + /* * Done with purge, notify sleepers of the grim news. */ @@ -1821,6 +1821,7 @@ vgonel(vp, p) if ((vp->v_type == VBLK || vp->v_type == VCHR) && vp->v_rdev != NULL) { simple_lock(&spechash_slock); SLIST_REMOVE(&vp->v_hashchain, vp, vnode, v_specnext); + freedev(vp->v_rdev); simple_unlock(&spechash_slock); vp->v_rdev = NULL; } diff --git a/sys/sys/conf.h b/sys/sys/conf.h index 4e5a94a..bc293e0 100644 --- a/sys/sys/conf.h +++ b/sys/sys/conf.h @@ -50,9 +50,10 @@ struct tty; struct vnode; struct specinfo { - + u_int si_flags; +#define SI_STASHED 0x0001 /* created in stashed storage */ udev_t si_udev; - SLIST_ENTRY(specinfo) si_hash; + LIST_ENTRY(specinfo) si_hash; SLIST_HEAD(, vnode) si_hlist; char si_name[SPECNAMELEN + 1]; void *si_drv1, *si_drv2; @@ -127,6 +128,7 @@ typedef int l_modem_t __P((struct tty *tp, int flag)); /* This is type of the function DEVFS uses to hook into the kernel with */ typedef void devfs_create_t __P((dev_t dev, uid_t uid, gid_t gid, int perms)); +typedef void devfs_remove_t __P((dev_t dev)); /* * XXX: The dummy argument can be used to do what strategy1() never @@ -275,11 +277,13 @@ dev_t chrtoblk __P((dev_t dev)); struct cdevsw *devsw __P((dev_t dev)); int devsw_module_handler __P((struct module *mod, int what, void *arg)); char *devtoname __P((dev_t dev)); +void freedev __P((dev_t dev)); int iskmemdev __P((dev_t dev)); int iszerodev __P((dev_t dev)); dev_t makebdev __P((int maj, int min)); dev_t make_dev __P((struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms, char *fmt, ...)) __printflike(6, 7); int lminor __P((dev_t dev)); +void remove_dev __P((dev_t dev)); void setconf __P((void)); extern devfs_create_t *devfs_create_hook; diff --git a/sys/sys/linedisc.h b/sys/sys/linedisc.h index 4e5a94a..bc293e0 100644 --- a/sys/sys/linedisc.h +++ b/sys/sys/linedisc.h @@ -50,9 +50,10 @@ struct tty; struct vnode; struct specinfo { - + u_int si_flags; +#define SI_STASHED 0x0001 /* created in stashed storage */ udev_t si_udev; - SLIST_ENTRY(specinfo) si_hash; + LIST_ENTRY(specinfo) si_hash; SLIST_HEAD(, vnode) si_hlist; char si_name[SPECNAMELEN + 1]; void *si_drv1, *si_drv2; @@ -127,6 +128,7 @@ typedef int l_modem_t __P((struct tty *tp, int flag)); /* This is type of the function DEVFS uses to hook into the kernel with */ typedef void devfs_create_t __P((dev_t dev, uid_t uid, gid_t gid, int perms)); +typedef void devfs_remove_t __P((dev_t dev)); /* * XXX: The dummy argument can be used to do what strategy1() never @@ -275,11 +277,13 @@ dev_t chrtoblk __P((dev_t dev)); struct cdevsw *devsw __P((dev_t dev)); int devsw_module_handler __P((struct module *mod, int what, void *arg)); char *devtoname __P((dev_t dev)); +void freedev __P((dev_t dev)); int iskmemdev __P((dev_t dev)); int iszerodev __P((dev_t dev)); dev_t makebdev __P((int maj, int min)); dev_t make_dev __P((struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms, char *fmt, ...)) __printflike(6, 7); int lminor __P((dev_t dev)); +void remove_dev __P((dev_t dev)); void setconf __P((void)); extern devfs_create_t *devfs_create_hook; |