summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/relocation.c50
-rw-r--r--fs/btrfs/relocation.h1
-rw-r--r--fs/btrfs/volumes.c18
3 files changed, 69 insertions, 0 deletions
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index 310b7d817a27..6de508323dbd 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -3859,6 +3859,56 @@ static const char *stage_to_string(enum reloc_stage stage)
return "unknown";
}
+int btrfs_translate_remap(struct btrfs_fs_info *fs_info, u64 *logical, u64 *length)
+{
+ int ret;
+ struct btrfs_key key, found_key;
+ struct extent_buffer *leaf;
+ struct btrfs_remap_item *remap;
+ BTRFS_PATH_AUTO_FREE(path);
+
+ path = btrfs_alloc_path();
+ if (!path)
+ return -ENOMEM;
+
+ key.objectid = *logical;
+ key.type = (u8)-1;
+ key.offset = (u64)-1;
+
+ ret = btrfs_search_slot(NULL, fs_info->remap_root, &key, path, 0, 0);
+ if (ret < 0)
+ return ret;
+
+ leaf = path->nodes[0];
+ if (path->slots[0] == 0)
+ return -ENOENT;
+
+ path->slots[0]--;
+
+ btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
+
+ if (found_key.type != BTRFS_REMAP_KEY &&
+ found_key.type != BTRFS_IDENTITY_REMAP_KEY) {
+ return -ENOENT;
+ }
+
+ if (found_key.objectid > *logical ||
+ found_key.objectid + found_key.offset <= *logical) {
+ return -ENOENT;
+ }
+
+ if (*logical + *length > found_key.objectid + found_key.offset)
+ *length = found_key.objectid + found_key.offset - *logical;
+
+ if (found_key.type == BTRFS_IDENTITY_REMAP_KEY)
+ return 0;
+
+ remap = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_remap_item);
+ *logical += btrfs_remap_address(leaf, remap) - found_key.objectid;
+
+ return 0;
+}
+
/*
* function to relocate all extents in a block group.
*/
diff --git a/fs/btrfs/relocation.h b/fs/btrfs/relocation.h
index 5c36b3f84b57..c0ee26004fc1 100644
--- a/fs/btrfs/relocation.h
+++ b/fs/btrfs/relocation.h
@@ -31,5 +31,6 @@ int btrfs_should_cancel_balance(const struct btrfs_fs_info *fs_info);
struct btrfs_root *find_reloc_root(struct btrfs_fs_info *fs_info, u64 bytenr);
bool btrfs_should_ignore_reloc_root(const struct btrfs_root *root);
u64 btrfs_get_reloc_bg_bytenr(const struct btrfs_fs_info *fs_info);
+int btrfs_translate_remap(struct btrfs_fs_info *fs_info, u64 *logical, u64 *length);
#endif
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 6280a1a4c407..2a4bda452d85 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -6586,6 +6586,24 @@ int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
if (IS_ERR(map))
return PTR_ERR(map);
+ if (map->type & BTRFS_BLOCK_GROUP_REMAPPED) {
+ u64 new_logical = logical;
+
+ ret = btrfs_translate_remap(fs_info, &new_logical, length);
+ if (ret)
+ return ret;
+
+ if (new_logical != logical) {
+ btrfs_free_chunk_map(map);
+
+ map = btrfs_get_chunk_map(fs_info, new_logical, *length);
+ if (IS_ERR(map))
+ return PTR_ERR(map);
+
+ logical = new_logical;
+ }
+ }
+
num_copies = btrfs_chunk_map_num_copies(map);
if (io_geom.mirror_num > num_copies)
return -EINVAL;