@@ -728,26 +728,51 @@ static int btrfs_statfs(struct dentry *dentry,
struct kstatfs *buf)
struct btrfs_super_block *disk_super = &root->fs_info->super_copy;
struct list_head *head = &root->fs_info->space_info;
struct btrfs_space_info *found;
- u64 total_used = 0;
- u64 total_used_data = 0;
+ int factor = 1;
+ u64 metadata_fuzz;
+ u64 pool_free = 0;
+ u64 data_avail = 0;
+ u64 data_used = 0;
int bits = dentry->d_sb->s_blocksize_bits;
__be32 *fsid = (__be32 *)root->fs_info->fsid;
rcu_read_lock();
list_for_each_entry_rcu(found, head, list) {
if (found->flags & (BTRFS_BLOCK_GROUP_METADATA |
- BTRFS_BLOCK_GROUP_SYSTEM))
- total_used_data += found->disk_total;
- else
- total_used_data += found->disk_used;
- total_used += found->disk_used;
+ BTRFS_BLOCK_GROUP_SYSTEM)) {
+ /* This is space that could be used for data in a pinch,
+ report it as such. */
+ data_avail += found->total_bytes - found->bytes_used;
+ } else {
+ data_avail += found->total_bytes;
+ data_used += found->bytes_used;
+
+ if (found->flags & (BTRFS_BLOCK_GROUP_DUP |
+ BTRFS_BLOCK_GROUP_RAID1 |
+ BTRFS_BLOCK_GROUP_RAID10))
+ factor = 2;
+ }
+
+ pool_free += found->disk_total;
}
rcu_read_unlock();
+ pool_free = btrfs_super_total_bytes(disk_super) - pool_free;
+ do_div(pool_free, factor);
+
+ /* Estimate ~3% of the free pool will go to metadata */
+ metadata_fuzz = pool_free;
+ do_div(metadata_fuzz, 32);
+
+ /* Reported sizes in terms of how much data can fit in files. Metadata
+ size is reflected by the difference between the reported size and
+ the actual size of the partition. We're interested directly useful
+ numbers, even if they don't reflect the particulars: that's what
+ the df ioctl is for. */
buf->f_namelen = BTRFS_NAME_LEN;
- buf->f_blocks = btrfs_super_total_bytes(disk_super) >> bits;
- buf->f_bfree = buf->f_blocks - (total_used >> bits);
- buf->f_bavail = buf->f_blocks - (total_used_data >> bits);
+ buf->f_blocks = (pool_free + data_avail - metadata_fuzz) >> bits;
+ buf->f_bfree = buf->f_blocks - (data_used >> bits);
+ buf->f_bavail = buf->f_bfree;
buf->f_bsize = dentry->d_sb->s_blocksize;
buf->f_type = BTRFS_SUPER_MAGIC;