From d621aa5431ba4a281d7a370db5dcc432323ea835 Mon Sep 17 00:00:00 2001 From: Chunwei Chen Date: Mon, 21 Dec 2015 11:57:18 -0800 Subject: [PATCH] Make xattr dir truncate and remove in one tx We need truncate and remove be in the same tx when doing zfs_rmnode on xattr dir. Otherwise, if we truncate and crash, we'll end up with inconsistent zap object on the delete queue. We do this by skipping dmu_free_long_range and let zfs_znode_delete to do the work. Signed-off-by: Chunwei Chen Signed-off-by: Brian Behlendorf Issue #4114 Issue #4052 Issue #4006 Issue #3018 Issue #2861 --- module/zfs/zfs_dir.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/module/zfs/zfs_dir.c b/module/zfs/zfs_dir.c index 712cb46564..c1eadd0dc2 100644 --- a/module/zfs/zfs_dir.c +++ b/module/zfs/zfs_dir.c @@ -632,15 +632,22 @@ zfs_rmnode(znode_t *zp) } /* - * Free up all the data in the file. + * Free up all the data in the file. We don't do this for directories + * because we need truncate and remove to be in the same tx, like in + * zfs_znode_delete(). Otherwise, if we crash here we'll end up with + * an inconsistent truncated zap object in the delete queue. Note a + * truncated file is harmless since it only contains user data. */ - error = dmu_free_long_range(os, zp->z_id, 0, DMU_OBJECT_END); - if (error) { - /* - * Not enough space. Leave the file in the unlinked set. - */ - zfs_znode_dmu_fini(zp); - return; + if (S_ISREG(ZTOI(zp)->i_mode)) { + error = dmu_free_long_range(os, zp->z_id, 0, DMU_OBJECT_END); + if (error) { + /* + * Not enough space. Leave the file in the unlinked + * set. + */ + zfs_znode_dmu_fini(zp); + return; + } } /*