summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMateusz Guzik <mjguzik@gmail.com>2021-04-26 21:44:40 +0200
committerTony Hutter <hutter2@llnl.gov>2021-06-23 13:22:14 -0700
commita78a93e67e883db4d984bf673d1155a6906999fc (patch)
tree37f4a2fe4ad89322ae7b91fb9ec83ce910aff3f6
parent9a68ceba10223476e144cbf65e05cd1f456ba915 (diff)
FreeBSD: damage control racing .. lookups in face of mkdir/rmdir
External-issue: https://reviews.freebsd.org/D29769 Reviewed-by: Alexander Motin <mav@FreeBSD.org> Reviewed-by: Ryan Moeller <ryan@iXsystems.com> Signed-off-by: Mateusz Guzik <mjguzik@gmail.com> Closes #11926
-rw-r--r--module/os/freebsd/zfs/zfs_vnops_os.c27
1 files changed, 27 insertions, 0 deletions
diff --git a/module/os/freebsd/zfs/zfs_vnops_os.c b/module/os/freebsd/zfs/zfs_vnops_os.c
index eb72f294d..be8ac1fc6 100644
--- a/module/os/freebsd/zfs/zfs_vnops_os.c
+++ b/module/os/freebsd/zfs/zfs_vnops_os.c
@@ -1013,6 +1013,9 @@ zfs_lookup(vnode_t *dvp, const char *nm, vnode_t **vpp,
znode_t *zdp = VTOZ(dvp);
znode_t *zp;
zfsvfs_t *zfsvfs = zdp->z_zfsvfs;
+#if __FreeBSD_version > 1300124
+ seqc_t dvp_seqc;
+#endif
int error = 0;
/*
@@ -1038,6 +1041,10 @@ zfs_lookup(vnode_t *dvp, const char *nm, vnode_t **vpp,
ZFS_ENTER(zfsvfs);
ZFS_VERIFY_ZP(zdp);
+#if __FreeBSD_version > 1300124
+ dvp_seqc = vn_seqc_read_notmodify(dvp);
+#endif
+
*vpp = NULL;
if (flags & LOOKUP_XATTR) {
@@ -1207,6 +1214,26 @@ zfs_lookup(vnode_t *dvp, const char *nm, vnode_t **vpp,
}
}
+#if __FreeBSD_version > 1300124
+ if ((cnp->cn_flags & ISDOTDOT) != 0) {
+ /*
+ * FIXME: zfs_lookup_lock relocks vnodes and does nothing to
+ * handle races. In particular different callers may end up
+ * with different vnodes and will try to add conflicting
+ * entries to the namecache.
+ *
+ * While finding different result may be acceptable in face
+ * of concurrent modification, adding conflicting entries
+ * trips over an assert in the namecache.
+ *
+ * Ultimately let an entry through once everything settles.
+ */
+ if (!vn_seqc_consistent(dvp, dvp_seqc)) {
+ cnp->cn_flags &= ~MAKEENTRY;
+ }
+ }
+#endif
+
/* Insert name into cache (as non-existent) if appropriate. */
if (zfsvfs->z_use_namecache && !zfsvfs->z_replay &&
error == ENOENT && (cnp->cn_flags & MAKEENTRY) != 0)