Index: sys/fs/devfs/devfs_devs.c =================================================================== --- sys/fs/devfs/devfs_devs.c +++ sys/fs/devfs/devfs_devs.c @@ -144,6 +144,7 @@ LIST_INIT(&cdev->si_children); vfs_timestamp(&ts); cdev->si_atime = cdev->si_mtime = cdev->si_ctime = ts; + mtx_init(&cdev->si_threadlock, "devthrd", NULL, MTX_DEF); return (cdev); } @@ -180,6 +181,7 @@ devfs_free_cdp_inode(cdp->cdp_inode); if (cdp->cdp_maxdirent > 0) free(cdp->cdp_dirents, M_DEVFS2); + mtx_destroy(&cdev->si_threadlock); free(cdp, M_CDEVP); } Index: sys/kern/kern_conf.c =================================================================== --- sys/kern/kern_conf.c +++ sys/kern/kern_conf.c @@ -186,7 +186,7 @@ *ref = 0; return (dev->si_devsw); } - dev_lock(); + mtx_lock(&dev->si_threadlock); csw = dev->si_devsw; if (csw != NULL) { cdp = cdev2priv(dev); @@ -195,7 +195,7 @@ else csw = NULL; } - dev_unlock(); + mtx_unlock(&dev->si_threadlock); if (csw != NULL) *ref = 1; return (csw); @@ -223,19 +223,21 @@ } csw = NULL; - dev_lock(); + VI_LOCK(vp); dev = vp->v_rdev; if (dev == NULL) { - dev_unlock(); + VI_UNLOCK(vp); return (NULL); } + mtx_lock(&dev->si_threadlock); cdp = cdev2priv(dev); if ((cdp->cdp_flags & CDP_SCHED_DTR) == 0) { csw = dev->si_devsw; if (csw != NULL) atomic_add_long(&dev->si_threadcount, 1); } - dev_unlock(); + mtx_unlock(&dev->si_threadlock); + VI_UNLOCK(vp); if (csw != NULL) { *devp = dev; *ref = 1; @@ -1133,20 +1135,26 @@ dev->si_flags &= ~SI_CLONELIST; } + mtx_lock(&dev->si_threadlock); csw = dev->si_devsw; dev->si_devsw = NULL; /* already NULL for SI_ALIAS */ while (csw != NULL && csw->d_purge != NULL && dev->si_threadcount) { csw->d_purge(dev); + mtx_unlock(&dev->si_threadlock); msleep(csw, &devmtx, PRIBIO, "devprg", hz/10); + mtx_lock(&dev->si_threadlock); if (dev->si_threadcount) printf("Still %lu threads in %s\n", dev->si_threadcount, devtoname(dev)); } while (dev->si_threadcount != 0) { /* Use unique dummy wait ident */ + mtx_unlock(&dev->si_threadlock); msleep(&csw, &devmtx, PRIBIO, "devdrn", hz / 10); + mtx_lock(&dev->si_threadlock); } + mtx_unlock(&dev->si_threadlock); dev_unlock(); if ((cdp->cdp_flags & CDP_UNREF_DTR) == 0) { /* avoid out of order notify events */ Index: sys/kern/subr_witness.c =================================================================== --- sys/kern/subr_witness.c +++ sys/kern/subr_witness.c @@ -601,6 +601,7 @@ { "vm map (system)", &lock_class_mtx_sleep }, { "vnode interlock", &lock_class_mtx_sleep }, { "cdev", &lock_class_mtx_sleep }, + { "devthrd", &lock_class_mtx_sleep }, { NULL, NULL }, /* * VM Index: sys/sys/conf.h =================================================================== --- sys/sys/conf.h +++ sys/sys/conf.h @@ -48,6 +48,9 @@ #include #endif +#include +#include + struct snapdata; struct devfs_dirent; struct cdevsw; @@ -84,6 +87,7 @@ struct cdevsw *si_devsw; int si_iosize_max; /* maximum I/O size (for physio &al) */ u_long si_usecount; + struct mtx si_threadlock; /* protects si_devsw association */ u_long si_threadcount; union { struct snapdata *__sid_snapdata; @@ -167,7 +171,8 @@ #define D_VERSION_02 0x28042009 /* Add d_mmap_single */ #define D_VERSION_03 0x17122009 /* d_mmap takes memattr,vm_ooffset_t */ #define D_VERSION_04 0x5c48c353 /* SPECNAMELEN bumped to MAXNAMLEN */ -#define D_VERSION D_VERSION_04 +#define D_VERSION_05 0x5ddc0b6c /* per-dev lock to protect si_devsw */ +#define D_VERSION D_VERSION_05 /* * Flags used for internal housekeeping