|
@@ -108,7 +108,7 @@ const struct btrfs_raid_attr btrfs_raid_array[BTRFS_NR_RAID_TYPES] = {
|
|
|
},
|
|
|
};
|
|
|
|
|
|
-const u64 const btrfs_raid_group[BTRFS_NR_RAID_TYPES] = {
|
|
|
+const u64 btrfs_raid_group[BTRFS_NR_RAID_TYPES] = {
|
|
|
[BTRFS_RAID_RAID10] = BTRFS_BLOCK_GROUP_RAID10,
|
|
|
[BTRFS_RAID_RAID1] = BTRFS_BLOCK_GROUP_RAID1,
|
|
|
[BTRFS_RAID_DUP] = BTRFS_BLOCK_GROUP_DUP,
|
|
@@ -233,6 +233,7 @@ static struct btrfs_device *__alloc_device(void)
|
|
|
spin_lock_init(&dev->reada_lock);
|
|
|
atomic_set(&dev->reada_in_flight, 0);
|
|
|
atomic_set(&dev->dev_stats_ccnt, 0);
|
|
|
+ btrfs_device_data_ordered_init(dev);
|
|
|
INIT_RADIX_TREE(&dev->reada_zones, GFP_NOFS & ~__GFP_DIRECT_RECLAIM);
|
|
|
INIT_RADIX_TREE(&dev->reada_extents, GFP_NOFS & ~__GFP_DIRECT_RECLAIM);
|
|
|
|
|
@@ -1183,7 +1184,7 @@ again:
|
|
|
struct map_lookup *map;
|
|
|
int i;
|
|
|
|
|
|
- map = (struct map_lookup *)em->bdev;
|
|
|
+ map = em->map_lookup;
|
|
|
for (i = 0; i < map->num_stripes; i++) {
|
|
|
u64 end;
|
|
|
|
|
@@ -2755,7 +2756,7 @@ int btrfs_remove_chunk(struct btrfs_trans_handle *trans,
|
|
|
free_extent_map(em);
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
- map = (struct map_lookup *)em->bdev;
|
|
|
+ map = em->map_lookup;
|
|
|
lock_chunks(root->fs_info->chunk_root);
|
|
|
check_system_chunk(trans, extent_root, map->type);
|
|
|
unlock_chunks(root->fs_info->chunk_root);
|
|
@@ -3751,7 +3752,7 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
|
|
|
if (btrfs_get_num_tolerated_disk_barrier_failures(bctl->meta.target) <
|
|
|
btrfs_get_num_tolerated_disk_barrier_failures(bctl->data.target)) {
|
|
|
btrfs_warn(fs_info,
|
|
|
- "metatdata profile 0x%llx has lower redundancy than data profile 0x%llx",
|
|
|
+ "metadata profile 0x%llx has lower redundancy than data profile 0x%llx",
|
|
|
bctl->meta.target, bctl->data.target);
|
|
|
}
|
|
|
|
|
@@ -4718,7 +4719,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
|
|
|
goto error;
|
|
|
}
|
|
|
set_bit(EXTENT_FLAG_FS_MAPPING, &em->flags);
|
|
|
- em->bdev = (struct block_device *)map;
|
|
|
+ em->map_lookup = map;
|
|
|
em->start = start;
|
|
|
em->len = num_bytes;
|
|
|
em->block_start = 0;
|
|
@@ -4813,7 +4814,7 @@ int btrfs_finish_chunk_alloc(struct btrfs_trans_handle *trans,
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
- map = (struct map_lookup *)em->bdev;
|
|
|
+ map = em->map_lookup;
|
|
|
item_size = btrfs_chunk_item_size(map->num_stripes);
|
|
|
stripe_size = em->orig_block_len;
|
|
|
|
|
@@ -4968,7 +4969,7 @@ int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset)
|
|
|
if (!em)
|
|
|
return 1;
|
|
|
|
|
|
- map = (struct map_lookup *)em->bdev;
|
|
|
+ map = em->map_lookup;
|
|
|
for (i = 0; i < map->num_stripes; i++) {
|
|
|
if (map->stripes[i].dev->missing) {
|
|
|
miss_ndevs++;
|
|
@@ -5048,7 +5049,7 @@ int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len)
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
- map = (struct map_lookup *)em->bdev;
|
|
|
+ map = em->map_lookup;
|
|
|
if (map->type & (BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID1))
|
|
|
ret = map->num_stripes;
|
|
|
else if (map->type & BTRFS_BLOCK_GROUP_RAID10)
|
|
@@ -5084,7 +5085,7 @@ unsigned long btrfs_full_stripe_len(struct btrfs_root *root,
|
|
|
BUG_ON(!em);
|
|
|
|
|
|
BUG_ON(em->start > logical || em->start + em->len < logical);
|
|
|
- map = (struct map_lookup *)em->bdev;
|
|
|
+ map = em->map_lookup;
|
|
|
if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK)
|
|
|
len = map->stripe_len * nr_data_stripes(map);
|
|
|
free_extent_map(em);
|
|
@@ -5105,7 +5106,7 @@ int btrfs_is_parity_mirror(struct btrfs_mapping_tree *map_tree,
|
|
|
BUG_ON(!em);
|
|
|
|
|
|
BUG_ON(em->start > logical || em->start + em->len < logical);
|
|
|
- map = (struct map_lookup *)em->bdev;
|
|
|
+ map = em->map_lookup;
|
|
|
if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK)
|
|
|
ret = 1;
|
|
|
free_extent_map(em);
|
|
@@ -5264,7 +5265,7 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, int rw,
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
- map = (struct map_lookup *)em->bdev;
|
|
|
+ map = em->map_lookup;
|
|
|
offset = logical - em->start;
|
|
|
|
|
|
stripe_len = map->stripe_len;
|
|
@@ -5378,35 +5379,33 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, int rw,
|
|
|
* target drive.
|
|
|
*/
|
|
|
for (i = 0; i < tmp_num_stripes; i++) {
|
|
|
- if (tmp_bbio->stripes[i].dev->devid == srcdev_devid) {
|
|
|
- /*
|
|
|
- * In case of DUP, in order to keep it
|
|
|
- * simple, only add the mirror with the
|
|
|
- * lowest physical address
|
|
|
- */
|
|
|
- if (found &&
|
|
|
- physical_of_found <=
|
|
|
- tmp_bbio->stripes[i].physical)
|
|
|
- continue;
|
|
|
- index_srcdev = i;
|
|
|
- found = 1;
|
|
|
- physical_of_found =
|
|
|
- tmp_bbio->stripes[i].physical;
|
|
|
- }
|
|
|
+ if (tmp_bbio->stripes[i].dev->devid != srcdev_devid)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * In case of DUP, in order to keep it simple, only add
|
|
|
+ * the mirror with the lowest physical address
|
|
|
+ */
|
|
|
+ if (found &&
|
|
|
+ physical_of_found <= tmp_bbio->stripes[i].physical)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ index_srcdev = i;
|
|
|
+ found = 1;
|
|
|
+ physical_of_found = tmp_bbio->stripes[i].physical;
|
|
|
}
|
|
|
|
|
|
- if (found) {
|
|
|
- mirror_num = index_srcdev + 1;
|
|
|
- patch_the_first_stripe_for_dev_replace = 1;
|
|
|
- physical_to_patch_in_first_stripe = physical_of_found;
|
|
|
- } else {
|
|
|
+ btrfs_put_bbio(tmp_bbio);
|
|
|
+
|
|
|
+ if (!found) {
|
|
|
WARN_ON(1);
|
|
|
ret = -EIO;
|
|
|
- btrfs_put_bbio(tmp_bbio);
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- btrfs_put_bbio(tmp_bbio);
|
|
|
+ mirror_num = index_srcdev + 1;
|
|
|
+ patch_the_first_stripe_for_dev_replace = 1;
|
|
|
+ physical_to_patch_in_first_stripe = physical_of_found;
|
|
|
} else if (mirror_num > map->num_stripes) {
|
|
|
mirror_num = 0;
|
|
|
}
|
|
@@ -5806,7 +5805,7 @@ int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree,
|
|
|
free_extent_map(em);
|
|
|
return -EIO;
|
|
|
}
|
|
|
- map = (struct map_lookup *)em->bdev;
|
|
|
+ map = em->map_lookup;
|
|
|
|
|
|
length = em->len;
|
|
|
rmap_len = map->stripe_len;
|
|
@@ -6069,7 +6068,8 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio,
|
|
|
bbio->fs_info = root->fs_info;
|
|
|
atomic_set(&bbio->stripes_pending, bbio->num_stripes);
|
|
|
|
|
|
- if (bbio->raid_map) {
|
|
|
+ if ((bbio->map_type & BTRFS_BLOCK_GROUP_RAID56_MASK) &&
|
|
|
+ ((rw & WRITE) || (mirror_num > 1))) {
|
|
|
/* In this case, map_length has been set to the length of
|
|
|
a single stripe; not the whole write */
|
|
|
if (rw & WRITE) {
|
|
@@ -6210,6 +6210,7 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
|
|
|
struct extent_map *em;
|
|
|
u64 logical;
|
|
|
u64 length;
|
|
|
+ u64 stripe_len;
|
|
|
u64 devid;
|
|
|
u8 uuid[BTRFS_UUID_SIZE];
|
|
|
int num_stripes;
|
|
@@ -6218,6 +6219,37 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
|
|
|
|
|
|
logical = key->offset;
|
|
|
length = btrfs_chunk_length(leaf, chunk);
|
|
|
+ stripe_len = btrfs_chunk_stripe_len(leaf, chunk);
|
|
|
+ num_stripes = btrfs_chunk_num_stripes(leaf, chunk);
|
|
|
+ /* Validation check */
|
|
|
+ if (!num_stripes) {
|
|
|
+ btrfs_err(root->fs_info, "invalid chunk num_stripes: %u",
|
|
|
+ num_stripes);
|
|
|
+ return -EIO;
|
|
|
+ }
|
|
|
+ if (!IS_ALIGNED(logical, root->sectorsize)) {
|
|
|
+ btrfs_err(root->fs_info,
|
|
|
+ "invalid chunk logical %llu", logical);
|
|
|
+ return -EIO;
|
|
|
+ }
|
|
|
+ if (!length || !IS_ALIGNED(length, root->sectorsize)) {
|
|
|
+ btrfs_err(root->fs_info,
|
|
|
+ "invalid chunk length %llu", length);
|
|
|
+ return -EIO;
|
|
|
+ }
|
|
|
+ if (!is_power_of_2(stripe_len)) {
|
|
|
+ btrfs_err(root->fs_info, "invalid chunk stripe length: %llu",
|
|
|
+ stripe_len);
|
|
|
+ return -EIO;
|
|
|
+ }
|
|
|
+ if (~(BTRFS_BLOCK_GROUP_TYPE_MASK | BTRFS_BLOCK_GROUP_PROFILE_MASK) &
|
|
|
+ btrfs_chunk_type(leaf, chunk)) {
|
|
|
+ btrfs_err(root->fs_info, "unrecognized chunk type: %llu",
|
|
|
+ ~(BTRFS_BLOCK_GROUP_TYPE_MASK |
|
|
|
+ BTRFS_BLOCK_GROUP_PROFILE_MASK) &
|
|
|
+ btrfs_chunk_type(leaf, chunk));
|
|
|
+ return -EIO;
|
|
|
+ }
|
|
|
|
|
|
read_lock(&map_tree->map_tree.lock);
|
|
|
em = lookup_extent_mapping(&map_tree->map_tree, logical, 1);
|
|
@@ -6234,7 +6266,6 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
|
|
|
em = alloc_extent_map();
|
|
|
if (!em)
|
|
|
return -ENOMEM;
|
|
|
- num_stripes = btrfs_chunk_num_stripes(leaf, chunk);
|
|
|
map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS);
|
|
|
if (!map) {
|
|
|
free_extent_map(em);
|
|
@@ -6242,7 +6273,7 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
|
|
|
}
|
|
|
|
|
|
set_bit(EXTENT_FLAG_FS_MAPPING, &em->flags);
|
|
|
- em->bdev = (struct block_device *)map;
|
|
|
+ em->map_lookup = map;
|
|
|
em->start = logical;
|
|
|
em->len = length;
|
|
|
em->orig_start = 0;
|
|
@@ -6944,7 +6975,7 @@ void btrfs_update_commit_device_bytes_used(struct btrfs_root *root,
|
|
|
/* In order to kick the device replace finish process */
|
|
|
lock_chunks(root);
|
|
|
list_for_each_entry(em, &transaction->pending_chunks, list) {
|
|
|
- map = (struct map_lookup *)em->bdev;
|
|
|
+ map = em->map_lookup;
|
|
|
|
|
|
for (i = 0; i < map->num_stripes; i++) {
|
|
|
dev = map->stripes[i].dev;
|