btrfs-progs: check, fix csum check in the presence of non-inlined refs
authorFilipe David Borba Manana <fdmanana@gmail.com>
Wed, 7 May 2014 12:09:14 +0000 (13:09 +0100)
committerDavid Sterba <dsterba@suse.cz>
Fri, 10 Oct 2014 08:38:29 +0000 (10:38 +0200)
When we have non-inlined extent references, we were failing to find the
corresponding extent item for an existing csum item in the csum tree.

Reproducer:

   mkfs.btrfs -f /dev/sdd
   mount /dev/sdd /mnt

   xfs_io -f -c "falloc 780366 135302" /mnt/foo
   xfs_io -c "falloc 327680 151552" /mnt/foo
   xfs_io -c "pwrite -S 0xff -b 131072 0 131072" /mnt/foo
   sync

   for i in `seq 1 40`; do btrfs subvolume snapshot /mnt /mnt/snap$i ; done
   umount /mnt

   btrfs check /dev/sdd

The check command exited with status 1 and the following output:

   Checking filesystem on /dev/sdd
   UUID: 2416ab5f-9d71-457e-bb13-a27d4f6b399a
   checking extents
   checking free space cache
   checking fs roots
   checking csums
   There are no extents for csum range 12980224-12984320
   Csum exists for 12980224-12984320 but there is no extent record
   found 1388544 bytes used err is 1
   total csum bytes: 132
   total tree bytes: 704512
   total fs tree bytes: 573440
   total extent tree bytes: 16384
   btree space waste bytes: 564479
   file data blocks allocated: 19341312
    referenced 14606336
   Btrfs v3.14.1-94-g80597e7

After this change it no longer erroneously reports a missing extent for the
csum item and exits with a status of 0.

Also added missing btrfs_prev_leaf() return value checks, as we were ignoring
errors and non-existence of left siblings completely.

Signed-off-by: Filipe David Borba Manana <fdmanana@gmail.com>
Signed-off-by: David Sterba <dsterba@suse.cz>
cmds-check.c

index 64934a9..86ba1dd 100644 (file)
@@ -3792,8 +3792,7 @@ static int check_extent_exists(struct btrfs_root *root, u64 bytenr,
 
        key.objectid = bytenr;
        key.type = BTRFS_EXTENT_ITEM_KEY;
-       key.offset = 0;
-
+       key.offset = (u64)-1;
 
 again:
        ret = btrfs_search_slot(NULL, root->fs_info->extent_root, &key, path,
@@ -3803,10 +3802,17 @@ again:
                btrfs_free_path(path);
                return ret;
        } else if (ret) {
-               if (path->slots[0])
+               if (path->slots[0] > 0) {
                        path->slots[0]--;
-               else
-                       btrfs_prev_leaf(root, path);
+               } else {
+                       ret = btrfs_prev_leaf(root, path);
+                       if (ret < 0) {
+                               goto out;
+                       } else if (ret > 0) {
+                               ret = 0;
+                               goto out;
+                       }
+               }
        }
 
        btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
@@ -3816,13 +3822,22 @@ again:
         * bytenr, so walk back one more just in case.  Dear future traveler,
         * first congrats on mastering time travel.  Now if it's not too much
         * trouble could you go back to 2006 and tell Chris to make the
-        * BLOCK_GROUP_ITEM_KEY lower than the EXTENT_ITEM_KEY please?
+        * BLOCK_GROUP_ITEM_KEY (and BTRFS_*_REF_KEY) lower than the
+        * EXTENT_ITEM_KEY please?
         */
-       if (key.type == BTRFS_BLOCK_GROUP_ITEM_KEY) {
-               if (path->slots[0])
+       while (key.type > BTRFS_EXTENT_ITEM_KEY) {
+               if (path->slots[0] > 0) {
                        path->slots[0]--;
-               else
-                       btrfs_prev_leaf(root, path);
+               } else {
+                       ret = btrfs_prev_leaf(root, path);
+                       if (ret < 0) {
+                               goto out;
+                       } else if (ret > 0) {
+                               ret = 0;
+                               goto out;
+                       }
+               }
+               btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
        }
 
        while (num_bytes) {
@@ -3894,7 +3909,8 @@ again:
        }
        ret = 0;
 
-       if (num_bytes) {
+out:
+       if (num_bytes && !ret) {
                fprintf(stderr, "There are no extents for csum range "
                        "%Lu-%Lu\n", bytenr, bytenr+num_bytes);
                ret = 1;