Fix the race between devfs_fp_check and devfs_reclaim. Derefence the

vnode' v_rdev and increment the dev threadcount , as well as clear it
(in devfs_reclaim) under the dev_lock().

Reviewed by:	tegge
Approved by:	pjd (mentor)
This commit is contained in:
Konstantin Belousov 2006-10-20 07:59:50 +00:00
parent 32c3bb77fa
commit 1663075c64
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=163529
3 changed files with 29 additions and 5 deletions

View File

@ -78,12 +78,14 @@ static int
devfs_fp_check(struct file *fp, struct cdev **devp, struct cdevsw **dswp)
{
*devp = fp->f_vnode->v_rdev;
if (*devp != fp->f_data)
*dswp = devvn_refthread(fp->f_vnode, devp);
if (*devp != fp->f_data) {
if (*dswp != NULL)
dev_relthread(*devp);
return (ENXIO);
}
KASSERT((*devp)->si_refcount > 0,
("devfs: un-referenced struct cdev *(%s)", devtoname(*devp)));
*dswp = dev_refthread(*devp);
if (*dswp == NULL)
return (ENXIO);
return (0);
@ -965,13 +967,15 @@ devfs_reclaim(struct vop_reclaim_args *ap)
vnode_destroy_vobject(vp);
dev_lock();
dev = vp->v_rdev;
vp->v_rdev = NULL;
if (dev == NULL)
if (dev == NULL) {
dev_unlock();
return (0);
}
dev_lock();
dev->si_usecount -= vp->v_usecount;
dev_unlock();
dev_rel(dev);

View File

@ -125,6 +125,24 @@ dev_refthread(struct cdev *dev)
return (csw);
}
struct cdevsw *
devvn_refthread(struct vnode *vp, struct cdev **devp)
{
struct cdevsw *csw;
mtx_assert(&devmtx, MA_NOTOWNED);
csw = NULL;
dev_lock();
*devp = vp->v_rdev;
if (*devp != NULL) {
csw = (*devp)->si_devsw;
if (csw != NULL)
(*devp)->si_threadcount++;
}
dev_unlock();
return (csw);
}
void
dev_relthread(struct cdev *dev)
{

View File

@ -105,6 +105,7 @@ struct thread;
struct uio;
struct knote;
struct clonedevs;
struct vnode;
/*
* Note: d_thread_t is provided as a transition aid for those drivers
@ -244,6 +245,7 @@ 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 *dev_refthread(struct cdev *_dev);
struct cdevsw *devvn_refthread(struct vnode *vp, struct cdev **devp);
void dev_relthread(struct cdev *_dev);
void dev_depends(struct cdev *_pdev, struct cdev *_cdev);
void dev_ref(struct cdev *dev);