Home Home > GIT Browse > SLE12-SP3
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2019-05-20 11:12:56 +0200
committerTakashi Iwai <tiwai@suse.de>2019-05-20 11:12:56 +0200
commitf4eea6414a60ff97f9109a4d524ae24dddfcc30e (patch)
tree6c4e391c048361779daeb33e5e9e3e9b238310b2
parenta8035b3f4095034db6794102cbbc1fed056f1a23 (diff)
parent6a8288c8ee4f143e077f6540aa8043c2539fb269 (diff)
Merge branch 'users/wqu/SLE12-SP3/for-next' into SLE12-SP3SLE12-SP3
Pull btrfs fixes from Qu Wenruo (bsc#1063638 bsc#1128052 bsc#1108838)
-rw-r--r--patches.fixes/0001-btrfs-extent-tree-Fix-a-bug-that-btrfs-is-unable-to-.patch72
-rw-r--r--patches.suse/0001-btrfs-delayed-ref-Introduce-better-documented-delaye.patch187
-rw-r--r--patches.suse/0002-btrfs-extent-tree-Open-code-process_func-in-__btrfs_.patch82
-rw-r--r--patches.suse/0003-btrfs-delayed-ref-Use-btrfs_ref-to-refactor-btrfs_ad.patch205
-rw-r--r--patches.suse/0004-btrfs-delayed-ref-Use-btrfs_ref-to-refactor-btrfs_ad.patch127
-rw-r--r--patches.suse/0006-btrfs-extent-tree-Use-btrfs_ref-to-refactor-add_pinn.patch72
-rw-r--r--patches.suse/0007-btrfs-extent-tree-Use-btrfs_ref-to-refactor-btrfs_in.patch370
-rw-r--r--patches.suse/0008-btrfs-extent-tree-Use-btrfs_ref-to-refactor-btrfs_fr.patch258
-rw-r--r--patches.suse/0009-btrfs-qgroup-Don-t-scan-leaf-if-we-re-modifying-relo.patch67
-rw-r--r--series.conf9
10 files changed, 1449 insertions, 0 deletions
diff --git a/patches.fixes/0001-btrfs-extent-tree-Fix-a-bug-that-btrfs-is-unable-to-.patch b/patches.fixes/0001-btrfs-extent-tree-Fix-a-bug-that-btrfs-is-unable-to-.patch
new file mode 100644
index 0000000000..7e11b1bc2f
--- /dev/null
+++ b/patches.fixes/0001-btrfs-extent-tree-Fix-a-bug-that-btrfs-is-unable-to-.patch
@@ -0,0 +1,72 @@
+From 14ae4ec1ee1466b701e0518f9acbb0bbd8ab0684 Mon Sep 17 00:00:00 2001
+From: Qu Wenruo <wqu@suse.com>
+Date: Fri, 10 May 2019 12:45:05 +0800
+Patch-mainline: Submitted, linux-btrfs
+References: bsc#1063638 bsc#1128052 bsc#1108838
+Subject: [PATCH] btrfs: extent-tree: Fix a bug that btrfs is unable to add
+ pinned bytes
+
+Commit ddf30cf03fb5 ("btrfs: extent-tree: Use btrfs_ref to refactor
+add_pinned_bytes()") refactored add_pinned_bytes(), but during that
+refactor, there are two callers which add the pinned bytes instead
+of subtracting.
+
+That refactor misses those two caller, causing incorrect pinned bytes
+calculation and resulting unexpected ENOSPC error.
+
+Fix it by adding a new parameter @sign to restore the original behavior.
+
+Reported-by: kernel test robot <rong.a.chen@intel.com>
+Fixes: ddf30cf03fb5 ("btrfs: extent-tree: Use btrfs_ref to refactor add_pinned_bytes()")
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+---
+ fs/btrfs/extent-tree.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+--- a/fs/btrfs/extent-tree.c
++++ b/fs/btrfs/extent-tree.c
+@@ -756,12 +756,14 @@ static struct btrfs_space_info *__find_s
+ }
+
+ static void add_pinned_bytes(struct btrfs_fs_info *fs_info,
+- struct btrfs_ref *ref)
++ struct btrfs_ref *ref, int sign)
+ {
+ struct btrfs_space_info *space_info;
+- s64 num_bytes = -ref->len;
++ s64 num_bytes;
+ u64 flags;
+
++ ASSERT(sign == 1 || sign == -1);
++ num_bytes = sign * ref->len;
+ if (ref->type == BTRFS_REF_METADATA) {
+ if (ref->tree_ref.root == BTRFS_CHUNK_TREE_OBJECTID)
+ flags = BTRFS_BLOCK_GROUP_SYSTEM;
+@@ -2114,7 +2116,7 @@ int btrfs_inc_extent_ref(struct btrfs_tr
+ generic_ref, 0, NULL,
+ &old_ref_mod, &new_ref_mod);
+ if (ret == 0 && old_ref_mod < 0 && new_ref_mod >= 0)
+- add_pinned_bytes(fs_info, generic_ref);
++ add_pinned_bytes(fs_info, generic_ref, -1);
+
+ return ret;
+ }
+@@ -7228,7 +7230,7 @@ void btrfs_free_tree_block(struct btrfs_
+ }
+ out:
+ if (pin)
+- add_pinned_bytes(root->fs_info, &generic_ref);
++ add_pinned_bytes(root->fs_info, &generic_ref, 1);
+
+ if (last_ref) {
+
+@@ -7270,7 +7272,7 @@ int btrfs_free_extent(struct btrfs_trans
+ }
+
+ if (ret == 0 && old_ref_mod >= 0 && new_ref_mod < 0)
+- add_pinned_bytes(fs_info, ref);
++ add_pinned_bytes(fs_info, ref, 1);
+
+ return ret;
+ }
diff --git a/patches.suse/0001-btrfs-delayed-ref-Introduce-better-documented-delaye.patch b/patches.suse/0001-btrfs-delayed-ref-Introduce-better-documented-delaye.patch
new file mode 100644
index 0000000000..28d84692fd
--- /dev/null
+++ b/patches.suse/0001-btrfs-delayed-ref-Introduce-better-documented-delaye.patch
@@ -0,0 +1,187 @@
+From b28b1f0ce44c1b9ebc1c43e3eba18c1f1f5d9cec Mon Sep 17 00:00:00 2001
+From: Qu Wenruo <wqu@suse.com>
+Git-commit: b28b1f0ce44c1b9ebc1c43e3eba18c1f1f5d9cec
+Patch-mainline: v5.2-rc1
+References: bsc#1063638 bsc#1128052 bsc#1108838
+Date: Thu, 4 Apr 2019 14:45:29 +0800
+Subject: [PATCH 1/9] btrfs: delayed-ref: Introduce better documented delayed
+ ref structures
+
+Current delayed ref interface has several problems:
+
+- Longer and longer parameter lists
+ bytenr
+ num_bytes
+ parent
+ ---------- so far so good
+ ref_root
+ owner
+ offset
+ ---------- I don't feel good now
+
+- Different interpretation of the same parameter
+
+ Above @owner for data ref is inode number (u64),
+ while for tree ref, it's level (int).
+
+ They are even in different size range.
+ For level we only need 0 ~ 8, while for ino it's
+ BTRFS_FIRST_FREE_OBJECTID ~ BTRFS_LAST_FREE_OBJECTID.
+
+ And @offset doesn't even make sense for tree ref.
+
+ Such parameter reuse may look clever as an hidden union, but it
+ destroys code readability.
+
+To solve both problems, we introduce a new structure, btrfs_ref to solve
+them:
+
+- Structure instead of long parameter list
+ This makes later expansion easier, and is better documented.
+
+- Use btrfs_ref::type to distinguish data and tree ref
+
+- Use proper union to store data/tree ref specific structures.
+
+- Use separate functions to fill data/tree ref data, with a common generic
+ function to fill common bytenr/num_bytes members.
+
+All parameters will find its place in btrfs_ref, and an extra member,
+@real_root, inspired by ref-verify code, is newly introduced for later
+qgroup code, to record which tree is triggered by this extent modification.
+
+This patch doesn't touch any code, but provides the basis for further
+refactoring.
+
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+---
+ fs/btrfs/delayed-ref.h | 109 +++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 109 insertions(+)
+
+--- a/fs/btrfs/delayed-ref.h
++++ b/fs/btrfs/delayed-ref.h
+@@ -192,6 +192,83 @@ struct btrfs_delayed_ref_root {
+ u64 qgroup_to_skip;
+ };
+
++enum btrfs_ref_type {
++ BTRFS_REF_NOT_SET,
++ BTRFS_REF_DATA,
++ BTRFS_REF_METADATA,
++ BTRFS_REF_LAST,
++};
++
++struct btrfs_data_ref {
++ /* For EXTENT_DATA_REF */
++
++ /* Root which refers to this data extent */
++ u64 ref_root;
++
++ /* Inode which refers to this data extent */
++ u64 ino;
++
++ /*
++ * file_offset - extent_offset
++ *
++ * file_offset is the key.offset of the EXTENT_DATA key.
++ * extent_offset is btrfs_file_extent_offset() of the EXTENT_DATA data.
++ */
++ u64 offset;
++};
++
++struct btrfs_tree_ref {
++ /*
++ * Level of this tree block
++ *
++ * Shared for skinny (TREE_BLOCK_REF) and normal tree ref.
++ */
++ int level;
++
++ /*
++ * Root which refers to this tree block.
++ *
++ * For TREE_BLOCK_REF (skinny metadata, either inline or keyed)
++ */
++ u64 root;
++
++ /* For non-skinny metadata, no special member needed */
++};
++
++struct btrfs_ref {
++ enum btrfs_ref_type type;
++ int action;
++
++ /*
++ * Whether this extent should go through qgroup record.
++ *
++ * Normally false, but for certain cases like delayed subtree scan,
++ * setting this flag can hugely reduce qgroup overhead.
++ */
++ bool skip_qgroup;
++
++ /*
++ * Optional. For which root is this modification.
++ * Mostly used for qgroup optimization.
++ *
++ * When unset, data/tree ref init code will populate it.
++ * In certain cases, we're modifying reference for a different root.
++ * E.g. COW fs tree blocks for balance.
++ * In that case, tree_ref::root will be fs tree, but we're doing this
++ * for reloc tree, then we should set @real_root to reloc tree.
++ */
++ u64 real_root;
++ u64 bytenr;
++ u64 len;
++
++ /* Bytenr of the parent tree block */
++ u64 parent;
++ union {
++ struct btrfs_data_ref data_ref;
++ struct btrfs_tree_ref tree_ref;
++ };
++};
++
+ extern struct kmem_cache *btrfs_delayed_ref_head_cachep;
+ extern struct kmem_cache *btrfs_delayed_tree_ref_cachep;
+ extern struct kmem_cache *btrfs_delayed_data_ref_cachep;
+@@ -200,6 +277,38 @@ extern struct kmem_cache *btrfs_delayed_
+ int btrfs_delayed_ref_init(void);
+ void btrfs_delayed_ref_exit(void);
+
++static inline void btrfs_init_generic_ref(struct btrfs_ref *generic_ref,
++ int action, u64 bytenr, u64 len, u64 parent)
++{
++ generic_ref->action = action;
++ generic_ref->bytenr = bytenr;
++ generic_ref->len = len;
++ generic_ref->parent = parent;
++}
++
++static inline void btrfs_init_tree_ref(struct btrfs_ref *generic_ref,
++ int level, u64 root)
++{
++ /* If @real_root not set, use @root as fallback */
++ if (!generic_ref->real_root)
++ generic_ref->real_root = root;
++ generic_ref->tree_ref.level = level;
++ generic_ref->tree_ref.root = root;
++ generic_ref->type = BTRFS_REF_METADATA;
++}
++
++static inline void btrfs_init_data_ref(struct btrfs_ref *generic_ref,
++ u64 ref_root, u64 ino, u64 offset)
++{
++ /* If @real_root not set, use @root as fallback */
++ if (!generic_ref->real_root)
++ generic_ref->real_root = ref_root;
++ generic_ref->data_ref.ref_root = ref_root;
++ generic_ref->data_ref.ino = ino;
++ generic_ref->data_ref.offset = offset;
++ generic_ref->type = BTRFS_REF_DATA;
++}
++
+ static inline struct btrfs_delayed_extent_op *
+ btrfs_alloc_delayed_extent_op(void)
+ {
diff --git a/patches.suse/0002-btrfs-extent-tree-Open-code-process_func-in-__btrfs_.patch b/patches.suse/0002-btrfs-extent-tree-Open-code-process_func-in-__btrfs_.patch
new file mode 100644
index 0000000000..58694bc648
--- /dev/null
+++ b/patches.suse/0002-btrfs-extent-tree-Open-code-process_func-in-__btrfs_.patch
@@ -0,0 +1,82 @@
+From dd28b6a5aad306c417477db700ed0848c923a31c Mon Sep 17 00:00:00 2001
+From: Qu Wenruo <wqu@suse.com>
+Git-commit: dd28b6a5aad306c417477db700ed0848c923a31c
+Patch-mainline: v5.2-rc1
+References: bsc#1063638 bsc#1128052 bsc#1108838
+Date: Thu, 4 Apr 2019 14:45:30 +0800
+Subject: [PATCH 2/9] btrfs: extent-tree: Open-code process_func in
+ __btrfs_mod_ref
+
+The process_func function pointer is local to __btrfs_mod_ref() and
+points to either btrfs_inc_extent_ref() or btrfs_free_extent().
+
+Open code it to make later delayed ref refactor easier, so we can
+refactor btrfs_inc_extent_ref() and btrfs_free_extent() in different
+patches.
+
+Reviewed-by: Nikolay Borisov <nborisov@suse.com>
+Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+---
+ fs/btrfs/extent-tree.c | 29 ++++++++++++++++-------------
+ 1 file changed, 16 insertions(+), 13 deletions(-)
+
+--- a/fs/btrfs/extent-tree.c
++++ b/fs/btrfs/extent-tree.c
+@@ -3246,9 +3246,6 @@ static int __btrfs_mod_ref(struct btrfs_
+ int i;
+ int level;
+ int ret = 0;
+- int (*process_func)(struct btrfs_trans_handle *, struct btrfs_root *,
+- u64, u64, u64, u64, u64, u64);
+-
+
+ if (btrfs_test_is_dummy_root(root))
+ return 0;
+@@ -3260,11 +3257,6 @@ static int __btrfs_mod_ref(struct btrfs_
+ if (!test_bit(BTRFS_ROOT_REF_COWS, &root->state) && level == 0)
+ return 0;
+
+- if (inc)
+- process_func = btrfs_inc_extent_ref;
+- else
+- process_func = btrfs_free_extent;
+-
+ if (full_backref)
+ parent = buf->start;
+ else
+@@ -3286,16 +3278,27 @@ static int __btrfs_mod_ref(struct btrfs_
+
+ num_bytes = btrfs_file_extent_disk_num_bytes(buf, fi);
+ key.offset -= btrfs_file_extent_offset(buf, fi);
+- ret = process_func(trans, root, bytenr, num_bytes,
+- parent, ref_root, key.objectid,
+- key.offset);
++ if (inc)
++ ret = btrfs_inc_extent_ref(trans, root, bytenr,
++ num_bytes, parent, ref_root,
++ key.objectid, key.offset);
++ else
++ ret = btrfs_free_extent(trans, root, bytenr,
++ num_bytes, parent, ref_root,
++ key.objectid, 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);
++ if (inc)
++ ret = btrfs_inc_extent_ref(trans, root, bytenr,
++ num_bytes, parent, ref_root,
++ level - 1, 0);
++ else
++ ret = btrfs_free_extent(trans, root, bytenr,
++ num_bytes, parent, ref_root,
++ level - 1, 0);
+ if (ret)
+ goto fail;
+ }
diff --git a/patches.suse/0003-btrfs-delayed-ref-Use-btrfs_ref-to-refactor-btrfs_ad.patch b/patches.suse/0003-btrfs-delayed-ref-Use-btrfs_ref-to-refactor-btrfs_ad.patch
new file mode 100644
index 0000000000..dda9e67942
--- /dev/null
+++ b/patches.suse/0003-btrfs-delayed-ref-Use-btrfs_ref-to-refactor-btrfs_ad.patch
@@ -0,0 +1,205 @@
+From ed4f255b9bacb774c99ded17647f138c3f61546d Mon Sep 17 00:00:00 2001
+From: Qu Wenruo <wqu@suse.com>
+Date: Thu, 4 Apr 2019 14:45:31 +0800
+Git-commit: ed4f255b9bacb774c99ded17647f138c3f61546d
+Patch-mainline: v5.2-rc1
+References: bsc#1063638 bsc#1128052 bsc#1108838
+Subject: [PATCH 3/9] btrfs: delayed-ref: Use btrfs_ref to refactor
+ btrfs_add_delayed_tree_ref()
+
+btrfs_add_delayed_tree_ref() has a longer and longer parameter list, and
+some callers like btrfs_inc_extent_ref() are using @owner as level for
+delayed tree ref.
+
+Instead of making the parameter list longer, use btrfs_ref to refactor
+it, so each parameter assignment should be self-explaining without dirty
+level/owner trick, and provides the basis for later refactoring.
+
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+---
+ fs/btrfs/delayed-ref.c | 24 +++++++++++++++++-------
+ fs/btrfs/delayed-ref.h | 3 +--
+ fs/btrfs/extent-tree.c | 42 +++++++++++++++++++++++++++---------------
+ 3 files changed, 45 insertions(+), 24 deletions(-)
+
+--- a/fs/btrfs/delayed-ref.c
++++ b/fs/btrfs/delayed-ref.c
+@@ -720,8 +720,7 @@ static void init_delayed_ref_common(stru
+ */
+ int btrfs_add_delayed_tree_ref(struct btrfs_fs_info *fs_info,
+ struct btrfs_trans_handle *trans,
+- u64 bytenr, u64 num_bytes, u64 parent,
+- u64 ref_root, int level, int action,
++ struct btrfs_ref *generic_ref,
+ struct btrfs_delayed_extent_op *extent_op,
+ int *old_ref_mod, int *new_ref_mod)
+ {
+@@ -729,10 +728,18 @@ int btrfs_add_delayed_tree_ref(struct bt
+ struct btrfs_delayed_ref_head *head_ref;
+ struct btrfs_delayed_ref_root *delayed_refs;
+ struct btrfs_qgroup_extent_record *record = NULL;
+- bool is_system = (ref_root == BTRFS_CHUNK_TREE_OBJECTID);
++ bool is_system;
++ int action = generic_ref->action;
++ int level = generic_ref->tree_ref.level;
+ int ret;
++ u64 bytenr = generic_ref->bytenr;
++ u64 num_bytes = generic_ref->len;
++ u64 parent = generic_ref->parent;
+ u8 ref_type;
+
++ is_system = (generic_ref->real_root == BTRFS_CHUNK_TREE_OBJECTID);
++
++ ASSERT(generic_ref->type == BTRFS_REF_METADATA && generic_ref->action);
+ BUG_ON(extent_op && extent_op->is_data);
+ ref = kmem_cache_alloc(btrfs_delayed_tree_ref_cachep, GFP_NOFS);
+ if (!ref)
+@@ -743,8 +750,8 @@ int btrfs_add_delayed_tree_ref(struct bt
+ else
+ ref_type = BTRFS_TREE_BLOCK_REF_KEY;
+ init_delayed_ref_common(fs_info, &ref->node, bytenr, num_bytes,
+- ref_root, action, ref_type);
+- ref->root = ref_root;
++ generic_ref->tree_ref.root, action, ref_type);
++ ref->root = generic_ref->tree_ref.root;
+ ref->parent = parent;
+ ref->level = level;
+
+@@ -753,14 +760,17 @@ int btrfs_add_delayed_tree_ref(struct bt
+ goto free_ref;
+
+ if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) &&
+- is_fstree(ref_root)) {
++ is_fstree(generic_ref->real_root) &&
++ is_fstree(generic_ref->tree_ref.root) &&
++ !generic_ref->skip_qgroup) {
+ record = kzalloc(sizeof(*record), GFP_NOFS);
+ if (!record)
+ goto free_head_ref;
+ }
+
+ init_delayed_ref_head(head_ref, record, bytenr, num_bytes,
+- ref_root, 0, action, false, is_system);
++ generic_ref->tree_ref.root, 0, action, false,
++ is_system);
+ head_ref->extent_op = extent_op;
+
+ delayed_refs = &trans->transaction->delayed_refs;
+--- a/fs/btrfs/delayed-ref.h
++++ b/fs/btrfs/delayed-ref.h
+@@ -350,8 +350,7 @@ static inline void btrfs_put_delayed_ref
+
+ int btrfs_add_delayed_tree_ref(struct btrfs_fs_info *fs_info,
+ struct btrfs_trans_handle *trans,
+- u64 bytenr, u64 num_bytes, u64 parent,
+- u64 ref_root, int level, int action,
++ struct btrfs_ref *generic_ref,
+ struct btrfs_delayed_extent_op *extent_op,
+ int *old_ref_mod, int *new_ref_mod);
+ int btrfs_add_delayed_data_ref(struct btrfs_fs_info *fs_info,
+--- a/fs/btrfs/extent-tree.c
++++ b/fs/btrfs/extent-tree.c
+@@ -2099,16 +2099,19 @@ int btrfs_inc_extent_ref(struct btrfs_tr
+ {
+ int old_ref_mod, new_ref_mod;
+ int ret;
++ struct btrfs_ref generic_ref = { 0 };
+ struct btrfs_fs_info *fs_info = root->fs_info;
+
+ BUG_ON(owner < BTRFS_FIRST_FREE_OBJECTID &&
+ root_objectid == BTRFS_TREE_LOG_OBJECTID);
+
++ btrfs_init_generic_ref(&generic_ref, BTRFS_ADD_DELAYED_REF, bytenr,
++ num_bytes, parent);
++ generic_ref.real_root = root->root_key.objectid;
+ if (owner < BTRFS_FIRST_FREE_OBJECTID) {
+- ret = btrfs_add_delayed_tree_ref(fs_info, trans, bytenr,
+- num_bytes,
+- parent, root_objectid, (int)owner,
+- BTRFS_ADD_DELAYED_REF, NULL,
++ btrfs_init_tree_ref(&generic_ref, (int)owner, root_objectid);
++ ret = btrfs_add_delayed_tree_ref(fs_info, trans,
++ &generic_ref, NULL,
+ &old_ref_mod, &new_ref_mod);
+ } else {
+ ret = btrfs_add_delayed_data_ref(fs_info, trans, bytenr,
+@@ -7176,17 +7179,20 @@ void btrfs_free_tree_block(struct btrfs_
+ struct extent_buffer *buf,
+ u64 parent, int last_ref)
+ {
++ struct btrfs_ref generic_ref = { 0 };
+ int pin = 1;
+ int ret;
+
++ btrfs_init_generic_ref(&generic_ref, BTRFS_DROP_DELAYED_REF,
++ buf->start, buf->len, parent);
++ btrfs_init_tree_ref(&generic_ref, btrfs_header_level(buf),
++ root->root_key.objectid);
++
+ if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) {
+ int old_ref_mod, new_ref_mod;
+
+ ret = btrfs_add_delayed_tree_ref(root->fs_info, trans,
+- buf->start, buf->len,
+- parent, root->root_key.objectid,
+- btrfs_header_level(buf),
+- BTRFS_DROP_DELAYED_REF, NULL,
++ &generic_ref, NULL,
+ &old_ref_mod, &new_ref_mod);
+ BUG_ON(ret); /* -ENOMEM */
+ pin = old_ref_mod >= 0 && new_ref_mod < 0;
+@@ -7240,10 +7246,14 @@ int btrfs_free_extent(struct btrfs_trans
+ int old_ref_mod, new_ref_mod;
+ int ret;
+ struct btrfs_fs_info *fs_info = root->fs_info;
++ struct btrfs_ref generic_ref = { 0 };
+
+ if (btrfs_test_is_dummy_root(root))
+ return 0;
+
++ btrfs_init_generic_ref(&generic_ref, BTRFS_DROP_DELAYED_REF, bytenr,
++ num_bytes, parent);
++ generic_ref.real_root = root->root_key.objectid;
+ /*
+ * tree log blocks never actually go into the extent allocation
+ * tree, just update pinning info and exit early.
+@@ -7255,10 +7265,9 @@ int btrfs_free_extent(struct btrfs_trans
+ old_ref_mod = new_ref_mod = 0;
+ ret = 0;
+ } else if (owner < BTRFS_FIRST_FREE_OBJECTID) {
+- ret = btrfs_add_delayed_tree_ref(fs_info, trans, bytenr,
+- num_bytes,
+- parent, root_objectid, (int)owner,
+- BTRFS_DROP_DELAYED_REF, NULL,
++ btrfs_init_tree_ref(&generic_ref, (int)owner, root_objectid);
++ ret = btrfs_add_delayed_tree_ref(fs_info, trans,
++ &generic_ref, NULL,
+ &old_ref_mod, &new_ref_mod);
+ } else {
+ ret = btrfs_add_delayed_data_ref(fs_info, trans, bytenr,
+@@ -8389,6 +8398,7 @@ struct extent_buffer *btrfs_alloc_tree_b
+ struct btrfs_block_rsv *block_rsv;
+ struct extent_buffer *buf;
+ struct btrfs_delayed_extent_op *extent_op;
++ struct btrfs_ref generic_ref = { 0 };
+ u64 flags = 0;
+ int ret;
+ u32 blocksize = root->nodesize;
+@@ -8443,10 +8453,12 @@ struct extent_buffer *btrfs_alloc_tree_b
+ extent_op->is_data = false;
+ extent_op->level = level;
+
++ btrfs_init_generic_ref(&generic_ref, BTRFS_ADD_DELAYED_EXTENT,
++ ins.objectid, ins.offset, parent);
++ generic_ref.real_root = root->root_key.objectid;
++ btrfs_init_tree_ref(&generic_ref, level, root_objectid);
+ ret = btrfs_add_delayed_tree_ref(root->fs_info, trans,
+- ins.objectid, ins.offset,
+- parent, root_objectid, level,
+- BTRFS_ADD_DELAYED_EXTENT,
++ &generic_ref,
+ extent_op, NULL, NULL);
+ if (ret)
+ goto out_free_delayed;
diff --git a/patches.suse/0004-btrfs-delayed-ref-Use-btrfs_ref-to-refactor-btrfs_ad.patch b/patches.suse/0004-btrfs-delayed-ref-Use-btrfs_ref-to-refactor-btrfs_ad.patch
new file mode 100644
index 0000000000..493e407029
--- /dev/null
+++ b/patches.suse/0004-btrfs-delayed-ref-Use-btrfs_ref-to-refactor-btrfs_ad.patch
@@ -0,0 +1,127 @@
+From 76675593b69f2fcd57e24d9dd2a9b278f0130d0b Mon Sep 17 00:00:00 2001
+From: Qu Wenruo <wqu@suse.com>
+Date: Thu, 4 Apr 2019 14:45:32 +0800
+Git-commit: 76675593b69f2fcd57e24d9dd2a9b278f0130d0b
+Patch-mainline: v5.2-rc1
+References: bsc#1063638 bsc#1128052 bsc#1108838
+Subject: [PATCH 4/9] btrfs: delayed-ref: Use btrfs_ref to refactor
+ btrfs_add_delayed_data_ref()
+
+Just like btrfs_add_delayed_tree_ref(), use btrfs_ref to refactor
+btrfs_add_delayed_data_ref().
+
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+---
+ fs/btrfs/delayed-ref.c | 16 ++++++++++++----
+ fs/btrfs/delayed-ref.h | 4 +---
+ fs/btrfs/extent-tree.c | 25 ++++++++++++-------------
+ 3 files changed, 25 insertions(+), 20 deletions(-)
+
+--- a/fs/btrfs/delayed-ref.c
++++ b/fs/btrfs/delayed-ref.c
+@@ -807,9 +807,7 @@ free_ref:
+ */
+ 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, u64 reserved, int action,
++ struct btrfs_ref *generic_ref, u64 reserved,
+ struct btrfs_delayed_extent_op *extent_op,
+ int *old_ref_mod, int *new_ref_mod)
+ {
+@@ -817,9 +815,17 @@ int btrfs_add_delayed_data_ref(struct bt
+ struct btrfs_delayed_ref_head *head_ref;
+ struct btrfs_delayed_ref_root *delayed_refs;
+ struct btrfs_qgroup_extent_record *record = NULL;
++ int action = generic_ref->action;
+ int ret;
++ u64 bytenr = generic_ref->bytenr;
++ u64 num_bytes = generic_ref->len;
++ u64 parent = generic_ref->parent;
++ u64 ref_root = generic_ref->data_ref.ref_root;
++ u64 owner = generic_ref->data_ref.ino;
++ u64 offset = generic_ref->data_ref.offset;
+ u8 ref_type;
+
++ ASSERT(generic_ref->type == BTRFS_REF_DATA && action);
+ BUG_ON(extent_op && !extent_op->is_data);
+ ref = kmem_cache_alloc(btrfs_delayed_data_ref_cachep, GFP_NOFS);
+ if (!ref)
+@@ -843,7 +849,9 @@ int btrfs_add_delayed_data_ref(struct bt
+ }
+
+ if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) &&
+- is_fstree(ref_root)) {
++ is_fstree(ref_root) &&
++ is_fstree(generic_ref->real_root) &&
++ !generic_ref->skip_qgroup) {
+ record = kzalloc(sizeof(*record), GFP_NOFS);
+ if (!record) {
+ kmem_cache_free(btrfs_delayed_data_ref_cachep, ref);
+--- a/fs/btrfs/delayed-ref.h
++++ b/fs/btrfs/delayed-ref.h
+@@ -355,9 +355,7 @@ int btrfs_add_delayed_tree_ref(struct bt
+ int *old_ref_mod, int *new_ref_mod);
+ 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, u64 reserved, int action,
++ struct btrfs_ref *generic_ref, u64 reserved,
+ struct btrfs_delayed_extent_op *extent_op,
+ int *old_ref_mod, int *new_ref_mod);
+ int btrfs_add_delayed_qgroup_reserve(struct btrfs_fs_info *fs_info,
+--- a/fs/btrfs/extent-tree.c
++++ b/fs/btrfs/extent-tree.c
+@@ -2114,10 +2114,9 @@ int btrfs_inc_extent_ref(struct btrfs_tr
+ &generic_ref, NULL,
+ &old_ref_mod, &new_ref_mod);
+ } else {
+- ret = btrfs_add_delayed_data_ref(fs_info, trans, bytenr,
+- num_bytes, parent, root_objectid,
+- owner, offset, 0,
+- BTRFS_ADD_DELAYED_REF, NULL,
++ btrfs_init_data_ref(&generic_ref, root_objectid, owner, offset);
++ ret = btrfs_add_delayed_data_ref(fs_info, trans,
++ &generic_ref, 0, NULL,
+ &old_ref_mod, &new_ref_mod);
+ }
+ if (ret == 0 && old_ref_mod < 0 && new_ref_mod >= 0)
+@@ -7270,11 +7269,9 @@ int btrfs_free_extent(struct btrfs_trans
+ &generic_ref, NULL,
+ &old_ref_mod, &new_ref_mod);
+ } else {
+- ret = btrfs_add_delayed_data_ref(fs_info, trans, bytenr,
+- num_bytes,
+- parent, root_objectid, owner,
+- offset, 0,
+- BTRFS_DROP_DELAYED_REF, NULL,
++ btrfs_init_data_ref(&generic_ref, root_objectid, owner, offset);
++ ret = btrfs_add_delayed_data_ref(fs_info, trans,
++ &generic_ref, 0, NULL,
+ &old_ref_mod, &new_ref_mod);
+ }
+
+@@ -8215,14 +8212,16 @@ int btrfs_alloc_reserved_file_extent(str
+ u64 offset, u64 ram_bytes,
+ struct btrfs_key *ins)
+ {
++ struct btrfs_ref generic_ref = { 0 };
+ int ret;
+
+ BUG_ON(root_objectid == BTRFS_TREE_LOG_OBJECTID);
+
+- ret = btrfs_add_delayed_data_ref(root->fs_info, trans, ins->objectid,
+- ins->offset, 0,
+- root_objectid, owner, offset,
+- ram_bytes, BTRFS_ADD_DELAYED_EXTENT,
++ btrfs_init_generic_ref(&generic_ref, BTRFS_ADD_DELAYED_EXTENT,
++ ins->objectid, ins->offset, 0);
++ btrfs_init_data_ref(&generic_ref, root->root_key.objectid, owner, offset);
++ ret = btrfs_add_delayed_data_ref(root->fs_info, trans,
++ &generic_ref, ram_bytes,
+ NULL, NULL, NULL);
+ return ret;
+ }
diff --git a/patches.suse/0006-btrfs-extent-tree-Use-btrfs_ref-to-refactor-add_pinn.patch b/patches.suse/0006-btrfs-extent-tree-Use-btrfs_ref-to-refactor-add_pinn.patch
new file mode 100644
index 0000000000..3cc3688f1a
--- /dev/null
+++ b/patches.suse/0006-btrfs-extent-tree-Use-btrfs_ref-to-refactor-add_pinn.patch
@@ -0,0 +1,72 @@
+From ddf30cf03fb53b9a0ad0f355a69dbedf416edde9 Mon Sep 17 00:00:00 2001
+From: Qu Wenruo <wqu@suse.com>
+Date: Thu, 4 Apr 2019 14:45:34 +0800
+Git-commit: ddf30cf03fb53b9a0ad0f355a69dbedf416edde9
+Patch-mainline: v5.2-rc1
+References: bsc#1063638 bsc#1128052 bsc#1108838
+Subject: [PATCH 6/9] btrfs: extent-tree: Use btrfs_ref to refactor
+ add_pinned_bytes()
+
+Since add_pinned_bytes() only needs to know if the extent is metadata
+and if it's a chunk tree extent, btrfs_ref is a perfect match for it, as
+we don't need various owner/level trick to determine extent type.
+
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Reviewed-by: Nikolay Borisov <nborisov@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+---
+ fs/btrfs/extent-tree.c | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+--- a/fs/btrfs/extent-tree.c
++++ b/fs/btrfs/extent-tree.c
+@@ -755,14 +755,15 @@ static struct btrfs_space_info *__find_s
+ return NULL;
+ }
+
+-static void add_pinned_bytes(struct btrfs_fs_info *fs_info, s64 num_bytes,
+- u64 owner, u64 root_objectid)
++static void add_pinned_bytes(struct btrfs_fs_info *fs_info,
++ struct btrfs_ref *ref)
+ {
+ struct btrfs_space_info *space_info;
++ s64 num_bytes = -ref->len;
+ u64 flags;
+
+- if (owner < BTRFS_FIRST_FREE_OBJECTID) {
+- if (root_objectid == BTRFS_CHUNK_TREE_OBJECTID)
++ if (ref->type == BTRFS_REF_METADATA) {
++ if (ref->tree_ref.root == BTRFS_CHUNK_TREE_OBJECTID)
+ flags = BTRFS_BLOCK_GROUP_SYSTEM;
+ else
+ flags = BTRFS_BLOCK_GROUP_METADATA;
+@@ -2120,7 +2121,7 @@ int btrfs_inc_extent_ref(struct btrfs_tr
+ &old_ref_mod, &new_ref_mod);
+ }
+ if (ret == 0 && old_ref_mod < 0 && new_ref_mod >= 0)
+- add_pinned_bytes(fs_info, -num_bytes, owner, root_objectid);
++ add_pinned_bytes(fs_info, &generic_ref);
+
+ return ret;
+ }
+@@ -7224,9 +7225,8 @@ void btrfs_free_tree_block(struct btrfs_
+ }
+ out:
+ if (pin)
+- add_pinned_bytes(root->fs_info, buf->len,
+- btrfs_header_level(buf),
+- root->root_key.objectid);
++ add_pinned_bytes(root->fs_info, &generic_ref);
++
+ if (last_ref) {
+
+ /*
+@@ -7276,7 +7276,7 @@ int btrfs_free_extent(struct btrfs_trans
+ }
+
+ if (ret == 0 && old_ref_mod >= 0 && new_ref_mod < 0)
+- add_pinned_bytes(fs_info, num_bytes, owner, root_objectid);
++ add_pinned_bytes(fs_info, &generic_ref);
+
+ return ret;
+ }
diff --git a/patches.suse/0007-btrfs-extent-tree-Use-btrfs_ref-to-refactor-btrfs_in.patch b/patches.suse/0007-btrfs-extent-tree-Use-btrfs_ref-to-refactor-btrfs_in.patch
new file mode 100644
index 0000000000..d895a0d7ef
--- /dev/null
+++ b/patches.suse/0007-btrfs-extent-tree-Use-btrfs_ref-to-refactor-btrfs_in.patch
@@ -0,0 +1,370 @@
+From 82fa113fccc41fe5204b4ce35341d69ebde0020f Mon Sep 17 00:00:00 2001
+From: Qu Wenruo <wqu@suse.com>
+Date: Thu, 4 Apr 2019 14:45:35 +0800
+Git-commit: 82fa113fccc41fe5204b4ce35341d69ebde0020f
+Patch-mainline: v5.2-rc1
+References: bsc#1063638 bsc#1128052 bsc#1108838
+Subject: [PATCH 7/9] btrfs: extent-tree: Use btrfs_ref to refactor
+ btrfs_inc_extent_ref()
+
+Use the new btrfs_ref structure and replace parameter list to clean up
+the usage of owner and level to distinguish the extent types.
+
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+---
+ fs/btrfs/ctree.h | 5 +---
+ fs/btrfs/extent-tree.c | 55 +++++++++++++++++++++++++++----------------------
+ fs/btrfs/file.c | 17 ++++++++++-----
+ fs/btrfs/inode.c | 10 +++++---
+ fs/btrfs/ioctl.c | 15 ++++++++-----
+ fs/btrfs/relocation.c | 42 ++++++++++++++++++++++++-------------
+ fs/btrfs/tree-log.c | 11 +++++++--
+ 7 files changed, 96 insertions(+), 59 deletions(-)
+
+--- a/fs/btrfs/ctree.h
++++ b/fs/btrfs/ctree.h
+@@ -51,6 +51,7 @@ extern struct kmem_cache *btrfs_bit_radi
+ extern struct kmem_cache *btrfs_path_cachep;
+ extern struct kmem_cache *btrfs_free_space_cachep;
+ struct btrfs_ordered_sum;
++struct btrfs_ref;
+
+ #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
+ #define STATIC noinline
+@@ -2679,9 +2680,7 @@ void btrfs_prepare_extent_commit(struct
+ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root);
+ 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);
++ struct btrfs_ref *generic_ref);
+
+ int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root);
+--- a/fs/btrfs/extent-tree.c
++++ b/fs/btrfs/extent-tree.c
+@@ -2094,34 +2094,27 @@ int btrfs_discard_extent(struct btrfs_ro
+
+ /* Can return -ENOMEM */
+ 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)
++ struct btrfs_ref *generic_ref)
+ {
+ int old_ref_mod, new_ref_mod;
+ int ret;
+- struct btrfs_ref generic_ref = { 0 };
+- struct btrfs_fs_info *fs_info = root->fs_info;
++ struct btrfs_fs_info *fs_info = trans->fs_info;
+
+- BUG_ON(owner < BTRFS_FIRST_FREE_OBJECTID &&
+- root_objectid == BTRFS_TREE_LOG_OBJECTID);
++ ASSERT(generic_ref->type != BTRFS_REF_NOT_SET &&
++ generic_ref->action);
++ BUG_ON(generic_ref->type == BTRFS_REF_METADATA &&
++ generic_ref->tree_ref.root == BTRFS_TREE_LOG_OBJECTID);
+
+- btrfs_init_generic_ref(&generic_ref, BTRFS_ADD_DELAYED_REF, bytenr,
+- num_bytes, parent);
+- generic_ref.real_root = root->root_key.objectid;
+- if (owner < BTRFS_FIRST_FREE_OBJECTID) {
+- btrfs_init_tree_ref(&generic_ref, (int)owner, root_objectid);
++ if (generic_ref->type == BTRFS_REF_METADATA)
+ ret = btrfs_add_delayed_tree_ref(fs_info, trans,
+- &generic_ref, NULL,
++ generic_ref, NULL,
+ &old_ref_mod, &new_ref_mod);
+- } else {
+- btrfs_init_data_ref(&generic_ref, root_objectid, owner, offset);
++ else
+ ret = btrfs_add_delayed_data_ref(fs_info, trans,
+- &generic_ref, 0, NULL,
++ generic_ref, 0, NULL,
+ &old_ref_mod, &new_ref_mod);
+- }
+ if (ret == 0 && old_ref_mod < 0 && new_ref_mod >= 0)
+- add_pinned_bytes(fs_info, &generic_ref);
++ add_pinned_bytes(fs_info, generic_ref);
+
+ return ret;
+ }
+@@ -3246,7 +3239,10 @@ static int __btrfs_mod_ref(struct btrfs_
+ u32 nritems;
+ struct btrfs_key key;
+ struct btrfs_file_extent_item *fi;
++ struct btrfs_ref generic_ref = { 0 };
++ bool for_reloc = btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC);
+ int i;
++ int action;
+ int level;
+ int ret = 0;
+
+@@ -3264,6 +3260,10 @@ static int __btrfs_mod_ref(struct btrfs_
+ parent = buf->start;
+ else
+ parent = 0;
++ if (inc)
++ action = BTRFS_ADD_DELAYED_REF;
++ else
++ action = BTRFS_DROP_DELAYED_REF;
+
+ for (i = 0; i < nritems; i++) {
+ if (level == 0) {
+@@ -3281,10 +3281,14 @@ static int __btrfs_mod_ref(struct btrfs_
+
+ num_bytes = btrfs_file_extent_disk_num_bytes(buf, fi);
+ key.offset -= btrfs_file_extent_offset(buf, fi);
++ btrfs_init_generic_ref(&generic_ref, action, bytenr,
++ num_bytes, parent);
++ generic_ref.real_root = root->root_key.objectid;
++ btrfs_init_data_ref(&generic_ref, ref_root, key.objectid,
++ key.offset);
++ generic_ref.skip_qgroup = for_reloc;
+ if (inc)
+- ret = btrfs_inc_extent_ref(trans, root, bytenr,
+- num_bytes, parent, ref_root,
+- key.objectid, key.offset);
++ ret = btrfs_inc_extent_ref(trans, &generic_ref);
+ else
+ ret = btrfs_free_extent(trans, root, bytenr,
+ num_bytes, parent, ref_root,
+@@ -3294,10 +3298,13 @@ static int __btrfs_mod_ref(struct btrfs_
+ } else {
+ bytenr = btrfs_node_blockptr(buf, i);
+ num_bytes = root->nodesize;
++ btrfs_init_generic_ref(&generic_ref, action, bytenr,
++ num_bytes, parent);
++ generic_ref.real_root = root->root_key.objectid;
++ btrfs_init_tree_ref(&generic_ref, level - 1, ref_root);
++ generic_ref.skip_qgroup = for_reloc;
+ if (inc)
+- ret = btrfs_inc_extent_ref(trans, root, bytenr,
+- num_bytes, parent, ref_root,
+- level - 1, 0);
++ ret = btrfs_inc_extent_ref(trans, &generic_ref);
+ else
+ ret = btrfs_free_extent(trans, root, bytenr,
+ num_bytes, parent, ref_root,
+--- a/fs/btrfs/file.c
++++ b/fs/btrfs/file.c
+@@ -698,6 +698,7 @@ int __btrfs_drop_extents(struct btrfs_tr
+ {
+ struct extent_buffer *leaf;
+ struct btrfs_file_extent_item *fi;
++ struct btrfs_ref ref = { 0 };
+ struct btrfs_key key;
+ struct btrfs_key new_key;
+ u64 ino = btrfs_ino(inode);
+@@ -851,11 +852,14 @@ next_slot:
+ btrfs_mark_buffer_dirty(leaf);
+
+ if (update_refs && disk_bytenr > 0) {
+- ret = btrfs_inc_extent_ref(trans, root,
+- disk_bytenr, num_bytes, 0,
++ btrfs_init_generic_ref(&ref,
++ BTRFS_ADD_DELAYED_REF,
++ disk_bytenr, num_bytes, 0);
++ btrfs_init_data_ref(&ref,
+ root->root_key.objectid,
+ new_key.objectid,
+ start - extent_offset);
++ ret = btrfs_inc_extent_ref(trans, &ref);
+ BUG_ON(ret); /* -ENOMEM */
+ }
+ key.offset = start;
+@@ -1077,6 +1081,7 @@ int btrfs_mark_extent_written(struct btr
+ struct extent_buffer *leaf;
+ struct btrfs_path *path;
+ struct btrfs_file_extent_item *fi;
++ struct btrfs_ref ref = { 0 };
+ struct btrfs_key key;
+ struct btrfs_key new_key;
+ u64 bytenr;
+@@ -1222,9 +1227,11 @@ again:
+ extent_end - split);
+ btrfs_mark_buffer_dirty(leaf);
+
+- ret = btrfs_inc_extent_ref(trans, root, bytenr, num_bytes, 0,
+- root->root_key.objectid,
+- ino, orig_offset);
++ btrfs_init_generic_ref(&ref, BTRFS_ADD_DELAYED_REF, bytenr,
++ num_bytes, 0);
++ btrfs_init_data_ref(&ref, root->root_key.objectid, ino,
++ orig_offset);
++ ret = btrfs_inc_extent_ref(trans, &ref);
+ if (ret) {
+ btrfs_abort_transaction(trans, ret);
+ goto out;
+--- a/fs/btrfs/inode.c
++++ b/fs/btrfs/inode.c
+@@ -2507,6 +2507,7 @@ static noinline int relink_extent_backre
+ struct btrfs_file_extent_item *item;
+ struct btrfs_ordered_extent *ordered;
+ struct btrfs_trans_handle *trans;
++ struct btrfs_ref ref = { 0 };
+ struct btrfs_fs_info *fs_info;
+ struct btrfs_root *root;
+ struct btrfs_key key;
+@@ -2679,10 +2680,11 @@ again:
+ inode_add_bytes(inode, len);
+ btrfs_release_path(path);
+
+- ret = btrfs_inc_extent_ref(trans, root, new->bytenr,
+- new->disk_len, 0,
+- backref->root_id, backref->inum,
+- new->file_pos); /* start - extent_offset */
++ btrfs_init_generic_ref(&ref, BTRFS_ADD_DELAYED_REF, new->bytenr,
++ new->disk_len, 0);
++ btrfs_init_data_ref(&ref, backref->root_id, backref->inum,
++ new->file_pos); /* start - extent_offset */
++ ret = btrfs_inc_extent_ref(trans, &ref);
+ if (ret) {
+ btrfs_abort_transaction(trans, ret);
+ goto out_free_path;
+--- a/fs/btrfs/ioctl.c
++++ b/fs/btrfs/ioctl.c
+@@ -3830,12 +3830,17 @@ process_slot:
+ datal);
+
+ if (disko) {
++ struct btrfs_ref ref = { 0 };
++
+ 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);
++ btrfs_init_generic_ref(&ref,
++ BTRFS_ADD_DELAYED_REF, disko,
++ diskl, 0);
++ btrfs_init_data_ref(&ref,
++ root->root_key.objectid,
++ btrfs_ino(inode),
++ new_key.offset - datao);
++ ret = btrfs_inc_extent_ref(trans, &ref);
+ if (ret) {
+ btrfs_abort_transaction(trans,
+ ret);
+--- a/fs/btrfs/relocation.c
++++ b/fs/btrfs/relocation.c
+@@ -1680,6 +1680,8 @@ int replace_file_extents(struct btrfs_tr
+
+ nritems = btrfs_header_nritems(leaf);
+ for (i = 0; i < nritems; i++) {
++ struct btrfs_ref ref = { 0 };
++
+ cond_resched();
+ btrfs_item_key_to_cpu(leaf, &key, i);
+ if (key.type != BTRFS_EXTENT_DATA_KEY)
+@@ -1740,10 +1742,12 @@ int replace_file_extents(struct btrfs_tr
+ dirty = 1;
+
+ key.offset -= btrfs_file_extent_offset(leaf, fi);
+- ret = btrfs_inc_extent_ref(trans, root, new_bytenr,
+- num_bytes, parent,
+- btrfs_header_owner(leaf),
+- key.objectid, key.offset);
++ btrfs_init_generic_ref(&ref, BTRFS_ADD_DELAYED_REF, new_bytenr,
++ num_bytes, parent);
++ ref.real_root = root->root_key.objectid;
++ btrfs_init_data_ref(&ref, btrfs_header_owner(leaf),
++ key.objectid, key.offset);
++ ret = btrfs_inc_extent_ref(trans, &ref);
+ if (ret) {
+ btrfs_abort_transaction(trans, ret);
+ break;
+@@ -1792,6 +1796,7 @@ int replace_path(struct btrfs_trans_hand
+ {
+ struct extent_buffer *eb;
+ struct extent_buffer *parent;
++ struct btrfs_ref ref = { 0 };
+ struct btrfs_key key;
+ u64 old_bytenr;
+ u64 new_bytenr;
+@@ -1950,13 +1955,17 @@ again:
+ path->slots[level], old_ptr_gen);
+ btrfs_mark_buffer_dirty(path->nodes[level]);
+
+- ret = btrfs_inc_extent_ref(trans, src, old_bytenr, blocksize,
+- path->nodes[level]->start,
+- src->root_key.objectid, level - 1, 0);
++ btrfs_init_generic_ref(&ref, BTRFS_ADD_DELAYED_REF, old_bytenr,
++ blocksize, path->nodes[level]->start);
++ ref.skip_qgroup = true;
++ btrfs_init_tree_ref(&ref, level - 1, src->root_key.objectid);
++ ret = btrfs_inc_extent_ref(trans, &ref);
+ BUG_ON(ret);
+- ret = btrfs_inc_extent_ref(trans, dest, new_bytenr, blocksize,
+- 0, dest->root_key.objectid, level - 1,
+- 0);
++ btrfs_init_generic_ref(&ref, BTRFS_ADD_DELAYED_REF, new_bytenr,
++ blocksize, 0);
++ ref.skip_qgroup = true;
++ btrfs_init_tree_ref(&ref, level - 1, dest->root_key.objectid);
++ ret = btrfs_inc_extent_ref(trans, &ref);
+ BUG_ON(ret);
+
+ ret = btrfs_free_extent(trans, src, new_bytenr, blocksize,
+@@ -2758,6 +2767,7 @@ static int do_relocation(struct btrfs_tr
+ rc->backref_cache.path[node->level] = node;
+ list_for_each_entry(edge, &node->upper, list[LOWER]) {
+ struct btrfs_key first_key;
++ struct btrfs_ref ref = { 0 };
+
+ cond_resched();
+
+@@ -2855,11 +2865,13 @@ static int do_relocation(struct btrfs_tr
+ trans->transid);
+ btrfs_mark_buffer_dirty(upper->eb);
+
+- ret = btrfs_inc_extent_ref(trans, root,
+- node->eb->start, blocksize,
+- upper->eb->start,
+- btrfs_header_owner(upper->eb),
+- node->level, 0);
++ btrfs_init_generic_ref(&ref, BTRFS_ADD_DELAYED_REF,
++ node->eb->start, blocksize,
++ upper->eb->start);
++ ref.real_root = root->root_key.objectid;
++ btrfs_init_tree_ref(&ref, node->level,
++ btrfs_header_owner(upper->eb));
++ ret = btrfs_inc_extent_ref(trans, &ref);
+ BUG_ON(ret);
+
+ ret = btrfs_drop_subtree(trans, root, eb, upper->eb);
+--- a/fs/btrfs/tree-log.c
++++ b/fs/btrfs/tree-log.c
+@@ -698,9 +698,11 @@ static noinline int replay_one_extent(st
+ goto out;
+
+ if (ins.objectid > 0) {
++ struct btrfs_ref ref = { 0 };
+ u64 csum_start;
+ u64 csum_end;
+ LIST_HEAD(ordered_sums);
++
+ /*
+ * is this extent already allocated in the extent
+ * allocation tree? If so, just add a reference
+@@ -708,10 +710,13 @@ static noinline int replay_one_extent(st
+ ret = btrfs_lookup_data_extent(root, ins.objectid,
+ ins.offset);
+ if (ret == 0) {
+- ret = btrfs_inc_extent_ref(trans, root,
+- ins.objectid, ins.offset,
+- 0, root->root_key.objectid,
++ btrfs_init_generic_ref(&ref,
++ BTRFS_ADD_DELAYED_REF,
++ ins.objectid, ins.offset, 0);
++ btrfs_init_data_ref(&ref,
++ root->root_key.objectid,
+ key->objectid, offset);
++ ret = btrfs_inc_extent_ref(trans, &ref);
+ if (ret)
+ goto out;
+ } else {
diff --git a/patches.suse/0008-btrfs-extent-tree-Use-btrfs_ref-to-refactor-btrfs_fr.patch b/patches.suse/0008-btrfs-extent-tree-Use-btrfs_ref-to-refactor-btrfs_fr.patch
new file mode 100644
index 0000000000..a03ffdbdd3
--- /dev/null
+++ b/patches.suse/0008-btrfs-extent-tree-Use-btrfs_ref-to-refactor-btrfs_fr.patch
@@ -0,0 +1,258 @@
+From ffd4bb2a19cd29681f5b70a200654ab92619de8a Mon Sep 17 00:00:00 2001
+From: Qu Wenruo <wqu@suse.com>
+Date: Thu, 4 Apr 2019 14:45:36 +0800
+Git-commit: ffd4bb2a19cd29681f5b70a200654ab92619de8a
+Patch-mainline: v5.2-rc1
+References: bsc#1063638 bsc#1128052 bsc#1108838
+Subject: [PATCH 8/9] btrfs: extent-tree: Use btrfs_ref to refactor
+ btrfs_free_extent()
+
+Similar to btrfs_inc_extent_ref(), use btrfs_ref to replace the long
+parameter list and the confusing @owner parameter.
+
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+---
+ fs/btrfs/ctree.h | 5 +----
+ fs/btrfs/extent-tree.c | 46 ++++++++++++++++++----------------------------
+ fs/btrfs/file.c | 22 ++++++++++++----------
+ fs/btrfs/inode.c | 12 ++++++++----
+ fs/btrfs/relocation.c | 25 ++++++++++++++++---------
+ 5 files changed, 55 insertions(+), 55 deletions(-)
+
+--- a/fs/btrfs/ctree.h
++++ b/fs/btrfs/ctree.h
+@@ -2666,10 +2666,7 @@ int btrfs_set_disk_extent_flags(struct b
+ struct btrfs_root *root,
+ u64 bytenr, u64 num_bytes, u64 flags,
+ int level, int is_data);
+-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 btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_ref *ref);
+
+ int btrfs_free_reserved_extent(struct btrfs_root *root, u64 start, u64 len,
+ int delalloc);
+--- a/fs/btrfs/extent-tree.c
++++ b/fs/btrfs/extent-tree.c
+@@ -3290,9 +3290,7 @@ static int __btrfs_mod_ref(struct btrfs_
+ if (inc)
+ ret = btrfs_inc_extent_ref(trans, &generic_ref);
+ else
+- ret = btrfs_free_extent(trans, root, bytenr,
+- num_bytes, parent, ref_root,
+- key.objectid, key.offset);
++ ret = btrfs_free_extent(trans, &generic_ref);
+ if (ret)
+ goto fail;
+ } else {
+@@ -3306,9 +3304,7 @@ static int __btrfs_mod_ref(struct btrfs_
+ if (inc)
+ ret = btrfs_inc_extent_ref(trans, &generic_ref);
+ else
+- ret = btrfs_free_extent(trans, root, bytenr,
+- num_bytes, parent, ref_root,
+- level - 1, 0);
++ ret = btrfs_free_extent(trans, &generic_ref);
+ if (ret)
+ goto fail;
+ }
+@@ -7245,45 +7241,36 @@ 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 btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_ref *ref)
+ {
+ int old_ref_mod, new_ref_mod;
+ int ret;
+- struct btrfs_fs_info *fs_info = root->fs_info;
+- struct btrfs_ref generic_ref = { 0 };
+-
+- if (btrfs_test_is_dummy_root(root))
+- return 0;
++ struct btrfs_fs_info *fs_info = trans->fs_info;
+
+- btrfs_init_generic_ref(&generic_ref, BTRFS_DROP_DELAYED_REF, bytenr,
+- num_bytes, parent);
+- generic_ref.real_root = root->root_key.objectid;
+ /*
+ * tree log blocks never actually go into the extent allocation
+ * tree, just update pinning info and exit early.
+ */
+- if (root_objectid == BTRFS_TREE_LOG_OBJECTID) {
+- WARN_ON(owner >= BTRFS_FIRST_FREE_OBJECTID);
++ if ((ref->type == BTRFS_REF_METADATA &&
++ ref->tree_ref.root == BTRFS_TREE_LOG_OBJECTID) ||
++ (ref->type == BTRFS_REF_DATA &&
++ ref->data_ref.ref_root == BTRFS_TREE_LOG_OBJECTID)) {
+ /* unlocks the pinned mutex */
+- btrfs_pin_extent(root, bytenr, num_bytes, 1);
++ btrfs_pin_extent(fs_info->tree_root, ref->bytenr, ref->len, 1);
+ old_ref_mod = new_ref_mod = 0;
+ ret = 0;
+- } else if (owner < BTRFS_FIRST_FREE_OBJECTID) {
+- btrfs_init_tree_ref(&generic_ref, (int)owner, root_objectid);
++ } else if (ref->type == BTRFS_REF_METADATA) {
+ ret = btrfs_add_delayed_tree_ref(fs_info, trans,
+- &generic_ref, NULL,
++ ref, NULL,
+ &old_ref_mod, &new_ref_mod);
+ } else {
+- btrfs_init_data_ref(&generic_ref, root_objectid, owner, offset);
+ ret = btrfs_add_delayed_data_ref(fs_info, trans,
+- &generic_ref, 0, NULL,
++ ref, 0, NULL,
+ &old_ref_mod, &new_ref_mod);
+ }
+
+ if (ret == 0 && old_ref_mod >= 0 && new_ref_mod < 0)
+- add_pinned_bytes(fs_info, &generic_ref);
++ add_pinned_bytes(fs_info, ref);
+
+ return ret;
+ }
+@@ -8680,6 +8667,7 @@ static noinline int do_walk_down(struct
+ u32 blocksize;
+ struct btrfs_key key;
+ struct btrfs_key first_key;
++ struct btrfs_ref ref = { 0 };
+ struct extent_buffer *next;
+ int level = wc->level;
+ int reada = 0;
+@@ -8826,8 +8814,10 @@ skip:
+ ret);
+ }
+ }
+- ret = btrfs_free_extent(trans, root, bytenr, blocksize, parent,
+- root->root_key.objectid, level - 1, 0);
++ btrfs_init_generic_ref(&ref, BTRFS_DROP_DELAYED_REF, bytenr,
++ root->nodesize, parent);
++ btrfs_init_tree_ref(&ref, level - 1, root->root_key.objectid);
++ ret = btrfs_free_extent(trans, &ref);
+ if (ret)
+ goto out_unlock;
+ }
+--- a/fs/btrfs/file.c
++++ b/fs/btrfs/file.c
+@@ -933,11 +933,14 @@ delete_extent_item:
+ extent_end = ALIGN(extent_end,
+ root->sectorsize);
+ } else if (update_refs && disk_bytenr > 0) {
+- ret = btrfs_free_extent(trans, root,
+- disk_bytenr, num_bytes, 0,
++ btrfs_init_generic_ref(&ref,
++ BTRFS_DROP_DELAYED_REF,
++ disk_bytenr, num_bytes, 0);
++ btrfs_init_data_ref(&ref,
+ root->root_key.objectid,
+- key.objectid, key.offset -
+- extent_offset);
++ key.objectid,
++ key.offset - extent_offset);
++ ret = btrfs_free_extent(trans, &ref);
+ BUG_ON(ret); /* -ENOMEM */
+ inode_sub_bytes(inode,
+ extent_end - key.offset);
+@@ -1253,6 +1256,9 @@ again:
+
+ other_start = end;
+ other_end = 0;
++ btrfs_init_generic_ref(&ref, BTRFS_DROP_DELAYED_REF, bytenr,
++ num_bytes, 0);
++ btrfs_init_data_ref(&ref, root->root_key.objectid, ino, orig_offset);
+ if (extent_mergeable(leaf, path->slots[0] + 1,
+ ino, bytenr, orig_offset,
+ &other_start, &other_end)) {
+@@ -1263,9 +1269,7 @@ again:
+ extent_end = other_end;
+ del_slot = path->slots[0] + 1;
+ del_nr++;
+- ret = btrfs_free_extent(trans, root, bytenr, num_bytes,
+- 0, root->root_key.objectid,
+- ino, orig_offset);
++ ret = btrfs_free_extent(trans, &ref);
+ if (ret) {
+ btrfs_abort_transaction(trans, ret);
+ goto out;
+@@ -1283,9 +1287,7 @@ again:
+ key.offset = other_start;
+ del_slot = path->slots[0];
+ del_nr++;
+- ret = btrfs_free_extent(trans, root, bytenr, num_bytes,
+- 0, root->root_key.objectid,
+- ino, orig_offset);
++ ret = btrfs_free_extent(trans, &ref);
+ if (ret) {
+ btrfs_abort_transaction(trans, ret);
+ goto out;
+--- a/fs/btrfs/inode.c
++++ b/fs/btrfs/inode.c
+@@ -4643,12 +4643,16 @@ delete:
+ if (found_extent &&
+ (test_bit(BTRFS_ROOT_REF_COWS, &root->state) ||
+ root == root->fs_info->tree_root)) {
++ struct btrfs_ref ref = { 0 };
++
+ btrfs_set_path_blocking(path);
+ bytes_deleted += extent_num_bytes;
+- ret = btrfs_free_extent(trans, root, extent_start,
+- extent_num_bytes, 0,
+- btrfs_header_owner(leaf),
+- ino, extent_offset);
++ btrfs_init_generic_ref(&ref, BTRFS_DROP_DELAYED_REF,
++ extent_start, extent_num_bytes, 0);
++ ref.real_root = root->root_key.objectid;
++ btrfs_init_data_ref(&ref, btrfs_header_owner(leaf),
++ ino, extent_offset);
++ ret = btrfs_free_extent(trans, &ref);
+ BUG_ON(ret);
+ if (btrfs_should_throttle_delayed_refs(trans, root))
+ btrfs_async_run_delayed_refs(root,
+--- a/fs/btrfs/relocation.c
++++ b/fs/btrfs/relocation.c
+@@ -1753,9 +1753,12 @@ int replace_file_extents(struct btrfs_tr
+ break;
+ }
+
+- ret = btrfs_free_extent(trans, root, bytenr, num_bytes,
+- parent, btrfs_header_owner(leaf),
+- key.objectid, key.offset);
++ btrfs_init_generic_ref(&ref, BTRFS_DROP_DELAYED_REF, bytenr,
++ num_bytes, parent);
++ ref.real_root = root->root_key.objectid;
++ btrfs_init_data_ref(&ref, btrfs_header_owner(leaf),
++ key.objectid, key.offset);
++ ret = btrfs_free_extent(trans, &ref);
+ if (ret) {
+ btrfs_abort_transaction(trans, ret);
+ break;
+@@ -1968,14 +1971,18 @@ again:
+ ret = btrfs_inc_extent_ref(trans, &ref);
+ BUG_ON(ret);
+
+- ret = btrfs_free_extent(trans, src, new_bytenr, blocksize,
+- path->nodes[level]->start,
+- src->root_key.objectid, level - 1, 0);
++ btrfs_init_generic_ref(&ref, BTRFS_DROP_DELAYED_REF, new_bytenr,
++ blocksize, path->nodes[level]->start);
++ btrfs_init_tree_ref(&ref, level - 1, src->root_key.objectid);
++ ref.skip_qgroup = true;
++ ret = btrfs_free_extent(trans, &ref);
+ BUG_ON(ret);
+
+- ret = btrfs_free_extent(trans, dest, old_bytenr, blocksize,
+- 0, dest->root_key.objectid, level - 1,
+- 0);
++ btrfs_init_generic_ref(&ref, BTRFS_DROP_DELAYED_REF, old_bytenr,
++ blocksize, 0);
++ btrfs_init_tree_ref(&ref, level - 1, dest->root_key.objectid);
++ ref.skip_qgroup = true;
++ ret = btrfs_free_extent(trans, &ref);
+ BUG_ON(ret);
+
+ btrfs_unlock_up_safe(path, 0);
diff --git a/patches.suse/0009-btrfs-qgroup-Don-t-scan-leaf-if-we-re-modifying-relo.patch b/patches.suse/0009-btrfs-qgroup-Don-t-scan-leaf-if-we-re-modifying-relo.patch
new file mode 100644
index 0000000000..a036863c8e
--- /dev/null
+++ b/patches.suse/0009-btrfs-qgroup-Don-t-scan-leaf-if-we-re-modifying-relo.patch
@@ -0,0 +1,67 @@
+From c4140cbf35b90422be6589024f47e132eb2298b1 Mon Sep 17 00:00:00 2001
+From: Qu Wenruo <wqu@suse.com>
+Date: Thu, 4 Apr 2019 14:45:37 +0800
+Git-commit: c4140cbf35b90422be6589024f47e132eb2298b1
+Patch-mainline: v5.2-rc1
+References: bsc#1063638 bsc#1128052 bsc#1108838
+Subject: [PATCH 9/9] btrfs: qgroup: Don't scan leaf if we're modifying reloc
+ tree
+
+Since reloc tree doesn't contribute to qgroup numbers, just skip them.
+
+This should catch the final cause of unnecessary data ref processing
+when running balance of metadata with qgroups on.
+
+The 4G data 16 snapshots test (*) should explain it pretty well:
+
+ | delayed subtree | refactor delayed ref | this patch
+---------------------------------------------------------------------
+relocated | 22653 | 22673 | 22744
+qgroup dirty | 122792 | 48360 | 70
+time | 24.494 | 11.606 | 3.944
+
+Finally, we're at the stage where qgroup + metadata balance cost no
+obvious overhead.
+
+Test environment:
+
+Test VM:
+- vRAM 8G
+- vCPU 8
+- block dev vitrio-blk, 'unsafe' cache mode
+- host block 850evo
+
+Test workload:
+- Copy 4G data from /usr/ to one subvolume
+- Create 16 snapshots of that subvolume, and modify 3 files in each
+ snapshot
+- Enable quota, rescan
+- Time "btrfs balance start -m"
+
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+---
+ fs/btrfs/extent-tree.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+--- a/fs/btrfs/extent-tree.c
++++ b/fs/btrfs/extent-tree.c
+@@ -8906,11 +8906,13 @@ static noinline int walk_up_proc(struct
+ else
+ ret = btrfs_dec_ref(trans, root, eb, 0);
+ BUG_ON(ret); /* -ENOMEM */
+- ret = btrfs_qgroup_trace_leaf_items(trans, root, eb);
+- if (ret) {
+- btrfs_err_rl(root->fs_info,
+- "error %d accounting leaf items. Quota is out of sync, rescan required.",
+- ret);
++ if (is_fstree(root->root_key.objectid)) {
++ ret = btrfs_qgroup_trace_leaf_items(trans, root, eb);
++ if (ret) {
++ btrfs_err_rl(root->fs_info,
++ "error %d accounting leaf items. Quota is out of sync, rescan required.",
++ ret);
++ }
+ }
+ }
+ /* make block locked assertion in clean_tree_block happy */
diff --git a/series.conf b/series.conf
index 2bfd74ed52..ef90ef8342 100644
--- a/series.conf
+++ b/series.conf
@@ -25340,6 +25340,14 @@
patches.arch/s390-speculation-support-mitigations-cmdline-option.patch
patches.fixes/0001-btrfs-Don-t-panic-when-we-can-t-find-a-root-key.patch
patches.fixes/0001-btrfs-reloc-Fix-NULL-pointer-dereference-due-to-expa.patch
+ patches.suse/0001-btrfs-delayed-ref-Introduce-better-documented-delaye.patch
+ patches.suse/0002-btrfs-extent-tree-Open-code-process_func-in-__btrfs_.patch
+ patches.suse/0003-btrfs-delayed-ref-Use-btrfs_ref-to-refactor-btrfs_ad.patch
+ patches.suse/0004-btrfs-delayed-ref-Use-btrfs_ref-to-refactor-btrfs_ad.patch
+ patches.suse/0006-btrfs-extent-tree-Use-btrfs_ref-to-refactor-add_pinn.patch
+ patches.suse/0007-btrfs-extent-tree-Use-btrfs_ref-to-refactor-btrfs_in.patch
+ patches.suse/0008-btrfs-extent-tree-Use-btrfs_ref-to-refactor-btrfs_fr.patch
+ patches.suse/0009-btrfs-qgroup-Don-t-scan-leaf-if-we-re-modifying-relo.patch
patches.fixes/block-disk_events-introduce-event-flags.patch
patches.fixes/Revert-ide-unexport-DISK_EVENT_MEDIA_CHANGE-for-ide-.patch
patches.fixes/Revert-block-unexport-DISK_EVENT_MEDIA_CHANGE-for-le.patch
@@ -25381,6 +25389,7 @@
# out-of-tree patches
patches.kabi/0001-move-power_up_on_resume-flag-to-end-of-structure-for.patch
patches.suse/0001-drm-ttm-Remove-warning-about-inconsistent-mapping-in.patch
+ patches.fixes/0001-btrfs-extent-tree-Fix-a-bug-that-btrfs-is-unable-to-.patch
########################################################
# end of sorted patches