diff options
-rw-r--r-- | cmds-check.c | 10 | ||||
-rw-r--r-- | extent-tree.c | 15 | ||||
-rw-r--r-- | volumes.h | 23 |
3 files changed, 38 insertions, 10 deletions
diff --git a/cmds-check.c b/cmds-check.c index 670ccd1f..907d60c5 100644 --- a/cmds-check.c +++ b/cmds-check.c @@ -4662,8 +4662,8 @@ static int add_extent_rec_nolookup(struct cache_tree *extent_cache, bytes_used += rec->nr; if (tmpl->metadata) - rec->crossing_stripes = check_crossing_stripes(rec->start, - global_info->tree_root->nodesize); + rec->crossing_stripes = check_crossing_stripes(global_info, + rec->start, global_info->tree_root->nodesize); check_extent_type(rec); return ret; } @@ -4764,7 +4764,8 @@ static int add_extent_rec(struct cache_tree *extent_cache, */ if (tmpl->metadata) rec->crossing_stripes = check_crossing_stripes( - rec->start, global_info->tree_root->nodesize); + global_info, rec->start, + global_info->tree_root->nodesize); check_extent_type(rec); maybe_free_extent_rec(extent_cache, rec); return ret; @@ -9359,7 +9360,8 @@ static int check_extent_item(struct btrfs_fs_info *fs_info, if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) metadata = 1; - if (metadata && check_crossing_stripes(key.objectid, eb->len)) { + if (metadata && check_crossing_stripes(global_info, key.objectid, + eb->len)) { error("bad metadata [%llu, %llu) crossing stripe boundary", key.objectid, key.objectid + nodesize); err |= CROSSING_STRIPE_BOUNDARY; diff --git a/extent-tree.c b/extent-tree.c index f6d0a7c1..3b1577e7 100644 --- a/extent-tree.c +++ b/extent-tree.c @@ -2606,11 +2606,20 @@ check_failed: } if (!(data & BTRFS_BLOCK_GROUP_DATA)) { - if (check_crossing_stripes(ins->objectid, num_bytes)) { - search_start = round_down(ins->objectid + num_bytes, - BTRFS_STRIPE_LEN); + if (check_crossing_stripes(info, ins->objectid, num_bytes)) { + struct btrfs_block_group_cache *bg_cache; + u64 bg_offset; + + bg_cache = btrfs_lookup_block_group(info, ins->objectid); + if (!bg_cache) + goto no_bg_cache; + bg_offset = ins->objectid - bg_cache->key.objectid; + + search_start = round_up(bg_offset + num_bytes, + BTRFS_STRIPE_LEN) + bg_offset; goto new_group; } +no_bg_cache: block_group = btrfs_lookup_block_group(info, ins->objectid); if (block_group) trans->block_group = block_group; @@ -155,11 +155,28 @@ struct map_lookup { * Check if the given range cross stripes. * To ensure kernel scrub won't causing bug on with METADATA in mixed * block group + * + * Return 1 if the range crosses STRIPE boundary + * Return 0 if the range doesn't cross STRIPE boundary or it + * doesn't belong to any block group (no boundary to cross) */ -static inline int check_crossing_stripes(u64 start, u64 len) +static inline int check_crossing_stripes(struct btrfs_fs_info *fs_info, + u64 start, u64 len) { - return (start / BTRFS_STRIPE_LEN) != - ((start + len - 1) / BTRFS_STRIPE_LEN); + struct btrfs_block_group_cache *bg_cache; + u64 bg_offset; + + bg_cache = btrfs_lookup_block_group(fs_info, start); + /* + * Does not belong to block group, no boundary to cross + * although it's a bigger problem, but here we don't care. + */ + if (!bg_cache) + return 0; + bg_offset = start - bg_cache->key.objectid; + + return (bg_offset / BTRFS_STRIPE_LEN != + (bg_offset + len - 1) / BTRFS_STRIPE_LEN); } int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, |