Btrfs: devid subset filter
authorIlya Dryomov <idryomov@gmail.com>
Mon, 16 Jan 2012 20:04:48 +0000 (22:04 +0200)
committerIlya Dryomov <idryomov@gmail.com>
Mon, 16 Jan 2012 20:04:48 +0000 (22:04 +0200)
Select chunks which have at least one byte of at least one stripe
located on a device with devid X in a given [pstart,pend) physical
address range.

This filter only works when devid filter is turned on.

Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
fs/btrfs/volumes.c
fs/btrfs/volumes.h

index 9ff5cd09a25611f2a23746aef45074d27a871d99..c60071a448a5a9dd0056c686321a9da1d6aae8e9 100644 (file)
@@ -2167,6 +2167,46 @@ static int chunk_devid_filter(struct extent_buffer *leaf,
        return 1;
 }
 
+/* [pstart, pend) */
+static int chunk_drange_filter(struct extent_buffer *leaf,
+                              struct btrfs_chunk *chunk,
+                              u64 chunk_offset,
+                              struct btrfs_balance_args *bargs)
+{
+       struct btrfs_stripe *stripe;
+       int num_stripes = btrfs_chunk_num_stripes(leaf, chunk);
+       u64 stripe_offset;
+       u64 stripe_length;
+       int factor;
+       int i;
+
+       if (!(bargs->flags & BTRFS_BALANCE_ARGS_DEVID))
+               return 0;
+
+       if (btrfs_chunk_type(leaf, chunk) & (BTRFS_BLOCK_GROUP_DUP |
+            BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10))
+               factor = 2;
+       else
+               factor = 1;
+       factor = num_stripes / factor;
+
+       for (i = 0; i < num_stripes; i++) {
+               stripe = btrfs_stripe_nr(chunk, i);
+               if (btrfs_stripe_devid(leaf, stripe) != bargs->devid)
+                       continue;
+
+               stripe_offset = btrfs_stripe_offset(leaf, stripe);
+               stripe_length = btrfs_chunk_length(leaf, chunk);
+               do_div(stripe_length, factor);
+
+               if (stripe_offset < bargs->pend &&
+                   stripe_offset + stripe_length > bargs->pstart)
+                       return 0;
+       }
+
+       return 1;
+}
+
 static int should_balance_chunk(struct btrfs_root *root,
                                struct extent_buffer *leaf,
                                struct btrfs_chunk *chunk, u64 chunk_offset)
@@ -2206,6 +2246,12 @@ static int should_balance_chunk(struct btrfs_root *root,
                return 0;
        }
 
+       /* drange filter, makes sense only with devid filter */
+       if ((bargs->flags & BTRFS_BALANCE_ARGS_DRANGE) &&
+           chunk_drange_filter(leaf, chunk, chunk_offset, bargs)) {
+               return 0;
+       }
+
        return 1;
 }
 
index 7cfec03c29b8f32d22d34c77a5f78cc03de25c01..844b08e388f25a9bc61472e4e8b413f8b13e9164 100644 (file)
@@ -202,6 +202,7 @@ struct map_lookup {
 #define BTRFS_BALANCE_ARGS_PROFILES    (1ULL << 0)
 #define BTRFS_BALANCE_ARGS_USAGE       (1ULL << 1)
 #define BTRFS_BALANCE_ARGS_DEVID       (1ULL << 2)
+#define BTRFS_BALANCE_ARGS_DRANGE      (1ULL << 3)
 
 struct btrfs_balance_args;
 struct btrfs_balance_control {