summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/kern_conf.c67
-rw-r--r--sys/kern/vfs_export.c3
-rw-r--r--sys/kern/vfs_subr.c3
-rw-r--r--sys/sys/conf.h8
-rw-r--r--sys/sys/linedisc.h8
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;
OpenPOWER on IntegriCloud