Stop enforcing additional reference on all cdevs, which was introduced
in r277199. Acquire the neccessary reference in delist_dev_locked() and inform destroy_devl() about it using CDP_UNREF_DTR flag. Fix some style nits, add asserts. Discussed with: hselasky Tested by: pho Sponsored by: The FreeBSD Foundation MFC after: 1 week
This commit is contained in:
parent
a57a934a38
commit
3b50dff506
sys
@ -137,12 +137,6 @@ devfs_alloc(int flags)
|
||||
vfs_timestamp(&ts);
|
||||
cdev->si_atime = cdev->si_mtime = cdev->si_ctime = ts;
|
||||
cdev->si_cred = NULL;
|
||||
/*
|
||||
* Avoid race with dev_rel() by setting the initial
|
||||
* reference count to 1. This last reference is taken
|
||||
* by the destroy_dev() function.
|
||||
*/
|
||||
cdev->si_refcount = 1;
|
||||
|
||||
return (cdev);
|
||||
}
|
||||
|
@ -56,6 +56,7 @@ struct cdev_priv {
|
||||
u_int cdp_flags;
|
||||
#define CDP_ACTIVE (1 << 0)
|
||||
#define CDP_SCHED_DTR (1 << 1)
|
||||
#define CDP_UNREF_DTR (1 << 2)
|
||||
|
||||
u_int cdp_inuse;
|
||||
u_int cdp_maxdirent;
|
||||
|
@ -116,6 +116,8 @@ dev_free_devlocked(struct cdev *cdev)
|
||||
|
||||
mtx_assert(&devmtx, MA_OWNED);
|
||||
cdp = cdev2priv(cdev);
|
||||
KASSERT((cdp->cdp_flags & CDP_UNREF_DTR) == 0,
|
||||
("destroy_dev() was not called after delist_dev(%p)", cdev));
|
||||
TAILQ_INSERT_HEAD(&cdevp_free_list, cdp, cdp_list);
|
||||
}
|
||||
|
||||
@ -1035,6 +1037,7 @@ destroy_devl(struct cdev *dev)
|
||||
{
|
||||
struct cdevsw *csw;
|
||||
struct cdev_privdata *p;
|
||||
struct cdev_priv *cdp;
|
||||
|
||||
mtx_assert(&devmtx, MA_OWNED);
|
||||
KASSERT(dev->si_flags & SI_NAMED,
|
||||
@ -1043,7 +1046,18 @@ destroy_devl(struct cdev *dev)
|
||||
("WARNING: Driver mistake: destroy_dev on eternal %d\n",
|
||||
dev2unit(dev)));
|
||||
|
||||
devfs_destroy(dev);
|
||||
cdp = cdev2priv(dev);
|
||||
if ((cdp->cdp_flags & CDP_UNREF_DTR) == 0) {
|
||||
/*
|
||||
* Avoid race with dev_rel(), e.g. from the populate
|
||||
* loop. If CDP_UNREF_DTR flag is set, the reference
|
||||
* to be dropped at the end of destroy_devl() was
|
||||
* already taken by delist_dev_locked().
|
||||
*/
|
||||
dev_refl(dev);
|
||||
|
||||
devfs_destroy(dev);
|
||||
}
|
||||
|
||||
/* Remove name marking */
|
||||
dev->si_flags &= ~SI_NAMED;
|
||||
@ -1103,19 +1117,27 @@ destroy_devl(struct cdev *dev)
|
||||
}
|
||||
}
|
||||
dev->si_flags &= ~SI_ALIAS;
|
||||
dev->si_refcount--; /* Avoid race with dev_rel() */
|
||||
cdp->cdp_flags &= ~CDP_UNREF_DTR;
|
||||
dev->si_refcount--;
|
||||
|
||||
if (dev->si_refcount > 0) {
|
||||
if (dev->si_refcount > 0)
|
||||
LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list);
|
||||
} else {
|
||||
else
|
||||
dev_free_devlocked(dev);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
delist_dev_locked(struct cdev *dev)
|
||||
{
|
||||
struct cdev_priv *cdp;
|
||||
struct cdev *child;
|
||||
|
||||
mtx_assert(&devmtx, MA_OWNED);
|
||||
cdp = cdev2priv(dev);
|
||||
if ((cdp->cdp_flags & CDP_UNREF_DTR) != 0)
|
||||
return;
|
||||
cdp->cdp_flags |= CDP_UNREF_DTR;
|
||||
dev_refl(dev);
|
||||
devfs_destroy(dev);
|
||||
LIST_FOREACH(child, &dev->si_children, si_siblings)
|
||||
delist_dev_locked(child);
|
||||
@ -1124,6 +1146,7 @@ delist_dev_locked(struct cdev *dev)
|
||||
void
|
||||
delist_dev(struct cdev *dev)
|
||||
{
|
||||
|
||||
dev_lock();
|
||||
delist_dev_locked(dev);
|
||||
dev_unlock();
|
||||
|
Loading…
x
Reference in New Issue
Block a user