]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
crimson/os/seastore: add "move_mapping" to TransactionManager and LBAManager
authorXuehan Xu <xuxuehan@qianxin.com>
Tue, 26 Aug 2025 06:28:55 +0000 (14:28 +0800)
committerXuehan Xu <xuxuehan@qianxin.com>
Mon, 25 May 2026 08:55:31 +0000 (16:55 +0800)
Signed-off-by: Xuehan Xu <xuxuehan@qianxin.com>
src/crimson/os/seastore/cache.h
src/crimson/os/seastore/lba/btree_lba_manager.cc
src/crimson/os/seastore/lba/btree_lba_manager.h
src/crimson/os/seastore/lba_manager.h
src/crimson/os/seastore/linked_tree_node.h
src/crimson/os/seastore/transaction_manager.h

index 9d289c1672c2948ca7eb8a97a89960128be9cb28..bcf15a3fda725b01f0f90c16443c279550bfc257 100644 (file)
@@ -1216,20 +1216,15 @@ public:
     Transaction &t,
     laddr_t remap_laddr,
     paddr_t remap_paddr,
+    extent_len_t remap_offset,
     extent_len_t remap_length,
-    laddr_t original_laddr,
-    std::optional<ceph::bufferptr> &original_bptr) {
+    const std::optional<ceph::bufferptr> &original_bptr) {
     LOG_PREFIX(Cache::alloc_remapped_extent);
-    assert(remap_laddr >= original_laddr);
     TCachedExtentRef<T> ext;
     if (original_bptr.has_value()) {
       // shallow copy the buffer from original extent
-      auto remap_offset = remap_laddr.get_byte_distance<
-       extent_len_t>(original_laddr);
-
       auto nbp = ceph::bufferptr(buffer::create_page_aligned(remap_length));
       original_bptr->copy_out(remap_offset, remap_length, nbp.c_str());
-
       // ExtentPlacementManager::alloc_new_extent will make a new
       // (relative/temp) paddr, so make extent directly
       ext = CachedExtent::make_cached_extent_ref<T>(std::move(nbp));
index d2c35cfeb4016c72038234e42e1b4eb3f3f36513..019684a350f56e2316b9f4f3ad2c506d4595324e 100644 (file)
@@ -1097,4 +1097,132 @@ BtreeLBAManager::remap_mappings(
   co_return ret;
 }
 
+BtreeLBAManager::move_mapping_ret
+BtreeLBAManager::_copy_mapping(
+  op_context_t c,
+  LBABtree &btree,
+  LBACursorRef src,
+  laddr_t dest_laddr,
+  LBACursorRef dest,
+  LogicalChildNode *extent)
+{
+  LOG_PREFIX(BtreeLBAManager::_copy_mapping);
+  assert(src && dest);
+  assert(dest->is_viewable());
+  assert(src->is_viewable());
+  assert(!src->is_end());
+  assert(src->get_refcount() == EXTENT_DEFAULT_REF_COUNT);
+  assert(!src->is_indirect() == (bool)extent);
+  DEBUGT("src={} dest={}", c.trans, *src, *dest);
+  move_mapping_ret_t ret{std::move(src), std::move(dest)};
+  auto &cursor = *ret.dest;
+  auto iter = btree.make_partial_iter(c, cursor);
+  if (!iter.is_end()) {
+    assert(iter.get_key() >= dest_laddr + ret.src->get_length());
+  }
+  // insert the src mapping to dest
+  // attach extent to the new mapping if it exists
+  pladdr_t addr;
+  if (ret.src->is_indirect()) {
+    addr = ret.src->get_intermediate_key().get_local_clone_id();
+  } else {
+    addr = ret.src->get_paddr();
+  }
+  auto [niter, inserted] = co_await btree.insert(
+      c,
+      std::move(iter),
+      dest_laddr,
+      lba_map_val_t{
+       ret.src->get_length(),
+        std::move(addr),
+       EXTENT_DEFAULT_REF_COUNT,
+       ret.src->is_indirect() ? 0 : ret.src->get_checksum(),
+       ret.src->get_extent_type()},
+      extent ? extent : get_reserved_ptr<LBALeafNode, laddr_t>());
+  ceph_assert(inserted);
+  ret.dest = niter.get_cursor(c);
+  co_await ret.src->refresh();
+  co_return ret;
+}
+
+BtreeLBAManager::move_mapping_ret
+BtreeLBAManager::_move_mapping(
+  Transaction &t,
+  LBACursorRef src,
+  laddr_t dest_laddr,
+  LBACursorRef dest,
+  LogicalChildNode *extent) {
+  LOG_PREFIX(BtreeLBAManager::_move_mapping);
+  assert(src && dest);
+  assert(dest->is_viewable());
+  assert(src->is_viewable());
+  assert(!src->is_end());
+  assert(src->get_refcount() == EXTENT_DEFAULT_REF_COUNT);
+  DEBUGT("src={} dest={}", t, *src, *dest);
+  auto c = get_context(t);
+  auto btree = co_await get_btree<LBABtree>(cache, c);
+  auto ret = co_await _copy_mapping(
+    c, btree, std::move(src), dest_laddr, std::move(dest), extent);
+
+  ret.src = co_await update_mapping_refcount(
+    c.trans, ret.src, -1
+  ).handle_error_interruptible(
+    move_mapping_iertr::pass_further{},
+    crimson::ct_error::assert_all{"unexpected error"});
+
+  co_await ret.dest->refresh();
+  auto iter = btree.make_partial_iter(c, *ret.dest);
+  iter = co_await iter.next(c);
+  ret.dest = iter.get_cursor(c);
+
+  co_return ret;
+}
+
+BtreeLBAManager::move_mapping_ret
+BtreeLBAManager::move_and_clone_direct_mapping(
+  Transaction &t,
+  LBACursorRef src,
+  laddr_t dest_laddr,
+  LBACursorRef dest,
+  LogicalChildNode &extent)
+{
+  LOG_PREFIX(BtreeLBAManager::move_and_clone_direct_mapping);
+  assert(src && dest);
+  assert(dest->is_viewable());
+  assert(src->is_viewable());
+  assert(!src->is_indirect());
+  assert(!src->is_end());
+  assert(src->get_refcount() == EXTENT_DEFAULT_REF_COUNT);
+  DEBUGT("src={} dest={}", t, *src, *dest);
+  auto c = get_context(t);
+  auto btree = co_await get_btree<LBABtree>(cache, c);
+  auto ret = co_await _copy_mapping(
+    c, btree, std::move(src), dest_laddr, std::move(dest), &extent);
+
+  // turn the src mapping into an indirect one pointing to
+  // the previously inserted mapping
+  auto cursor = co_await _update_mapping(
+    c.trans,
+    *ret.src,
+    [&ret](const auto &in) {
+      lba_map_val_t val = in;
+      val.pladdr = ret.dest->get_key().get_local_clone_id();
+      val.checksum = 0;
+      return val;
+    },
+    nullptr
+  ).handle_error_interruptible(
+    move_mapping_iertr::pass_further{},
+    crimson::ct_error::assert_all{"unexpected error"});
+
+  assert(cursor->is_indirect());
+  auto iter = btree.make_partial_iter(c, *cursor);
+  DEBUGT("resetting child ptr, leaf: {}, pos: {}",
+        t, *iter.get_leaf_node(), iter.get_leaf_pos());
+  iter.get_leaf_node()->reset_child_ptr(iter.get_leaf_pos());
+  ret.src = std::move(cursor);
+  co_await ret.dest->refresh();
+  co_return ret;
+}
+
 }
index 04628f7ee26f919b78bfe0594d664a329f9c1517..04944968ea5d48fe3d5f8d17f92c186c79556642 100644 (file)
@@ -105,6 +105,34 @@ public:
     extent_len_t len,
     bool updateref) final;
 
+  move_mapping_ret move_indirect_mapping(
+    Transaction &t,
+    LBACursorRef src,
+    laddr_t dest_laddr,
+    LBACursorRef dest) final {
+    assert(src->is_indirect());
+    return _move_mapping(
+      t, std::move(src), dest_laddr, std::move(dest), nullptr);
+  }
+
+  move_mapping_ret move_direct_mapping(
+    Transaction &t,
+    LBACursorRef src,
+    laddr_t dest_laddr,
+    LBACursorRef dest,
+    LogicalChildNode &extent) final {
+    assert(!src->is_indirect());
+    return _move_mapping(
+      t, std::move(src), dest_laddr, std::move(dest), &extent);
+  }
+
+  move_mapping_ret move_and_clone_direct_mapping(
+    Transaction &t,
+    LBACursorRef src,
+    laddr_t dest_laddr,
+    LBACursorRef dest,
+    LogicalChildNode &extent) final;
+
 #ifdef UNIT_TESTS_BUILT
   get_end_mapping_ret get_end_mapping(Transaction &t) final;
 #endif
@@ -324,6 +352,37 @@ private:
   seastar::metrics::metric_group metrics;
   void register_metrics(store_index_t store_index);
 
+  /*
+   * _move_mapping
+   *
+   * copy the mapping "src" to "dest" and remove the "src" mapping.
+   *
+   * Return: the mappings next to "src" and the "dest" mapping
+   */
+  move_mapping_ret _move_mapping(
+    Transaction &t,
+    LBACursorRef src,
+    laddr_t dest_laddr,
+    LBACursorRef dest,
+    LogicalChildNode *extent);
+
+  /*
+   * _copy_mapping
+   *
+   * copy the mapping "src" to "dest", the extent attached to
+   * "src" will also be attached to the dest. This is the building
+   * block for _move_mapping and move_and_clone_direct_mapping
+   *
+   * Return: the "src" and the new "dest"
+   */
+  move_mapping_ret _copy_mapping(
+    op_context_t c,
+    LBABtree &btree,
+    LBACursorRef src,
+    laddr_t dest_laddr,
+    LBACursorRef dest,
+    LogicalChildNode *extent);
+
   /**
    * _update_mapping
    *
index a0e4dcec518a2c463492662d1cdf4d009b7d938a..3e3d1d9f8529de7950284c128f74303ecf1eb61d 100644 (file)
@@ -114,6 +114,54 @@ public:
                                // direct mapping
   ) = 0;
 
+  struct move_mapping_ret_t {
+    LBACursorRef src;
+    LBACursorRef dest;
+  };
+  /*
+   * move_and_clone_direct_mapping
+   *
+   * move the direct mapping "src" to "dest" and clone it at the
+   * position of "src".
+   *
+   * Return: the new indirect mapping and the moved direct mapping
+   */
+  using move_mapping_iertr = alloc_extent_iertr;
+  using move_mapping_ret = move_mapping_iertr::future<move_mapping_ret_t>;
+  virtual move_mapping_ret move_and_clone_direct_mapping(
+    Transaction &t,
+    LBACursorRef src,
+    laddr_t dest_laddr,
+    LBACursorRef dest,
+    LogicalChildNode &extent) = 0;
+
+  /*
+   * move_indirect_mapping
+   *
+   * move the indirect mapping "src" to dest, and remove "src".
+   *
+   * Return: the mapping next to "src" and the original "dest"
+   */
+  virtual move_mapping_ret move_indirect_mapping(
+    Transaction &t,
+    LBACursorRef src,
+    laddr_t dest_laddr,
+    LBACursorRef dest) = 0;
+
+  /*
+   * move_direct_mapping
+   *
+   * move the indirect mapping "src" to dest, and remove "src".
+   *
+   * Return: the mapping next to "src" and the original "dest"
+   */
+  virtual move_mapping_ret move_direct_mapping(
+    Transaction &t,
+    LBACursorRef src,
+    laddr_t dest_laddr,
+    LBACursorRef dest,
+    LogicalChildNode &extent) = 0;
+
   virtual alloc_extent_ret reserve_region(
     Transaction &t,
     laddr_hint_t hint,
index bd077130f6c8dbdfc4c584692f1704979ea2446f..737985e863f08bb6798a867993a9c91f37916068 100644 (file)
@@ -425,6 +425,10 @@ public:
     }
   }
 
+  void reset_child_ptr(btreenode_pos_t pos) {
+    children[pos] = get_reserved_ptr<T, node_key_t>();
+  }
+
 protected:
   ParentNode(btreenode_pos_t capacity)
     : children(capacity, nullptr) {}
index 945f9063e1fa83c420f7a3b7648e057397dcbf19..6e18d4c86254185c2242902f114f3494e2c9a665 100644 (file)
@@ -1471,8 +1471,8 @@ private:
           t,
           remap_laddr,
           remap_paddr,
+          remap_offset,
           remap_len,
-          original_laddr,
           original_bptr);
         // user must initialize the logical extent themselves.
         remapped_extent->set_seen_by_users();