[RFC ONLY 6/8] btrfs: add code to read raid extent

Johannes Thumshirn
2022-05-16T14:32:04Z

Add boilerplate code to lookup the physical address from the
raid-stripe-tree when a read on an RAID volume formatted with the
raid-stripe-tree was attempted.

Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
---
fs/btrfs/raid-stripe-tree.c | 68 +++++++++++++++++++++++++++++++++++++
fs/btrfs/raid-stripe-tree.h | 3 ++
fs/btrfs/volumes.c | 23 +++++++++++--
3 files changed, 91 insertions(+), 3 deletions(-)

diff --git a/fs/btrfs/raid-stripe-tree.c b/fs/btrfs/raid-stripe-tree.c
index 370ea68fe343..ecc8205be760 100644
--- a/fs/btrfs/raid-stripe-tree.c
+++ b/fs/btrfs/raid-stripe-tree.c
@@ -1,10 +1,78 @@
// SPDX-License-Identifier: GPL-2.0

+#include <linux/btrfs_tree.h>
+
#include "ctree.h"
#include "transaction.h"
#include "disk-io.h"
#include "raid-stripe-tree.h"
#include "volumes.h"
+#include "misc.h"
+
+int btrfs_get_raid_extent_offset(struct btrfs_fs_info *fs_info,
+ u64 logical, u64 length, u64 map_type,
+ u64 devid, u64 *physical)
+{
+ struct btrfs_root *stripe_root = fs_info->stripe_root;
+ struct btrfs_dp_stripe *raid_stripe;
+ struct btrfs_key stripe_key;
+ struct btrfs_key found_key;
+ struct btrfs_path *path;
+ struct extent_buffer *leaf;
+ u64 offset;
+ u64 found_logical, found_length;
+ int num_stripes;
+ int slot;
+ int ret;
+ int i;
+
+ stripe_key.objectid = logical;
+ stripe_key.type = BTRFS_RAID_STRIPE_KEY;
+ stripe_key.offset = length;
+
+ path = btrfs_alloc_path();
+ if (!path)
+ return -ENOMEM;
+
+ num_stripes = btrfs_bg_type_to_factor(map_type);
+
+ ret = btrfs_search_slot_for_read(stripe_root, &stripe_key, path, 0, 0);
+ if (ret < 0) {
+ goto out;
+ }
+
+ if (ret == 1)
+ ret = 0;
+
+ while (1) {
+ leaf = path->nodes[0];
+ slot = path->slots[0];
+
+ btrfs_item_key_to_cpu(leaf, &found_key, slot);
+ found_logical = found_key.objectid;
+ found_length = found_key.offset;
+
+ if (!in_range(logical, found_logical, found_length))
+ goto next;
+ offset = logical - found_logical;
+
+ raid_stripe = btrfs_item_ptr(leaf, slot, struct btrfs_dp_stripe);
+ for (i = 0; i < num_stripes; i++) {
+ if (btrfs_stripe_extent_devid_nr(leaf, raid_stripe, i) != devid)
+ continue;
+ *physical = btrfs_stripe_extent_offset_nr(leaf, raid_stripe, i) + offset;
+ goto out;
+ }
+next:
+ ret = btrfs_next_item(stripe_root, path);
+ if (ret)
+ break;
+ }
+out:
+ btrfs_free_path(path);
+
+ return ret;
+}

int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start,
u64 length)
diff --git a/fs/btrfs/raid-stripe-tree.h b/fs/btrfs/raid-stripe-tree.h
index 766634df8601..1bfa6274eef8 100644
--- a/fs/btrfs/raid-stripe-tree.h
+++ b/fs/btrfs/raid-stripe-tree.h
@@ -5,6 +5,9 @@

#include "volumes.h"

+int btrfs_get_raid_extent_offset(struct btrfs_fs_info *fs_info,
+ u64 logical, u64 length, u64 map_type,
+ u64 devid, u64 *physical);
int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start,
u64 length);
void btrfs_raid_stripe_tree_fn(struct work_struct *work);
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 36acef2ae5d8..38329728425c 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -6559,11 +6559,29 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info,
ret = -ENOMEM;
goto out;
}
+ bioc->map_type = map->type;

for (i = 0; i < num_stripes; i++) {
- bioc->stripes[i].physical = map->stripes[stripe_index].physical +
- stripe_offset + stripe_nr * map->stripe_len;
+ u64 physical;
+
bioc->stripes[i].dev = map->stripes[stripe_index].dev;
+
+ if (fs_info->stripe_root && op == BTRFS_MAP_READ &&
+ btrfs_need_stripe_tree_update(bioc)) {
+ ret = btrfs_get_raid_extent_offset(fs_info, logical,
+ map->stripe_len,
+ map->type,
+ bioc->stripes[i].dev->devid,
+ &physical);
+ if (ret) {
+ btrfs_put_bioc(bioc);
+ goto out;
+ }
+ } else {
+ physical = map->stripes[stripe_index].physical +
+ stripe_offset + stripe_nr * map->stripe_len;
+ }
+ bioc->stripes[i].physical = physical;
stripe_index++;
}

@@ -6600,7 +6618,6 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info,
}

*bioc_ret = bioc;
- bioc->map_type = map->type;
bioc->num_stripes = num_stripes;
bioc->max_errors = max_errors;
bioc->mirror_num = mirror_num;
--
2.35.1