git: 30bfb2fa0fad - main - ffs_vput_pair(): try harder to recover from the vnode reclaim

Konstantin Belousov kib at FreeBSD.org
Fri Feb 12 01:07:20 UTC 2021


The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=30bfb2fa0fad8e5bbcce369df46dcaa2e08324f3

commit 30bfb2fa0fad8e5bbcce369df46dcaa2e08324f3
Author:     Konstantin Belousov <kib at FreeBSD.org>
AuthorDate: 2021-01-27 18:10:51 +0000
Commit:     Konstantin Belousov <kib at FreeBSD.org>
CommitDate: 2021-02-12 01:02:21 +0000

    ffs_vput_pair(): try harder to recover from the vnode reclaim
    
    In particular, if unlock_vp is false, save vp's inode number and
    generation. If ffs_inotovp() can re-create the vnode with the same
    number and generation after we finished with handling dvp, then we most
    likely raced with unmount, and were able to restore atomicity of open.
    We use FFSV_REPLACE_DOOMED there, to drop the old vnode.
    
    This additional recovery is not strictly required, but it improves the
    quality of the implementation.
    
    Suggested by:   mckusick
    Reviewed by:    chs, mckusick
    Tested by:      pho
    MFC after:      2 weeks
    Sponsored by:   The FreeBSD Foundation
---
 sys/ufs/ffs/ffs_vnops.c | 39 ++++++++++++++++++++++++++++++++++++---
 1 file changed, 36 insertions(+), 3 deletions(-)

diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c
index 623b13790ce0..2ac67adad5f2 100644
--- a/sys/ufs/ffs/ffs_vnops.c
+++ b/sys/ufs/ffs/ffs_vnops.c
@@ -1924,8 +1924,11 @@ ffs_getpages_async(struct vop_getpages_async_args *ap)
 static int
 ffs_vput_pair(struct vop_vput_pair_args *ap)
 {
-	struct vnode *dvp, *vp, **vpp;
-	struct inode *dp;
+	struct mount *mp;
+	struct vnode *dvp, *vp, *vp1, **vpp;
+	struct inode *dp, *ip;
+	ino_t ip_ino;
+	u_int64_t ip_gen;
 	int error, vp_locked;
 
 	dvp = ap->a_dvp;
@@ -1940,12 +1943,17 @@ ffs_vput_pair(struct vop_vput_pair_args *ap)
 		return (0);
 	}
 
+	mp = NULL;
 	if (vp != NULL) {
 		if (ap->a_unlock_vp) {
 			vput(vp);
 		} else {
 			MPASS(vp->v_type != VNON);
 			vp_locked = VOP_ISLOCKED(vp);
+			ip = VTOI(vp);
+			ip_ino = ip->i_number;
+			ip_gen = ip->i_gen;
+			mp = vp->v_mount;
 			VOP_UNLOCK(vp);
 		}
 	}
@@ -1957,6 +1965,7 @@ ffs_vput_pair(struct vop_vput_pair_args *ap)
 
 	if (vp == NULL || ap->a_unlock_vp)
 		return (0);
+	MPASS(mp != NULL);
 
 	/*
 	 * It is possible that vp is reclaimed at this point. Only
@@ -1970,5 +1979,29 @@ ffs_vput_pair(struct vop_vput_pair_args *ap)
 	 *    and respond to dead vnodes by returning ESTALE.
 	 */
 	VOP_LOCK(vp, vp_locked | LK_RETRY);
-	return (0);
+	if (!VN_IS_DOOMED(vp))
+		return (0);
+
+	/*
+	 * Try harder to recover from reclaimed vp if reclaim was not
+	 * because underlying inode was cleared.  We saved inode
+	 * number and inode generation, so we can try to reinstantiate
+	 * exactly same version of inode.  If this fails, return
+	 * original doomed vnode and let caller to handle
+	 * consequences.
+	 *
+	 * Note that callers must keep write started around
+	 * VOP_VPUT_PAIR() calls, so it is safe to use mp without
+	 * busying it.
+	 */
+	VOP_UNLOCK(vp);
+	error = ffs_inotovp(mp, ip_ino, ip_gen, LK_EXCLUSIVE, &vp1,
+	    FFSV_REPLACE_DOOMED);
+	if (error != 0) {
+		VOP_LOCK(vp, vp_locked | LK_RETRY);
+	} else {
+		vrele(vp);
+		*vpp = vp1;
+	}
+	return (error);
 }


More information about the dev-commits-src-main mailing list