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:
Poul-Henning Kamp 2004-09-23 07:17:41 +00:00
parent 2371026f0b
commit a0e78d2eb0
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=135600
5 changed files with 90 additions and 86 deletions

View File

@ -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);
}

View File

@ -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 *

View File

@ -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();
}
/*

View File

@ -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);
}

View File

@ -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);