From: Greg Kroah-Hartman Date: Sat, 12 Dec 2015 19:46:45 +0000 (-0800) Subject: 4.2-stable patches X-Git-Tag: v4.1.15~8 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6315c23bd82d873210236dea9d501dcc2bd044cb;p=thirdparty%2Fkernel%2Fstable-queue.git 4.2-stable patches added patches: btrfs-fix-regression-running-delayed-references-when-using-qgroups.patch --- diff --git a/queue-4.2/btrfs-fix-regression-running-delayed-references-when-using-qgroups.patch b/queue-4.2/btrfs-fix-regression-running-delayed-references-when-using-qgroups.patch new file mode 100644 index 00000000000..221f17fb092 --- /dev/null +++ b/queue-4.2/btrfs-fix-regression-running-delayed-references-when-using-qgroups.patch @@ -0,0 +1,832 @@ +From b06c4bf5c874a57254b197f53ddf588e7a24a2bf Mon Sep 17 00:00:00 2001 +From: Filipe Manana +Date: Fri, 23 Oct 2015 07:52:54 +0100 +Subject: Btrfs: fix regression running delayed references when using qgroups +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Filipe Manana + +commit b06c4bf5c874a57254b197f53ddf588e7a24a2bf upstream. + +In the kernel 4.2 merge window we had a big changes to the implementation +of delayed references and qgroups which made the no_quota field of delayed +references not used anymore. More specifically the no_quota field is not +used anymore as of: + + commit 0ed4792af0e8 ("btrfs: qgroup: Switch to new extent-oriented qgroup mechanism.") + +Leaving the no_quota field actually prevents delayed references from +getting merged, which in turn cause the following BUG_ON(), at +fs/btrfs/extent-tree.c, to be hit when qgroups are enabled: + + static int run_delayed_tree_ref(...) + { + (...) + BUG_ON(node->ref_mod != 1); + (...) + } + +This happens on a scenario like the following: + + 1) Ref1 bytenr X, action = BTRFS_ADD_DELAYED_REF, no_quota = 1, added. + + 2) Ref2 bytenr X, action = BTRFS_DROP_DELAYED_REF, no_quota = 0, added. + It's not merged with Ref1 because Ref1->no_quota != Ref2->no_quota. + + 3) Ref3 bytenr X, action = BTRFS_ADD_DELAYED_REF, no_quota = 1, added. + It's not merged with the reference at the tail of the list of refs + for bytenr X because the reference at the tail, Ref2 is incompatible + due to Ref2->no_quota != Ref3->no_quota. + + 4) Ref4 bytenr X, action = BTRFS_DROP_DELAYED_REF, no_quota = 0, added. + It's not merged with the reference at the tail of the list of refs + for bytenr X because the reference at the tail, Ref3 is incompatible + due to Ref3->no_quota != Ref4->no_quota. + + 5) We run delayed references, trigger merging of delayed references, + through __btrfs_run_delayed_refs() -> btrfs_merge_delayed_refs(). + + 6) Ref1 and Ref3 are merged as Ref1->no_quota = Ref3->no_quota and + all other conditions are satisfied too. So Ref1 gets a ref_mod + value of 2. + + 7) Ref2 and Ref4 are merged as Ref2->no_quota = Ref4->no_quota and + all other conditions are satisfied too. So Ref2 gets a ref_mod + value of 2. + + 8) Ref1 and Ref2 aren't merged, because they have different values + for their no_quota field. + + 9) Delayed reference Ref1 is picked for running (select_delayed_ref() + always prefers references with an action == BTRFS_ADD_DELAYED_REF). + So run_delayed_tree_ref() is called for Ref1 which triggers the + BUG_ON because Ref1->red_mod != 1 (equals 2). + +So fix this by removing the no_quota field, as it's not used anymore as +of commit 0ed4792af0e8 ("btrfs: qgroup: Switch to new extent-oriented +qgroup mechanism."). + +The use of no_quota was also buggy in at least two places: + +1) At delayed-refs.c:btrfs_add_delayed_tree_ref() - we were setting + no_quota to 0 instead of 1 when the following condition was true: + is_fstree(ref_root) || !fs_info->quota_enabled + +2) At extent-tree.c:__btrfs_inc_extent_ref() - we were attempting to + reset a node's no_quota when the condition "!is_fstree(root_objectid) + || !root->fs_info->quota_enabled" was true but we did it only in + an unused local stack variable, that is, we never reset the no_quota + value in the node itself. + +This fixes the remainder of problems several people have been having when +running delayed references, mostly while a balance is running in parallel, +on a 4.2+ kernel. + +Very special thanks to Stéphane Lesimple for helping debugging this issue +and testing this fix on his multi terabyte filesystem (which took more +than one day to balance alone, plus fsck, etc). + +Also, this fixes deadlock issue when using the clone ioctl with qgroups +enabled, as reported by Elias Probst in the mailing list. The deadlock +happens because after calling btrfs_insert_empty_item we have our path +holding a write lock on a leaf of the fs/subvol tree and then before +releasing the path we called check_ref() which did backref walking, when +qgroups are enabled, and tried to read lock the same leaf. The trace for +this case is the following: + + INFO: task systemd-nspawn:6095 blocked for more than 120 seconds. + (...) + Call Trace: + [] schedule+0x74/0x83 + [] btrfs_tree_read_lock+0xc0/0xea + [] ? wait_woken+0x74/0x74 + [] btrfs_search_old_slot+0x51a/0x810 + [] btrfs_next_old_leaf+0xdf/0x3ce + [] ? ulist_add_merge+0x1b/0x127 + [] __resolve_indirect_refs+0x62a/0x667 + [] ? btrfs_clear_lock_blocking_rw+0x78/0xbe + [] find_parent_nodes+0xaf3/0xfc6 + [] __btrfs_find_all_roots+0x92/0xf0 + [] btrfs_find_all_roots+0x45/0x65 + [] ? btrfs_get_tree_mod_seq+0x2b/0x88 + [] check_ref+0x64/0xc4 + [] btrfs_clone+0x66e/0xb5d + [] btrfs_ioctl_clone+0x48f/0x5bb + [] ? native_sched_clock+0x28/0x77 + [] btrfs_ioctl+0xabc/0x25cb + (...) + +The problem goes away by eleminating check_ref(), which no longer is +needed as its purpose was to get a value for the no_quota field of +a delayed reference (this patch removes the no_quota field as mentioned +earlier). + +Reported-by: Stéphane Lesimple +Tested-by: Stéphane Lesimple +Reported-by: Elias Probst +Reported-by: Peter Becker +Reported-by: Malte Schröder +Reported-by: Derek Dongray +Reported-by: Erkki Seppala +Signed-off-by: Filipe Manana +Reviewed-by: Qu Wenruo +Signed-off-by: Greg Kroah-Hartman + +--- + fs/btrfs/ctree.h | 4 - + fs/btrfs/delayed-ref.c | 139 ++++++++++++++++++++++++++++++++++++++++++------- + fs/btrfs/delayed-ref.h | 7 -- + fs/btrfs/extent-tree.c | 45 +++++---------- + fs/btrfs/file.c | 10 +-- + fs/btrfs/inode.c | 4 - + fs/btrfs/ioctl.c | 62 --------------------- + fs/btrfs/relocation.c | 16 ++--- + fs/btrfs/tree-log.c | 2 + 9 files changed, 156 insertions(+), 133 deletions(-) + +--- a/fs/btrfs/ctree.h ++++ b/fs/btrfs/ctree.h +@@ -3404,7 +3404,7 @@ int btrfs_set_disk_extent_flags(struct b + int btrfs_free_extent(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + u64 bytenr, u64 num_bytes, u64 parent, u64 root_objectid, +- u64 owner, u64 offset, int no_quota); ++ u64 owner, u64 offset); + + int btrfs_free_reserved_extent(struct btrfs_root *root, u64 start, u64 len, + int delalloc); +@@ -3417,7 +3417,7 @@ int btrfs_finish_extent_commit(struct bt + int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + u64 bytenr, u64 num_bytes, u64 parent, +- u64 root_objectid, u64 owner, u64 offset, int no_quota); ++ u64 root_objectid, u64 owner, u64 offset); + + int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans, + struct btrfs_root *root); +--- a/fs/btrfs/delayed-ref.c ++++ b/fs/btrfs/delayed-ref.c +@@ -310,6 +310,119 @@ next: + } + } + ++static bool merge_ref(struct btrfs_trans_handle *trans, ++ struct btrfs_delayed_ref_root *delayed_refs, ++ struct btrfs_delayed_ref_head *head, ++ struct btrfs_delayed_ref_node *ref, ++ u64 seq) ++{ ++ struct btrfs_delayed_ref_node *next; ++ bool done = false; ++ ++ next = list_first_entry(&head->ref_list, struct btrfs_delayed_ref_node, ++ list); ++ while (!done && &next->list != &head->ref_list) { ++ int mod; ++ struct btrfs_delayed_ref_node *next2; ++ ++ next2 = list_next_entry(next, list); ++ ++ if (next == ref) ++ goto next; ++ ++ if (seq && next->seq >= seq) ++ goto next; ++ ++ if (next->type != ref->type) ++ goto next; ++ ++ if ((ref->type == BTRFS_TREE_BLOCK_REF_KEY || ++ ref->type == BTRFS_SHARED_BLOCK_REF_KEY) && ++ comp_tree_refs(btrfs_delayed_node_to_tree_ref(ref), ++ btrfs_delayed_node_to_tree_ref(next), ++ ref->type)) ++ goto next; ++ if ((ref->type == BTRFS_EXTENT_DATA_REF_KEY || ++ ref->type == BTRFS_SHARED_DATA_REF_KEY) && ++ comp_data_refs(btrfs_delayed_node_to_data_ref(ref), ++ btrfs_delayed_node_to_data_ref(next))) ++ goto next; ++ ++ if (ref->action == next->action) { ++ mod = next->ref_mod; ++ } else { ++ if (ref->ref_mod < next->ref_mod) { ++ swap(ref, next); ++ done = true; ++ } ++ mod = -next->ref_mod; ++ } ++ ++ drop_delayed_ref(trans, delayed_refs, head, next); ++ ref->ref_mod += mod; ++ if (ref->ref_mod == 0) { ++ drop_delayed_ref(trans, delayed_refs, head, ref); ++ done = true; ++ } else { ++ /* ++ * Can't have multiples of the same ref on a tree block. ++ */ ++ WARN_ON(ref->type == BTRFS_TREE_BLOCK_REF_KEY || ++ ref->type == BTRFS_SHARED_BLOCK_REF_KEY); ++ } ++next: ++ next = next2; ++ } ++ ++ return done; ++} ++ ++void btrfs_merge_delayed_refs(struct btrfs_trans_handle *trans, ++ struct btrfs_fs_info *fs_info, ++ struct btrfs_delayed_ref_root *delayed_refs, ++ struct btrfs_delayed_ref_head *head) ++{ ++ struct btrfs_delayed_ref_node *ref; ++ u64 seq = 0; ++ ++ assert_spin_locked(&head->lock); ++ ++ if (list_empty(&head->ref_list)) ++ return; ++ ++ /* We don't have too many refs to merge for data. */ ++ if (head->is_data) ++ return; ++ ++ spin_lock(&fs_info->tree_mod_seq_lock); ++ if (!list_empty(&fs_info->tree_mod_seq_list)) { ++ struct seq_list *elem; ++ ++ elem = list_first_entry(&fs_info->tree_mod_seq_list, ++ struct seq_list, list); ++ seq = elem->seq; ++ } ++ spin_unlock(&fs_info->tree_mod_seq_lock); ++ ++ ref = list_first_entry(&head->ref_list, struct btrfs_delayed_ref_node, ++ list); ++ while (&ref->list != &head->ref_list) { ++ if (seq && ref->seq >= seq) ++ goto next; ++ ++ if (merge_ref(trans, delayed_refs, head, ref, seq)) { ++ if (list_empty(&head->ref_list)) ++ break; ++ ref = list_first_entry(&head->ref_list, ++ struct btrfs_delayed_ref_node, ++ list); ++ continue; ++ } ++next: ++ ref = list_next_entry(ref, list); ++ } ++} ++ + int btrfs_check_delayed_seq(struct btrfs_fs_info *fs_info, + struct btrfs_delayed_ref_root *delayed_refs, + u64 seq) +@@ -405,8 +518,7 @@ add_delayed_ref_tail_merge(struct btrfs_ + exist = list_entry(href->ref_list.prev, struct btrfs_delayed_ref_node, + list); + /* No need to compare bytenr nor is_head */ +- if (exist->type != ref->type || exist->no_quota != ref->no_quota || +- exist->seq != ref->seq) ++ if (exist->type != ref->type || exist->seq != ref->seq) + goto add_tail; + + if ((exist->type == BTRFS_TREE_BLOCK_REF_KEY || +@@ -637,7 +749,7 @@ add_delayed_tree_ref(struct btrfs_fs_inf + struct btrfs_delayed_ref_head *head_ref, + struct btrfs_delayed_ref_node *ref, u64 bytenr, + u64 num_bytes, u64 parent, u64 ref_root, int level, +- int action, int no_quota) ++ int action) + { + struct btrfs_delayed_tree_ref *full_ref; + struct btrfs_delayed_ref_root *delayed_refs; +@@ -659,7 +771,6 @@ add_delayed_tree_ref(struct btrfs_fs_inf + ref->action = action; + ref->is_head = 0; + ref->in_tree = 1; +- ref->no_quota = no_quota; + ref->seq = seq; + + full_ref = btrfs_delayed_node_to_tree_ref(ref); +@@ -692,7 +803,7 @@ add_delayed_data_ref(struct btrfs_fs_inf + struct btrfs_delayed_ref_head *head_ref, + struct btrfs_delayed_ref_node *ref, u64 bytenr, + u64 num_bytes, u64 parent, u64 ref_root, u64 owner, +- u64 offset, int action, int no_quota) ++ u64 offset, int action) + { + struct btrfs_delayed_data_ref *full_ref; + struct btrfs_delayed_ref_root *delayed_refs; +@@ -715,7 +826,6 @@ add_delayed_data_ref(struct btrfs_fs_inf + ref->action = action; + ref->is_head = 0; + ref->in_tree = 1; +- ref->no_quota = no_quota; + ref->seq = seq; + + full_ref = btrfs_delayed_node_to_data_ref(ref); +@@ -746,17 +856,13 @@ int btrfs_add_delayed_tree_ref(struct bt + struct btrfs_trans_handle *trans, + u64 bytenr, u64 num_bytes, u64 parent, + u64 ref_root, int level, int action, +- struct btrfs_delayed_extent_op *extent_op, +- int no_quota) ++ struct btrfs_delayed_extent_op *extent_op) + { + struct btrfs_delayed_tree_ref *ref; + struct btrfs_delayed_ref_head *head_ref; + struct btrfs_delayed_ref_root *delayed_refs; + struct btrfs_qgroup_extent_record *record = NULL; + +- if (!is_fstree(ref_root) || !fs_info->quota_enabled) +- no_quota = 0; +- + BUG_ON(extent_op && extent_op->is_data); + ref = kmem_cache_alloc(btrfs_delayed_tree_ref_cachep, GFP_NOFS); + if (!ref) +@@ -785,8 +891,7 @@ int btrfs_add_delayed_tree_ref(struct bt + bytenr, num_bytes, action, 0); + + add_delayed_tree_ref(fs_info, trans, head_ref, &ref->node, bytenr, +- num_bytes, parent, ref_root, level, action, +- no_quota); ++ num_bytes, parent, ref_root, level, action); + spin_unlock(&delayed_refs->lock); + + return 0; +@@ -807,17 +912,13 @@ int btrfs_add_delayed_data_ref(struct bt + u64 bytenr, u64 num_bytes, + u64 parent, u64 ref_root, + u64 owner, u64 offset, int action, +- struct btrfs_delayed_extent_op *extent_op, +- int no_quota) ++ struct btrfs_delayed_extent_op *extent_op) + { + struct btrfs_delayed_data_ref *ref; + struct btrfs_delayed_ref_head *head_ref; + struct btrfs_delayed_ref_root *delayed_refs; + struct btrfs_qgroup_extent_record *record = NULL; + +- if (!is_fstree(ref_root) || !fs_info->quota_enabled) +- no_quota = 0; +- + BUG_ON(extent_op && !extent_op->is_data); + ref = kmem_cache_alloc(btrfs_delayed_data_ref_cachep, GFP_NOFS); + if (!ref) +@@ -853,7 +954,7 @@ int btrfs_add_delayed_data_ref(struct bt + + add_delayed_data_ref(fs_info, trans, head_ref, &ref->node, bytenr, + num_bytes, parent, ref_root, owner, offset, +- action, no_quota); ++ action); + spin_unlock(&delayed_refs->lock); + + return 0; +--- a/fs/btrfs/delayed-ref.h ++++ b/fs/btrfs/delayed-ref.h +@@ -68,7 +68,6 @@ struct btrfs_delayed_ref_node { + + unsigned int action:8; + unsigned int type:8; +- unsigned int no_quota:1; + /* is this node still in the rbtree? */ + unsigned int is_head:1; + unsigned int in_tree:1; +@@ -233,15 +232,13 @@ int btrfs_add_delayed_tree_ref(struct bt + struct btrfs_trans_handle *trans, + u64 bytenr, u64 num_bytes, u64 parent, + u64 ref_root, int level, int action, +- struct btrfs_delayed_extent_op *extent_op, +- int no_quota); ++ struct btrfs_delayed_extent_op *extent_op); + int btrfs_add_delayed_data_ref(struct btrfs_fs_info *fs_info, + struct btrfs_trans_handle *trans, + u64 bytenr, u64 num_bytes, + u64 parent, u64 ref_root, + u64 owner, u64 offset, int action, +- struct btrfs_delayed_extent_op *extent_op, +- int no_quota); ++ struct btrfs_delayed_extent_op *extent_op); + int btrfs_add_delayed_extent_op(struct btrfs_fs_info *fs_info, + struct btrfs_trans_handle *trans, + u64 bytenr, u64 num_bytes, +--- a/fs/btrfs/extent-tree.c ++++ b/fs/btrfs/extent-tree.c +@@ -95,8 +95,7 @@ static int alloc_reserved_tree_block(str + struct btrfs_root *root, + u64 parent, u64 root_objectid, + u64 flags, struct btrfs_disk_key *key, +- int level, struct btrfs_key *ins, +- int no_quota); ++ int level, struct btrfs_key *ins); + static int do_chunk_alloc(struct btrfs_trans_handle *trans, + struct btrfs_root *extent_root, u64 flags, + int force); +@@ -1941,8 +1940,7 @@ int btrfs_discard_extent(struct btrfs_ro + int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + u64 bytenr, u64 num_bytes, u64 parent, +- u64 root_objectid, u64 owner, u64 offset, +- int no_quota) ++ u64 root_objectid, u64 owner, u64 offset) + { + int ret; + struct btrfs_fs_info *fs_info = root->fs_info; +@@ -1954,12 +1952,12 @@ int btrfs_inc_extent_ref(struct btrfs_tr + ret = btrfs_add_delayed_tree_ref(fs_info, trans, bytenr, + num_bytes, + parent, root_objectid, (int)owner, +- BTRFS_ADD_DELAYED_REF, NULL, no_quota); ++ BTRFS_ADD_DELAYED_REF, NULL); + } else { + ret = btrfs_add_delayed_data_ref(fs_info, trans, bytenr, + num_bytes, + parent, root_objectid, owner, offset, +- BTRFS_ADD_DELAYED_REF, NULL, no_quota); ++ BTRFS_ADD_DELAYED_REF, NULL); + } + return ret; + } +@@ -1980,15 +1978,11 @@ static int __btrfs_inc_extent_ref(struct + u64 num_bytes = node->num_bytes; + u64 refs; + int ret; +- int no_quota = node->no_quota; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + +- if (!is_fstree(root_objectid) || !root->fs_info->quota_enabled) +- no_quota = 1; +- + path->reada = 1; + path->leave_spinning = 1; + /* this will setup the path even if it fails to insert the back ref */ +@@ -2223,8 +2217,7 @@ static int run_delayed_tree_ref(struct b + parent, ref_root, + extent_op->flags_to_set, + &extent_op->key, +- ref->level, &ins, +- node->no_quota); ++ ref->level, &ins); + } else if (node->action == BTRFS_ADD_DELAYED_REF) { + ret = __btrfs_inc_extent_ref(trans, root, node, + parent, ref_root, +@@ -3052,7 +3045,7 @@ static int __btrfs_mod_ref(struct btrfs_ + int level; + int ret = 0; + int (*process_func)(struct btrfs_trans_handle *, struct btrfs_root *, +- u64, u64, u64, u64, u64, u64, int); ++ u64, u64, u64, u64, u64, u64); + + + if (btrfs_test_is_dummy_root(root)) +@@ -3093,15 +3086,14 @@ static int __btrfs_mod_ref(struct btrfs_ + key.offset -= btrfs_file_extent_offset(buf, fi); + ret = process_func(trans, root, bytenr, num_bytes, + parent, ref_root, key.objectid, +- key.offset, 1); ++ key.offset); + if (ret) + goto fail; + } else { + bytenr = btrfs_node_blockptr(buf, i); + num_bytes = root->nodesize; + ret = process_func(trans, root, bytenr, num_bytes, +- parent, ref_root, level - 1, 0, +- 1); ++ parent, ref_root, level - 1, 0); + if (ret) + goto fail; + } +@@ -6151,7 +6143,6 @@ static int __btrfs_free_extent(struct bt + int extent_slot = 0; + int found_extent = 0; + int num_to_del = 1; +- int no_quota = node->no_quota; + u32 item_size; + u64 refs; + u64 bytenr = node->bytenr; +@@ -6160,9 +6151,6 @@ static int __btrfs_free_extent(struct bt + bool skinny_metadata = btrfs_fs_incompat(root->fs_info, + SKINNY_METADATA); + +- if (!info->quota_enabled || !is_fstree(root_objectid)) +- no_quota = 1; +- + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; +@@ -6488,7 +6476,7 @@ void btrfs_free_tree_block(struct btrfs_ + buf->start, buf->len, + parent, root->root_key.objectid, + btrfs_header_level(buf), +- BTRFS_DROP_DELAYED_REF, NULL, 0); ++ BTRFS_DROP_DELAYED_REF, NULL); + BUG_ON(ret); /* -ENOMEM */ + } + +@@ -6536,7 +6524,7 @@ out: + /* Can return -ENOMEM */ + int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, + u64 bytenr, u64 num_bytes, u64 parent, u64 root_objectid, +- u64 owner, u64 offset, int no_quota) ++ u64 owner, u64 offset) + { + int ret; + struct btrfs_fs_info *fs_info = root->fs_info; +@@ -6559,13 +6547,13 @@ int btrfs_free_extent(struct btrfs_trans + ret = btrfs_add_delayed_tree_ref(fs_info, trans, bytenr, + num_bytes, + parent, root_objectid, (int)owner, +- BTRFS_DROP_DELAYED_REF, NULL, no_quota); ++ BTRFS_DROP_DELAYED_REF, NULL); + } else { + ret = btrfs_add_delayed_data_ref(fs_info, trans, bytenr, + num_bytes, + parent, root_objectid, owner, + offset, BTRFS_DROP_DELAYED_REF, +- NULL, no_quota); ++ NULL); + } + return ret; + } +@@ -7347,8 +7335,7 @@ static int alloc_reserved_tree_block(str + struct btrfs_root *root, + u64 parent, u64 root_objectid, + u64 flags, struct btrfs_disk_key *key, +- int level, struct btrfs_key *ins, +- int no_quota) ++ int level, struct btrfs_key *ins) + { + int ret; + struct btrfs_fs_info *fs_info = root->fs_info; +@@ -7438,7 +7425,7 @@ int btrfs_alloc_reserved_file_extent(str + ret = btrfs_add_delayed_data_ref(root->fs_info, trans, ins->objectid, + ins->offset, 0, + root_objectid, owner, offset, +- BTRFS_ADD_DELAYED_EXTENT, NULL, 0); ++ BTRFS_ADD_DELAYED_EXTENT, NULL); + return ret; + } + +@@ -7655,7 +7642,7 @@ struct extent_buffer *btrfs_alloc_tree_b + ins.objectid, ins.offset, + parent, root_objectid, level, + BTRFS_ADD_DELAYED_EXTENT, +- extent_op, 0); ++ extent_op); + if (ret) + goto out_free_delayed; + } +@@ -8203,7 +8190,7 @@ skip: + } + } + ret = btrfs_free_extent(trans, root, bytenr, blocksize, parent, +- root->root_key.objectid, level - 1, 0, 0); ++ root->root_key.objectid, level - 1, 0); + BUG_ON(ret); /* -ENOMEM */ + } + btrfs_tree_unlock(next); +--- a/fs/btrfs/file.c ++++ b/fs/btrfs/file.c +@@ -855,7 +855,7 @@ next_slot: + disk_bytenr, num_bytes, 0, + root->root_key.objectid, + new_key.objectid, +- start - extent_offset, 1); ++ start - extent_offset); + BUG_ON(ret); /* -ENOMEM */ + } + key.offset = start; +@@ -933,7 +933,7 @@ delete_extent_item: + disk_bytenr, num_bytes, 0, + root->root_key.objectid, + key.objectid, key.offset - +- extent_offset, 0); ++ extent_offset); + BUG_ON(ret); /* -ENOMEM */ + inode_sub_bytes(inode, + extent_end - key.offset); +@@ -1212,7 +1212,7 @@ again: + + ret = btrfs_inc_extent_ref(trans, root, bytenr, num_bytes, 0, + root->root_key.objectid, +- ino, orig_offset, 1); ++ ino, orig_offset); + BUG_ON(ret); /* -ENOMEM */ + + if (split == start) { +@@ -1239,7 +1239,7 @@ again: + del_nr++; + ret = btrfs_free_extent(trans, root, bytenr, num_bytes, + 0, root->root_key.objectid, +- ino, orig_offset, 0); ++ ino, orig_offset); + BUG_ON(ret); /* -ENOMEM */ + } + other_start = 0; +@@ -1256,7 +1256,7 @@ again: + del_nr++; + ret = btrfs_free_extent(trans, root, bytenr, num_bytes, + 0, root->root_key.objectid, +- ino, orig_offset, 0); ++ ino, orig_offset); + BUG_ON(ret); /* -ENOMEM */ + } + if (del_nr == 0) { +--- a/fs/btrfs/inode.c ++++ b/fs/btrfs/inode.c +@@ -2575,7 +2575,7 @@ again: + ret = btrfs_inc_extent_ref(trans, root, new->bytenr, + new->disk_len, 0, + backref->root_id, backref->inum, +- new->file_pos, 0); /* start - extent_offset */ ++ new->file_pos); /* start - extent_offset */ + if (ret) { + btrfs_abort_transaction(trans, root, ret); + goto out_free_path; +@@ -4488,7 +4488,7 @@ delete: + ret = btrfs_free_extent(trans, root, extent_start, + extent_num_bytes, 0, + btrfs_header_owner(leaf), +- ino, extent_offset, 0); ++ ino, extent_offset); + BUG_ON(ret); + if (btrfs_should_throttle_delayed_refs(trans, root)) + btrfs_async_run_delayed_refs(root, +--- a/fs/btrfs/ioctl.c ++++ b/fs/btrfs/ioctl.c +@@ -3195,41 +3195,6 @@ out: + return ret; + } + +-/* Helper to check and see if this root currently has a ref on the given disk +- * bytenr. If it does then we need to update the quota for this root. This +- * doesn't do anything if quotas aren't enabled. +- */ +-static int check_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, +- u64 disko) +-{ +- struct seq_list tree_mod_seq_elem = SEQ_LIST_INIT(tree_mod_seq_elem); +- struct ulist *roots; +- struct ulist_iterator uiter; +- struct ulist_node *root_node = NULL; +- int ret; +- +- if (!root->fs_info->quota_enabled) +- return 1; +- +- btrfs_get_tree_mod_seq(root->fs_info, &tree_mod_seq_elem); +- ret = btrfs_find_all_roots(trans, root->fs_info, disko, +- tree_mod_seq_elem.seq, &roots); +- if (ret < 0) +- goto out; +- ret = 0; +- ULIST_ITER_INIT(&uiter); +- while ((root_node = ulist_next(roots, &uiter))) { +- if (root_node->val == root->objectid) { +- ret = 1; +- break; +- } +- } +- ulist_free(roots); +-out: +- btrfs_put_tree_mod_seq(root->fs_info, &tree_mod_seq_elem); +- return ret; +-} +- + static int clone_finish_inode_update(struct btrfs_trans_handle *trans, + struct inode *inode, + u64 endoff, +@@ -3488,9 +3453,7 @@ static int btrfs_clone(struct inode *src + u32 nritems; + int slot; + int ret; +- int no_quota; + const u64 len = olen_aligned; +- u64 last_disko = 0; + u64 last_dest_end = destoff; + + ret = -ENOMEM; +@@ -3536,7 +3499,6 @@ static int btrfs_clone(struct inode *src + + nritems = btrfs_header_nritems(path->nodes[0]); + process_slot: +- no_quota = 1; + if (path->slots[0] >= nritems) { + ret = btrfs_next_leaf(BTRFS_I(src)->root, path); + if (ret < 0) +@@ -3688,35 +3650,13 @@ process_slot: + btrfs_set_file_extent_num_bytes(leaf, extent, + datal); + +- /* +- * We need to look up the roots that point at +- * this bytenr and see if the new root does. If +- * it does not we need to make sure we update +- * quotas appropriately. +- */ +- if (disko && root != BTRFS_I(src)->root && +- disko != last_disko) { +- no_quota = check_ref(trans, root, +- disko); +- if (no_quota < 0) { +- btrfs_abort_transaction(trans, +- root, +- ret); +- btrfs_end_transaction(trans, +- root); +- ret = no_quota; +- goto out; +- } +- } +- + if (disko) { + inode_add_bytes(inode, datal); + ret = btrfs_inc_extent_ref(trans, root, + disko, diskl, 0, + root->root_key.objectid, + btrfs_ino(inode), +- new_key.offset - datao, +- no_quota); ++ new_key.offset - datao); + if (ret) { + btrfs_abort_transaction(trans, + root, +--- a/fs/btrfs/relocation.c ++++ b/fs/btrfs/relocation.c +@@ -1716,7 +1716,7 @@ int replace_file_extents(struct btrfs_tr + ret = btrfs_inc_extent_ref(trans, root, new_bytenr, + num_bytes, parent, + btrfs_header_owner(leaf), +- key.objectid, key.offset, 1); ++ key.objectid, key.offset); + if (ret) { + btrfs_abort_transaction(trans, root, ret); + break; +@@ -1724,7 +1724,7 @@ int replace_file_extents(struct btrfs_tr + + ret = btrfs_free_extent(trans, root, bytenr, num_bytes, + parent, btrfs_header_owner(leaf), +- key.objectid, key.offset, 1); ++ key.objectid, key.offset); + if (ret) { + btrfs_abort_transaction(trans, root, ret); + break; +@@ -1900,23 +1900,21 @@ again: + + ret = btrfs_inc_extent_ref(trans, src, old_bytenr, blocksize, + path->nodes[level]->start, +- src->root_key.objectid, level - 1, 0, +- 1); ++ src->root_key.objectid, level - 1, 0); + BUG_ON(ret); + ret = btrfs_inc_extent_ref(trans, dest, new_bytenr, blocksize, + 0, dest->root_key.objectid, level - 1, +- 0, 1); ++ 0); + BUG_ON(ret); + + ret = btrfs_free_extent(trans, src, new_bytenr, blocksize, + path->nodes[level]->start, +- src->root_key.objectid, level - 1, 0, +- 1); ++ src->root_key.objectid, level - 1, 0); + BUG_ON(ret); + + ret = btrfs_free_extent(trans, dest, old_bytenr, blocksize, + 0, dest->root_key.objectid, level - 1, +- 0, 1); ++ 0); + BUG_ON(ret); + + btrfs_unlock_up_safe(path, 0); +@@ -2746,7 +2744,7 @@ static int do_relocation(struct btrfs_tr + node->eb->start, blocksize, + upper->eb->start, + btrfs_header_owner(upper->eb), +- node->level, 0, 1); ++ node->level, 0); + BUG_ON(ret); + + ret = btrfs_drop_subtree(trans, root, eb, upper->eb); +--- a/fs/btrfs/tree-log.c ++++ b/fs/btrfs/tree-log.c +@@ -700,7 +700,7 @@ static noinline int replay_one_extent(st + ret = btrfs_inc_extent_ref(trans, root, + ins.objectid, ins.offset, + 0, root->root_key.objectid, +- key->objectid, offset, 0); ++ key->objectid, offset); + if (ret) + goto out; + } else { diff --git a/queue-4.2/ext4-crypto-fix-bugs-in-ext4_encrypted_zeroout.patch b/queue-4.2/ext4-crypto-fix-bugs-in-ext4_encrypted_zeroout.patch deleted file mode 100644 index 09eb7405fac..00000000000 --- a/queue-4.2/ext4-crypto-fix-bugs-in-ext4_encrypted_zeroout.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 36086d43f6575c081067de9855786a2fc91df77b Mon Sep 17 00:00:00 2001 -From: Theodore Ts'o -Date: Sat, 3 Oct 2015 10:49:29 -0400 -Subject: ext4 crypto: fix bugs in ext4_encrypted_zeroout() - -From: Theodore Ts'o - -commit 36086d43f6575c081067de9855786a2fc91df77b upstream. - -Fix multiple bugs in ext4_encrypted_zeroout(), including one that -could cause us to write an encrypted zero page to the wrong location -on disk, potentially causing data and file system corruption. -Fortunately, this tends to only show up in stress tests, but even with -these fixes, we are seeing some test failures with generic/127 --- but -these are now caused by data failures instead of metadata corruption. - -Since ext4_encrypted_zeroout() is only used for some optimizations to -keep the extent tree from being too fragmented, and -ext4_encrypted_zeroout() itself isn't all that optimized from a time -or IOPS perspective, disable the extent tree optimization for -encrypted inodes for now. This prevents the data corruption issues -reported by generic/127 until we can figure out what's going wrong. - -Signed-off-by: Theodore Ts'o -Signed-off-by: Greg Kroah-Hartman - ---- - fs/ext4/crypto.c | 23 +++++++++++++++++++---- - fs/ext4/extents.c | 3 +++ - 2 files changed, 22 insertions(+), 4 deletions(-) - ---- a/fs/ext4/crypto.c -+++ b/fs/ext4/crypto.c -@@ -410,7 +410,13 @@ int ext4_encrypted_zeroout(struct inode - ext4_lblk_t lblk = ex->ee_block; - ext4_fsblk_t pblk = ext4_ext_pblock(ex); - unsigned int len = ext4_ext_get_actual_len(ex); -- int err = 0; -+ int ret, err = 0; -+ -+#if 0 -+ ext4_msg(inode->i_sb, KERN_CRIT, -+ "ext4_encrypted_zeroout ino %lu lblk %u len %u", -+ (unsigned long) inode->i_ino, lblk, len); -+#endif - - BUG_ON(inode->i_sb->s_blocksize != PAGE_CACHE_SIZE); - -@@ -436,17 +442,26 @@ int ext4_encrypted_zeroout(struct inode - goto errout; - } - bio->bi_bdev = inode->i_sb->s_bdev; -- bio->bi_iter.bi_sector = pblk; -- err = bio_add_page(bio, ciphertext_page, -+ bio->bi_iter.bi_sector = -+ pblk << (inode->i_sb->s_blocksize_bits - 9); -+ ret = bio_add_page(bio, ciphertext_page, - inode->i_sb->s_blocksize, 0); -- if (err) { -+ if (ret != inode->i_sb->s_blocksize) { -+ /* should never happen! */ -+ ext4_msg(inode->i_sb, KERN_ERR, -+ "bio_add_page failed: %d", ret); -+ WARN_ON(1); - bio_put(bio); -+ err = -EIO; - goto errout; - } - err = submit_bio_wait(WRITE, bio); -+ if ((err == 0) && bio->bi_error) -+ err = -EIO; - bio_put(bio); - if (err) - goto errout; -+ lblk++; pblk++; - } - err = 0; - errout: ---- a/fs/ext4/extents.c -+++ b/fs/ext4/extents.c -@@ -3558,6 +3558,9 @@ static int ext4_ext_convert_to_initializ - max_zeroout = sbi->s_extent_max_zeroout_kb >> - (inode->i_sb->s_blocksize_bits - 10); - -+ if (ext4_encrypted_inode(inode)) -+ max_zeroout = 0; -+ - /* If extent is less than s_max_zeroout_kb, zeroout directly */ - if (max_zeroout && (ee_len <= max_zeroout)) { - err = ext4_ext_zeroout(inode, ex); diff --git a/queue-4.2/series b/queue-4.2/series index 5237c581be4..ce9bf3efc19 100644 --- a/queue-4.2/series +++ b/queue-4.2/series @@ -47,7 +47,6 @@ btrfs-fix-signed-overflows-in-btrfs_sync_file.patch rbd-don-t-put-snap_context-twice-in-rbd_queue_workfn.patch ext4-crypto-fix-memory-leak-in-ext4_bio_write_page.patch ext4-crypto-replace-some-bug_on-s-with-error-checks.patch -ext4-crypto-fix-bugs-in-ext4_encrypted_zeroout.patch ext4-fix-potential-use-after-free-in-__ext4_journal_stop.patch ext4-jbd2-ensure-entering-into-panic-after-recording-an-error-in-superblock.patch firewire-ohci-fix-jmicron-jmb38x-it-context-discovery.patch @@ -60,3 +59,4 @@ ocfs2-fix-umask-ignored-issue.patch ceph-fix-message-length-computation.patch alsa-hda-hdmi-apply-skylake-fix-ups-to-broxton-display-codec.patch cobalt-fix-kconfig-dependency.patch +btrfs-fix-regression-running-delayed-references-when-using-qgroups.patch