1) Fix a deadlock in the VFS:
- threadA runs vfs_rel(mp1) - threadB does unmount the mp1 fs, sets MNTK_UNMOUNT and drop MNT_ILOCK() - threadA runs vfs_busy(mp1) and, as long as, MNTK_UNMOUNT is set, sleeps waiting for threadB to complete the unmount - threadB, in vfs_mount_destroy(), finds mnt_lock > 0 and sleeps waiting for the refcount to expire. Fix the deadlock by adding a flag called MNTK_REFEXPIRE which signals the unmounter is waiting for mnt_ref to expire. The vfs_busy contenders got awake, fails, and if they retry the MNTK_REFEXPIRE won't allow them to sleep again. 2) Simplify significantly the code of vfs_mount_destroy() trimming unnecessary codes: - as long as any reference exited, it is no-more possible to have write-op (primarty and secondary) in progress. - it is no needed to drop and reacquire the mount lock. - filling the structures with dummy values is unuseful as long as it is going to be freed. Tested by: pho, Andrea Barberio <insomniac at slackware dot it> Discussed with: kib
This commit is contained in:
parent
fd14c50bbb
commit
4a0f807602
@ -507,29 +507,20 @@ vfs_mount_destroy(struct mount *mp)
|
||||
{
|
||||
|
||||
MNT_ILOCK(mp);
|
||||
mp->mnt_kern_flag |= MNTK_REFEXPIRE;
|
||||
if (mp->mnt_kern_flag & MNTK_MWAIT) {
|
||||
mp->mnt_kern_flag &= ~MNTK_MWAIT;
|
||||
wakeup(mp);
|
||||
}
|
||||
while (mp->mnt_ref)
|
||||
msleep(mp, MNT_MTX(mp), PVFS, "mntref", 0);
|
||||
if (mp->mnt_writeopcount > 0) {
|
||||
printf("Waiting for mount point write ops\n");
|
||||
while (mp->mnt_writeopcount > 0) {
|
||||
mp->mnt_kern_flag |= MNTK_SUSPEND;
|
||||
msleep(&mp->mnt_writeopcount,
|
||||
MNT_MTX(mp),
|
||||
PZERO, "mntdestroy2", 0);
|
||||
}
|
||||
printf("mount point write ops completed\n");
|
||||
}
|
||||
if (mp->mnt_secondary_writes > 0) {
|
||||
printf("Waiting for mount point secondary write ops\n");
|
||||
while (mp->mnt_secondary_writes > 0) {
|
||||
mp->mnt_kern_flag |= MNTK_SUSPEND;
|
||||
msleep(&mp->mnt_secondary_writes,
|
||||
MNT_MTX(mp),
|
||||
PZERO, "mntdestroy3", 0);
|
||||
}
|
||||
printf("mount point secondary write ops completed\n");
|
||||
}
|
||||
MNT_IUNLOCK(mp);
|
||||
KASSERT(mp->mnt_ref == 0,
|
||||
("%s: invalid refcount in the drain path @ %s:%d", __func__,
|
||||
__FILE__, __LINE__));
|
||||
if (mp->mnt_writeopcount != 0)
|
||||
panic("vfs_mount_destroy: nonzero writeopcount");
|
||||
if (mp->mnt_secondary_writes != 0)
|
||||
panic("vfs_mount_destroy: nonzero secondary_writes");
|
||||
mp->mnt_vfc->vfc_refcount--;
|
||||
if (!TAILQ_EMPTY(&mp->mnt_nvnodelist)) {
|
||||
struct vnode *vp;
|
||||
@ -538,18 +529,10 @@ vfs_mount_destroy(struct mount *mp)
|
||||
vprint("", vp);
|
||||
panic("unmount: dangling vnode");
|
||||
}
|
||||
MNT_ILOCK(mp);
|
||||
if (mp->mnt_kern_flag & MNTK_MWAIT)
|
||||
wakeup(mp);
|
||||
if (mp->mnt_writeopcount != 0)
|
||||
panic("vfs_mount_destroy: nonzero writeopcount");
|
||||
if (mp->mnt_secondary_writes != 0)
|
||||
panic("vfs_mount_destroy: nonzero secondary_writes");
|
||||
if (mp->mnt_nvnodelistsize != 0)
|
||||
panic("vfs_mount_destroy: nonzero nvnodelistsize");
|
||||
mp->mnt_writeopcount = -1000;
|
||||
mp->mnt_nvnodelistsize = -1000;
|
||||
mp->mnt_secondary_writes = -1000;
|
||||
if (mp->mnt_lockref != 0)
|
||||
panic("vfs_mount_destroy: nonzero lock refcount");
|
||||
MNT_IUNLOCK(mp);
|
||||
#ifdef MAC
|
||||
mac_mount_destroy(mp);
|
||||
|
@ -345,7 +345,7 @@ vfs_busy(struct mount *mp, int flags)
|
||||
MNT_ILOCK(mp);
|
||||
MNT_REF(mp);
|
||||
if (mp->mnt_kern_flag & MNTK_UNMOUNT) {
|
||||
if (flags & MBF_NOWAIT) {
|
||||
if (flags & MBF_NOWAIT || mp->mnt_kern_flag & MNTK_REFEXPIRE) {
|
||||
MNT_REL(mp);
|
||||
MNT_IUNLOCK(mp);
|
||||
return (ENOENT);
|
||||
|
@ -316,6 +316,7 @@ void __mnt_vnode_markerfree(struct vnode **mvp, struct mount *mp);
|
||||
#define MNTK_SOFTDEP 0x00000004 /* async disabled by softdep */
|
||||
#define MNTK_NOINSMNTQ 0x00000008 /* insmntque is not allowed */
|
||||
#define MNTK_DRAINING 0x00000010 /* lock draining is happening */
|
||||
#define MNTK_REFEXPIRE 0x00000020 /* refcount expiring is happening */
|
||||
#define MNTK_UNMOUNT 0x01000000 /* unmount in progress */
|
||||
#define MNTK_MWAIT 0x02000000 /* waiting for unmount to finish */
|
||||
#define MNTK_SUSPEND 0x08000000 /* request write suspension */
|
||||
|
Loading…
Reference in New Issue
Block a user