[prev in list] [next in list] [prev in thread] [next in thread]
List: linux-btrfs
Subject: Re: [PATCH v2 2/2] Btrfs: scrub raid56 stripes in the right way
From: Shilong Wang <wangshilong1991 () gmail ! com>
Date: 2014-03-31 13:06:29
Message-ID: CAP9B-Qm0--qe1Vk+ih0Xrvd=EMo0geaccOG8T4BRTbiFu43wrg () mail ! gmail ! com
[Download RAW message or body]
2014-03-31 20:54 GMT+08:00 Shilong Wang <wangshilong1991@gmail.com>:
> 2014-03-31 18:34 GMT+08:00 Wang Shilong <wangsl.fnst@cn.fujitsu.com>:
>> Steps to reproduce:
>> # mkfs.btrfs -f /dev/sda[8-11] -m raid5 -d raid5
>> # mount /dev/sda8 /mnt
>> # btrfs scrub start -BR /mnt
>> # echo $? <--unverified errors make return value be 3
>>
>> This is because we don't setup right mapping between physical
>> and logical address for raid56, which makes checksum mismatch.
>> But we will find everthing is fine later when rechecking using
>> btrfs_map_block().
>>
>> This patch fixed the problem by settuping right mappings and
>> we only verify data stripes' checksums.
>>
>> Signed-off-by: Wang Shilong <wangsl.fnst@cn.fujitsu.com>
>> ---
>> v1->v2:
>> on the right way to fix the problem.
>> ---
>> fs/btrfs/scrub.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++--------
>> 1 file changed, 71 insertions(+), 12 deletions(-)
>>
>> diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
>> index db21a13..ebe4c5e 100644
>> --- a/fs/btrfs/scrub.c
>> +++ b/fs/btrfs/scrub.c
>> @@ -2235,6 +2235,43 @@ behind_scrub_pages:
>> return 0;
>> }
>>
>> +/*
>> + * Given a physical address, this will calculate it's
>> + * logical offset. if this is a parity stripe, it will return
>> + * the most left data stripe's logical offset.
>> + *
>> + * return 0 if it is a data stripe, 1 means parity stripe.
>> + */
>> +static int get_raid56_logic_offset(u64 physical, int num,
>> + struct map_lookup *map, u64 *offset)
>> +{
>> + int i;
>> + int j = 0;
>> + u64 stripe_nr;
>> + u64 tmp;
>> + u64 last_offset;
>> + int stripe_index;
>> +
>> + last_offset = (physical - map->stripes[num].physical) *
>> + nr_data_stripes(map);
>> + *offset = last_offset;
>> + for (i = 0; i < nr_data_stripes(map); i++) {
>> + *offset += i * map->stripe_len;
> oops, this is obviously wrong, it should be£º
It shoule be:
*offset = last_offset + i * map->stripe_len;
Will fix this in v3.
>
>> + stripe_nr = *offset;
>> + do_div(stripe_nr, map->stripe_len);
>> +
>> + stripe_index = do_div(stripe_nr, nr_data_stripes(map));
>> + tmp = stripe_nr + stripe_index;
>> + stripe_index = do_div(tmp, map->num_stripes);
>> + if (stripe_index == num)
>> + return 0;
>> + if (stripe_index < num)
>> + j++;
>> + }
>> + *offset = last_offset + j * map->stripe_len;
>> + return 1;
>> +}
>> +
>> static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
>> struct map_lookup *map,
>> struct btrfs_device *scrub_dev,
>> @@ -2269,16 +2306,10 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
>> u64 extent_len;
>> struct btrfs_device *extent_dev;
>> int extent_mirror_num;
>> - int stop_loop;
>> -
>> - if (map->type & (BTRFS_BLOCK_GROUP_RAID5 |
>> - BTRFS_BLOCK_GROUP_RAID6)) {
>> - if (num >= nr_data_stripes(map)) {
>> - return 0;
>> - }
>> - }
>> + int stop_loop = 0;
>>
>> nstripes = length;
>> + physical = map->stripes[num].physical;
>> offset = 0;
>> do_div(nstripes, map->stripe_len);
>> if (map->type & BTRFS_BLOCK_GROUP_RAID0) {
>> @@ -2296,6 +2327,11 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
>> } else if (map->type & BTRFS_BLOCK_GROUP_DUP) {
>> increment = map->stripe_len;
>> mirror_num = num % map->num_stripes + 1;
>> + } else if (map->type & (BTRFS_BLOCK_GROUP_RAID5 |
>> + BTRFS_BLOCK_GROUP_RAID6)) {
>> + get_raid56_logic_offset(physical, num, map, &offset);
>> + increment = map->stripe_len * nr_data_stripes(map);
>> + mirror_num = 1;
>> } else {
>> increment = map->stripe_len;
>> mirror_num = 1;
>> @@ -2357,10 +2393,18 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
>> * now find all extents for each stripe and scrub them
>> */
>> logical = base + offset;
>> - physical = map->stripes[num].physical;
>> logic_end = logical + increment * nstripes;
>> ret = 0;
>> while (logical < logic_end) {
>> + /* for raid56, we skip parity stripe */
>> + if (map->type & (BTRFS_BLOCK_GROUP_RAID5 |
>> + BTRFS_BLOCK_GROUP_RAID6)) {
>> + ret = get_raid56_logic_offset(physical, num,
>> + map, &logical);
>> + logical += base;
>> + if (ret)
>> + goto skip;
>> + }
>> /*
>> * canceled?
>> */
>> @@ -2504,9 +2548,23 @@ again:
>> scrub_free_csums(sctx);
>> if (extent_logical + extent_len <
>> key.objectid + bytes) {
>> - logical += increment;
>> - physical += map->stripe_len;
>> -
>> + if (map->type & (BTRFS_BLOCK_GROUP_RAID5 |
>> + BTRFS_BLOCK_GROUP_RAID6)) {
>> + /*
>> + * loop until we find next data stripe
>> + * or we have finished all stripes.
>> + */
>> + do {
>> + physical += map->stripe_len;
>> + ret = get_raid56_logic_offset(
>> + physical, num,
>> + map, &logical);
>> + logical += base;
>> + } while (logical < logic_end && ret);
>> + } else {
>> + physical += map->stripe_len;
>> + logical += increment;
>> + }
>> if (logical < key.objectid + bytes) {
>> cond_resched();
>> goto again;
>> @@ -2521,6 +2579,7 @@ next:
>> path->slots[0]++;
>> }
>> btrfs_release_path(path);
>> +skip:
>> logical += increment;
>> physical += map->stripe_len;
>> spin_lock(&sctx->stat_lock);
>> --
>> 1.9.0
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic