From: Chunwei Chen Date: Fri, 18 Dec 2015 19:39:41 +0000 (-0800) Subject: Fix empty xattr dir causing lockup X-Git-Tag: zfs-0.7.0-rc1~333 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=29572ccdeff7ddb1211b0f26dea69e0a2f262faf;p=zfs 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 Signed-off-by: Brian Behlendorf Closes #4114 Closes #4052 Closes #4006 Closes #3018 Closes #2861 --- 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)