2014-03-31 18:34 GMT+08:00 Wang Shilong <wangsl.fnst@xxxxxxxxxxxxxx>: > 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@xxxxxxxxxxxxxx> > --- > 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: > + 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@xxxxxxxxxxxxxxx > 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@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html