--- /dev/null
+From 4311e198e8c8ee86d37e42046500a8b8d9b6bd1f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jan 2020 09:31:05 -0500
+Subject: btrfs: do not zero f_bavail if we have available space
+
+From: Josef Bacik <josef@toxicpanda.com>
+
+[ Upstream commit d55966c4279bfc6a0cf0b32bf13f5df228a1eeb6 ]
+
+There was some logic added a while ago to clear out f_bavail in statfs()
+if we did not have enough free metadata space to satisfy our global
+reserve. This was incorrect at the time, however didn't really pose a
+problem for normal file systems because we would often allocate chunks
+if we got this low on free metadata space, and thus wouldn't really hit
+this case unless we were actually full.
+
+Fast forward to today and now we are much better about not allocating
+metadata chunks all of the time. Couple this with d792b0f19711 ("btrfs:
+always reserve our entire size for the global reserve") which now means
+we'll easily have a larger global reserve than our free space, we are
+now more likely to trip over this while still having plenty of space.
+
+Fix this by skipping this logic if the global rsv's space_info is not
+full. space_info->full is 0 unless we've attempted to allocate a chunk
+for that space_info and that has failed. If this happens then the space
+for the global reserve is definitely sacred and we need to report
+b_avail == 0, but before then we can just use our calculated b_avail.
+
+Reported-by: Martin Steigerwald <martin@lichtvoll.de>
+Fixes: ca8a51b3a979 ("btrfs: statfs: report zero available if metadata are exhausted")
+CC: stable@vger.kernel.org # 4.5+
+Reviewed-by: Qu Wenruo <wqu@suse.com>
+Tested-By: Martin Steigerwald <martin@lichtvoll.de>
+Signed-off-by: Josef Bacik <josef@toxicpanda.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/super.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
+index fd98802bee90c..df211bad255c7 100644
+--- a/fs/btrfs/super.c
++++ b/fs/btrfs/super.c
+@@ -2052,7 +2052,15 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
+ */
+ thresh = 4 * 1024 * 1024;
+
+- if (!mixed && total_free_meta - thresh < block_rsv->size)
++ /*
++ * We only want to claim there's no available space if we can no longer
++ * allocate chunks for our metadata profile and our global reserve will
++ * not fit in the free metadata space. If we aren't ->full then we
++ * still can allocate chunks and thus are fine using the currently
++ * calculated f_bavail.
++ */
++ if (!mixed && block_rsv->space_info->full &&
++ total_free_meta - thresh < block_rsv->size)
+ buf->f_bavail = 0;
+
+ buf->f_type = BTRFS_SUPER_MAGIC;
+--
+2.20.1
+
--- /dev/null
+From ce7b786533bdcea27a4e46f03ffd7df377de2682 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 30 Mar 2016 21:53:38 +0100
+Subject: btrfs: fix mixed block count of available space
+
+From: Luis de Bethencourt <luisbg@osg.samsung.com>
+
+[ Upstream commit ae02d1bd070767e109f4a6f1bb1f466e9698a355 ]
+
+Metadata for mixed block is already accounted in total data and should not
+be counted as part of the free metadata space.
+
+Signed-off-by: Luis de Bethencourt <luisbg@osg.samsung.com>
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=114281
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/super.c | 16 +++++++++++++---
+ 1 file changed, 13 insertions(+), 3 deletions(-)
+
+diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
+index 0f99336c37eb4..fd98802bee90c 100644
+--- a/fs/btrfs/super.c
++++ b/fs/btrfs/super.c
+@@ -1978,6 +1978,7 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
+ struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv;
+ int ret;
+ u64 thresh = 0;
++ int mixed = 0;
+
+ /*
+ * holding chunk_muext to avoid allocating new chunks, holding
+@@ -2003,8 +2004,17 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
+ }
+ }
+ }
+- if (found->flags & BTRFS_BLOCK_GROUP_METADATA)
+- total_free_meta += found->disk_total - found->disk_used;
++
++ /*
++ * Metadata in mixed block goup profiles are accounted in data
++ */
++ if (!mixed && found->flags & BTRFS_BLOCK_GROUP_METADATA) {
++ if (found->flags & BTRFS_BLOCK_GROUP_DATA)
++ mixed = 1;
++ else
++ total_free_meta += found->disk_total -
++ found->disk_used;
++ }
+
+ total_used += found->disk_used;
+ }
+@@ -2042,7 +2052,7 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
+ */
+ thresh = 4 * 1024 * 1024;
+
+- if (total_free_meta - thresh < block_rsv->size)
++ if (!mixed && total_free_meta - thresh < block_rsv->size)
+ buf->f_bavail = 0;
+
+ buf->f_type = BTRFS_SUPER_MAGIC;
+--
+2.20.1
+