aboutsummaryrefslogtreecommitdiff
path: root/sys/ufs/ffs
diff options
context:
space:
mode:
authorKirk McKusick <mckusick@FreeBSD.org>2012-03-28 21:21:19 +0000
committerKirk McKusick <mckusick@FreeBSD.org>2012-03-28 21:21:19 +0000
commit6c09f4a27ca5b8e919b97f994d05a773c493dfe2 (patch)
tree10030561d05cd2b87ce963df2246de55b590037f /sys/ufs/ffs
parentf5f9340b9807d44d200658ba1bbbbbb57ab72e07 (diff)
downloadsrc-6c09f4a27ca5b8e919b97f994d05a773c493dfe2.tar.gz
src-6c09f4a27ca5b8e919b97f994d05a773c493dfe2.zip
A refinement of change 232351 to avoid a race with a forcible unmount.
While we have a snapshot vnode unlocked to avoid a deadlock with another inode in the same inode block being updated, the filesystem containing it may be forcibly unmounted. When that happens the snapshot vnode is revoked. We need to check for that condition and fail appropriately. This change will be included along with 232351 when it is MFC'ed to 9. Spotted by: kib Reviewed by: kib
Notes
Notes: svn path=/head/; revision=233629
Diffstat (limited to 'sys/ufs/ffs')
-rw-r--r--sys/ufs/ffs/ffs_inode.c23
1 files changed, 19 insertions, 4 deletions
diff --git a/sys/ufs/ffs/ffs_inode.c b/sys/ufs/ffs/ffs_inode.c
index 9d0144a16a98..6175ed83a4ff 100644
--- a/sys/ufs/ffs/ffs_inode.c
+++ b/sys/ufs/ffs/ffs_inode.c
@@ -106,6 +106,7 @@ ffs_update(vp, waitfor)
flags = 0;
if (IS_SNAPSHOT(ip))
flags = GB_LOCK_NOWAIT;
+loop:
error = breadn_flags(ip->i_devvp,
fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
(int) fs->fs_bsize, 0, 0, 0, NOCRED, flags, &bp);
@@ -115,13 +116,27 @@ ffs_update(vp, waitfor)
return (error);
}
KASSERT((IS_SNAPSHOT(ip)), ("EBUSY from non-snapshot"));
- vref(vp); /* Protect against ffs_snapgone() */
+ /*
+ * Wait for our inode block to become available.
+ *
+ * Hold a reference to the vnode to protect against
+ * ffs_snapgone(). Since we hold a reference, it can only
+ * get reclaimed (VI_DOOMED flag) in a forcible downgrade
+ * or unmount. For an unmount, the entire filesystem will be
+ * gone, so we cannot attempt to touch anything associated
+ * with it while the vnode is unlocked; all we can do is
+ * pause briefly and try again. If when we relock the vnode
+ * we discover that it has been reclaimed, updating it is no
+ * longer necessary and we can just return an error.
+ */
+ vref(vp);
VOP_UNLOCK(vp, 0);
- (void) bread(ip->i_devvp,
- fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
- (int) fs->fs_bsize, NOCRED, &bp);
+ pause("ffsupd", 1);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
vrele(vp);
+ if ((vp->v_iflag & VI_DOOMED) != 0)
+ return (ENOENT);
+ goto loop;
}
if (DOINGSOFTDEP(vp))
softdep_update_inodeblock(ip, bp, waitfor);