aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorDavid Sterba <dsterba@suse.cz>2014-07-01 10:21:33 -0400
committerChris Mason <clm@fb.com>2014-08-15 10:43:10 -0400
commitba7b6e62f420f5a8832bc161ab0c7ba767f65b3d (patch)
tree7ecd471565cba20fd416ec2bcfbc527ca260fb27 /fs/btrfs
parent19583ca584d6f574384e17fe7613dfaeadcdc4a6 (diff)
btrfs: adjust statfs calculations according to raid profiles
This has been discussed in thread: http://thread.gmane.org/gmane.comp.file-systems.btrfs/32528 and this patch implements this proposal: http://thread.gmane.org/gmane.comp.file-systems.btrfs/32536 Works fine for "clean" raid profiles where the raid factor correction does the right job. Otherwise it's pessimistic and may show low space although there's still some left. The df nubmers are lightly wrong in case of mixed block groups, but this is not a major usecase and can be addressed later. The RAID56 numbers are wrong almost the same way as before and will be addressed separately. CC: Hugo Mills <hugo@carfax.org.uk> CC: cwillu <cwillu@cwillu.com> CC: Josef Bacik <jbacik@fb.com> Signed-off-by: David Sterba <dsterba@suse.cz> Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/super.c51
1 files changed, 45 insertions, 6 deletions
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 8e16bca69c56..18cdcd1dbe11 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -1672,6 +1672,21 @@ static int btrfs_calc_avail_data_space(struct btrfs_root *root, u64 *free_bytes)
1672 return 0; 1672 return 0;
1673} 1673}
1674 1674
1675/*
1676 * Calculate numbers for 'df', pessimistic in case of mixed raid profiles.
1677 *
1678 * If there's a redundant raid level at DATA block groups, use the respective
1679 * multiplier to scale the sizes.
1680 *
1681 * Unused device space usage is based on simulating the chunk allocator
1682 * algorithm that respects the device sizes, order of allocations and the
1683 * 'alloc_start' value, this is a close approximation of the actual use but
1684 * there are other factors that may change the result (like a new metadata
1685 * chunk).
1686 *
1687 * FIXME: not accurate for mixed block groups, total and free/used are ok,
1688 * available appears slightly larger.
1689 */
1675static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) 1690static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
1676{ 1691{
1677 struct btrfs_fs_info *fs_info = btrfs_sb(dentry->d_sb); 1692 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)
1682 u64 total_free_data = 0; 1697 u64 total_free_data = 0;
1683 int bits = dentry->d_sb->s_blocksize_bits; 1698 int bits = dentry->d_sb->s_blocksize_bits;
1684 __be32 *fsid = (__be32 *)fs_info->fsid; 1699 __be32 *fsid = (__be32 *)fs_info->fsid;
1700 unsigned factor = 1;
1701 struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv;
1685 int ret; 1702 int ret;
1686 1703
1687 /* holding chunk_muext to avoid allocating new chunks */ 1704 /* holding chunk_muext to avoid allocating new chunks */
@@ -1689,30 +1706,52 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
1689 rcu_read_lock(); 1706 rcu_read_lock();
1690 list_for_each_entry_rcu(found, head, list) { 1707 list_for_each_entry_rcu(found, head, list) {
1691 if (found->flags & BTRFS_BLOCK_GROUP_DATA) { 1708 if (found->flags & BTRFS_BLOCK_GROUP_DATA) {
1709 int i;
1710
1692 total_free_data += found->disk_total - found->disk_used; 1711 total_free_data += found->disk_total - found->disk_used;
1693 total_free_data -= 1712 total_free_data -=
1694 btrfs_account_ro_block_groups_free_space(found); 1713 btrfs_account_ro_block_groups_free_space(found);
1714
1715 for (i = 0; i < BTRFS_NR_RAID_TYPES; i++) {
1716 if (!list_empty(&found->block_groups[i])) {
1717 switch (i) {
1718 case BTRFS_RAID_DUP:
1719 case BTRFS_RAID_RAID1:
1720 case BTRFS_RAID_RAID10:
1721 factor = 2;
1722 }
1723 }
1724 }
1695 } 1725 }
1696 1726
1697 total_used += found->disk_used; 1727 total_used += found->disk_used;
1698 } 1728 }
1729
1699 rcu_read_unlock(); 1730 rcu_read_unlock();
1700 1731
1701 buf->f_namelen = BTRFS_NAME_LEN; 1732 buf->f_blocks = div_u64(btrfs_super_total_bytes(disk_super), factor);
1702 buf->f_blocks = btrfs_super_total_bytes(disk_super) >> bits; 1733 buf->f_blocks >>= bits;
1703 buf->f_bfree = buf->f_blocks - (total_used >> bits); 1734 buf->f_bfree = buf->f_blocks - (div_u64(total_used, factor) >> bits);
1704 buf->f_bsize = dentry->d_sb->s_blocksize; 1735
1705 buf->f_type = BTRFS_SUPER_MAGIC; 1736 /* Account global block reserve as used, it's in logical size already */
1737 spin_lock(&block_rsv->lock);
1738 buf->f_bfree -= block_rsv->size >> bits;
1739 spin_unlock(&block_rsv->lock);
1740
1706 buf->f_bavail = total_free_data; 1741 buf->f_bavail = total_free_data;
1707 ret = btrfs_calc_avail_data_space(fs_info->tree_root, &total_free_data); 1742 ret = btrfs_calc_avail_data_space(fs_info->tree_root, &total_free_data);
1708 if (ret) { 1743 if (ret) {
1709 mutex_unlock(&fs_info->chunk_mutex); 1744 mutex_unlock(&fs_info->chunk_mutex);
1710 return ret; 1745 return ret;
1711 } 1746 }
1712 buf->f_bavail += total_free_data; 1747 buf->f_bavail += div_u64(total_free_data, factor);
1713 buf->f_bavail = buf->f_bavail >> bits; 1748 buf->f_bavail = buf->f_bavail >> bits;
1714 mutex_unlock(&fs_info->chunk_mutex); 1749 mutex_unlock(&fs_info->chunk_mutex);
1715 1750
1751 buf->f_type = BTRFS_SUPER_MAGIC;
1752 buf->f_bsize = dentry->d_sb->s_blocksize;
1753 buf->f_namelen = BTRFS_NAME_LEN;
1754
1716 /* We treat it as constant endianness (it doesn't matter _which_) 1755 /* We treat it as constant endianness (it doesn't matter _which_)
1717 because we want the fsid to come out the same whether mounted 1756 because we want the fsid to come out the same whether mounted
1718 on a big-endian or little-endian host */ 1757 on a big-endian or little-endian host */