diff options
author | Mateusz Guzik <mjguzik@gmail.com> | 2021-04-26 21:44:40 +0200 |
---|---|---|
committer | Tony Hutter <hutter2@llnl.gov> | 2021-06-23 13:22:14 -0700 |
commit | a78a93e67e883db4d984bf673d1155a6906999fc (patch) | |
tree | 37f4a2fe4ad89322ae7b91fb9ec83ce910aff3f6 | |
parent | 9a68ceba10223476e144cbf65e05cd1f456ba915 (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.c | 27 |
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) |