Merge branch 'for-chris-4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/fdmana...
authorChris Mason <clm@fb.com>
Tue, 13 Dec 2016 17:14:42 +0000 (09:14 -0800)
committerChris Mason <clm@fb.com>
Tue, 13 Dec 2016 17:14:42 +0000 (09:14 -0800)
Patches queued up by Filipe:

The most important change is still the fix for the extent tree
corruption that happens due to balance when qgroups are enabled (a
regression introduced in 4.7 by a fix for a regression from the last
qgroups rework). This has been hitting SLE and openSUSE users and QA
very badly, where transactions keep getting aborted when running
delayed references leaving the root filesystem in RO mode and nearly
unusable.  There are fixes here that allow us to run xfstests again
with the integrity checker enabled, which has been impossible since 4.8
(apparently I'm the only one running xfstests with the integrity
checker enabled, which is useful to validate dirtied leafs, like
checking if there are keys out of order, etc).  The rest are just some
trivial fixes, most of them tagged for stable, and two cleanups.

Signed-off-by: Chris Mason <clm@fb.com>
fs/btrfs/delayed-ref.h
fs/btrfs/disk-io.c
fs/btrfs/file.c
fs/btrfs/qgroup.c
fs/btrfs/relocation.c
fs/btrfs/tree-log.c

index dba97842b47a18d387eb5d8c01c9199b499cacdf..50947b5a915252590be5f2caf8d024bfd9f15794 100644 (file)
  * ref_head. Must clean this mess up later.
  */
 struct btrfs_delayed_ref_node {
-       /*
-        * ref_head use rb tree, stored in ref_root->href.
-        * indexed by bytenr
-        */
-       struct rb_node rb_node;
-
        /*data/tree ref use list, stored in ref_head->ref_list. */
        struct list_head list;
        /*
index 848d5e1c05852ae4f10c717441de1ca8067581a1..066d9b929a0c97da14427fd5cf482baea4345fcc 100644 (file)
@@ -560,7 +560,15 @@ static noinline int check_leaf(struct btrfs_root *root,
        u32 nritems = btrfs_header_nritems(leaf);
        int slot;
 
-       if (nritems == 0) {
+       /*
+        * Extent buffers from a relocation tree have a owner field that
+        * corresponds to the subvolume tree they are based on. So just from an
+        * extent buffer alone we can not find out what is the id of the
+        * corresponding subvolume tree, so we can not figure out if the extent
+        * buffer corresponds to the root of the relocation tree or not. So skip
+        * this check for relocation trees.
+        */
+       if (nritems == 0 && !btrfs_header_flag(leaf, BTRFS_HEADER_FLAG_RELOC)) {
                struct btrfs_root *check_root;
 
                key.objectid = btrfs_header_owner(leaf);
@@ -573,17 +581,24 @@ static noinline int check_leaf(struct btrfs_root *root,
                 * open_ctree() some roots has not yet been set up.
                 */
                if (!IS_ERR_OR_NULL(check_root)) {
+                       struct extent_buffer *eb;
+
+                       eb = btrfs_root_node(check_root);
                        /* if leaf is the root, then it's fine */
-                       if (leaf->start !=
-                           btrfs_root_bytenr(&check_root->root_item)) {
+                       if (leaf != eb) {
                                CORRUPT("non-root leaf's nritems is 0",
-                                       leaf, root, 0);
+                                       leaf, check_root, 0);
+                               free_extent_buffer(eb);
                                return -EIO;
                        }
+                       free_extent_buffer(eb);
                }
                return 0;
        }
 
+       if (nritems == 0)
+               return 0;
+
        /* Check the 0 item */
        if (btrfs_item_offset_nr(leaf, 0) + btrfs_item_size_nr(leaf, 0) !=
            BTRFS_LEAF_DATA_SIZE(fs_info)) {
index 140271b1ea2edb10a4b15323ce7a90ebd7216cd6..448f57d108d1d93fc35a119b37c87126a399dd5a 100644 (file)
@@ -2372,7 +2372,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
        u64 tail_len;
        u64 orig_start = offset;
        u64 cur_offset;
-       u64 min_size = btrfs_calc_trunc_metadata_size(fs_info, 1);
+       u64 min_size = btrfs_calc_trans_metadata_size(fs_info, 1);
        u64 drop_end;
        int ret = 0;
        int err = 0;
@@ -2519,7 +2519,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
                ret = -ENOMEM;
                goto out_free;
        }
-       rsv->size = btrfs_calc_trunc_metadata_size(fs_info, 1);
+       rsv->size = btrfs_calc_trans_metadata_size(fs_info, 1);
        rsv->failfast = 1;
 
        /*
index 3e473e9a4844006d2d235dfb9e5052c41b753a0a..662821f1252c063b3659266833b8fb08fcc04365 100644 (file)
@@ -2555,10 +2555,6 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work)
        int err = -ENOMEM;
        int ret = 0;
 
-       mutex_lock(&fs_info->qgroup_rescan_lock);
-       fs_info->qgroup_rescan_running = true;
-       mutex_unlock(&fs_info->qgroup_rescan_lock);
-
        path = btrfs_alloc_path();
        if (!path)
                goto out;
@@ -2669,6 +2665,7 @@ qgroup_rescan_init(struct btrfs_fs_info *fs_info, u64 progress_objectid,
                sizeof(fs_info->qgroup_rescan_progress));
        fs_info->qgroup_rescan_progress.objectid = progress_objectid;
        init_completion(&fs_info->qgroup_rescan_completion);
+       fs_info->qgroup_rescan_running = true;
 
        spin_unlock(&fs_info->qgroup_lock);
        mutex_unlock(&fs_info->qgroup_rescan_lock);
index 5d222c8d221383e80d563a726e00e21a770514f1..379711048fb0407fa05c79f7bf12e92863a71da3 100644 (file)
@@ -1388,7 +1388,6 @@ static struct btrfs_root *create_reloc_root(struct btrfs_trans_handle *trans,
        struct extent_buffer *eb;
        struct btrfs_root_item *root_item;
        struct btrfs_key root_key;
-       u64 last_snap = 0;
        int ret;
 
        root_item = kmalloc(sizeof(*root_item), GFP_NOFS);
@@ -1399,14 +1398,22 @@ static struct btrfs_root *create_reloc_root(struct btrfs_trans_handle *trans,
        root_key.offset = objectid;
 
        if (root->root_key.objectid == objectid) {
+               u64 commit_root_gen;
+
                /* called by btrfs_init_reloc_root */
                ret = btrfs_copy_root(trans, root, root->commit_root, &eb,
                                      BTRFS_TREE_RELOC_OBJECTID);
                BUG_ON(ret);
-
-               last_snap = btrfs_root_last_snapshot(&root->root_item);
-               btrfs_set_root_last_snapshot(&root->root_item,
-                                            trans->transid - 1);
+               /*
+                * Set the last_snapshot field to the generation of the commit
+                * root - like this ctree.c:btrfs_block_can_be_shared() behaves
+                * correctly (returns true) when the relocation root is created
+                * either inside the critical section of a transaction commit
+                * (through transaction.c:qgroup_account_snapshot()) and when
+                * it's created before the transaction commit is started.
+                */
+               commit_root_gen = btrfs_header_generation(root->commit_root);
+               btrfs_set_root_last_snapshot(&root->root_item, commit_root_gen);
        } else {
                /*
                 * called by btrfs_reloc_post_snapshot_hook.
@@ -1430,12 +1437,6 @@ static struct btrfs_root *create_reloc_root(struct btrfs_trans_handle *trans,
                memset(&root_item->drop_progress, 0,
                       sizeof(struct btrfs_disk_key));
                root_item->drop_level = 0;
-               /*
-                * abuse rtransid, it is safe because it is impossible to
-                * receive data into a relocation tree.
-                */
-               btrfs_set_root_rtransid(root_item, last_snap);
-               btrfs_set_root_otransid(root_item, trans->transid);
        }
 
        btrfs_tree_unlock(eb);
@@ -2406,9 +2407,6 @@ void merge_reloc_roots(struct reloc_control *rc)
        struct btrfs_fs_info *fs_info = rc->extent_root->fs_info;
        struct btrfs_root *root;
        struct btrfs_root *reloc_root;
-       u64 last_snap;
-       u64 otransid;
-       u64 objectid;
        LIST_HEAD(reloc_roots);
        int found = 0;
        int ret = 0;
@@ -2447,14 +2445,6 @@ again:
                        list_del_init(&reloc_root->root_list);
                }
 
-               /*
-                * we keep the old last snapshot transid in rtranid when we
-                * created the relocation tree.
-                */
-               last_snap = btrfs_root_rtransid(&reloc_root->root_item);
-               otransid = btrfs_root_otransid(&reloc_root->root_item);
-               objectid = reloc_root->root_key.offset;
-
                ret = btrfs_drop_snapshot(reloc_root, rc->block_rsv, 0, 1);
                if (ret < 0) {
                        if (list_empty(&reloc_root->root_list))
index f7324189413c842b269c856681e017e62b04cc1b..f10bf5213ed8a48b95a8cf3cf51dc3c2c81b8463 100644 (file)
@@ -1948,12 +1948,11 @@ static noinline int find_dir_range(struct btrfs_root *root,
 next:
        /* check the next slot in the tree to see if it is a valid item */
        nritems = btrfs_header_nritems(path->nodes[0]);
+       path->slots[0]++;
        if (path->slots[0] >= nritems) {
                ret = btrfs_next_leaf(root, path);
                if (ret)
                        goto out;
-       } else {
-               path->slots[0]++;
        }
 
        btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
@@ -5224,6 +5223,7 @@ process_leaf:
                        if (di_key.type == BTRFS_ROOT_ITEM_KEY)
                                continue;
 
+                       btrfs_release_path(path);
                        di_inode = btrfs_iget(fs_info->sb, &di_key, root, NULL);
                        if (IS_ERR(di_inode)) {
                                ret = PTR_ERR(di_inode);
@@ -5232,13 +5232,12 @@ process_leaf:
 
                        if (btrfs_inode_in_log(di_inode, trans->transid)) {
                                iput(di_inode);
-                               continue;
+                               break;
                        }
 
                        ctx->log_new_dentries = false;
                        if (type == BTRFS_FT_DIR || type == BTRFS_FT_SYMLINK)
                                log_mode = LOG_INODE_ALL;
-                       btrfs_release_path(path);
                        ret = btrfs_log_inode(trans, root, di_inode,
                                              log_mode, 0, LLONG_MAX, ctx);
                        if (!ret &&