]> granicus.if.org Git - zfs/commitdiff
Make xattr dir truncate and remove in one tx
authorChunwei Chen <tuxoko@gmail.com>
Mon, 21 Dec 2015 19:57:18 +0000 (11:57 -0800)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Mon, 28 Dec 2015 17:48:26 +0000 (09:48 -0800)
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 <david.chen@osnexus.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Issue #4114
Issue #4052
Issue #4006
Issue #3018
Issue #2861

module/zfs/zfs_dir.c

index 712cb4656430292eedbc4653502e20e6e218b24c..c1eadd0dc2508c382a46661ebc4ab9dac5cd941a 100644 (file)
@@ -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;
+               }
        }
 
        /*