]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/btrfs/ctree.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi...
[karo-tx-linux.git] / fs / btrfs / ctree.c
index bbbe4f1c5086cd82e1fffd0e72f3acc2528928b2..aeab453b8e24482cd9f956a87882ea23549921f2 100644 (file)
@@ -1506,6 +1506,10 @@ static inline int should_cow_block(struct btrfs_trans_handle *trans,
                                   struct btrfs_root *root,
                                   struct extent_buffer *buf)
 {
+#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
+       if (unlikely(test_bit(BTRFS_ROOT_DUMMY_ROOT, &root->state)))
+               return 0;
+#endif
        /* ensure we can see the force_cow */
        smp_rmb();
 
@@ -5093,7 +5097,17 @@ int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path)
                return ret;
        btrfs_item_key(path->nodes[0], &found_key, 0);
        ret = comp_keys(&found_key, &key);
-       if (ret < 0)
+       /*
+        * We might have had an item with the previous key in the tree right
+        * before we released our path. And after we released our path, that
+        * item might have been pushed to the first slot (0) of the leaf we
+        * were holding due to a tree balance. Alternatively, an item with the
+        * previous key can exist as the only element of a leaf (big fat item).
+        * Therefore account for these 2 cases, so that our callers (like
+        * btrfs_previous_item) don't miss an existing item with a key matching
+        * the previous key we computed above.
+        */
+       if (ret <= 0)
                return 0;
        return 1;
 }
@@ -5704,6 +5718,24 @@ again:
                ret = 0;
                goto done;
        }
+       /*
+        * So the above check misses one case:
+        * - after releasing the path above, someone has removed the item that
+        *   used to be at the very end of the block, and balance between leafs
+        *   gets another one with bigger key.offset to replace it.
+        *
+        * This one should be returned as well, or we can get leaf corruption
+        * later(esp. in __btrfs_drop_extents()).
+        *
+        * And a bit more explanation about this check,
+        * with ret > 0, the key isn't found, the path points to the slot
+        * where it should be inserted, so the path->slots[0] item must be the
+        * bigger one.
+        */
+       if (nritems > 0 && ret > 0 && path->slots[0] == nritems - 1) {
+               ret = 0;
+               goto done;
+       }
 
        while (level < BTRFS_MAX_LEVEL) {
                if (!path->nodes[level]) {