diff mbox

[V2] Re: Provide a better free space estimate on RAID1

Message ID 52F65D09.3030400@libero.it (mailing list archive)
State New, archived
Headers show

Commit Message

Goffredo Baroncelli Feb. 8, 2014, 4:36 p.m. UTC
On 02/07/2014 05:40 AM, Roman Mamedov wrote:
> On Thu, 06 Feb 2014 20:54:19 +0100
> Goffredo Baroncelli <kreijack@libero.it> wrote:
> 
[...]

Even I am not entirely convinced, I update the Roman's PoC in order
to take in account all the RAID levels.

The filesystem test is composed by 7 51GB disks. Here my "df" results:

Profile: single
Filesystem                          Size  Used Avail Use% Mounted on
/dev/vdc                            351G  512K  348G   1% /mnt/btrfs1

Profile: raid1
Filesystem                          Size  Used Avail Use% Mounted on
/dev/vdc                            351G  1.3M  150G   1% /mnt/btrfs1

Profile: raid10
Filesystem                          Size  Used Avail Use% Mounted on
/dev/vdc                            351G  2.3M  153G   1% /mnt/btrfs1

Profile: raid5
Filesystem                          Size  Used Avail Use% Mounted on
/dev/vdc                            351G  2.0M  298G   1% /mnt/btrfs1

Profile: raid6
Filesystem                          Size  Used Avail Use% Mounted on
/dev/vdc                            351G  1.8M  248G   1% /mnt/btrfs1


Note that RAID1 and RAID10 can only use an even number of disks.
The mixing mode (data and metadata in the same chunk) 
return strange results.

Below my patch.

BR
G.Baroncelli

Changes history:
V1	First issue
V2	Correct a (old) bug when in RAID10 the disks aren't 
        a multiple of 4
diff mbox

Patch

diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index d71a11d..aea9afa 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -1481,10 +1481,16 @@  static int btrfs_calc_avail_data_space(struct btrfs_root *root, u64 *free_bytes)
                num_stripes = nr_devices;
        } else if (type & BTRFS_BLOCK_GROUP_RAID1) {
                min_stripes = 2;
-               num_stripes = 2;
+               num_stripes = nr_devices & ~1llu;
        } else if (type & BTRFS_BLOCK_GROUP_RAID10) {
                min_stripes = 4;
-               num_stripes = 4;
+               num_stripes = nr_devices & ~1llu;
+       } else if (type & BTRFS_BLOCK_GROUP_RAID5) {
+               min_stripes = 3;
+               num_stripes = nr_devices;
+       } else if (type & BTRFS_BLOCK_GROUP_RAID6) {
+               min_stripes = 4;
+               num_stripes = nr_devices;
        }
 
        if (type & BTRFS_BLOCK_GROUP_DUP)
@@ -1561,8 +1567,30 @@  static int btrfs_calc_avail_data_space(struct btrfs_root *root, u64 *free_bytes)
                if (devices_info[i].max_avail >= min_stripe_size) {
                        int j;
                        u64 alloc_size;
+                       int k;
 
-                       avail_space += devices_info[i].max_avail * num_stripes;
+                       /*
+                        * Depending by the RAID profile, we use some
+                        * disk space as redundancy:
+                        * RAID1, RAID10, DUP -> half of space used as redundancy
+                        * RAID5              -> 1 stripe used as redundancy
+                        * RAID6              -> 2 stripes used as redundancy
+                        * RAID0,LINEAR       -> no redundancy
+                        */
+                       if (type & BTRFS_BLOCK_GROUP_RAID1) {
+                               k = num_stripes >> 1;
+                       } else if (type & BTRFS_BLOCK_GROUP_DUP) {
+                               k = num_stripes >> 1;
+                       } else if (type & BTRFS_BLOCK_GROUP_RAID10) {
+                               k = num_stripes >> 1;
+                       } else if (type & BTRFS_BLOCK_GROUP_RAID5) {
+                               k = num_stripes-1;
+                       } else if (type & BTRFS_BLOCK_GROUP_RAID6) {
+                               k = num_stripes-2;
+                       } else { /* RAID0/LINEAR */
+                               k = num_stripes;
+                       }
+                       avail_space += devices_info[i].max_avail * k;
                        alloc_size = devices_info[i].max_avail;
                        for (j = i + 1 - num_stripes; j <= i; j++)
                                devices_info[j].max_avail -= alloc_size;