summaryrefslogtreecommitdiff
path: root/fs/btrfs/super.c
diff options
context:
space:
mode:
authorDavid Sterba <dsterba@suse.com>2016-05-16 15:46:23 +0200
committerDavid Sterba <dsterba@suse.com>2016-05-16 15:46:23 +0200
commit73d32ce21e1701eaafcea3cbc2a8f27ab1967abe (patch)
tree136c03e4be575e4466ef9df119b8debdf768a56a /fs/btrfs/super.c
parent02da2d72174c61988eb4456b53f405e3ebdebce4 (diff)
parent4673272f43ae790ab9ec04e38a7542f82bb8f020 (diff)
Merge branch 'misc-4.7' into for-chris-4.7-20160516
Diffstat (limited to 'fs/btrfs/super.c')
-rw-r--r--fs/btrfs/super.c22
1 files changed, 18 insertions, 4 deletions
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 00b8f37cc306..fe03efb5bec0 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -2051,6 +2051,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
@@ -2076,8 +2077,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;
}
@@ -2090,7 +2100,11 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
/* Account global block reserve as used, it's in logical size already */
spin_lock(&block_rsv->lock);
- buf->f_bfree -= block_rsv->size >> bits;
+ /* Mixed block groups accounting is not byte-accurate, avoid overflow */
+ if (buf->f_bfree >= block_rsv->size >> bits)
+ buf->f_bfree -= block_rsv->size >> bits;
+ else
+ buf->f_bfree = 0;
spin_unlock(&block_rsv->lock);
buf->f_bavail = div_u64(total_free_data, factor);
@@ -2115,7 +2129,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;