]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
crimson/os/seastore: support rename for static layout of laddr
authorZhang Song <zhangsong02@qianxin.com>
Tue, 26 Aug 2025 03:42:49 +0000 (11:42 +0800)
committerXuehan Xu <xuxuehan@qianxin.com>
Mon, 25 May 2026 08:55:32 +0000 (16:55 +0800)
Signed-off-by: Zhang Song <zhangsong02@qianxin.com>
Signed-off-by: Xuehan Xu <xuxuehan@qianxin.com>
src/crimson/os/seastore/cache.cc
src/crimson/os/seastore/cache.h
src/crimson/os/seastore/object_data_handler.cc
src/crimson/os/seastore/object_data_handler.h
src/crimson/os/seastore/omap_manager/btree/omap_btree_node_impl.cc
src/crimson/os/seastore/seastore.cc
src/crimson/os/seastore/seastore.h
src/crimson/os/seastore/transaction_manager.cc
src/crimson/os/seastore/transaction_manager.h

index b991e0c1295a95a2711a74585e4ae973caff1118..c6840d7670feda7628de2f75e5aea87da2b278b6 100644 (file)
@@ -1156,6 +1156,44 @@ void Cache::check_full_extent_integrity(
   }
 }
 
+CachedExtentRef Cache::alloc_remapped_extent_by_type(
+  Transaction &t,
+  extent_types_t type,
+  laddr_t remap_laddr,
+  paddr_t remap_paddr,
+  extent_len_t remap_offset,
+  extent_len_t remap_length,
+  const std::optional<ceph::bufferptr> &original_bptr)
+{
+  ceph_assert(is_logical_type(type));
+  switch (type) {
+  case extent_types_t::ROOT_META:
+    return alloc_remapped_extent<RootMetaBlock>(
+      t, remap_laddr, remap_paddr, remap_offset, remap_length, original_bptr);
+  case extent_types_t::OMAP_INNER:
+    return alloc_remapped_extent<omap_manager::OMapInnerNode>(
+      t, remap_laddr, remap_paddr, remap_offset, remap_length, original_bptr);
+  case extent_types_t::OMAP_LEAF:
+    return alloc_remapped_extent<omap_manager::OMapLeafNode>(
+      t, remap_laddr, remap_paddr, remap_offset, remap_length, original_bptr);
+  case extent_types_t::ONODE_BLOCK_STAGED:
+    return alloc_remapped_extent<onode::SeastoreNodeExtent>(
+      t, remap_laddr, remap_paddr, remap_offset, remap_length, original_bptr);
+  case extent_types_t::COLL_BLOCK:
+    return alloc_remapped_extent<collection_manager::CollectionNode>(
+      t, remap_laddr, remap_paddr, remap_offset, remap_length, original_bptr);
+  case extent_types_t::OBJECT_DATA_BLOCK:
+    return alloc_remapped_extent<ObjectDataBlock>(
+      t, remap_laddr, remap_paddr, remap_offset, remap_length, original_bptr);
+  case extent_types_t::TEST_BLOCK:
+    return alloc_remapped_extent<TestBlock>(
+      t, remap_laddr, remap_paddr, remap_offset, remap_length, original_bptr);
+  default:
+    ceph_abort("invalid extent type");
+    return CachedExtentRef();
+  }
+}
+
 CachedExtentRef Cache::alloc_new_non_data_extent_by_type(
   Transaction &t,        ///< [in, out] current transaction
   extent_types_t type,   ///< [in] type tag
index bcf15a3fda725b01f0f90c16443c279550bfc257..e6ebb2a72670a04416d4cfb6185ac62e61519b92 100644 (file)
@@ -1246,6 +1246,15 @@ public:
     return extent;
   }
 
+  CachedExtentRef alloc_remapped_extent_by_type(
+    Transaction &t,
+    extent_types_t type,
+    laddr_t remap_laddr,
+    paddr_t remap_paddr,
+    extent_len_t remap_offset,
+    extent_len_t remap_length,
+    const std::optional<ceph::bufferptr> &original_bptr);
+
   /**
    * alloc_new_non_data_extent_by_type
    *
index 1167c8f6a1d9b61d54a4ad35b3a08b2806f30e09..9ebd21e003c2b12f60f6dfcc752ca2db3cacd4a4 100644 (file)
@@ -104,6 +104,7 @@ auto with_objects_data(
 ObjectDataHandler::write_iertr::future<std::optional<LBAMapping>>
 ObjectDataHandler::prepare_data_reservation(
   context_t ctx,
+  Onode &onode,
   object_data_t &object_data,
   extent_len_t size)
 {
@@ -117,13 +118,12 @@ ObjectDataHandler::prepare_data_reservation(
            object_data.get_reserved_data_len());
     return write_iertr::make_ready_future<std::optional<LBAMapping>>();
   } else {
+    auto hint = onode.get_data_hint();
     DEBUGT("reserving: {}~0x{:x}",
-           ctx.t,
-           ctx.onode.get_data_hint(),
-           max_object_size);
+           ctx.t, hint, max_object_size);
     return ctx.tm.reserve_region(
       ctx.t,
-      ctx.onode.get_data_hint(),
+      hint,
       max_object_size,
       extent_types_t::OBJECT_DATA_BLOCK
     ).si_then([max_object_size=max_object_size, &object_data](auto pin) {
@@ -1295,7 +1295,7 @@ ObjectDataHandler::clone_ret ObjectDataHandler::clone_range(
     ceph_assert(!object_data.is_null());
     data_t data;
     auto dest_mapping = co_await prepare_data_reservation(
-      ctx, d_object_data, object_data.get_reserved_data_len());
+      ctx, *ctx.d_onode, d_object_data, object_data.get_reserved_data_len());
     if (!dest_mapping) {
       auto d_base = d_object_data.get_reserved_data_base();
       auto laddr = (d_base + srcoff).get_aligned_laddr(
@@ -1359,6 +1359,7 @@ ObjectDataHandler::zero_ret ObjectDataHandler::zero(
              object_data.is_null());
       return prepare_data_reservation(
        ctx,
+       ctx.onode,
        object_data,
        p2roundup(offset + len, ctx.tm.get_block_size())
       ).si_then([this, ctx, offset, len, &object_data](auto mapping) {
@@ -1388,7 +1389,7 @@ ObjectDataHandler::touch(context_t ctx)
 {
   return with_object_data(ctx, [this, ctx](auto &obj_data) {
     return prepare_data_reservation(
-      ctx, obj_data, max_object_size
+      ctx, ctx.onode, obj_data, max_object_size
     ).discard_result();
   });
 }
@@ -1411,6 +1412,7 @@ ObjectDataHandler::write_ret ObjectDataHandler::write(
              object_data.is_null());
       return prepare_data_reservation(
        ctx,
+       ctx.onode,
        object_data,
        p2roundup(offset + bl.length(), ctx.tm.get_block_size())
       ).si_then([this, ctx, offset, &object_data, &bl]
@@ -1681,6 +1683,7 @@ ObjectDataHandler::truncate_ret ObjectDataHandler::truncate(
       } else if (offset > object_data.get_reserved_data_len()) {
        return prepare_data_reservation(
          ctx,
+         ctx.onode,
          object_data,
          p2roundup(offset, ctx.tm.get_block_size())).discard_result();
       } else {
@@ -1750,7 +1753,7 @@ ObjectDataHandler::do_clone(
   auto old_base = object_data.get_reserved_data_base();
   auto old_len = object_data.get_reserved_data_len();
   auto mapping = co_await prepare_data_reservation(
-    ctx, d_object_data, old_len);
+    ctx, *ctx.d_onode, d_object_data, old_len);
   ceph_assert(mapping.has_value());
   DEBUGT("new obj reserve_data_base: {}, len 0x{:x}",
     ctx.t,
@@ -1792,6 +1795,70 @@ ObjectDataHandler::clone_ret ObjectDataHandler::clone(
   });
 }
 
+ObjectDataHandler::rename_ret
+ObjectDataHandler::rename(context_t ctx)
+{
+  bool move_indirect = true;
+  if (!ctx.onode.get_hobj().is_temp()) {
+    // we are moving an object in a logical pool
+    // to another object, we should copy the content
+    // of indirect mappings to the new location
+    // instead of moving indirect mappings directly
+    move_indirect = false;
+  }
+  return with_objects_data(
+    ctx,
+    [ctx, this, move_indirect](object_data_t &src, object_data_t &dst)
+    -> rename_ret {
+    ceph_assert(!src.is_null());
+    ceph_assert(dst.is_null());
+    auto dst_mapping = co_await prepare_data_reservation(
+      ctx, *ctx.d_onode, dst, src.get_reserved_data_len());
+    assert(dst_mapping);
+    auto src_mapping = co_await ctx.tm.get_pin(
+      ctx.t, src.get_reserved_data_base()
+    ).handle_error_interruptible(
+      rename_iertr::pass_further{},
+      crimson::ct_error::assert_all("invalid error")
+    );
+    auto dst_prefix = dst_mapping->get_key();
+    dst_mapping = co_await ctx.tm.remove(
+      ctx.t, std::move(*dst_mapping)
+    ).handle_error_interruptible(
+      rename_iertr::pass_further{},
+      crimson::ct_error::assert_all("invalid error")
+    );
+    src_mapping = co_await src_mapping.refresh();
+    co_await ctx.tm.move_region(
+      ctx.t,
+      std::move(src_mapping),
+      std::move(*dst_mapping),
+      dst_prefix,
+      move_indirect);
+
+    auto old_md_start = src.get_reserved_data_base()
+      .with_metadata()
+      .with_offset_by_blocks(0);
+    auto md_mapping = co_await ctx.tm.lower_bound_pin(ctx.t, old_md_start);
+    if (md_mapping.is_end() ||
+       md_mapping.get_key().get_clone_prefix() !=
+       old_md_start.get_clone_prefix()) {
+      co_return;
+    }
+    auto new_prefix = dst
+       .get_reserved_data_base()
+       .get_clone_prefix()
+       .with_metadata();
+    auto md_dst_mapping = co_await ctx.tm.lower_bound_pin(ctx.t, new_prefix);
+    co_await ctx.tm.move_region(
+      ctx.t,
+      md_mapping,
+      md_dst_mapping,
+      new_prefix,
+      move_indirect);
+  });
+}
+
 } // namespace crimson::os::seastore
 
 #if FMT_VERSION >= 90000
index 49b7804dd9d2ff406fa3378d739713dadb83a2cb..44b3d6f39a7888f9c1bcd78192db328d18360968 100644 (file)
@@ -415,6 +415,9 @@ public:
     extent_len_t len,
     extent_len_t destoff);
 
+  using rename_iertr = base_iertr;
+  using rename_ret = rename_iertr::future<>;
+  rename_ret rename(context_t ctx);
 private:
   /// Updates region [_offset, _offset + bl.length) to bl
   write_ret overwrite(
@@ -444,6 +447,7 @@ private:
   write_iertr::future<std::optional<LBAMapping>>
   prepare_data_reservation(
     context_t ctx,
+    Onode &onode,
     object_data_t &object_data,
     extent_len_t size);
 
index 80c4666cbd037fafe44ec6ad0745081e8790399b..120e6f07ad7885dc75085f10ca40424e03d8b5dd 100644 (file)
@@ -702,12 +702,14 @@ OMapInnerNode::get_containing_child(const std::string &key)
 
 std::ostream &OMapLeafNode::print_detail_l(std::ostream &out) const
 {
-  out << ", size=" << get_size()
-         << ", depth=" << get_meta().depth
-        << ", is_root=" << is_btree_root();
-  if (get_size() > 0) {
-    out << ", begin=" << get_begin()
-       << ", end=" << get_end();
+  if (is_fully_loaded()) {
+    out << ", size=" << get_size()
+       << ", depth=" << get_meta().depth
+       << ", is_root=" << is_btree_root();
+    if (get_size() > 0) {
+      out << ", begin=" << get_begin()
+         << ", end=" << get_end();
+    }
   }
   if (this->child_node_t::is_parent_valid())
     return out << ", parent=" << (void*)this->child_node_t::peek_parent_node().get();
index 638e061e96b18c62205c670b57f467b880f4bd48..dac5e97dcee87ef254b6193ace0e02858cac1575 100644 (file)
@@ -2068,11 +2068,35 @@ SeaStore::Shard::_rename(
   OnodeRef &onode,
   OnodeRef &d_onode)
 {
+  auto &objHandler = ObjectDataHandler(max_object_size);
+  co_await objHanlder.rename(ObjectDataHandler::context_t{
+    *transaction_manager, *ctx.transaction, *onode, d_onode.get()
+  });
+  auto get_prefix = [](Onode &onode) {
+    auto p = onode.get_clone_prefix();
+    assert(p);
+    return *p;
+  };
+  auto src_prefix = get_prefix(*onode);
+  auto dst_prefix = get_prefix(*d_onode);
+
+  auto rename_omap_root = [&](omap_type_t type) {
+    auto root = onode->get_root(type).get(d_onode->get_metadata_hint());
+    if (root.is_null()) {
+      return root;
+    }
+    auto offset = root.addr.get_byte_distance<loffset_t>(src_prefix);
+    root.update(
+      (dst_prefix + offset).checked_to_laddr(),
+      root.depth, d_onode->get_metadata_hint(), type);
+    return root;
+  };
+
   auto olayout = onode->get_layout();
   uint32_t size = olayout.size;
-  auto omap_root = rename_omap_root(omap_type_t::OMAP, *onode, *d_onode);
-  auto xattr_root = rename_omap_root(omap_type_t::XATTR, *onode, *d_onode);
-  auto object_data = olayout.object_data.get();
+  auto omap_root = rename_omap_root(omap_type_t::OMAP);
+  auto xattr_root = rename_omap_root(omap_type_t::XATTR);
+  auto log_root = rename_omap_root(omap_type_t::LOG);
   auto oi_bl = ceph::bufferlist::static_from_mem(
     &olayout.oi[0],
     (uint32_t)olayout.oi_size);
@@ -2083,16 +2107,15 @@ SeaStore::Shard::_rename(
   d_onode->update_onode_size(*ctx.transaction, size);
   d_onode->update_omap_root(*ctx.transaction, omap_root);
   d_onode->update_xattr_root(*ctx.transaction, xattr_root);
-  d_onode->update_object_data(*ctx.transaction, object_data);
+  d_onode->update_log_root(*ctx.transaction, log_root);
   d_onode->update_object_info(*ctx.transaction, oi_bl);
   d_onode->update_snapset(*ctx.transaction, ss_bl);
-  return onode_manager->erase_onode(
+  co_await onode_manager->erase_onode(
     *ctx.transaction, onode
   ).handle_error_interruptible(
     crimson::ct_error::input_output_error::pass_further(),
     crimson::ct_error::assert_all{
-      "Invalid error in SeaStoreS::_rename"}
-  );
+      "Invalid error in SeaStoreS::_rename"});
 }
 
 SeaStore::Shard::tm_ret
index 029f2216554e6363302a48fb5251fc5d3c86b297..70f334efdb90a7121a86fc4aa04bafb6d68ba421 100644 (file)
@@ -441,14 +441,6 @@ public:
         onode.get_metadata_hint(device->get_block_size()));
     }
 
-    omap_root_t rename_omap_root(
-      omap_type_t type,
-      Onode& onode,
-      Onode& d_onode) const {
-      return onode.get_root(type).get(
-        d_onode.get_metadata_hint(device->get_block_size()));
-    }
-
     omaptree_get_value_ret omaptree_get_value(
       Transaction& t,
       omap_root_t&& root,
index 52bcb187abf691df434c3a450f41310075ddd222..11b113b3378323cb241f774eff1be2180ddb98c9 100644 (file)
@@ -4,12 +4,15 @@
 #include "include/denc.h"
 #include "include/intarith.h"
 
+#include "crimson/common/coroutine.h"
 #include "crimson/os/seastore/logging.h"
 #include "crimson/os/seastore/transaction_manager.h"
 #include "crimson/os/seastore/journal.h"
 #include "crimson/os/seastore/journal/circular_bounded_journal.h"
 #include "crimson/os/seastore/lba/lba_btree_node.h"
 #include "crimson/os/seastore/random_block_manager/rbm_device.h"
+#include "crimson/os/seastore/object_data_handler.h"
+#include "crimson/os/seastore/omap_manager/btree/omap_btree_node_impl.h"
 
 /*
  * TransactionManager logs
@@ -410,6 +413,58 @@ TransactionManager::refs_ret TransactionManager::remove(
   });
 }
 
+base_iertr::future<LogicalChildNodeRef>
+TransactionManager::relocate_logical_extent(
+  Transaction &t, LBAMapping mapping)
+{
+  LOG_PREFIX(TransactionManager::relocate_logical_extent);
+  SUBDEBUGT(seastore_tm, "relocate {}", t, mapping);
+  assert(!mapping.is_indirect());
+  assert(!mapping.is_zero_reserved());
+  assert(mapping.is_viewable());
+  auto v = get_extent_if_linked(t, *(mapping.direct_cursor));
+  if (!v.has_child()) {
+    auto &child_pos = v.get_child_pos();
+    auto laddr = mapping.get_key();
+    std::ignore = cache->retire_absent_extent_addr_by_type(
+      t,
+      laddr,
+      mapping.get_val(),
+      mapping.get_length(),
+      mapping.get_extent_type(),
+      [laddr, &child_pos](auto &extent) {
+        auto lextent = extent.template cast<LogicalChildNode>();
+        assert(extent.is_logical());
+        assert(!lextent->has_laddr());
+        assert(!extent.has_been_invalidated());
+        child_pos.link_child(lextent.get());
+        lextent->set_laddr(laddr);
+      }
+    );
+    co_return cache->alloc_remapped_extent_by_type(
+      t, mapping.get_extent_type(), mapping.get_key(),
+      mapping.get_val(), 0, mapping.get_length(), std::nullopt
+    )->cast<LogicalChildNode>();
+  }
+
+  auto extent = co_await v.get_child_fut().si_then([](auto ext) {
+    return ext;
+  });
+
+  if (extent->is_stable()) {
+    cache->retire_extent(t, extent);
+    co_return cache->alloc_remapped_extent_by_type(
+      t, mapping.get_extent_type(), mapping.get_key(),
+      mapping.get_val(), 0, mapping.get_length(), std::nullopt
+    )->cast<LogicalChildNode>();
+  } else {
+    //TODO: relocating logical extents doesn't support
+    //      mutation pending extents yet.
+    assert(extent->is_initial_pending() || extent->is_exist_clean());
+    co_return extent;
+  }
+}
+
 TransactionManager::submit_transaction_iertr::future<>
 TransactionManager::submit_transaction(
   Transaction &t)
@@ -817,6 +872,139 @@ TransactionManager::rewrite_extent_ret TransactionManager::rewrite_extent(
   });
 }
 
+TransactionManager::move_region_ret
+TransactionManager::move_region(
+  Transaction &t,
+  LBAMapping src,
+  LBAMapping dst,
+  laddr_t dst_prefix,
+  bool move_indirect)
+{
+  LOG_PREFIX(TransactionManager::move_region);
+  DEBUGT("src: {}, dst: {}, prefix: {}", t, src, dst, dst_prefix);
+  auto src_prefix = src.get_key().get_metadata_prefix();
+  assert(dst.get_key().get_metadata_prefix() != dst_prefix);
+  auto calc_dst_key = [&src, dst_prefix] {
+    auto key = src.get_key();
+    auto offset = key.get_byte_distance<loffset_t>(key.get_metadata_prefix());
+    return (dst_prefix + offset).checked_to_laddr();
+  };
+
+  assert(src.is_viewable());
+  assert(dst.is_viewable());
+  // move mapping from src to dst
+  while (src.get_key().get_metadata_prefix() == src_prefix) {
+    if (src.is_indirect()) {
+      if (move_indirect) {
+        auto ret = co_await lba_manager->move_indirect_mapping(
+          t,
+          src.get_effective_cursor_ref(),
+          calc_dst_key(),
+          dst.get_effective_cursor_ref());
+        src = co_await resolve_cursor_to_mapping(t, std::move(ret.src));
+        dst = co_await resolve_cursor_to_mapping(t, std::move(ret.dest));
+      } else {
+        using namespace crimson::os::seastore::omap_manager;
+        switch (src.get_extent_type()) {
+        case extent_types_t::OBJECT_DATA_BLOCK:
+          {
+            auto maybe_indirect_extent = co_await read_pin<ObjectDataBlock>(
+              t, src, src.get_intermediate_offset(), src.get_length());
+            auto extents = co_await alloc_data_extents<ObjectDataBlock>(
+              t,
+              laddr_hint_t::create_as_fixed(calc_dst_key()),
+              src.get_length(),
+              dst
+            ).handle_error_interruptible(
+              move_region_iertr::pass_further(),
+              crimson::ct_error::assert_all("invalid error"));
+            auto off = 0;
+            auto bl = maybe_indirect_extent.get_range(
+              src.get_intermediate_offset(),
+              src.get_length());
+            auto iter = bl.begin();
+            for (auto &extent : extents) {
+              auto &ext = *extent;
+              assert(off + ext.get_length() <= src.get_length());
+              iter.copy(ext.get_length(), ext.get_bptr().c_str());
+              off += ext.get_length();
+            }
+          }
+          break;
+        case extent_types_t::OMAP_LEAF:
+          {
+            auto maybe_indirect_extent = co_await read_pin<OMapLeafNode>(
+              t, src, src.get_intermediate_offset(), src.get_length());
+            auto extent = co_await alloc_non_data_extent<OMapLeafNode>(
+              t,
+              laddr_hint_t::create_as_fixed(calc_dst_key()),
+              src.get_length()
+            ).handle_error_interruptible(
+              move_region_iertr::pass_further(),
+              crimson::ct_error::assert_all("invalid error"));
+            extent->set_bptr(maybe_indirect_extent.extent->get_bptr());
+          }
+          break;
+        case extent_types_t::OMAP_INNER:
+          {
+            auto maybe_indirect_extent = co_await read_pin<OMapInnerNode>(
+              t, src, src.get_intermediate_offset(), src.get_length());
+            auto extent = co_await alloc_non_data_extent<OMapInnerNode>(
+              t,
+              laddr_hint_t::create_as_fixed(calc_dst_key()),
+              src.get_length()
+            ).handle_error_interruptible(
+              move_region_iertr::pass_further(),
+              crimson::ct_error::assert_all("invalid error"));
+            extent->set_bptr(maybe_indirect_extent.extent->get_bptr());
+          }
+          break;
+        default:
+          ceph_abort("unexpected extent type");
+          break;
+        }
+        auto cursor = co_await lba_manager->update_mapping_refcount(
+          t, src.indirect_cursor, -1
+        ).handle_error_interruptible(
+          move_region_iertr::pass_further(),
+          crimson::ct_error::assert_all("invalid error"));
+        src = co_await resolve_cursor_to_mapping(t, std::move(cursor));
+        dst = co_await dst.refresh();
+      }
+    } else if (!src.is_zero_reserved()) {
+      auto extent = co_await relocate_logical_extent(t, src);
+      auto laddr = calc_dst_key();
+      extent->set_laddr(laddr);
+      auto ret = co_await lba_manager->move_direct_mapping(
+        t, src.get_effective_cursor_ref(),
+        laddr, dst.get_effective_cursor_ref(), *extent);
+      src = co_await resolve_cursor_to_mapping(t, std::move(ret.src));
+      dst = co_await resolve_cursor_to_mapping(t, std::move(ret.dest));
+    } else { // src is direct mapping
+      auto len = src.get_length();
+      auto dst_key = calc_dst_key();
+      auto type = src.get_extent_type();
+      dst = co_await dst.refresh();
+      auto insert = co_await reserve_region(
+        t, std::move(dst), dst_key, len, type
+      ).handle_error_interruptible(
+        move_region_iertr::pass_further(),
+        crimson::ct_error::assert_all("invalid error"));
+      src = co_await src.refresh();
+      auto cursor = co_await lba_manager->update_mapping_refcount(
+        t, src.get_effective_cursor_ref(), -1
+      ).handle_error_interruptible(
+        move_region_iertr::pass_further(),
+        crimson::ct_error::assert_all("invalid error"));
+      src = co_await resolve_cursor_to_mapping(t, std::move(cursor));
+      dst = co_await insert.next();
+    }
+    assert(src.is_viewable());
+    assert(dst.is_viewable());
+  }
+  co_return;
+}
+
 TransactionManager::get_extents_if_live_ret
 TransactionManager::get_extents_if_live(
   Transaction &t,
index 6e18d4c86254185c2242902f114f3494e2c9a665..d1b7c11f85951948633a51e6bfb74c6255d7f23c 100644 (file)
@@ -104,6 +104,16 @@ public:
     return cache->reset_transaction_preserve_handle(t);
   }
 
+  /**
+   * relocate_logical_extent
+   *
+   * Make a new logical extent to update its laddr. The caller is
+   * responsible to update the corresponding lba mapping.
+   */
+  base_iertr::future<LogicalChildNodeRef> relocate_logical_extent(
+    Transaction &t,
+    LBAMapping mapping);
+
   /**
    * get_pin
    *
@@ -790,6 +800,15 @@ public:
     co_return clone_range_ret_t{shared_direct, std::move(pos)};
   }
 
+  using move_region_iertr = base_iertr;
+  using move_region_ret = move_region_iertr::future<>;
+  move_region_ret move_region(
+    Transaction &t,
+    LBAMapping src,
+    LBAMapping dst,
+    laddr_t dst_prefix,
+    bool move_indirect);
+
   /* alloc_extents
    *
    * allocates more than one new blocks of type T.