diff options
author | Brian Behlendorf <[email protected]> | 2015-12-16 14:17:49 -0800 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2015-12-18 13:17:44 -0800 |
commit | a8ad3bf02cace90c45bc25df1bff1089d19e79f1 (patch) | |
tree | e258b8c194dc5e1c1ecd4c926c04b258e5fea148 /module | |
parent | 2727b9d3b63a938c1797d31378e6a5a1dcd43573 (diff) |
Fix z_xattr_lock/z_teardown_lock lock inversion
There exists a lock inversion between the z_xattr_lock and the
z_teardown_lock. Detect this case and return EBUSY so zfs_resume_fs()
will mark the inode stale and it can be safely revalidated on next
access.
* process-1
zpl_xattr_get -> Takes zp->z_xattr_lock
__zpl_xattr_get
zfs_lookup -> Takes zsb->z_teardown_lock in ZFS_ENTER macro
* process-2
zfs_ioc_recv -> Takes zsb->z_teardown_lock in zfs_suspend_fs()
zfs_resume_fs
zfs_rezget -> Takes zp->z_xattr_lock
Signed-off-by: Brian Behlendorf <[email protected]>
Signed-off-by: Chunwei Chen <[email protected]>
Closes #3969
Diffstat (limited to 'module')
-rw-r--r-- | module/zfs/zfs_znode.c | 11 |
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; |