From: Zhang Song Date: Tue, 26 Aug 2025 03:42:49 +0000 (+0800) Subject: crimson/os/seastore: support rename for static layout of laddr X-Git-Tag: v21.0.1~152^2~11 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=1aa88f34e74c795789590bb951e3d2c5c33ca818;p=ceph.git crimson/os/seastore: support rename for static layout of laddr Signed-off-by: Zhang Song Signed-off-by: Xuehan Xu --- diff --git a/src/crimson/os/seastore/cache.cc b/src/crimson/os/seastore/cache.cc index b991e0c1295a..c6840d7670fe 100644 --- a/src/crimson/os/seastore/cache.cc +++ b/src/crimson/os/seastore/cache.cc @@ -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 &original_bptr) +{ + ceph_assert(is_logical_type(type)); + switch (type) { + case extent_types_t::ROOT_META: + return alloc_remapped_extent( + t, remap_laddr, remap_paddr, remap_offset, remap_length, original_bptr); + case extent_types_t::OMAP_INNER: + return alloc_remapped_extent( + t, remap_laddr, remap_paddr, remap_offset, remap_length, original_bptr); + case extent_types_t::OMAP_LEAF: + return alloc_remapped_extent( + t, remap_laddr, remap_paddr, remap_offset, remap_length, original_bptr); + case extent_types_t::ONODE_BLOCK_STAGED: + return alloc_remapped_extent( + t, remap_laddr, remap_paddr, remap_offset, remap_length, original_bptr); + case extent_types_t::COLL_BLOCK: + return alloc_remapped_extent( + t, remap_laddr, remap_paddr, remap_offset, remap_length, original_bptr); + case extent_types_t::OBJECT_DATA_BLOCK: + return alloc_remapped_extent( + t, remap_laddr, remap_paddr, remap_offset, remap_length, original_bptr); + case extent_types_t::TEST_BLOCK: + return alloc_remapped_extent( + 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 diff --git a/src/crimson/os/seastore/cache.h b/src/crimson/os/seastore/cache.h index bcf15a3fda72..e6ebb2a72670 100644 --- a/src/crimson/os/seastore/cache.h +++ b/src/crimson/os/seastore/cache.h @@ -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 &original_bptr); + /** * alloc_new_non_data_extent_by_type * diff --git a/src/crimson/os/seastore/object_data_handler.cc b/src/crimson/os/seastore/object_data_handler.cc index 1167c8f6a1d9..9ebd21e003c2 100644 --- a/src/crimson/os/seastore/object_data_handler.cc +++ b/src/crimson/os/seastore/object_data_handler.cc @@ -104,6 +104,7 @@ auto with_objects_data( ObjectDataHandler::write_iertr::future> 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>(); } 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 diff --git a/src/crimson/os/seastore/object_data_handler.h b/src/crimson/os/seastore/object_data_handler.h index 49b7804dd9d2..44b3d6f39a78 100644 --- a/src/crimson/os/seastore/object_data_handler.h +++ b/src/crimson/os/seastore/object_data_handler.h @@ -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> prepare_data_reservation( context_t ctx, + Onode &onode, object_data_t &object_data, extent_len_t size); diff --git a/src/crimson/os/seastore/omap_manager/btree/omap_btree_node_impl.cc b/src/crimson/os/seastore/omap_manager/btree/omap_btree_node_impl.cc index 80c4666cbd03..120e6f07ad78 100644 --- a/src/crimson/os/seastore/omap_manager/btree/omap_btree_node_impl.cc +++ b/src/crimson/os/seastore/omap_manager/btree/omap_btree_node_impl.cc @@ -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(); diff --git a/src/crimson/os/seastore/seastore.cc b/src/crimson/os/seastore/seastore.cc index 638e061e96b1..dac5e97dcee8 100644 --- a/src/crimson/os/seastore/seastore.cc +++ b/src/crimson/os/seastore/seastore.cc @@ -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(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 diff --git a/src/crimson/os/seastore/seastore.h b/src/crimson/os/seastore/seastore.h index 029f2216554e..70f334efdb90 100644 --- a/src/crimson/os/seastore/seastore.h +++ b/src/crimson/os/seastore/seastore.h @@ -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, diff --git a/src/crimson/os/seastore/transaction_manager.cc b/src/crimson/os/seastore/transaction_manager.cc index 52bcb187abf6..11b113b33783 100644 --- a/src/crimson/os/seastore/transaction_manager.cc +++ b/src/crimson/os/seastore/transaction_manager.cc @@ -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 +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(); + 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(); + } + + 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(); + } 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(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( + t, src, src.get_intermediate_offset(), src.get_length()); + auto extents = co_await alloc_data_extents( + 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( + t, src, src.get_intermediate_offset(), src.get_length()); + auto extent = co_await alloc_non_data_extent( + 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( + t, src, src.get_intermediate_offset(), src.get_length()); + auto extent = co_await alloc_non_data_extent( + 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, diff --git a/src/crimson/os/seastore/transaction_manager.h b/src/crimson/os/seastore/transaction_manager.h index 6e18d4c86254..d1b7c11f8595 100644 --- a/src/crimson/os/seastore/transaction_manager.h +++ b/src/crimson/os/seastore/transaction_manager.h @@ -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 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.