From ae02d1bd070767e109f4a6f1bb1f466e9698a355 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Wed, 30 Mar 2016 21:53:38 +0100 Subject: btrfs: fix mixed block count of available space 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 Link: https://bugzilla.kernel.org/show_bug.cgi?id=114281 Signed-off-by: David Sterba --- fs/btrfs/super.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'fs/btrfs/super.c') diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 00b8f37cc306..bdca79ce45f1 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; } @@ -2115,7 +2125,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; -- cgit v1.2.3-70-g09d2 From 41b34accb265e3a20211a7a8ef3625678f1c6ec7 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Wed, 30 Mar 2016 23:18:14 +0100 Subject: btrfs: avoid overflowing f_bfree Since mixed block groups accounting isn't byte-accurate and f_bree is an unsigned integer, it could overflow. Avoid this. Signed-off-by: Luis de Bethencourt Suggested-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/super.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'fs/btrfs/super.c') diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index bdca79ce45f1..fe03efb5bec0 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -2100,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); -- cgit v1.2.3-70-g09d2