diff --git a/src/crimson/os/seastore/transaction_manager.h b/src/crimson/os/seastore/transaction_manager.h index 420d3da6f9d..9dcc577e777 100644 --- a/src/crimson/os/seastore/transaction_manager.h +++ b/src/crimson/os/seastore/transaction_manager.h @@ -291,6 +291,125 @@ public: }); } + /** + * remap_pin + * + * Remap original extent to new extents. + * Return the pins of new extent. + */ + struct remap_entry { + extent_len_t offset; + extent_len_t len; + remap_entry(extent_len_t _offset, extent_len_t _len) { + offset = _offset; + len = _len; + } + }; + using remap_pin_iertr = base_iertr; + template + using remap_pin_ret = remap_pin_iertr::future>; + template + remap_pin_ret remap_pin( + Transaction &t, + LBAMappingRef &&pin, + std::array remaps) { + +#ifndef NDEBUG + std::sort(remaps.begin(), remaps.end(), + [](remap_entry x, remap_entry y) { + return x.offset < y.offset; + }); + auto original_len = pin->get_length(); + extent_len_t total_remap_len = 0; + extent_len_t last_offset = 0; + extent_len_t last_len = 0; + + for (auto &remap : remaps) { + auto remap_offset = remap.offset; + auto remap_len = remap.len; + total_remap_len += remap.len; + ceph_assert(remap_offset >= (last_offset + last_len)); + last_offset = remap_offset; + last_len = remap_len; + } + ceph_assert(total_remap_len < original_len); +#endif + + // FIXME: paddr can be absolute and pending + ceph_assert(pin->get_val().is_absolute()); + return cache->get_extent_if_cached( + t, pin->get_val(), T::TYPE + ).si_then([this, &t, remaps, + original_laddr = pin->get_key(), + original_paddr = pin->get_val(), + original_len = pin->get_length()](auto ext) { + std::optional original_bptr; + LOG_PREFIX(TransactionManager::remap_pin); + SUBDEBUGT(seastore_tm, + "original laddr: {}, original paddr: {}, original length: {}," + " remap to {} extents", + t, original_laddr, original_paddr, original_len, remaps.size()); + if (ext) { + // FIXME: cannot and will not remap a dirty extent for now. + ceph_assert(!ext->is_dirty()); + ceph_assert(!ext->is_mutable()); + ceph_assert(ext->get_length() == original_len); + original_bptr = ext->get_bptr(); + } + return seastar::do_with( + std::array(), + 0, + std::move(original_bptr), + std::vector(remaps.begin(), remaps.end()), + [this, &t, original_laddr, original_paddr, original_len] + (auto &ret, auto &count, auto &original_bptr, auto &remaps) { + return dec_ref(t, original_laddr + ).si_then([this, &t, &original_bptr, &ret, &count, &remaps, + original_laddr, original_paddr, original_len](auto) { + return trans_intr::do_for_each( + remaps.begin(), + remaps.end(), + [this, &t, &original_bptr, &ret, &count, + original_laddr, original_paddr, original_len](auto &remap) { + LOG_PREFIX(TransactionManager::remap_pin); + auto remap_offset = remap.offset; + auto remap_len = remap.len; + auto remap_laddr = original_laddr + remap_offset; + auto remap_paddr = original_paddr.add_offset(remap_offset); + ceph_assert(remap_len < original_len); + ceph_assert(remap_offset + remap_len <= original_len); + ceph_assert(remap_len != 0); + ceph_assert(remap_offset % cache->get_block_size() == 0); + ceph_assert(remap_len % cache->get_block_size() == 0); + SUBDEBUGT(seastore_tm, + "remap laddr: {}, remap paddr: {}, remap length: {}", t, + remap_laddr, remap_paddr, remap_len); + return alloc_remapped_extent( + t, + remap_laddr, + remap_paddr, + remap_len, + original_laddr, + std::move(original_bptr) + ).si_then([&ret, &count, remap_laddr](auto &&npin) { + ceph_assert(npin->get_key() == remap_laddr); + ret[count++] = std::move(npin); + }); + }); + }).handle_error_interruptible( + remap_pin_iertr::pass_further{}, + crimson::ct_error::assert_all{ + "TransactionManager::remap_pin hit invalid error" + } + ).si_then([&ret, &count] { + ceph_assert(count == N); + return remap_pin_iertr::make_ready_future< + std::array>(std::move(ret)); + }); + }); + }); + } + /** * map_existing_extent *