summaryrefslogtreecommitdiffstats
path: root/module/zfs/zfs_znode.c
diff options
context:
space:
mode:
Diffstat (limited to 'module/zfs/zfs_znode.c')
-rw-r--r--module/zfs/zfs_znode.c11
1 files changed, 10 insertions, 1 deletions
diff --git a/module/zfs/zfs_znode.c b/module/zfs/zfs_znode.c
index bf360f1bc..6fda78e5f 100644
--- a/module/zfs/zfs_znode.c
+++ b/module/zfs/zfs_znode.c
@@ -1012,7 +1012,16 @@ zfs_rezget(znode_t *zp)
}
mutex_exit(&zp->z_acl_lock);
- rw_enter(&zp->z_xattr_lock, RW_WRITER);
+ /*
+ * Lock inversion with zpl_xattr_get->__zpl_xattr_get->zfs_lookup
+ * between z_xattr_lock and z_teardown_lock. Detect this case and
+ * return EBUSY so zfs_resume_fs() will mark the inode stale and it
+ * will safely be revalidated on next access.
+ */
+ err = rw_tryenter(&zp->z_xattr_lock, RW_WRITER);
+ if (!err)
+ return (SET_ERROR(EBUSY));
+
if (zp->z_xattr_cached) {
nvlist_free(zp->z_xattr_cached);
zp->z_xattr_cached = NULL;