From cf118ae8dc149c5c9fd9b70e89790c38824b85de Mon Sep 17 00:00:00 2001 From: Matthew Macy Date: Fri, 28 Feb 2020 14:53:18 -0800 Subject: Don't call zrele on passed zp in zfs_xattr_owner_unlinked on FreeBSD FreeBSD has a somewhat more cumbersome locking and refcounting protocol for the platform counterpart to znode. We need to not call zrele on the passed zp, but do need to do so on any intermediate zp. Reviewed-by: Brian Behlendorf Signed-off-by: Matt Macy Closes #10075 --- module/zfs/zfs_log.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/module/zfs/zfs_log.c b/module/zfs/zfs_log.c index cfb2f3be2..6951ef90b 100644 --- a/module/zfs/zfs_log.c +++ b/module/zfs/zfs_log.c @@ -231,14 +231,33 @@ zfs_xattr_owner_unlinked(znode_t *zp) { int unlinked = 0; znode_t *dzp; +#ifdef __FreeBSD__ + znode_t *tzp = zp; /* * zrele drops the vnode lock which violates the VOP locking contract * on FreeBSD. See comment at the top of zfs_replay.c for more detail. */ -#ifndef __FreeBSD__ + /* + * if zp is XATTR node, keep walking up via z_xattr_parent until we + * get the owner + */ + while (tzp->z_pflags & ZFS_XATTR) { + ASSERT3U(zp->z_xattr_parent, !=, 0); + if (zfs_zget(ZTOZSB(tzp), tzp->z_xattr_parent, &dzp) != 0) { + unlinked = 1; + break; + } + + if (tzp != zp) + zrele(tzp); + tzp = dzp; + unlinked = tzp->z_unlinked; + } + if (tzp != zp) + zrele(tzp); +#else zhold(zp); -#endif /* * if zp is XATTR node, keep walking up via z_xattr_parent until we * get the owner @@ -249,11 +268,11 @@ zfs_xattr_owner_unlinked(znode_t *zp) unlinked = 1; break; } + zrele(zp); zp = dzp; unlinked = zp->z_unlinked; } -#ifndef __FreeBSD__ zrele(zp); #endif return (unlinked); -- cgit v1.2.3