mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-16 10:20:30 +00:00
Device megapatch 6/6:
This is what we came here for: Hang dev_t's from their cdevsw, refcount cdevsw and dev_t and generally keep track of things a lot better than we used to: Hold a cdevsw reference around all entrances into the device driver, this will be necessary to safely determine when we can unload driver code. Hold a dev_t reference while the device is open. KASSERT that we do not enter the driver on a non-referenced dev_t. Remove old D_NAG code, anonymous dev_t's are not a problem now. When destroy_dev() is called on a referenced dev_t, move it to dead_cdevsw's list. When the refcount drops, free it. Check that cdevsw->d_version is correct. If not, set all methods to the dead_*() methods to prevent entrance into driver. Print warning on console to this effect. The device driver may still explode if it is also incompatible with newbus, but in that case we probably didn't get this far in the first place.
This commit is contained in:
parent
816d62bbb9
commit
cd690b60de
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=126082
@ -140,7 +140,6 @@ spec_open(ap)
|
||||
dev_t dev = vp->v_rdev;
|
||||
int error;
|
||||
struct cdevsw *dsw;
|
||||
const char *cp;
|
||||
|
||||
if (vp->v_type == VBLK)
|
||||
return (ENXIO);
|
||||
@ -194,6 +193,8 @@ spec_open(ap)
|
||||
vp->v_vflag |= VV_ISTTY;
|
||||
|
||||
VOP_UNLOCK(vp, 0, td);
|
||||
dev_ref(dev);
|
||||
cdevsw_ref(dsw);
|
||||
if(!(dsw->d_flags & D_NEEDGIANT)) {
|
||||
DROP_GIANT();
|
||||
if (dsw->d_fdopen != NULL)
|
||||
@ -205,6 +206,9 @@ spec_open(ap)
|
||||
error = dsw->d_fdopen(dev, ap->a_mode, td, ap->a_fdidx);
|
||||
else
|
||||
error = dsw->d_open(dev, ap->a_mode, S_IFCHR, td);
|
||||
cdevsw_rel(dsw);
|
||||
if (error != 0)
|
||||
dev_rel(dev);
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
|
||||
|
||||
if (error)
|
||||
@ -225,14 +229,6 @@ spec_open(ap)
|
||||
if (!dev->si_bsize_phys)
|
||||
dev->si_bsize_phys = DEV_BSIZE;
|
||||
}
|
||||
if ((dsw->d_flags & D_DISK) == 0) {
|
||||
cp = devtoname(dev);
|
||||
if (*cp == '#' && (dsw->d_flags & D_NAGGED) == 0) {
|
||||
printf("WARNING: driver %s should register devices with make_dev() (dev_t = \"%s\")\n",
|
||||
dsw->d_name, cp);
|
||||
dsw->d_flags |= D_NAGGED;
|
||||
}
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
|
||||
@ -267,12 +263,16 @@ spec_read(ap)
|
||||
|
||||
dsw = devsw(dev);
|
||||
VOP_UNLOCK(vp, 0, td);
|
||||
KASSERT(dev->si_refcount > 0,
|
||||
("specread() on un-referenced dev_t (%s)", devtoname(dev)));
|
||||
cdevsw_ref(dsw);
|
||||
if (!(dsw->d_flags & D_NEEDGIANT)) {
|
||||
DROP_GIANT();
|
||||
error = dsw->d_read(dev, uio, ap->a_ioflag);
|
||||
PICKUP_GIANT();
|
||||
} else
|
||||
error = dsw->d_read(dev, uio, ap->a_ioflag);
|
||||
cdevsw_rel(dsw);
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
|
||||
if (uio->uio_resid != resid || (error == 0 && resid != 0))
|
||||
vfs_timestamp(&dev->si_atime);
|
||||
@ -307,12 +307,16 @@ spec_write(ap)
|
||||
resid = uio->uio_resid;
|
||||
|
||||
VOP_UNLOCK(vp, 0, td);
|
||||
KASSERT(dev->si_refcount > 0,
|
||||
("spec_write() on un-referenced dev_t (%s)", devtoname(dev)));
|
||||
cdevsw_ref(dsw);
|
||||
if (!(dsw->d_flags & D_NEEDGIANT)) {
|
||||
DROP_GIANT();
|
||||
error = dsw->d_write(dev, uio, ap->a_ioflag);
|
||||
PICKUP_GIANT();
|
||||
} else
|
||||
error = dsw->d_write(dev, uio, ap->a_ioflag);
|
||||
cdevsw_rel(dsw);
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
|
||||
if (uio->uio_resid != resid || (error == 0 && resid != 0)) {
|
||||
vfs_timestamp(&dev->si_ctime);
|
||||
@ -342,6 +346,9 @@ spec_ioctl(ap)
|
||||
|
||||
dev = ap->a_vp->v_rdev;
|
||||
dsw = devsw(dev);
|
||||
KASSERT(dev->si_refcount > 0,
|
||||
("spec_ioctl() on un-referenced dev_t (%s)", devtoname(dev)));
|
||||
cdevsw_ref(dsw);
|
||||
if (!(dsw->d_flags & D_NEEDGIANT)) {
|
||||
DROP_GIANT();
|
||||
error = dsw->d_ioctl(dev, ap->a_command,
|
||||
@ -350,6 +357,7 @@ spec_ioctl(ap)
|
||||
} else
|
||||
error = dsw->d_ioctl(dev, ap->a_command,
|
||||
ap->a_data, ap->a_fflag, ap->a_td);
|
||||
cdevsw_rel(dsw);
|
||||
if (error == ENOIOCTL)
|
||||
error = ENOTTY;
|
||||
return (error);
|
||||
@ -371,12 +379,16 @@ spec_poll(ap)
|
||||
|
||||
dev = ap->a_vp->v_rdev;
|
||||
dsw = devsw(dev);
|
||||
KASSERT(dev->si_refcount > 0,
|
||||
("spec_poll() on un-referenced dev_t (%s)", devtoname(dev)));
|
||||
cdevsw_ref(dsw);
|
||||
if (!(dsw->d_flags & D_NEEDGIANT)) {
|
||||
DROP_GIANT();
|
||||
error = dsw->d_poll(dev, ap->a_events, ap->a_td);
|
||||
PICKUP_GIANT();
|
||||
} else
|
||||
error = dsw->d_poll(dev, ap->a_events, ap->a_td);
|
||||
cdevsw_rel(dsw);
|
||||
return(error);
|
||||
}
|
||||
|
||||
@ -394,12 +406,16 @@ spec_kqfilter(ap)
|
||||
|
||||
dev = ap->a_vp->v_rdev;
|
||||
dsw = devsw(dev);
|
||||
KASSERT(dev->si_refcount > 0,
|
||||
("spec_kqfilter() on un-referenced dev_t (%s)", devtoname(dev)));
|
||||
cdevsw_ref(dsw);
|
||||
if (!(dsw->d_flags & D_NEEDGIANT)) {
|
||||
DROP_GIANT();
|
||||
error = dsw->d_kqfilter(dev, ap->a_kn);
|
||||
PICKUP_GIANT();
|
||||
} else
|
||||
error = dsw->d_kqfilter(dev, ap->a_kn);
|
||||
cdevsw_rel(dsw);
|
||||
return (error);
|
||||
}
|
||||
|
||||
@ -631,12 +647,17 @@ spec_close(ap)
|
||||
return (0);
|
||||
}
|
||||
VI_UNLOCK(vp);
|
||||
KASSERT(dev->si_refcount > 0,
|
||||
("spec_close() on un-referenced dev_t (%s)", devtoname(dev)));
|
||||
cdevsw_ref(dsw);
|
||||
if (!(dsw->d_flags & D_NEEDGIANT)) {
|
||||
DROP_GIANT();
|
||||
error = dsw->d_close(dev, ap->a_fflag, S_IFCHR, td);
|
||||
PICKUP_GIANT();
|
||||
} else
|
||||
error = dsw->d_close(dev, ap->a_fflag, S_IFCHR, td);
|
||||
cdevsw_rel(dsw);
|
||||
dev_rel(dev);
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
@ -68,6 +68,63 @@ static LIST_HEAD(, cdev) dev_free;
|
||||
static int free_devt;
|
||||
SYSCTL_INT(_debug, OID_AUTO, free_devt, CTLFLAG_RW, &free_devt, 0, "");
|
||||
|
||||
static struct mtx devmtx;
|
||||
static void freedev(dev_t dev);
|
||||
|
||||
static void
|
||||
devlock(void)
|
||||
{
|
||||
if (!mtx_initialized(&devmtx))
|
||||
mtx_init(&devmtx, "dev_t", NULL, MTX_DEF);
|
||||
mtx_lock(&devmtx);
|
||||
}
|
||||
|
||||
static void
|
||||
devunlock(void)
|
||||
{
|
||||
mtx_unlock(&devmtx);
|
||||
}
|
||||
|
||||
void
|
||||
dev_ref(dev_t dev)
|
||||
{
|
||||
devlock();
|
||||
dev->si_refcount++;
|
||||
devunlock();
|
||||
}
|
||||
|
||||
void
|
||||
dev_rel(dev_t dev)
|
||||
{
|
||||
devlock();
|
||||
dev->si_refcount--;
|
||||
KASSERT(dev->si_refcount >= 0,
|
||||
("dev_rel(%s) gave negative count", devtoname(dev)));
|
||||
if (dev->si_devsw == NULL && dev->si_refcount == 0) {
|
||||
LIST_REMOVE(dev, si_list);
|
||||
freedev(dev);
|
||||
}
|
||||
devunlock();
|
||||
}
|
||||
|
||||
void
|
||||
cdevsw_ref(struct cdevsw *csw)
|
||||
{
|
||||
devlock();
|
||||
csw->d_refcount++;
|
||||
devunlock();
|
||||
}
|
||||
|
||||
void
|
||||
cdevsw_rel(struct cdevsw *csw)
|
||||
{
|
||||
devlock();
|
||||
csw->d_refcount--;
|
||||
KASSERT(csw->d_refcount >= 0,
|
||||
("cdevsw_vrel(%s) gave negative count", csw->d_name));
|
||||
devunlock();
|
||||
}
|
||||
|
||||
static dev_t makedev(int x, int y);
|
||||
|
||||
int
|
||||
@ -178,7 +235,7 @@ no_poll(dev_t dev __unused, int events, struct thread *td __unused)
|
||||
struct cdevsw *
|
||||
devsw(dev_t dev)
|
||||
{
|
||||
if (dev->si_devsw)
|
||||
if (dev->si_devsw != NULL)
|
||||
return (dev->si_devsw);
|
||||
return (&dead_cdevsw);
|
||||
}
|
||||
@ -230,7 +287,6 @@ allocdev(void)
|
||||
|
||||
if (LIST_FIRST(&dev_free)) {
|
||||
si = LIST_FIRST(&dev_free);
|
||||
LIST_REMOVE(si, si_hash);
|
||||
} else if (stashed >= DEVT_STASH) {
|
||||
MALLOC(si, struct cdev *, sizeof(*si), M_DEVT,
|
||||
M_USE_RESERVE | M_ZERO | M_WAITOK);
|
||||
@ -267,17 +323,10 @@ makedev(int x, int y)
|
||||
return (si);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
freedev(dev_t dev)
|
||||
{
|
||||
|
||||
if (!free_devt)
|
||||
return;
|
||||
if (SLIST_FIRST(&dev->si_hlist))
|
||||
return;
|
||||
if (dev->si_devsw || dev->si_drv1 || dev->si_drv2)
|
||||
return;
|
||||
LIST_REMOVE(dev, si_hash);
|
||||
if (dev->si_flags & SI_STASHED) {
|
||||
bzero(dev, sizeof(*dev));
|
||||
dev->si_flags |= SI_STASHED;
|
||||
@ -340,12 +389,41 @@ find_major(struct cdevsw *devsw)
|
||||
KASSERT(i > 0, ("Out of major numbers (%s)", devsw->d_name));
|
||||
devsw->d_maj = i;
|
||||
reserved_majors[i] = i;
|
||||
devsw->d_flags |= D_ALLOCMAJ;
|
||||
}
|
||||
|
||||
static void
|
||||
fini_cdevsw(struct cdevsw *devsw)
|
||||
{
|
||||
if (devsw->d_flags & D_ALLOCMAJ) {
|
||||
reserved_majors[devsw->d_maj] = 0;
|
||||
devsw->d_maj = MAJOR_AUTO;
|
||||
devsw->d_flags &= ~D_ALLOCMAJ;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
prep_cdevsw(struct cdevsw *devsw)
|
||||
{
|
||||
|
||||
devlock();
|
||||
|
||||
if (devsw->d_version != D_VERSION_00) {
|
||||
printf(
|
||||
"WARNING: Device driver \"%s\" has wrong version %s\n",
|
||||
devsw->d_name, "and is disabled. Recompile KLD module.");
|
||||
devsw->d_open = dead_open;
|
||||
devsw->d_close = dead_close;
|
||||
devsw->d_read = dead_read;
|
||||
devsw->d_write = dead_write;
|
||||
devsw->d_ioctl = dead_ioctl;
|
||||
devsw->d_poll = dead_poll;
|
||||
devsw->d_mmap = dead_mmap;
|
||||
devsw->d_strategy = dead_strategy;
|
||||
devsw->d_dump = dead_dump;
|
||||
devsw->d_kqfilter = dead_kqfilter;
|
||||
}
|
||||
|
||||
if (devsw->d_flags & D_TTY) {
|
||||
if (devsw->d_read == NULL) devsw->d_read = ttyread;
|
||||
if (devsw->d_write == NULL) devsw->d_write = ttywrite;
|
||||
@ -363,6 +441,11 @@ prep_cdevsw(struct cdevsw *devsw)
|
||||
if (devsw->d_strategy == NULL) devsw->d_strategy = no_strategy;
|
||||
if (devsw->d_dump == NULL) devsw->d_dump = no_dump;
|
||||
if (devsw->d_kqfilter == NULL) devsw->d_kqfilter = no_kqfilter;
|
||||
|
||||
LIST_INIT(&devsw->d_devs);
|
||||
|
||||
devsw->d_flags |= D_INIT;
|
||||
|
||||
if (devsw->d_maj == MAJOR_AUTO) {
|
||||
find_major(devsw);
|
||||
} else {
|
||||
@ -377,34 +460,37 @@ prep_cdevsw(struct cdevsw *devsw)
|
||||
reserved_majors[devsw->d_maj] = devsw->d_maj;
|
||||
}
|
||||
}
|
||||
devunlock();
|
||||
}
|
||||
|
||||
dev_t
|
||||
make_dev(struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms,
|
||||
const char *fmt, ...)
|
||||
make_dev(struct cdevsw *devsw, int minornr, uid_t uid, gid_t gid, int perms, const char *fmt, ...)
|
||||
{
|
||||
dev_t dev;
|
||||
va_list ap;
|
||||
int i;
|
||||
|
||||
KASSERT((minor & ~0xffff00ff) == 0,
|
||||
("Invalid minor (0x%x) in make_dev", minor));
|
||||
prep_cdevsw(devsw);
|
||||
dev = makedev(devsw->d_maj, minor);
|
||||
KASSERT((minornr & ~0xffff00ff) == 0,
|
||||
("Invalid minor (0x%x) in make_dev", minornr));
|
||||
|
||||
if (!(devsw->d_flags & D_INIT))
|
||||
prep_cdevsw(devsw);
|
||||
dev = makedev(devsw->d_maj, minornr);
|
||||
if (dev->si_flags & SI_CHEAPCLONE &&
|
||||
dev->si_flags & SI_NAMED &&
|
||||
dev->si_devsw == devsw) {
|
||||
/*
|
||||
* This is allowed as it removes races and generally
|
||||
* simplifies cloning devices.
|
||||
* XXX: still ??
|
||||
*/
|
||||
return (dev);
|
||||
}
|
||||
if (dev->si_flags & SI_NAMED) {
|
||||
printf( "WARNING: Driver mistake: repeat make_dev(\"%s\")\n",
|
||||
dev->si_name);
|
||||
panic("don't do that");
|
||||
}
|
||||
devlock();
|
||||
KASSERT(!(dev->si_flags & SI_NAMED),
|
||||
("make_dev() by driver %s on pre-existing device (maj=%d, min=%d, name=%s)",
|
||||
devsw->d_name, major(dev), minor(dev), devtoname(dev)));
|
||||
|
||||
va_start(ap, fmt);
|
||||
i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap);
|
||||
if (i > (sizeof dev->__si_namebuf - 1)) {
|
||||
@ -418,7 +504,9 @@ make_dev(struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms,
|
||||
dev->si_mode = perms;
|
||||
dev->si_flags |= SI_NAMED;
|
||||
|
||||
LIST_INSERT_HEAD(&devsw->d_devs, dev, si_list);
|
||||
devfs_create(dev);
|
||||
devunlock();
|
||||
return (dev);
|
||||
}
|
||||
|
||||
@ -439,9 +527,11 @@ void
|
||||
dev_depends(dev_t pdev, dev_t cdev)
|
||||
{
|
||||
|
||||
devlock();
|
||||
cdev->si_parent = pdev;
|
||||
cdev->si_flags |= SI_CHILD;
|
||||
LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings);
|
||||
devunlock();
|
||||
}
|
||||
|
||||
dev_t
|
||||
@ -452,9 +542,9 @@ make_dev_alias(dev_t pdev, const char *fmt, ...)
|
||||
int i;
|
||||
|
||||
dev = allocdev();
|
||||
devlock();
|
||||
dev->si_flags |= SI_ALIAS;
|
||||
dev->si_flags |= SI_NAMED;
|
||||
dev_depends(pdev, dev);
|
||||
va_start(ap, fmt);
|
||||
i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap);
|
||||
if (i > (sizeof dev->__si_namebuf - 1)) {
|
||||
@ -464,13 +554,14 @@ make_dev_alias(dev_t pdev, const char *fmt, ...)
|
||||
va_end(ap);
|
||||
|
||||
devfs_create(dev);
|
||||
devunlock();
|
||||
dev_depends(pdev, dev);
|
||||
return (dev);
|
||||
}
|
||||
|
||||
void
|
||||
destroy_dev(dev_t dev)
|
||||
static void
|
||||
idestroy_dev(dev_t dev)
|
||||
{
|
||||
|
||||
if (!(dev->si_flags & SI_NAMED)) {
|
||||
printf( "WARNING: Driver mistake: destroy_dev on %d/%d\n",
|
||||
major(dev), minor(dev));
|
||||
@ -478,24 +569,55 @@ destroy_dev(dev_t dev)
|
||||
}
|
||||
|
||||
devfs_destroy(dev);
|
||||
|
||||
/* Remove name marking */
|
||||
dev->si_flags &= ~SI_NAMED;
|
||||
|
||||
/* If we are a child, remove us from the parents list */
|
||||
if (dev->si_flags & SI_CHILD) {
|
||||
LIST_REMOVE(dev, si_siblings);
|
||||
dev->si_flags &= ~SI_CHILD;
|
||||
}
|
||||
|
||||
/* Kill our children */
|
||||
while (!LIST_EMPTY(&dev->si_children))
|
||||
destroy_dev(LIST_FIRST(&dev->si_children));
|
||||
idestroy_dev(LIST_FIRST(&dev->si_children));
|
||||
|
||||
/* Remove from clone list */
|
||||
if (dev->si_flags & SI_CLONELIST) {
|
||||
LIST_REMOVE(dev, si_clone);
|
||||
dev->si_flags &= ~SI_CLONELIST;
|
||||
}
|
||||
|
||||
if (!(dev->si_flags & SI_ALIAS)) {
|
||||
/* Remove from cdevsw list */
|
||||
LIST_REMOVE(dev, si_list);
|
||||
|
||||
/* If cdevsw has no dev_t's, clean it */
|
||||
if (LIST_EMPTY(&dev->si_devsw->d_devs))
|
||||
fini_cdevsw(dev->si_devsw);
|
||||
|
||||
LIST_REMOVE(dev, si_hash);
|
||||
}
|
||||
dev->si_drv1 = 0;
|
||||
dev->si_drv2 = 0;
|
||||
dev->si_devsw = 0;
|
||||
dev->si_devsw = NULL;
|
||||
bzero(&dev->__si_u, sizeof(dev->__si_u));
|
||||
dev->si_flags &= ~SI_ALIAS;
|
||||
freedev(dev);
|
||||
if (dev->si_refcount > 0) {
|
||||
LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list);
|
||||
} else {
|
||||
freedev(dev);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
destroy_dev(dev_t dev)
|
||||
{
|
||||
|
||||
devlock();
|
||||
idestroy_dev(dev);
|
||||
devunlock();
|
||||
}
|
||||
|
||||
const char *
|
||||
@ -672,12 +794,11 @@ sysctl_devname(SYSCTL_HANDLER_ARGS)
|
||||
return (error);
|
||||
if (ud == NOUDEV)
|
||||
return(EINVAL);
|
||||
dev = makedev(umajor(ud), uminor(ud));
|
||||
if (dev->si_name[0] == '\0')
|
||||
dev = udev2dev(ud);
|
||||
if (dev == NODEV)
|
||||
error = ENOENT;
|
||||
else
|
||||
error = SYSCTL_OUT(req, dev->si_name, strlen(dev->si_name) + 1);
|
||||
freedev(dev);
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
@ -3069,12 +3069,19 @@ bufdonebio(struct bio *bp)
|
||||
void
|
||||
dev_strategy(struct buf *bp)
|
||||
{
|
||||
struct cdevsw *csw;
|
||||
|
||||
if ((!bp->b_iocmd) || (bp->b_iocmd & (bp->b_iocmd - 1)))
|
||||
panic("b_iocmd botch");
|
||||
bp->b_io.bio_done = bufdonebio;
|
||||
bp->b_io.bio_caller2 = bp;
|
||||
csw = devsw(bp->b_io.bio_dev);
|
||||
KASSERT(bp->b_io.bio_dev->si_refcount > 0,
|
||||
("dev_strategy on un-referenced dev_t (%s)",
|
||||
devtoname(bp->b_io.bio_dev)));
|
||||
cdevsw_ref(csw);
|
||||
(*devsw(bp->b_io.bio_dev)->d_strategy)(&bp->b_io);
|
||||
cdevsw_rel(csw);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1853,6 +1853,7 @@ addalias(nvp, dev)
|
||||
{
|
||||
|
||||
KASSERT(nvp->v_type == VCHR, ("addalias on non-special vnode"));
|
||||
dev_ref(dev);
|
||||
nvp->v_rdev = dev;
|
||||
VI_LOCK(nvp);
|
||||
mtx_lock(&spechash_mtx);
|
||||
@ -2469,7 +2470,7 @@ vop_revoke(ap)
|
||||
mtx_lock(&spechash_mtx);
|
||||
vq = SLIST_FIRST(&dev->si_hlist);
|
||||
mtx_unlock(&spechash_mtx);
|
||||
if (!vq)
|
||||
if (vq == NULL)
|
||||
break;
|
||||
vgone(vq);
|
||||
}
|
||||
@ -2587,11 +2588,12 @@ vgonel(vp, td)
|
||||
* if it is on one.
|
||||
*/
|
||||
VI_LOCK(vp);
|
||||
if (vp->v_type == VCHR && vp->v_rdev != NULL && vp->v_rdev != NODEV) {
|
||||
if (vp->v_type == VCHR && vp->v_rdev != NODEV) {
|
||||
mtx_lock(&spechash_mtx);
|
||||
SLIST_REMOVE(&vp->v_rdev->si_hlist, vp, vnode, v_specnext);
|
||||
vp->v_rdev->si_usecount -= vp->v_usecount;
|
||||
mtx_unlock(&spechash_mtx);
|
||||
dev_rel(vp->v_rdev);
|
||||
vp->v_rdev = NULL;
|
||||
}
|
||||
|
||||
|
@ -69,6 +69,8 @@ struct cdev {
|
||||
struct timespec si_ctime;
|
||||
struct timespec si_mtime;
|
||||
udev_t si_udev;
|
||||
int si_refcount;
|
||||
LIST_ENTRY(cdev) si_list;
|
||||
LIST_ENTRY(cdev) si_clone;
|
||||
LIST_ENTRY(cdev) si_hash;
|
||||
SLIST_HEAD(, vnode) si_hlist;
|
||||
@ -195,10 +197,9 @@ typedef int dumper_t(
|
||||
#define D_TYPEMASK 0xffff
|
||||
|
||||
/*
|
||||
* Flags for d_flags.
|
||||
* Flags for d_flags which the drivers can set.
|
||||
*/
|
||||
#define D_MEMDISK 0x00010000 /* memory type disk */
|
||||
#define D_NAGGED 0x00020000 /* nagged about missing make_dev() */
|
||||
#define D_TRACKCLOSE 0x00080000 /* track all closes */
|
||||
#define D_MMAP_ANON 0x00100000 /* special treatment in vm_mmap.c */
|
||||
#define D_PSEUDO 0x00200000 /* make_dev() can return NULL */
|
||||
@ -210,25 +211,36 @@ typedef int dumper_t(
|
||||
#define D_VERSION_00 0x20011966
|
||||
#define D_VERSION D_VERSION_00
|
||||
|
||||
/*
|
||||
* Flags used for internal housekeeping
|
||||
*/
|
||||
#define D_INIT 0x80000000 /* cdevsw initialized */
|
||||
#define D_ALLOCMAJ 0x40000000 /* major# is allocated */
|
||||
|
||||
/*
|
||||
* Character device switch table
|
||||
*/
|
||||
struct cdevsw {
|
||||
int d_version;
|
||||
int d_maj;
|
||||
u_int d_flags;
|
||||
const char *d_name;
|
||||
d_open_t *d_open;
|
||||
d_fdopen_t *d_fdopen;
|
||||
d_close_t *d_close;
|
||||
d_read_t *d_read;
|
||||
d_write_t *d_write;
|
||||
d_ioctl_t *d_ioctl;
|
||||
d_poll_t *d_poll;
|
||||
d_mmap_t *d_mmap;
|
||||
d_strategy_t *d_strategy;
|
||||
dumper_t *d_dump;
|
||||
d_kqfilter_t *d_kqfilter;
|
||||
int d_version;
|
||||
int d_maj;
|
||||
u_int d_flags;
|
||||
const char *d_name;
|
||||
d_open_t *d_open;
|
||||
d_fdopen_t *d_fdopen;
|
||||
d_close_t *d_close;
|
||||
d_read_t *d_read;
|
||||
d_write_t *d_write;
|
||||
d_ioctl_t *d_ioctl;
|
||||
d_poll_t *d_poll;
|
||||
d_mmap_t *d_mmap;
|
||||
d_strategy_t *d_strategy;
|
||||
dumper_t *d_dump;
|
||||
d_kqfilter_t *d_kqfilter;
|
||||
|
||||
/* These fields should not be messed with by drivers */
|
||||
LIST_ENTRY(cdevsw) d_list;
|
||||
LIST_HEAD(, cdev) d_devs;
|
||||
int d_refcount;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -293,11 +305,14 @@ int clone_create(struct clonedevs **, struct cdevsw *, int *unit, dev_t *dev, u_
|
||||
int count_dev(dev_t _dev);
|
||||
void destroy_dev(dev_t _dev);
|
||||
struct cdevsw *devsw(dev_t _dev);
|
||||
void cdevsw_ref(struct cdevsw *);
|
||||
void cdevsw_rel(struct cdevsw *);
|
||||
const char *devtoname(dev_t _dev);
|
||||
int dev_named(dev_t _pdev, const char *_name);
|
||||
void dev_depends(dev_t _pdev, dev_t _cdev);
|
||||
void dev_ref(dev_t dev);
|
||||
void dev_rel(dev_t dev);
|
||||
void dev_strategy(struct buf *bp);
|
||||
void freedev(dev_t _dev);
|
||||
dev_t makebdev(int _maj, int _min);
|
||||
dev_t make_dev(struct cdevsw *_devsw, int _minor, uid_t _uid, gid_t _gid,
|
||||
int _perms, const char *_fmt, ...) __printflike(6, 7);
|
||||
|
@ -69,6 +69,8 @@ struct cdev {
|
||||
struct timespec si_ctime;
|
||||
struct timespec si_mtime;
|
||||
udev_t si_udev;
|
||||
int si_refcount;
|
||||
LIST_ENTRY(cdev) si_list;
|
||||
LIST_ENTRY(cdev) si_clone;
|
||||
LIST_ENTRY(cdev) si_hash;
|
||||
SLIST_HEAD(, vnode) si_hlist;
|
||||
@ -195,10 +197,9 @@ typedef int dumper_t(
|
||||
#define D_TYPEMASK 0xffff
|
||||
|
||||
/*
|
||||
* Flags for d_flags.
|
||||
* Flags for d_flags which the drivers can set.
|
||||
*/
|
||||
#define D_MEMDISK 0x00010000 /* memory type disk */
|
||||
#define D_NAGGED 0x00020000 /* nagged about missing make_dev() */
|
||||
#define D_TRACKCLOSE 0x00080000 /* track all closes */
|
||||
#define D_MMAP_ANON 0x00100000 /* special treatment in vm_mmap.c */
|
||||
#define D_PSEUDO 0x00200000 /* make_dev() can return NULL */
|
||||
@ -210,25 +211,36 @@ typedef int dumper_t(
|
||||
#define D_VERSION_00 0x20011966
|
||||
#define D_VERSION D_VERSION_00
|
||||
|
||||
/*
|
||||
* Flags used for internal housekeeping
|
||||
*/
|
||||
#define D_INIT 0x80000000 /* cdevsw initialized */
|
||||
#define D_ALLOCMAJ 0x40000000 /* major# is allocated */
|
||||
|
||||
/*
|
||||
* Character device switch table
|
||||
*/
|
||||
struct cdevsw {
|
||||
int d_version;
|
||||
int d_maj;
|
||||
u_int d_flags;
|
||||
const char *d_name;
|
||||
d_open_t *d_open;
|
||||
d_fdopen_t *d_fdopen;
|
||||
d_close_t *d_close;
|
||||
d_read_t *d_read;
|
||||
d_write_t *d_write;
|
||||
d_ioctl_t *d_ioctl;
|
||||
d_poll_t *d_poll;
|
||||
d_mmap_t *d_mmap;
|
||||
d_strategy_t *d_strategy;
|
||||
dumper_t *d_dump;
|
||||
d_kqfilter_t *d_kqfilter;
|
||||
int d_version;
|
||||
int d_maj;
|
||||
u_int d_flags;
|
||||
const char *d_name;
|
||||
d_open_t *d_open;
|
||||
d_fdopen_t *d_fdopen;
|
||||
d_close_t *d_close;
|
||||
d_read_t *d_read;
|
||||
d_write_t *d_write;
|
||||
d_ioctl_t *d_ioctl;
|
||||
d_poll_t *d_poll;
|
||||
d_mmap_t *d_mmap;
|
||||
d_strategy_t *d_strategy;
|
||||
dumper_t *d_dump;
|
||||
d_kqfilter_t *d_kqfilter;
|
||||
|
||||
/* These fields should not be messed with by drivers */
|
||||
LIST_ENTRY(cdevsw) d_list;
|
||||
LIST_HEAD(, cdev) d_devs;
|
||||
int d_refcount;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -293,11 +305,14 @@ int clone_create(struct clonedevs **, struct cdevsw *, int *unit, dev_t *dev, u_
|
||||
int count_dev(dev_t _dev);
|
||||
void destroy_dev(dev_t _dev);
|
||||
struct cdevsw *devsw(dev_t _dev);
|
||||
void cdevsw_ref(struct cdevsw *);
|
||||
void cdevsw_rel(struct cdevsw *);
|
||||
const char *devtoname(dev_t _dev);
|
||||
int dev_named(dev_t _pdev, const char *_name);
|
||||
void dev_depends(dev_t _pdev, dev_t _cdev);
|
||||
void dev_ref(dev_t dev);
|
||||
void dev_rel(dev_t dev);
|
||||
void dev_strategy(struct buf *bp);
|
||||
void freedev(dev_t _dev);
|
||||
dev_t makebdev(int _maj, int _min);
|
||||
dev_t make_dev(struct cdevsw *_devsw, int _minor, uid_t _uid, gid_t _gid,
|
||||
int _perms, const char *_fmt, ...) __printflike(6, 7);
|
||||
|
Loading…
Reference in New Issue
Block a user