aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2021-01-27 18:09:53 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2021-02-24 07:44:41 +0000
commit1de6eb52fdbfca2df545cf4860b8f18c1f140f70 (patch)
tree7991948d7a75971b0972723aed5146479d4115d1
parentd96c8375a6373a57a3c2a92b60a9f0dd1215d6c1 (diff)
downloadsrc-1de6eb52fdbfca2df545cf4860b8f18c1f140f70.tar.gz
src-1de6eb52fdbfca2df545cf4860b8f18c1f140f70.zip
FFS: implement special VOP_VPUT_PAIR().
(cherry picked from commit f2c9d038bdee547be07c8b0404547617b71f2232)
-rw-r--r--sys/ufs/ffs/ffs_vnops.c55
1 files changed, 55 insertions, 0 deletions
diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c
index be2653e32adc..623b13790ce0 100644
--- a/sys/ufs/ffs/ffs_vnops.c
+++ b/sys/ufs/ffs/ffs_vnops.c
@@ -130,6 +130,7 @@ static vop_listextattr_t ffs_listextattr;
static vop_openextattr_t ffs_openextattr;
static vop_setextattr_t ffs_setextattr;
static vop_vptofh_t ffs_vptofh;
+static vop_vput_pair_t ffs_vput_pair;
/* Global vfs data structures for ufs. */
struct vop_vector ffs_vnodeops1 = {
@@ -146,6 +147,7 @@ struct vop_vector ffs_vnodeops1 = {
.vop_reallocblks = ffs_reallocblks,
.vop_write = ffs_write,
.vop_vptofh = ffs_vptofh,
+ .vop_vput_pair = ffs_vput_pair,
};
VFS_VOP_VECTOR_REGISTER(ffs_vnodeops1);
@@ -182,6 +184,7 @@ struct vop_vector ffs_vnodeops2 = {
.vop_openextattr = ffs_openextattr,
.vop_setextattr = ffs_setextattr,
.vop_vptofh = ffs_vptofh,
+ .vop_vput_pair = ffs_vput_pair,
};
VFS_VOP_VECTOR_REGISTER(ffs_vnodeops2);
@@ -1917,3 +1920,55 @@ ffs_getpages_async(struct vop_getpages_async_args *ap)
return (error);
}
+
+static int
+ffs_vput_pair(struct vop_vput_pair_args *ap)
+{
+ struct vnode *dvp, *vp, **vpp;
+ struct inode *dp;
+ int error, vp_locked;
+
+ dvp = ap->a_dvp;
+ dp = VTOI(dvp);
+ vpp = ap->a_vpp;
+ vp = vpp != NULL ? *vpp : NULL;
+
+ if ((dp->i_flag & IN_NEEDSYNC) == 0) {
+ vput(dvp);
+ if (vp != NULL && ap->a_unlock_vp)
+ vput(vp);
+ return (0);
+ }
+
+ if (vp != NULL) {
+ if (ap->a_unlock_vp) {
+ vput(vp);
+ } else {
+ MPASS(vp->v_type != VNON);
+ vp_locked = VOP_ISLOCKED(vp);
+ VOP_UNLOCK(vp);
+ }
+ }
+
+ do {
+ error = ffs_syncvnode(dvp, MNT_WAIT, 0);
+ } while (error == ERELOOKUP);
+ vput(dvp);
+
+ if (vp == NULL || ap->a_unlock_vp)
+ return (0);
+
+ /*
+ * It is possible that vp is reclaimed at this point. Only
+ * routines that call us with a_unlock_vp == false can find
+ * that their vp has been reclaimed. There are three areas
+ * that are affected:
+ * 1) vn_open_cred() - later VOPs could fail, but
+ * dead_open() returns 0 to simulate successful open.
+ * 2) ffs_snapshot() - creation of snapshot fails with EBADF.
+ * 3) NFS server (several places) - code is prepared to detect
+ * and respond to dead vnodes by returning ESTALE.
+ */
+ VOP_LOCK(vp, vp_locked | LK_RETRY);
+ return (0);
+}