Btrfs: allow splitting of hole em's when dropping extent cache
authorJosef Bacik <jbacik@fusionio.com>
Thu, 11 Jul 2013 14:34:59 +0000 (10:34 -0400)
committerChris Mason <chris.mason@fusionio.com>
Fri, 9 Aug 2013 23:30:09 +0000 (19:30 -0400)
I noticed while running multi-threaded fsync tests that sometimes fsck would
complain about an improper gap.  This happens because we fail to add a hole
extent to the file, which was happening when we'd split a hole EM because
btrfs_drop_extent_cache was just discarding the whole em instead of splitting
it.  So this patch fixes this by allowing us to split a hole em properly, which
means that added holes actually get logged properly and we no longer see this
fsck error.  Thankfully we're tolerant of these sort of problems so a user would
not see any adverse effects of this bug, other than fsck complaining.  Thanks,

Signed-off-by: Josef Bacik <jbacik@fusionio.com>
Signed-off-by: Chris Mason <chris.mason@fusionio.com>
fs/btrfs/file.c

index a005fe2c072ad0751254adba0fa4e04db10cc996..8e686a427ce2e8e5e824419321f1f8f2dfe19acb 100644 (file)
@@ -596,20 +596,29 @@ void btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
                if (no_splits)
                        goto next;
 
-               if (em->block_start < EXTENT_MAP_LAST_BYTE &&
-                   em->start < start) {
+               if (em->start < start) {
                        split->start = em->start;
                        split->len = start - em->start;
-                       split->orig_start = em->orig_start;
-                       split->block_start = em->block_start;
 
-                       if (compressed)
-                               split->block_len = em->block_len;
-                       else
-                               split->block_len = split->len;
-                       split->ram_bytes = em->ram_bytes;
-                       split->orig_block_len = max(split->block_len,
-                                                   em->orig_block_len);
+                       if (em->block_start < EXTENT_MAP_LAST_BYTE) {
+                               split->orig_start = em->orig_start;
+                               split->block_start = em->block_start;
+
+                               if (compressed)
+                                       split->block_len = em->block_len;
+                               else
+                                       split->block_len = split->len;
+                               split->orig_block_len = max(split->block_len,
+                                               em->orig_block_len);
+                               split->ram_bytes = em->ram_bytes;
+                       } else {
+                               split->orig_start = split->start;
+                               split->block_len = 0;
+                               split->block_start = em->block_start;
+                               split->orig_block_len = 0;
+                               split->ram_bytes = split->len;
+                       }
+
                        split->generation = gen;
                        split->bdev = em->bdev;
                        split->flags = flags;
@@ -620,8 +629,7 @@ void btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
                        split = split2;
                        split2 = NULL;
                }
-               if (em->block_start < EXTENT_MAP_LAST_BYTE &&
-                   testend && em->start + em->len > start + len) {
+               if (testend && em->start + em->len > start + len) {
                        u64 diff = start + len - em->start;
 
                        split->start = start + len;
@@ -630,18 +638,28 @@ void btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
                        split->flags = flags;
                        split->compress_type = em->compress_type;
                        split->generation = gen;
-                       split->orig_block_len = max(em->block_len,
+
+                       if (em->block_start < EXTENT_MAP_LAST_BYTE) {
+                               split->orig_block_len = max(em->block_len,
                                                    em->orig_block_len);
-                       split->ram_bytes = em->ram_bytes;
 
-                       if (compressed) {
-                               split->block_len = em->block_len;
-                               split->block_start = em->block_start;
-                               split->orig_start = em->orig_start;
+                               split->ram_bytes = em->ram_bytes;
+                               if (compressed) {
+                                       split->block_len = em->block_len;
+                                       split->block_start = em->block_start;
+                                       split->orig_start = em->orig_start;
+                               } else {
+                                       split->block_len = split->len;
+                                       split->block_start = em->block_start
+                                               + diff;
+                                       split->orig_start = em->orig_start;
+                               }
                        } else {
-                               split->block_len = split->len;
-                               split->block_start = em->block_start + diff;
-                               split->orig_start = em->orig_start;
+                               split->ram_bytes = split->len;
+                               split->orig_start = split->start;
+                               split->block_len = 0;
+                               split->block_start = em->block_start;
+                               split->orig_block_len = 0;
                        }
 
                        ret = add_extent_mapping(em_tree, split, modified);