aboutsummaryrefslogtreecommitdiffstats
path: root/module
diff options
context:
space:
mode:
authorChunwei Chen <[email protected]>2015-12-18 11:39:41 -0800
committerBrian Behlendorf <[email protected]>2015-12-28 09:41:30 -0800
commit29572ccdeff7ddb1211b0f26dea69e0a2f262faf (patch)
tree42c5bf7b849d47a8029e94ed49484eecd73af003 /module
parent2ebc7b72b3989ac53c1753f79eaf71d95419c103 (diff)
Fix empty xattr dir causing lockup
During zfs_rmnode on a xattr dir, if the system crash just after dmu_free_long_range, we would get empty xattr dir in delete queue. This would cause blkid=0 be passed into zap_get_leaf_byblk when doing zfs_purgedir during mount, and would try to do rw_enter on a wrong structure and cause system lockup. We fix this by returning ENOENT when blkid is zero in zap_get_leaf_byblk. Signed-off-by: Chunwei Chen <[email protected]> Signed-off-by: Brian Behlendorf <[email protected]> Closes #4114 Closes #4052 Closes #4006 Closes #3018 Closes #2861
Diffstat (limited to 'module')
-rw-r--r--module/zfs/zap.c10
1 files changed, 10 insertions, 0 deletions
diff --git a/module/zfs/zap.c b/module/zfs/zap.c
index 4640fb98c..cf0b92c7d 100644
--- a/module/zfs/zap.c
+++ b/module/zfs/zap.c
@@ -504,6 +504,16 @@ zap_get_leaf_byblk(zap_t *zap, uint64_t blkid, dmu_tx_t *tx, krw_t lt,
ASSERT(RW_LOCK_HELD(&zap->zap_rwlock));
+ /*
+ * If system crashed just after dmu_free_long_range in zfs_rmnode, we
+ * would be left with an empty xattr dir in delete queue. blkid=0
+ * would be passed in when doing zfs_purgedir. If that's the case we
+ * should just return immediately. The underlying objects should
+ * already be freed, so this should be perfectly fine.
+ */
+ if (blkid == 0)
+ return (ENOENT);
+
err = dmu_buf_hold(zap->zap_objset, zap->zap_object,
blkid << bs, NULL, &db, DMU_READ_NO_PREFETCH);
if (err)