aboutsummaryrefslogtreecommitdiffstats
path: root/module/zfs/zfs_log.c
diff options
context:
space:
mode:
authorMatthew Macy <[email protected]>2020-02-28 14:53:18 -0800
committerGitHub <[email protected]>2020-02-28 14:53:18 -0800
commitcf118ae8dc149c5c9fd9b70e89790c38824b85de (patch)
tree9e3b2b13d18d45f827a7de17e28619a02ee6f0db /module/zfs/zfs_log.c
parentae9f92f6f31c81f4d1aa4602f812f912b4392e7c (diff)
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 <[email protected]> Signed-off-by: Matt Macy <[email protected]> Closes #10075
Diffstat (limited to 'module/zfs/zfs_log.c')
-rw-r--r--module/zfs/zfs_log.c25
1 files 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);