diff mbox

Make df report effective sizes, not physical sizes

Message ID AANLkTikE0b8h9H=DPPXGGYhQAd8kSzvQud8DJSFm0-Cx@mail.gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

cwillu Oct. 20, 2010, 11:19 a.m. UTC
None
diff mbox

Patch

diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index ea06877..81d5285 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -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;