Commit 5f52a2c5 authored by Chris Mason's avatar Chris Mason

Merge branch 'for-chris-4.10' of...

Merge branch 'for-chris-4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/fdmanana/linux into for-linus-4.10

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: default avatarChris Mason <clm@fb.com>
parents 7c4c71ac 2a7bf53f
...@@ -34,12 +34,6 @@ ...@@ -34,12 +34,6 @@
* ref_head. Must clean this mess up later. * ref_head. Must clean this mess up later.
*/ */
struct btrfs_delayed_ref_node { 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. */ /*data/tree ref use list, stored in ref_head->ref_list. */
struct list_head list; struct list_head list;
/* /*
......
...@@ -560,7 +560,15 @@ static noinline int check_leaf(struct btrfs_root *root, ...@@ -560,7 +560,15 @@ static noinline int check_leaf(struct btrfs_root *root,
u32 nritems = btrfs_header_nritems(leaf); u32 nritems = btrfs_header_nritems(leaf);
int slot; 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; struct btrfs_root *check_root;
key.objectid = btrfs_header_owner(leaf); key.objectid = btrfs_header_owner(leaf);
...@@ -573,17 +581,24 @@ static noinline int check_leaf(struct btrfs_root *root, ...@@ -573,17 +581,24 @@ static noinline int check_leaf(struct btrfs_root *root,
* open_ctree() some roots has not yet been set up. * open_ctree() some roots has not yet been set up.
*/ */
if (!IS_ERR_OR_NULL(check_root)) { 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 is the root, then it's fine */
if (leaf->start != if (leaf != eb) {
btrfs_root_bytenr(&check_root->root_item)) {
CORRUPT("non-root leaf's nritems is 0", CORRUPT("non-root leaf's nritems is 0",
leaf, root, 0); leaf, check_root, 0);
free_extent_buffer(eb);
return -EIO; return -EIO;
} }
free_extent_buffer(eb);
} }
return 0; return 0;
} }
if (nritems == 0)
return 0;
/* Check the 0 item */ /* Check the 0 item */
if (btrfs_item_offset_nr(leaf, 0) + btrfs_item_size_nr(leaf, 0) != if (btrfs_item_offset_nr(leaf, 0) + btrfs_item_size_nr(leaf, 0) !=
BTRFS_LEAF_DATA_SIZE(fs_info)) { BTRFS_LEAF_DATA_SIZE(fs_info)) {
......
...@@ -2372,7 +2372,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) ...@@ -2372,7 +2372,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
u64 tail_len; u64 tail_len;
u64 orig_start = offset; u64 orig_start = offset;
u64 cur_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; u64 drop_end;
int ret = 0; int ret = 0;
int err = 0; int err = 0;
...@@ -2519,7 +2519,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) ...@@ -2519,7 +2519,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
ret = -ENOMEM; ret = -ENOMEM;
goto out_free; 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; rsv->failfast = 1;
/* /*
......
...@@ -2555,10 +2555,6 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work) ...@@ -2555,10 +2555,6 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work)
int err = -ENOMEM; int err = -ENOMEM;
int ret = 0; 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(); path = btrfs_alloc_path();
if (!path) if (!path)
goto out; goto out;
...@@ -2669,6 +2665,7 @@ qgroup_rescan_init(struct btrfs_fs_info *fs_info, u64 progress_objectid, ...@@ -2669,6 +2665,7 @@ qgroup_rescan_init(struct btrfs_fs_info *fs_info, u64 progress_objectid,
sizeof(fs_info->qgroup_rescan_progress)); sizeof(fs_info->qgroup_rescan_progress));
fs_info->qgroup_rescan_progress.objectid = progress_objectid; fs_info->qgroup_rescan_progress.objectid = progress_objectid;
init_completion(&fs_info->qgroup_rescan_completion); init_completion(&fs_info->qgroup_rescan_completion);
fs_info->qgroup_rescan_running = true;
spin_unlock(&fs_info->qgroup_lock); spin_unlock(&fs_info->qgroup_lock);
mutex_unlock(&fs_info->qgroup_rescan_lock); mutex_unlock(&fs_info->qgroup_rescan_lock);
......
...@@ -1388,7 +1388,6 @@ static struct btrfs_root *create_reloc_root(struct btrfs_trans_handle *trans, ...@@ -1388,7 +1388,6 @@ static struct btrfs_root *create_reloc_root(struct btrfs_trans_handle *trans,
struct extent_buffer *eb; struct extent_buffer *eb;
struct btrfs_root_item *root_item; struct btrfs_root_item *root_item;
struct btrfs_key root_key; struct btrfs_key root_key;
u64 last_snap = 0;
int ret; int ret;
root_item = kmalloc(sizeof(*root_item), GFP_NOFS); root_item = kmalloc(sizeof(*root_item), GFP_NOFS);
...@@ -1399,14 +1398,22 @@ static struct btrfs_root *create_reloc_root(struct btrfs_trans_handle *trans, ...@@ -1399,14 +1398,22 @@ static struct btrfs_root *create_reloc_root(struct btrfs_trans_handle *trans,
root_key.offset = objectid; root_key.offset = objectid;
if (root->root_key.objectid == objectid) { if (root->root_key.objectid == objectid) {
u64 commit_root_gen;
/* called by btrfs_init_reloc_root */ /* called by btrfs_init_reloc_root */
ret = btrfs_copy_root(trans, root, root->commit_root, &eb, ret = btrfs_copy_root(trans, root, root->commit_root, &eb,
BTRFS_TREE_RELOC_OBJECTID); BTRFS_TREE_RELOC_OBJECTID);
BUG_ON(ret); BUG_ON(ret);
/*
last_snap = btrfs_root_last_snapshot(&root->root_item); * Set the last_snapshot field to the generation of the commit
btrfs_set_root_last_snapshot(&root->root_item, * root - like this ctree.c:btrfs_block_can_be_shared() behaves
trans->transid - 1); * 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 { } else {
/* /*
* called by btrfs_reloc_post_snapshot_hook. * called by btrfs_reloc_post_snapshot_hook.
...@@ -1430,12 +1437,6 @@ static struct btrfs_root *create_reloc_root(struct btrfs_trans_handle *trans, ...@@ -1430,12 +1437,6 @@ static struct btrfs_root *create_reloc_root(struct btrfs_trans_handle *trans,
memset(&root_item->drop_progress, 0, memset(&root_item->drop_progress, 0,
sizeof(struct btrfs_disk_key)); sizeof(struct btrfs_disk_key));
root_item->drop_level = 0; 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); btrfs_tree_unlock(eb);
...@@ -2406,9 +2407,6 @@ void merge_reloc_roots(struct reloc_control *rc) ...@@ -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_fs_info *fs_info = rc->extent_root->fs_info;
struct btrfs_root *root; struct btrfs_root *root;
struct btrfs_root *reloc_root; struct btrfs_root *reloc_root;
u64 last_snap;
u64 otransid;
u64 objectid;
LIST_HEAD(reloc_roots); LIST_HEAD(reloc_roots);
int found = 0; int found = 0;
int ret = 0; int ret = 0;
...@@ -2447,14 +2445,6 @@ void merge_reloc_roots(struct reloc_control *rc) ...@@ -2447,14 +2445,6 @@ void merge_reloc_roots(struct reloc_control *rc)
list_del_init(&reloc_root->root_list); 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); ret = btrfs_drop_snapshot(reloc_root, rc->block_rsv, 0, 1);
if (ret < 0) { if (ret < 0) {
if (list_empty(&reloc_root->root_list)) if (list_empty(&reloc_root->root_list))
......
...@@ -1948,12 +1948,11 @@ static noinline int find_dir_range(struct btrfs_root *root, ...@@ -1948,12 +1948,11 @@ static noinline int find_dir_range(struct btrfs_root *root,
next: next:
/* check the next slot in the tree to see if it is a valid item */ /* check the next slot in the tree to see if it is a valid item */
nritems = btrfs_header_nritems(path->nodes[0]); nritems = btrfs_header_nritems(path->nodes[0]);
path->slots[0]++;
if (path->slots[0] >= nritems) { if (path->slots[0] >= nritems) {
ret = btrfs_next_leaf(root, path); ret = btrfs_next_leaf(root, path);
if (ret) if (ret)
goto out; goto out;
} else {
path->slots[0]++;
} }
btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
...@@ -5224,6 +5223,7 @@ static int log_new_dir_dentries(struct btrfs_trans_handle *trans, ...@@ -5224,6 +5223,7 @@ static int log_new_dir_dentries(struct btrfs_trans_handle *trans,
if (di_key.type == BTRFS_ROOT_ITEM_KEY) if (di_key.type == BTRFS_ROOT_ITEM_KEY)
continue; continue;
btrfs_release_path(path);
di_inode = btrfs_iget(fs_info->sb, &di_key, root, NULL); di_inode = btrfs_iget(fs_info->sb, &di_key, root, NULL);
if (IS_ERR(di_inode)) { if (IS_ERR(di_inode)) {
ret = PTR_ERR(di_inode); ret = PTR_ERR(di_inode);
...@@ -5232,13 +5232,12 @@ static int log_new_dir_dentries(struct btrfs_trans_handle *trans, ...@@ -5232,13 +5232,12 @@ static int log_new_dir_dentries(struct btrfs_trans_handle *trans,
if (btrfs_inode_in_log(di_inode, trans->transid)) { if (btrfs_inode_in_log(di_inode, trans->transid)) {
iput(di_inode); iput(di_inode);
continue; break;
} }
ctx->log_new_dentries = false; ctx->log_new_dentries = false;
if (type == BTRFS_FT_DIR || type == BTRFS_FT_SYMLINK) if (type == BTRFS_FT_DIR || type == BTRFS_FT_SYMLINK)
log_mode = LOG_INODE_ALL; log_mode = LOG_INODE_ALL;
btrfs_release_path(path);
ret = btrfs_log_inode(trans, root, di_inode, ret = btrfs_log_inode(trans, root, di_inode,
log_mode, 0, LLONG_MAX, ctx); log_mode, 0, LLONG_MAX, ctx);
if (!ret && if (!ret &&
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment