Do not refcount the cdevsw, but rather maintain a cdev->si_threadcount
of the number of threads which are inside whatever is behind the cdevsw for this particular cdev. Make the device mutex visible through dev_lock() and dev_unlock(). We may want finer granularity later. Replace spechash_mtx use with dev_lock()/dev_unlock().
This commit is contained in:
parent
a5b75e6c38
commit
3947e54e89
@ -188,8 +188,9 @@ spec_open(ap)
|
||||
vp->v_vflag |= VV_ISTTY;
|
||||
|
||||
VOP_UNLOCK(vp, 0, td);
|
||||
dev_ref(dev);
|
||||
cdevsw_ref(dsw);
|
||||
dev_lock();
|
||||
dev->si_threadcount++;
|
||||
dev_unlock();
|
||||
if(!(dsw->d_flags & D_NEEDGIANT)) {
|
||||
DROP_GIANT();
|
||||
if (dsw->d_fdopen != NULL)
|
||||
@ -201,9 +202,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);
|
||||
dev_lock();
|
||||
dev->si_threadcount--;
|
||||
dev_unlock();
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
|
||||
|
||||
if (error)
|
||||
@ -260,14 +261,18 @@ spec_read(ap)
|
||||
VOP_UNLOCK(vp, 0, td);
|
||||
KASSERT(dev->si_refcount > 0,
|
||||
("specread() on un-referenced struct cdev *(%s)", devtoname(dev)));
|
||||
cdevsw_ref(dsw);
|
||||
dev_lock();
|
||||
dev->si_threadcount++;
|
||||
dev_unlock();
|
||||
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);
|
||||
dev_lock();
|
||||
dev->si_threadcount--;
|
||||
dev_unlock();
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
|
||||
if (uio->uio_resid != resid || (error == 0 && resid != 0))
|
||||
vfs_timestamp(&dev->si_atime);
|
||||
@ -304,14 +309,18 @@ spec_write(ap)
|
||||
VOP_UNLOCK(vp, 0, td);
|
||||
KASSERT(dev->si_refcount > 0,
|
||||
("spec_write() on un-referenced struct cdev *(%s)", devtoname(dev)));
|
||||
cdevsw_ref(dsw);
|
||||
dev_lock();
|
||||
dev->si_threadcount++;
|
||||
dev_unlock();
|
||||
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);
|
||||
dev_lock();
|
||||
dev->si_threadcount--;
|
||||
dev_unlock();
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
|
||||
if (uio->uio_resid != resid || (error == 0 && resid != 0)) {
|
||||
vfs_timestamp(&dev->si_ctime);
|
||||
@ -343,7 +352,9 @@ spec_ioctl(ap)
|
||||
dsw = devsw(dev);
|
||||
KASSERT(dev->si_refcount > 0,
|
||||
("spec_ioctl() on un-referenced struct cdev *(%s)", devtoname(dev)));
|
||||
cdevsw_ref(dsw);
|
||||
dev_lock();
|
||||
dev->si_threadcount++;
|
||||
dev_unlock();
|
||||
if (!(dsw->d_flags & D_NEEDGIANT)) {
|
||||
DROP_GIANT();
|
||||
error = dsw->d_ioctl(dev, ap->a_command,
|
||||
@ -352,7 +363,9 @@ spec_ioctl(ap)
|
||||
} else
|
||||
error = dsw->d_ioctl(dev, ap->a_command,
|
||||
ap->a_data, ap->a_fflag, ap->a_td);
|
||||
cdevsw_rel(dsw);
|
||||
dev_lock();
|
||||
dev->si_threadcount--;
|
||||
dev_unlock();
|
||||
if (error == ENOIOCTL)
|
||||
error = ENOTTY;
|
||||
return (error);
|
||||
@ -376,14 +389,18 @@ spec_poll(ap)
|
||||
dsw = devsw(dev);
|
||||
KASSERT(dev->si_refcount > 0,
|
||||
("spec_poll() on un-referenced struct cdev *(%s)", devtoname(dev)));
|
||||
cdevsw_ref(dsw);
|
||||
dev_lock();
|
||||
dev->si_threadcount++;
|
||||
dev_unlock();
|
||||
if (!(dsw->d_flags & D_NEEDGIANT)) {
|
||||
/* XXX: not yet DROP_GIANT(); */
|
||||
error = dsw->d_poll(dev, ap->a_events, ap->a_td);
|
||||
/* XXX: not yet PICKUP_GIANT(); */
|
||||
} else
|
||||
error = dsw->d_poll(dev, ap->a_events, ap->a_td);
|
||||
cdevsw_rel(dsw);
|
||||
dev_lock();
|
||||
dev->si_threadcount--;
|
||||
dev_unlock();
|
||||
return(error);
|
||||
}
|
||||
|
||||
@ -403,14 +420,18 @@ spec_kqfilter(ap)
|
||||
dsw = devsw(dev);
|
||||
KASSERT(dev->si_refcount > 0,
|
||||
("spec_kqfilter() on un-referenced struct cdev *(%s)", devtoname(dev)));
|
||||
cdevsw_ref(dsw);
|
||||
dev_lock();
|
||||
dev->si_threadcount++;
|
||||
dev_unlock();
|
||||
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);
|
||||
dev_lock();
|
||||
dev->si_threadcount--;
|
||||
dev_unlock();
|
||||
return (error);
|
||||
}
|
||||
|
||||
@ -595,15 +616,18 @@ spec_close(ap)
|
||||
VI_UNLOCK(vp);
|
||||
KASSERT(dev->si_refcount > 0,
|
||||
("spec_close() on un-referenced struct cdev *(%s)", devtoname(dev)));
|
||||
cdevsw_ref(dsw);
|
||||
dev_lock();
|
||||
dev->si_threadcount++;
|
||||
dev_unlock();
|
||||
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);
|
||||
dev_lock();
|
||||
dev->si_threadcount--;
|
||||
dev_unlock();
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
@ -73,16 +73,16 @@ static void freedev(struct cdev *dev);
|
||||
static struct cdev *newdev(int x, int y);
|
||||
|
||||
|
||||
static void
|
||||
devlock(void)
|
||||
void
|
||||
dev_lock(void)
|
||||
{
|
||||
if (!mtx_initialized(&devmtx))
|
||||
mtx_init(&devmtx, "cdev", NULL, MTX_DEF);
|
||||
mtx_lock(&devmtx);
|
||||
}
|
||||
|
||||
static void
|
||||
devunlock(void)
|
||||
void
|
||||
dev_unlock(void)
|
||||
{
|
||||
mtx_unlock(&devmtx);
|
||||
}
|
||||
@ -90,15 +90,15 @@ devunlock(void)
|
||||
void
|
||||
dev_ref(struct cdev *dev)
|
||||
{
|
||||
devlock();
|
||||
dev_lock();
|
||||
dev->si_refcount++;
|
||||
devunlock();
|
||||
dev_unlock();
|
||||
}
|
||||
|
||||
void
|
||||
dev_rel(struct cdev *dev)
|
||||
{
|
||||
devlock();
|
||||
|
||||
dev->si_refcount--;
|
||||
KASSERT(dev->si_refcount >= 0,
|
||||
("dev_rel(%s) gave negative count", devtoname(dev)));
|
||||
@ -106,25 +106,6 @@ dev_rel(struct cdev *dev)
|
||||
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();
|
||||
}
|
||||
|
||||
int
|
||||
@ -396,7 +377,7 @@ static void
|
||||
prep_cdevsw(struct cdevsw *devsw)
|
||||
{
|
||||
|
||||
devlock();
|
||||
dev_lock();
|
||||
|
||||
if (devsw->d_version != D_VERSION_00) {
|
||||
printf(
|
||||
@ -451,7 +432,7 @@ prep_cdevsw(struct cdevsw *devsw)
|
||||
reserved_majors[devsw->d_maj] = devsw->d_maj;
|
||||
}
|
||||
}
|
||||
devunlock();
|
||||
dev_unlock();
|
||||
}
|
||||
|
||||
struct cdev *
|
||||
@ -477,7 +458,7 @@ make_dev(struct cdevsw *devsw, int minornr, uid_t uid, gid_t gid, int perms, con
|
||||
*/
|
||||
return (dev);
|
||||
}
|
||||
devlock();
|
||||
dev_lock();
|
||||
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)));
|
||||
@ -497,7 +478,7 @@ make_dev(struct cdevsw *devsw, int minornr, uid_t uid, gid_t gid, int perms, con
|
||||
|
||||
LIST_INSERT_HEAD(&devsw->d_devs, dev, si_list);
|
||||
devfs_create(dev);
|
||||
devunlock();
|
||||
dev_unlock();
|
||||
return (dev);
|
||||
}
|
||||
|
||||
@ -518,11 +499,11 @@ void
|
||||
dev_depends(struct cdev *pdev, struct cdev *cdev)
|
||||
{
|
||||
|
||||
devlock();
|
||||
dev_lock();
|
||||
cdev->si_parent = pdev;
|
||||
cdev->si_flags |= SI_CHILD;
|
||||
LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings);
|
||||
devunlock();
|
||||
dev_unlock();
|
||||
}
|
||||
|
||||
struct cdev *
|
||||
@ -533,7 +514,7 @@ make_dev_alias(struct cdev *pdev, const char *fmt, ...)
|
||||
int i;
|
||||
|
||||
dev = allocdev();
|
||||
devlock();
|
||||
dev_lock();
|
||||
dev->si_flags |= SI_ALIAS;
|
||||
dev->si_flags |= SI_NAMED;
|
||||
va_start(ap, fmt);
|
||||
@ -545,7 +526,7 @@ make_dev_alias(struct cdev *pdev, const char *fmt, ...)
|
||||
va_end(ap);
|
||||
|
||||
devfs_create(dev);
|
||||
devunlock();
|
||||
dev_unlock();
|
||||
dev_depends(pdev, dev);
|
||||
return (dev);
|
||||
}
|
||||
@ -606,9 +587,9 @@ void
|
||||
destroy_dev(struct cdev *dev)
|
||||
{
|
||||
|
||||
devlock();
|
||||
dev_lock();
|
||||
idestroy_dev(dev);
|
||||
devunlock();
|
||||
dev_unlock();
|
||||
}
|
||||
|
||||
const char *
|
||||
|
@ -3098,18 +3098,24 @@ void
|
||||
dev_strategy(struct buf *bp)
|
||||
{
|
||||
struct cdevsw *csw;
|
||||
struct cdev *dev;
|
||||
|
||||
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 = bp->b_io.bio_dev;
|
||||
csw = devsw(dev);
|
||||
KASSERT(dev->si_refcount > 0,
|
||||
("dev_strategy on un-referenced struct cdev *(%s)",
|
||||
devtoname(bp->b_io.bio_dev)));
|
||||
cdevsw_ref(csw);
|
||||
devtoname(dev)));
|
||||
dev_lock();
|
||||
dev->si_threadcount++;
|
||||
dev_unlock();
|
||||
(*devsw(bp->b_io.bio_dev)->d_strategy)(&bp->b_io);
|
||||
cdevsw_rel(csw);
|
||||
dev_lock();
|
||||
dev->si_threadcount--;
|
||||
dev_unlock();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -156,12 +156,6 @@ static struct mtx mntid_mtx;
|
||||
*/
|
||||
static struct mtx vnode_free_list_mtx;
|
||||
|
||||
/*
|
||||
* For any iteration/modification of dev->si_hlist (linked through
|
||||
* v_specnext)
|
||||
*/
|
||||
static struct mtx spechash_mtx;
|
||||
|
||||
/* Publicly exported FS */
|
||||
struct nfs_public nfs_pub;
|
||||
|
||||
@ -283,7 +277,6 @@ vntblinit(void *dummy __unused)
|
||||
minvnodes = desiredvnodes / 4;
|
||||
mtx_init(&mountlist_mtx, "mountlist", NULL, MTX_DEF);
|
||||
mtx_init(&mntid_mtx, "mntid", NULL, MTX_DEF);
|
||||
mtx_init(&spechash_mtx, "spechash", NULL, MTX_DEF);
|
||||
TAILQ_INIT(&vnode_free_list);
|
||||
mtx_init(&vnode_free_list_mtx, "vnode_free_list", NULL, MTX_DEF);
|
||||
vnode_zone = uma_zcreate("VNODE", sizeof (struct vnode), NULL, NULL,
|
||||
@ -1899,9 +1892,9 @@ v_incr_usecount(struct vnode *vp, int delta)
|
||||
|
||||
vp->v_usecount += delta;
|
||||
if (vp->v_type == VCHR && vp->v_rdev != NULL) {
|
||||
mtx_lock(&spechash_mtx);
|
||||
dev_lock();
|
||||
vp->v_rdev->si_usecount += delta;
|
||||
mtx_unlock(&spechash_mtx);
|
||||
dev_unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1975,13 +1968,13 @@ 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);
|
||||
dev_lock();
|
||||
dev->si_refcount++;
|
||||
nvp->v_rdev = dev;
|
||||
SLIST_INSERT_HEAD(&dev->si_hlist, nvp, v_specnext);
|
||||
dev->si_usecount += nvp->v_usecount;
|
||||
mtx_unlock(&spechash_mtx);
|
||||
dev_unlock();
|
||||
VI_UNLOCK(nvp);
|
||||
}
|
||||
|
||||
@ -2585,9 +2578,9 @@ vop_revoke(ap)
|
||||
VI_UNLOCK(vp);
|
||||
dev = vp->v_rdev;
|
||||
for (;;) {
|
||||
mtx_lock(&spechash_mtx);
|
||||
dev_lock();
|
||||
vq = SLIST_FIRST(&dev->si_hlist);
|
||||
mtx_unlock(&spechash_mtx);
|
||||
dev_unlock();
|
||||
if (vq == NULL)
|
||||
break;
|
||||
vgone(vq);
|
||||
@ -2706,12 +2699,12 @@ vgonel(vp, td)
|
||||
*/
|
||||
VI_LOCK(vp);
|
||||
if (vp->v_type == VCHR && vp->v_rdev != NULL) {
|
||||
mtx_lock(&spechash_mtx);
|
||||
dev_lock();
|
||||
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;
|
||||
dev_unlock();
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2751,13 +2744,13 @@ vfinddev(dev, vpp)
|
||||
{
|
||||
struct vnode *vp;
|
||||
|
||||
mtx_lock(&spechash_mtx);
|
||||
dev_lock();
|
||||
SLIST_FOREACH(vp, &dev->si_hlist, v_specnext) {
|
||||
*vpp = vp;
|
||||
mtx_unlock(&spechash_mtx);
|
||||
dev_unlock();
|
||||
return (1);
|
||||
}
|
||||
mtx_unlock(&spechash_mtx);
|
||||
dev_unlock();
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -2770,9 +2763,9 @@ vcount(vp)
|
||||
{
|
||||
int count;
|
||||
|
||||
mtx_lock(&spechash_mtx);
|
||||
dev_lock();
|
||||
count = vp->v_rdev->si_usecount;
|
||||
mtx_unlock(&spechash_mtx);
|
||||
dev_unlock();
|
||||
return (count);
|
||||
}
|
||||
|
||||
@ -2785,9 +2778,9 @@ count_dev(dev)
|
||||
{
|
||||
int count;
|
||||
|
||||
mtx_lock(&spechash_mtx);
|
||||
dev_lock();
|
||||
count = dev->si_usecount;
|
||||
mtx_unlock(&spechash_mtx);
|
||||
dev_unlock();
|
||||
return(count);
|
||||
}
|
||||
|
||||
|
@ -222,7 +222,7 @@ struct cdevsw {
|
||||
/* These fields should not be messed with by drivers */
|
||||
LIST_ENTRY(cdevsw) d_list;
|
||||
LIST_HEAD(, cdev) d_devs;
|
||||
int d_refcount;
|
||||
int d_spare3;
|
||||
};
|
||||
|
||||
#endif /* _KERNEL */
|
||||
@ -263,8 +263,6 @@ int clone_create(struct clonedevs **, struct cdevsw *, int *unit, struct cdev **
|
||||
int count_dev(struct cdev *_dev);
|
||||
void destroy_dev(struct cdev *_dev);
|
||||
struct cdevsw *devsw(struct cdev *_dev);
|
||||
void cdevsw_ref(struct cdevsw *);
|
||||
void cdevsw_rel(struct cdevsw *);
|
||||
const char *devtoname(struct cdev *_dev);
|
||||
int dev_named(struct cdev *_pdev, const char *_name);
|
||||
void dev_depends(struct cdev *_pdev, struct cdev *_cdev);
|
||||
@ -276,6 +274,8 @@ struct cdev *make_dev(struct cdevsw *_devsw, int _minor, uid_t _uid, gid_t _gid,
|
||||
int _perms, const char *_fmt, ...) __printflike(6, 7);
|
||||
struct cdev *make_dev_alias(struct cdev *_pdev, const char *_fmt, ...) __printflike(2, 3);
|
||||
int dev2unit(struct cdev *_dev);
|
||||
void dev_lock(void);
|
||||
void dev_unlock(void);
|
||||
int unit2minor(int _unit);
|
||||
void setconf(void);
|
||||
struct cdev *getdiskbyname(char *_name);
|
||||
|
Loading…
x
Reference in New Issue
Block a user