]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-ci.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, 2 Feb 2026 11:37:02 +0000 (19:37 +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 b5967d9f808b7f83d20bf45c607af3e13ae05887..3f19add7dcafaa73c826934a16d028ff17e83624 100644 (file)
@@ -1225,20 +1225,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 4d7c22eaf5813cd7e477691fdcd246f7728a8146..5fd42857bf2e54599db394baab63cdbf3d2fdac2 100644 (file)
@@ -1360,12 +1360,14 @@ BtreeLBAManager::remap_mappings(
       assert(mapping.is_indirect() ||
        (val.pladdr.is_paddr() &&
         val.pladdr.get_paddr().is_absolute()));
+      // remove the remapped mapping
       return update_refcount(c.trans, &cursor, -1
       ).si_then([&mapping, &btree, &iter, c, &ret,
                &remaps, pladdr=val.pladdr](auto r) {
        assert(r.refcount == 0);
        auto &cursor = r.mapping.get_effective_cursor();
        iter = btree.make_partial_iter(c, cursor);
+       // insert new remap mapping
        return trans_intr::do_for_each(
          remaps,
          [&mapping, &btree, &iter, c, &ret, pladdr](auto &remap) {
@@ -1423,6 +1425,9 @@ BtreeLBAManager::remap_mappings(
        return base_iertr::now();
       }).si_then([this, c, &mapping, &remaps] {
        if (remaps.size() > 1 && mapping.is_indirect()) {
+         // increase the refcount of the direct mapping if
+         // the mapping is indirect and it's remapped into
+         // more than 1 mappings
          auto &cursor = mapping.direct_cursor;
          assert(cursor->is_viewable());
          return update_refcount(
@@ -1445,4 +1450,138 @@ BtreeLBAManager::remap_mappings(
   });
 }
 
+BtreeLBAManager::move_mapping_ret
+BtreeLBAManager::_copy_mapping(
+  op_context_t c,
+  LBABtree &btree,
+  LBAMapping src,
+  laddr_t dest_laddr,
+  LBAMapping dest,
+  LogicalChildNode *extent)
+{
+  LOG_PREFIX(BtreeLBAManager::_copy_mapping);
+  assert(dest.is_viewable());
+  assert(src.is_viewable());
+  assert(!src.is_end());
+  assert(src.direct_cursor->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.get_effective_cursor();
+  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
+  auto [niter, inserted] = co_await btree.insert(
+      c,
+      std::move(iter),
+      dest_laddr,
+      lba_map_val_t{
+       ret.src.get_length(),
+       ret.src.is_indirect()
+         ? pladdr_t(ret.src.get_intermediate_key().get_local_clone_id())
+         : pladdr_t(ret.src.get_val()),
+       EXTENT_DEFAULT_REF_COUNT,
+       ret.src.is_indirect() ? 0 : ret.src.get_checksum(),
+       ret.src.get_extent_type()});
+  ceph_assert(inserted);
+  // attach extent to the new mapping if it exists
+  auto &leaf_node = *niter.get_leaf_node();
+  leaf_node.insert_child_ptr(
+    niter.get_leaf_pos(),
+    extent ? extent : get_reserved_ptr<LBALeafNode, laddr_t>(),
+    leaf_node.get_size() - 1 /*the size before the insert*/);
+  ret.dest = LBAMapping::create_direct(niter.get_cursor(c));
+  ret.src = co_await ret.src.refresh();
+  co_return ret;
+}
+
+BtreeLBAManager::move_mapping_ret
+BtreeLBAManager::_move_mapping(
+  Transaction &t,
+  LBAMapping src,
+  laddr_t dest_laddr,
+  LBAMapping dest,
+  LogicalChildNode *extent) {
+  LOG_PREFIX(BtreeLBAManager::move_direct_mapping);
+  assert(dest.is_viewable());
+  assert(src.is_viewable());
+  assert(!src.is_indirect());
+  assert(!src.is_end());
+  assert(src.direct_cursor->get_refcount() == EXTENT_DEFAULT_REF_COUNT);
+  DEBUGT("src={} dest={}", t, src, dest);
+  auto c = get_context(t);
+  auto btree = co_await get_btree(t);
+  auto ret = co_await _copy_mapping(
+    c, btree, std::move(src), dest_laddr, std::move(dest), extent);
+
+  auto res = co_await update_refcount(
+    c.trans, &ret.src.get_effective_cursor(), -1
+  ).handle_error_interruptible(
+    move_mapping_iertr::pass_further{},
+    crimson::ct_error::assert_all{"unexpected error"});
+
+  ceph_assert(res.refcount == 0);
+
+  if (auto &cursor = res.mapping.get_effective_cursor();
+      cursor.is_indirect()) {
+    ret.src = LBAMapping::create_indirect(nullptr, &cursor);
+  } else {
+    ret.src = LBAMapping::create_direct(&cursor);
+  }
+  auto m = co_await ret.dest.refresh();
+  ret.dest = co_await m.next();
+
+  co_return ret;
+}
+
+BtreeLBAManager::move_mapping_ret
+BtreeLBAManager::move_and_clone_direct_mapping(
+  Transaction &t,
+  LBAMapping src,
+  laddr_t dest_laddr,
+  LBAMapping dest,
+  LogicalChildNode &extent)
+{
+  LOG_PREFIX(BtreeLBAManager::move_and_clone_direct_mapping);
+  assert(dest.is_viewable());
+  assert(src.is_viewable());
+  assert(!src.is_indirect());
+  assert(!src.is_end());
+  assert(src.direct_cursor->get_refcount() == EXTENT_DEFAULT_REF_COUNT);
+  DEBUGT("src={} dest={}", t, src, dest);
+  auto c = get_context(t);
+  auto btree = co_await get_btree(t);
+  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 res = co_await _update_mapping(
+    c.trans,
+    *ret.src.direct_cursor,
+    [&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(res.is_alive_mapping());
+  auto cursor = res.take_cursor();
+  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 = LBAMapping::create_indirect(nullptr, std::move(cursor));
+  ret.dest = co_await ret.dest.refresh();
+  co_return ret;
+}
+
 }
index e502604309649ecf99c6b1f4209f0535fc1a2859..7dbd3f1e62139f54469dd26cdb8b0027287585cf 100644 (file)
@@ -111,6 +111,34 @@ public:
     extent_len_t len,
     bool updateref) final;
 
+  move_mapping_ret move_indirect_mapping(
+    Transaction &t,
+    LBAMapping src,
+    laddr_t dest_laddr,
+    LBAMapping 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,
+    LBAMapping src,
+    laddr_t dest_laddr,
+    LBAMapping 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,
+    LBAMapping src,
+    laddr_t dest_laddr,
+    LBAMapping dest,
+    LogicalChildNode &extent) final;
+
 #ifdef UNIT_TESTS_BUILT
   get_end_mapping_ret get_end_mapping(Transaction &t) final;
 #endif
@@ -429,6 +457,12 @@ private:
     }
   };
 
+  base_iertr::future<LBABtree> get_btree(Transaction &t) {
+    return cache.get_root(t).si_then([](auto croot) {
+      return LBABtree(croot);
+    });
+  }
+
   op_context_t get_context(Transaction &t) {
     return op_context_t{cache, t};
   }
@@ -534,6 +568,37 @@ private:
     std::variant<laddr_t, LBACursor*> addr_or_cursor,
     int delta);
 
+  /*
+   * _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,
+    LBAMapping src,
+    laddr_t dest_laddr,
+    LBAMapping 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,
+    LBAMapping src,
+    laddr_t dest_laddr,
+    LBAMapping dest,
+    LogicalChildNode *extent);
+
   /**
    * _update_mapping
    *
index 450004debf9a08994e4187c12078ac8aa2292632..c8ba193df4ad69699b3ec82ba429f18270009758 100644 (file)
@@ -131,6 +131,54 @@ public:
                                // direct mapping
   ) = 0;
 
+  struct move_mapping_ret_t {
+    LBAMapping src;
+    LBAMapping 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,
+    LBAMapping src,
+    laddr_t dest_laddr,
+    LBAMapping 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,
+    LBAMapping src,
+    laddr_t dest_laddr,
+    LBAMapping 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,
+    LBAMapping src,
+    laddr_t dest_laddr,
+    LBAMapping dest,
+    LogicalChildNode &extent) = 0;
+
   virtual alloc_extent_ret reserve_region(
     Transaction &t,
     laddr_hint_t hint,
index 5849bc94cf718b83e7893a1f39fb376845256944..6581cf375fb359b643adccd1afdfd51b9d852610 100644 (file)
@@ -425,6 +425,10 @@ public:
     set_child_ptracker(child);
   }
 
+  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 f2e8b8752a4bb2225f0fd7cc53f0643b21a548ca..3e7276828e299323433326f0e191c1dfb6a82cc1 100644 (file)
@@ -1367,8 +1367,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();