RAID10 can accept as much as half of its disks to be missing, as long as
each sub stripe still has a good mirror.

Thanks to the per-chunk degradable check, we can handle it pretty easily
now.

So Add this special check for RAID10, to allow user to be creative
(or crazy) using btrfs RAID10.

Signed-off-by: Qu Wenruo <w...@suse.com>
---
 fs/btrfs/volumes.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index f209127a8bc6..65b10d13fc2d 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -7088,6 +7088,42 @@ int btrfs_read_sys_array(struct btrfs_fs_info *fs_info)
        return -EIO;
 }
 
+static bool check_raid10_rw_degradable(struct btrfs_fs_info *fs_info,
+                                      struct extent_map *em)
+{
+       struct map_lookup *map = em->map_lookup;
+       int sub_stripes = map->sub_stripes;
+       int num_stripes = map->num_stripes;
+       int tolerance = 1;
+       int i, j;
+
+       ASSERT(sub_stripes == 2);
+       ASSERT(num_stripes % sub_stripes == 0);
+       /*
+        * Check substripes as a group, in each group we need to
+        * have at least one good mirror;
+        */
+       for (i = 0; i < num_stripes / sub_stripes; i ++) {
+               int missing = 0;
+               for (j = 0; j < sub_stripes; j++) {
+                       struct btrfs_device *dev = map->stripes[i * 2 + j].dev;
+
+                       if (!dev || !dev->bdev ||
+                           test_bit(BTRFS_DEV_STATE_MISSING, &dev->dev_state) 
||
+                           dev->last_flush_error)
+                               missing++;
+               }
+               if (missing > tolerance) {
+                       btrfs_warn(fs_info,
+"chunk %llu stripes %d,%d missing %d devices, max tolerance is %d for writable 
mount",
+                                  em->start, i, i + sub_stripes - 1, missing,
+                                  tolerance);
+                       return false;
+               }
+       }
+       return true;
+}
+
 /*
  * Check if all chunks in the fs are OK for read-write degraded mount
  *
@@ -7119,6 +7155,14 @@ bool btrfs_check_rw_degradable(struct btrfs_fs_info 
*fs_info,
                int i;
 
                map = em->map_lookup;
+               if (map->type & BTRFS_BLOCK_GROUP_RAID10) {
+                       ret = check_raid10_rw_degradable(fs_info, em);
+                       if (!ret) {
+                               free_extent_map(em);
+                               goto out;
+                       }
+                       goto next;
+               }
                max_tolerated =
                        btrfs_get_num_tolerated_disk_barrier_failures(
                                        map->type);
@@ -7141,6 +7185,7 @@ bool btrfs_check_rw_degradable(struct btrfs_fs_info 
*fs_info,
                        ret = false;
                        goto out;
                }
+next:
                next_start = extent_map_end(em);
                free_extent_map(em);
 
-- 
2.22.0

Reply via email to