Add dev_t freeing code. Controlled by sysctl debug.free_devt, default
is off.
This commit is contained in:
parent
b40f30707d
commit
244faf2e1b
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user