devfs_free() calls free_unr(), that may sleep.
Postpone call to devfs_free() after cdev mutex is dropped. Reuse cdp_list link for queuing devices awaiting deletion in the cdevp_free_list. Reported by: Hans Petter Selasky <hselasky c2i net> Tested by: Peter Holm Approved by: re (kensmith) MFC after: 2 weeks
This commit is contained in:
parent
7550e3eac4
commit
9bc911d4a2
@ -54,6 +54,9 @@ static struct cdev *make_dev_credv(struct cdevsw *devsw, int minornr,
|
||||
struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt,
|
||||
va_list ap);
|
||||
|
||||
static struct cdev_priv_list cdevp_free_list =
|
||||
TAILQ_HEAD_INITIALIZER(cdevp_free_list);
|
||||
|
||||
void
|
||||
dev_lock(void)
|
||||
{
|
||||
@ -61,6 +64,31 @@ dev_lock(void)
|
||||
mtx_lock(&devmtx);
|
||||
}
|
||||
|
||||
static void
|
||||
dev_unlock_and_free(void)
|
||||
{
|
||||
struct cdev_priv *cdp;
|
||||
|
||||
mtx_assert(&devmtx, MA_OWNED);
|
||||
while ((cdp = TAILQ_FIRST(&cdevp_free_list)) != NULL) {
|
||||
TAILQ_REMOVE(&cdevp_free_list, cdp, cdp_list);
|
||||
mtx_unlock(&devmtx);
|
||||
devfs_free(&cdp->cdp_c);
|
||||
mtx_lock(&devmtx);
|
||||
}
|
||||
mtx_unlock(&devmtx);
|
||||
}
|
||||
|
||||
static void
|
||||
dev_free_devlocked(struct cdev *cdev)
|
||||
{
|
||||
struct cdev_priv *cdp;
|
||||
|
||||
mtx_assert(&devmtx, MA_OWNED);
|
||||
cdp = cdev->si_priv;
|
||||
TAILQ_INSERT_HEAD(&cdevp_free_list, cdp, cdp_list);
|
||||
}
|
||||
|
||||
void
|
||||
dev_unlock(void)
|
||||
{
|
||||
@ -417,7 +445,7 @@ newdev(struct cdevsw *csw, int y, struct cdev *si)
|
||||
udev = y;
|
||||
LIST_FOREACH(si2, &csw->d_devs, si_list) {
|
||||
if (si2->si_drv0 == udev) {
|
||||
devfs_free(si);
|
||||
dev_free_devlocked(si);
|
||||
return (si2);
|
||||
}
|
||||
}
|
||||
@ -548,7 +576,7 @@ make_dev_credv(struct cdevsw *devsw, int minornr, struct ucred *cr, uid_t uid,
|
||||
* simplifies cloning devices.
|
||||
* XXX: still ??
|
||||
*/
|
||||
dev_unlock();
|
||||
dev_unlock_and_free();
|
||||
return (dev);
|
||||
}
|
||||
KASSERT(!(dev->si_flags & SI_NAMED),
|
||||
@ -709,7 +737,7 @@ destroy_devl(struct cdev *dev)
|
||||
if (dev->si_refcount > 0) {
|
||||
LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list);
|
||||
} else {
|
||||
devfs_free(dev);
|
||||
dev_free_devlocked(dev);
|
||||
}
|
||||
}
|
||||
|
||||
@ -719,7 +747,7 @@ destroy_dev(struct cdev *dev)
|
||||
|
||||
dev_lock();
|
||||
destroy_devl(dev);
|
||||
dev_unlock();
|
||||
dev_unlock_and_free();
|
||||
}
|
||||
|
||||
const char *
|
||||
@ -839,8 +867,8 @@ clone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up, struct cdev **
|
||||
u = dev2unit(dev);
|
||||
if (u == (unit | extra)) {
|
||||
*dp = dev;
|
||||
devfs_free(ndev);
|
||||
dev_unlock();
|
||||
devfs_free(ndev);
|
||||
return (0);
|
||||
}
|
||||
if (unit == -1 && u == low) {
|
||||
@ -876,7 +904,7 @@ clone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up, struct cdev **
|
||||
LIST_INSERT_HEAD(&cd->head, dev, si_clone);
|
||||
dev->si_flags |= SI_CLONELIST;
|
||||
*up = unit;
|
||||
dev_unlock();
|
||||
dev_unlock_and_free();
|
||||
return (1);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user