@@ -233,3 +233,148 @@ int btrfs_insert_raid_extent(struct btrfs_trans_handle *trans,
return ret;
}
+
+static bool btrfs_physical_from_ordered_stripe(struct btrfs_fs_info *fs_info,
+ u64 logical, u64 *length,
+ int num_stripes,
+ struct btrfs_io_stripe *stripe)
+{
+ struct btrfs_ordered_stripe *os;
+ u64 offset;
+ u64 found_end;
+ u64 end;
+ int i;
+
+ os = btrfs_lookup_ordered_stripe(fs_info, logical);
+ if (!os)
+ return false;
+
+ end = logical + *length;
+ found_end = os->logical + os->num_bytes;
+ if (end > found_end)
+ *length -= end - found_end;
+
+ for (i = 0; i < num_stripes; i++) {
+ if (os->stripes[i].dev != stripe->dev)
+ continue;
+
+ ASSERT(logical >= os->logical);
+ offset = logical - os->logical;
+ stripe->physical = os->stripes[i].physical + offset;
+ btrfs_put_ordered_stripe(fs_info, os);
+ break;
+ }
+
+ return true;
+}
+
+int btrfs_get_raid_extent_offset(struct btrfs_fs_info *fs_info,
+ u64 logical, u64 *length, u64 map_type,
+ struct btrfs_io_stripe *stripe)
+{
+ struct btrfs_root *stripe_root = btrfs_stripe_tree_root(fs_info);
+ int num_stripes = btrfs_bg_type_to_factor(map_type);
+ struct btrfs_stripe_extent *stripe_extent;
+ struct btrfs_key stripe_key;
+ struct btrfs_key found_key;
+ struct btrfs_path *path;
+ struct extent_buffer *leaf;
+ u64 offset;
+ u64 found_logical;
+ u64 found_length;
+ u64 end;
+ u64 found_end;
+ int slot;
+ int ret;
+ int i;
+
+ /*
+ * If we still have the stripe in the ordered stripe tree get it from
+ * there
+ */
+ if (btrfs_physical_from_ordered_stripe(fs_info, logical, length,
+ num_stripes, stripe))
+ return 0;
+
+ stripe_key.objectid = logical;
+ stripe_key.type = BTRFS_RAID_STRIPE_KEY;
+ stripe_key.offset = 0;
+
+ path = btrfs_alloc_path();
+ if (!path)
+ return -ENOMEM;
+
+ ret = btrfs_search_slot(NULL, stripe_root, &stripe_key, path, 0, 0);
+ if (ret < 0)
+ goto free_path;
+ if (ret) {
+ if (path->slots[0] != 0)
+ path->slots[0]--;
+ }
+
+ end = logical + *length;
+
+ 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 (found_logical > end)
+ break;
+
+ if (!in_range(logical, found_logical, found_length))
+ goto next;
+
+ offset = logical - found_logical;
+ found_end = found_logical + found_length;
+
+ /*
+ * If we have a logically contiguous, but physically
+ * noncontinuous range, we need to split the bio. Record the
+ * length after which we must split the bio.
+ */
+ if (end > found_end)
+ *length -= end - found_end;
+
+ stripe_extent =
+ btrfs_item_ptr(leaf, slot, struct btrfs_stripe_extent);
+ for (i = 0; i < num_stripes; i++) {
+ if (btrfs_raid_stride_devid_nr(leaf,
+ stripe_extent, i) != stripe->dev->devid)
+ continue;
+ stripe->physical = btrfs_raid_stride_physical_nr(leaf,
+ stripe_extent, i) + offset;
+ ret = 0;
+ goto out;
+ }
+
+ /*
+ * If we're here, we haven't found the requested devid in the
+ * stripe.
+ */
+ ret = -ENOENT;
+ goto out;
+next:
+ ret = btrfs_next_item(stripe_root, path);
+ if (ret)
+ break;
+ }
+
+out:
+ if (ret > 0)
+ ret = -ENOENT;
+ if (ret && ret != -EIO) {
+ btrfs_err(fs_info,
+ "cannot find raid-stripe for logical [%llu, %llu]",
+ logical, logical + *length);
+ btrfs_print_tree(leaf, 1);
+ }
+
+free_path:
+ btrfs_free_path(path);
+
+ return ret;
+}
@@ -22,6 +22,9 @@ struct btrfs_ordered_stripe {
refcount_t ref;
};
+int btrfs_get_raid_extent_offset(struct btrfs_fs_info *fs_info,
+ u64 logical, u64 *length, u64 map_type,
+ struct btrfs_io_stripe *stripe);
int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start,
u64 length);
int btrfs_insert_raid_extent(struct btrfs_trans_handle *trans,
@@ -35,6 +35,7 @@
#include "relocation.h"
#include "scrub.h"
#include "super.h"
+#include "raid-stripe-tree.h"
#define BTRFS_BLOCK_GROUP_STRIPE_MASK (BTRFS_BLOCK_GROUP_RAID0 | \
BTRFS_BLOCK_GROUP_RAID10 | \
@@ -6324,12 +6325,21 @@ static u64 btrfs_max_io_len(struct map_lookup *map, enum btrfs_map_op op,
return U64_MAX;
}
-static void set_io_stripe(struct btrfs_io_stripe *dst, const struct map_lookup *map,
- u32 stripe_index, u64 stripe_offset, u64 stripe_nr)
+static int set_io_stripe(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
+ u64 logical, u64 *length, struct btrfs_io_stripe *dst,
+ struct map_lookup *map, u32 stripe_index,
+ u64 stripe_offset, u64 stripe_nr)
{
dst->dev = map->stripes[stripe_index].dev;
+
+ if (op == BTRFS_MAP_READ &&
+ btrfs_need_stripe_tree_update(fs_info, map->type))
+ return btrfs_get_raid_extent_offset(fs_info, logical, length,
+ map->type, dst);
+
dst->physical = map->stripes[stripe_index].physical +
stripe_offset + stripe_nr * map->stripe_len;
+ return 0;
}
int __btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
@@ -6518,13 +6528,14 @@ int __btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
smap->dev = dev_replace->tgtdev;
smap->physical = physical_to_patch_in_first_stripe;
*mirror_num_ret = map->num_stripes + 1;
+ ret = 0;
} else {
- set_io_stripe(smap, map, stripe_index, stripe_offset,
- stripe_nr);
*mirror_num_ret = mirror_num;
+ ret = set_io_stripe(fs_info, op, logical, length, smap,
+ map, stripe_index, stripe_offset,
+ stripe_nr);
}
*bioc_ret = NULL;
- ret = 0;
goto out;
}
@@ -6536,8 +6547,14 @@ int __btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
}
for (i = 0; i < num_stripes; i++) {
- set_io_stripe(&bioc->stripes[i], map, stripe_index, stripe_offset,
- stripe_nr);
+ ret = set_io_stripe(fs_info, op, logical, length,
+ &bioc->stripes[i], map, stripe_index,
+ stripe_offset, stripe_nr);
+ if (ret) {
+ btrfs_put_bioc(bioc);
+ goto out;
+ }
+
stripe_index++;
}