|
@@ -1672,6 +1672,21 @@ static int btrfs_calc_avail_data_space(struct btrfs_root *root, u64 *free_bytes)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Calculate numbers for 'df', pessimistic in case of mixed raid profiles.
|
|
|
+ *
|
|
|
+ * If there's a redundant raid level at DATA block groups, use the respective
|
|
|
+ * multiplier to scale the sizes.
|
|
|
+ *
|
|
|
+ * Unused device space usage is based on simulating the chunk allocator
|
|
|
+ * algorithm that respects the device sizes, order of allocations and the
|
|
|
+ * 'alloc_start' value, this is a close approximation of the actual use but
|
|
|
+ * there are other factors that may change the result (like a new metadata
|
|
|
+ * chunk).
|
|
|
+ *
|
|
|
+ * FIXME: not accurate for mixed block groups, total and free/used are ok,
|
|
|
+ * available appears slightly larger.
|
|
|
+ */
|
|
|
static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|
|
{
|
|
|
struct btrfs_fs_info *fs_info = btrfs_sb(dentry->d_sb);
|
|
@@ -1682,6 +1697,8 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|
|
u64 total_free_data = 0;
|
|
|
int bits = dentry->d_sb->s_blocksize_bits;
|
|
|
__be32 *fsid = (__be32 *)fs_info->fsid;
|
|
|
+ unsigned factor = 1;
|
|
|
+ struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv;
|
|
|
int ret;
|
|
|
|
|
|
/* holding chunk_muext to avoid allocating new chunks */
|
|
@@ -1689,30 +1706,52 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|
|
rcu_read_lock();
|
|
|
list_for_each_entry_rcu(found, head, list) {
|
|
|
if (found->flags & BTRFS_BLOCK_GROUP_DATA) {
|
|
|
+ int i;
|
|
|
+
|
|
|
total_free_data += found->disk_total - found->disk_used;
|
|
|
total_free_data -=
|
|
|
btrfs_account_ro_block_groups_free_space(found);
|
|
|
+
|
|
|
+ for (i = 0; i < BTRFS_NR_RAID_TYPES; i++) {
|
|
|
+ if (!list_empty(&found->block_groups[i])) {
|
|
|
+ switch (i) {
|
|
|
+ case BTRFS_RAID_DUP:
|
|
|
+ case BTRFS_RAID_RAID1:
|
|
|
+ case BTRFS_RAID_RAID10:
|
|
|
+ factor = 2;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
total_used += found->disk_used;
|
|
|
}
|
|
|
+
|
|
|
rcu_read_unlock();
|
|
|
|
|
|
- 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_bsize = dentry->d_sb->s_blocksize;
|
|
|
- buf->f_type = BTRFS_SUPER_MAGIC;
|
|
|
+ buf->f_blocks = div_u64(btrfs_super_total_bytes(disk_super), factor);
|
|
|
+ buf->f_blocks >>= bits;
|
|
|
+ buf->f_bfree = buf->f_blocks - (div_u64(total_used, factor) >> bits);
|
|
|
+
|
|
|
+ /* Account global block reserve as used, it's in logical size already */
|
|
|
+ spin_lock(&block_rsv->lock);
|
|
|
+ buf->f_bfree -= block_rsv->size >> bits;
|
|
|
+ spin_unlock(&block_rsv->lock);
|
|
|
+
|
|
|
buf->f_bavail = total_free_data;
|
|
|
ret = btrfs_calc_avail_data_space(fs_info->tree_root, &total_free_data);
|
|
|
if (ret) {
|
|
|
mutex_unlock(&fs_info->chunk_mutex);
|
|
|
return ret;
|
|
|
}
|
|
|
- buf->f_bavail += total_free_data;
|
|
|
+ buf->f_bavail += div_u64(total_free_data, factor);
|
|
|
buf->f_bavail = buf->f_bavail >> bits;
|
|
|
mutex_unlock(&fs_info->chunk_mutex);
|
|
|
|
|
|
+ buf->f_type = BTRFS_SUPER_MAGIC;
|
|
|
+ buf->f_bsize = dentry->d_sb->s_blocksize;
|
|
|
+ buf->f_namelen = BTRFS_NAME_LEN;
|
|
|
+
|
|
|
/* We treat it as constant endianness (it doesn't matter _which_)
|
|
|
because we want the fsid to come out the same whether mounted
|
|
|
on a big-endian or little-endian host */
|