mirror of
https://github.com/ceph/ceph
synced 2026-08-02 07:03:18 +00:00
crimson/os/seastore/lba: introduce shadow paddr
Signed-off-by: Zhang Song <zhangsong02@qianxin.com> Signed-off-by: Xuehan Xu <xuxuehan@qianxin.com>
This commit is contained in:
parent
671b1b4ffc
commit
ad7469ca59
@ -12,9 +12,13 @@ namespace lba {
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const lba_map_val_t& v)
|
||||
{
|
||||
return out << "lba_map_val_t("
|
||||
<< v.pladdr
|
||||
<< "~0x" << std::hex << v.len
|
||||
out << "lba_map_val_t(";
|
||||
if (v.shadow_paddr != P_ADDR_NULL) {
|
||||
out << '[' << v.pladdr << ',' << v.shadow_paddr << ']';
|
||||
} else {
|
||||
out << v.pladdr;
|
||||
}
|
||||
return out << "~0x" << std::hex << v.len
|
||||
<< ", type=" << (extent_types_t)v.type
|
||||
<< ", checksum=0x" << v.checksum
|
||||
<< ", refcount=" << std::dec << v.refcount
|
||||
|
||||
@ -110,6 +110,7 @@ struct lba_map_val_t {
|
||||
extent_len_t len = 0; ///< length of mapping
|
||||
pladdr_t pladdr; ///< direct addr of mapping or
|
||||
// laddr of a direct lba mapping(see btree_lba_manager.h)
|
||||
paddr_t shadow_paddr;
|
||||
extent_ref_count_t refcount = 0; ///< refcount
|
||||
checksum_t checksum = 0; ///< checksum of original block written at paddr (TODO)
|
||||
extent_types_t type = extent_types_t::NONE;
|
||||
@ -118,11 +119,12 @@ struct lba_map_val_t {
|
||||
lba_map_val_t(
|
||||
extent_len_t len,
|
||||
pladdr_t pladdr,
|
||||
paddr_t shadow_paddr,
|
||||
extent_ref_count_t refcount,
|
||||
checksum_t checksum,
|
||||
extent_types_t type)
|
||||
: len(len), pladdr(pladdr), refcount(refcount),
|
||||
checksum(checksum), type(type) {}
|
||||
: len(len), pladdr(pladdr), shadow_paddr(shadow_paddr),
|
||||
refcount(refcount), checksum(checksum), type(type) {}
|
||||
bool operator==(const lba_map_val_t&) const = default;
|
||||
};
|
||||
|
||||
@ -136,6 +138,7 @@ std::ostream& operator<<(std::ostream& out, const lba_map_val_t&);
|
||||
struct __attribute__((packed)) lba_map_val_le_t {
|
||||
extent_len_le_t len = init_extent_len_le(0);
|
||||
pladdr_le_t pladdr;
|
||||
paddr_le_t shadow_paddr;
|
||||
extent_ref_count_le_t refcount{0};
|
||||
checksum_le_t checksum{0};
|
||||
extent_types_le_t type{EXTENT_TYPES_MAX};
|
||||
@ -145,6 +148,7 @@ struct __attribute__((packed)) lba_map_val_le_t {
|
||||
explicit lba_map_val_le_t(const lba_map_val_t &val)
|
||||
: len(init_extent_len_le(val.len)),
|
||||
pladdr(pladdr_le_t(val.pladdr)),
|
||||
shadow_paddr(paddr_le_t(val.shadow_paddr)),
|
||||
refcount(val.refcount),
|
||||
checksum(val.checksum),
|
||||
type(static_cast<extent_types_le_t>(val.type)) {}
|
||||
@ -153,6 +157,7 @@ struct __attribute__((packed)) lba_map_val_le_t {
|
||||
return lba_map_val_t{
|
||||
len,
|
||||
pladdr,
|
||||
shadow_paddr,
|
||||
refcount,
|
||||
checksum,
|
||||
static_cast<extent_types_t>(type)};
|
||||
|
||||
@ -300,6 +300,7 @@ BtreeLBAManager::resolve_indirect_cursor(
|
||||
const LBACursor &indirect_cursor)
|
||||
{
|
||||
ceph_assert(indirect_cursor.is_indirect());
|
||||
ceph_assert(!indirect_cursor.has_shadow_paddr());
|
||||
return get_cursors(
|
||||
c,
|
||||
btree,
|
||||
@ -351,6 +352,7 @@ BtreeLBAManager::reserve_region(
|
||||
lba_map_val_t val{
|
||||
len,
|
||||
pladdr_t{P_ADDR_ZERO},
|
||||
P_ADDR_NULL,
|
||||
EXTENT_DEFAULT_REF_COUNT,
|
||||
0,
|
||||
type};
|
||||
@ -392,6 +394,7 @@ BtreeLBAManager::alloc_extents(
|
||||
lba_map_val_t{
|
||||
ext->get_length(),
|
||||
pladdr_t{ext->get_paddr()},
|
||||
P_ADDR_NULL,
|
||||
EXTENT_DEFAULT_REF_COUNT,
|
||||
ext->get_last_committed_crc(),
|
||||
ext->get_type()},
|
||||
@ -451,6 +454,7 @@ BtreeLBAManager::clone_mapping(
|
||||
lba_map_val_t{
|
||||
len,
|
||||
pladdr_t{inter_key.get_local_clone_id()},
|
||||
P_ADDR_NULL,
|
||||
EXTENT_DEFAULT_REF_COUNT,
|
||||
0,
|
||||
mapping->get_extent_type()},
|
||||
@ -880,7 +884,8 @@ BtreeLBAManager::scan_mappings(
|
||||
}
|
||||
ceph_assert((pos.get_key() + pos.get_val().len) > begin);
|
||||
if (pos.get_val().pladdr.is_paddr()) {
|
||||
f(pos.get_key(), pos.get_val().pladdr.get_paddr(), pos.get_val().len);
|
||||
f(pos.get_key(), pos.get_val().pladdr.get_paddr(),
|
||||
pos.get_val().shadow_paddr, pos.get_val().len);
|
||||
}
|
||||
return LBABtree::iterate_repeat_ret_inner(
|
||||
interruptible::ready_future_marker{},
|
||||
@ -956,11 +961,19 @@ BtreeLBAManager::update_mapping(
|
||||
assert(!addr.is_null());
|
||||
lba_map_val_t ret = in;
|
||||
ceph_assert(in.pladdr.is_paddr());
|
||||
ceph_assert(in.pladdr.get_paddr() == prev_addr);
|
||||
ceph_assert(in.len == prev_len);
|
||||
ret.pladdr = addr;
|
||||
ret.len = len;
|
||||
ret.checksum = checksum;
|
||||
if (prev_addr == in.pladdr.get_paddr()) {
|
||||
ret.pladdr = addr;
|
||||
ret.len = len;
|
||||
ret.checksum = checksum;
|
||||
if (ret.shadow_paddr != P_ADDR_NULL) {
|
||||
ceph_assert(
|
||||
addr.get_device_id() != ret.shadow_paddr.get_device_id());
|
||||
}
|
||||
} else {
|
||||
ceph_assert(in.shadow_paddr == prev_addr);
|
||||
ret.shadow_paddr = addr;
|
||||
}
|
||||
return ret;
|
||||
},
|
||||
&nextent
|
||||
@ -1314,6 +1327,9 @@ BtreeLBAManager::remap_mappings(
|
||||
} else {
|
||||
auto paddr = val.pladdr.get_paddr();
|
||||
val.pladdr = paddr + cur_off;
|
||||
if (val.shadow_paddr != P_ADDR_NULL) {
|
||||
val.shadow_paddr = val.shadow_paddr.add_offset(cur_off);
|
||||
}
|
||||
}
|
||||
val.len = remap.len;
|
||||
val.refcount = EXTENT_DEFAULT_REF_COUNT;
|
||||
@ -1539,6 +1555,7 @@ BtreeLBAManager::move_and_clone_direct_mapping(
|
||||
lba_map_val_t val = in;
|
||||
val.pladdr = ret.dest->get_key().get_local_clone_id();
|
||||
val.checksum = 0;
|
||||
val.shadow_paddr = P_ADDR_NULL;
|
||||
return val;
|
||||
},
|
||||
nullptr
|
||||
|
||||
@ -209,6 +209,7 @@ public:
|
||||
laddr_t dest_laddr,
|
||||
LBACursorRef dest) final {
|
||||
assert(src->is_indirect());
|
||||
assert(!src->has_shadow_paddr());
|
||||
return _move_mapping(
|
||||
t, std::move(src), dest_laddr, std::move(dest), nullptr);
|
||||
}
|
||||
@ -503,6 +504,7 @@ private:
|
||||
{
|
||||
len,
|
||||
pladdr_t(P_ADDR_ZERO),
|
||||
P_ADDR_NULL,
|
||||
EXTENT_DEFAULT_REF_COUNT,
|
||||
0,
|
||||
type
|
||||
@ -517,6 +519,7 @@ private:
|
||||
{
|
||||
len,
|
||||
pladdr_t(intermediate_key.get_local_clone_id()),
|
||||
P_ADDR_NULL,
|
||||
EXTENT_DEFAULT_REF_COUNT,
|
||||
0, // crc will only be used and checked with LBA direct mappings
|
||||
// also see pin_to_extent(_by_type)
|
||||
@ -533,7 +536,7 @@ private:
|
||||
LogicalChildNode& extent) {
|
||||
return {
|
||||
laddr,
|
||||
{len, pladdr_t(paddr), refcount, checksum, extent.get_type()},
|
||||
{len, pladdr_t(paddr), P_ADDR_NULL, refcount, checksum, extent.get_type()},
|
||||
&extent
|
||||
};
|
||||
}
|
||||
|
||||
@ -101,14 +101,14 @@ using LBAInternalNodeRef = LBAInternalNode::Ref;
|
||||
* checksum : ceph_le32[1] 4B
|
||||
* size : ceph_le32[1] 4B
|
||||
* meta : lba_node_meta_le_t[1] 36B
|
||||
* keys : laddr_le_t[CAPACITY] (106*16)B
|
||||
* values : lba_map_val_le_t[CAPACITY] (106*21)B
|
||||
* = 4077B
|
||||
* keys : laddr_le_t[CAPACITY] (88*16)B
|
||||
* values : lba_map_val_le_t[CAPACITY] (88*30)B
|
||||
* = 4092B
|
||||
*
|
||||
* TODO: update FixedKVNodeLayout to handle the above calculation
|
||||
* TODO: the above alignment probably isn't portable without further work
|
||||
*/
|
||||
constexpr size_t LEAF_NODE_CAPACITY = 106;
|
||||
constexpr size_t LEAF_NODE_CAPACITY = 88;
|
||||
|
||||
struct LBALeafNode
|
||||
: FixedKVLeafNode<
|
||||
@ -480,12 +480,22 @@ struct LBACursor : BtreeCursor<laddr_t, lba::lba_map_val_t, LBALeafNode> {
|
||||
}
|
||||
|
||||
extent_types_t get_extent_type() const {
|
||||
assert(iter.get_val().type != extent_types_t::NONE);
|
||||
assert(is_viewable());
|
||||
assert(!is_end());
|
||||
assert(iter.get_val().type != extent_types_t::NONE);
|
||||
return iter.get_val().type;
|
||||
}
|
||||
|
||||
bool has_shadow_paddr() const {
|
||||
return iter.get_val().shadow_paddr != P_ADDR_NULL;
|
||||
}
|
||||
|
||||
paddr_t get_shadow_paddr() const {
|
||||
assert(has_shadow_paddr());
|
||||
return iter.get_val().shadow_paddr;
|
||||
}
|
||||
|
||||
base_iertr::future<> refresh();
|
||||
private:
|
||||
|
||||
|
||||
@ -253,7 +253,7 @@ public:
|
||||
using scan_mappings_iertr = base_iertr;
|
||||
using scan_mappings_ret = scan_mappings_iertr::future<>;
|
||||
using scan_mappings_func_t = std::function<
|
||||
void(laddr_t, paddr_t, extent_len_t)>;
|
||||
void(laddr_t, paddr_t, paddr_t, extent_len_t)>;
|
||||
virtual scan_mappings_ret scan_mappings(
|
||||
Transaction &t,
|
||||
laddr_t begin,
|
||||
|
||||
@ -132,6 +132,18 @@ public:
|
||||
return direct_cursor->get_length();
|
||||
}
|
||||
|
||||
bool has_shadow_val() const {
|
||||
assert(is_linked_direct());
|
||||
assert(!direct_cursor->is_end());
|
||||
return direct_cursor->has_shadow_paddr();
|
||||
}
|
||||
|
||||
paddr_t get_shadow_val() const {
|
||||
assert(is_linked_direct());
|
||||
assert(!direct_cursor->is_end());
|
||||
return direct_cursor->get_shadow_paddr();
|
||||
}
|
||||
|
||||
checksum_t get_checksum() const {
|
||||
assert(is_linked_direct());
|
||||
assert(!direct_cursor->is_end());
|
||||
|
||||
@ -229,12 +229,33 @@ TransactionManager::ref_ret TransactionManager::remove(
|
||||
extent_ref_count_t refcount = cursor->get_refcount();
|
||||
auto laddr = cursor->get_laddr();
|
||||
auto length = cursor->get_length();
|
||||
paddr_t shadow_addr = P_ADDR_NULL;
|
||||
if (cursor->has_shadow_paddr()) {
|
||||
shadow_addr = cursor->get_shadow_paddr();
|
||||
}
|
||||
assert(refcount > 0);
|
||||
--refcount;
|
||||
co_await lba_manager->update_mapping_refcount(
|
||||
t, std::move(cursor), -1);
|
||||
if (refcount == 0) {
|
||||
cache->retire_extent(t, ref);
|
||||
if (shadow_addr != P_ADDR_NULL) {
|
||||
if (auto shadow = ref->get_shadow(); shadow) {
|
||||
cache->retire_extent(t, shadow);
|
||||
} else {
|
||||
auto laddr = ref->get_laddr();
|
||||
cache->retire_absent_extent_addr_by_type(
|
||||
t, laddr, shadow_addr, length, ref->get_type(),
|
||||
[laddr](auto &extent) {
|
||||
auto lextent = extent.template cast<LogicalChildNode>();
|
||||
assert(extent.is_logical());
|
||||
assert(!lextent->has_laddr());
|
||||
assert(!extent.has_been_invalidated());
|
||||
lextent->set_laddr(laddr);
|
||||
extent.set_shadow_extent(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
DEBUGT("removed {}~0x{:x} refcount={} -- {}",
|
||||
t, laddr, length,
|
||||
@ -317,6 +338,12 @@ TransactionManager::_remove(
|
||||
}
|
||||
);
|
||||
}
|
||||
if (mapping.has_shadow_val()) {
|
||||
cache->retire_absent_extent_addr(
|
||||
t, mapping.get_intermediate_base(),
|
||||
mapping.get_shadow_val(),
|
||||
mapping.get_intermediate_length());
|
||||
}
|
||||
}
|
||||
|
||||
LBACursorRef indirect_cursor;
|
||||
|
||||
@ -1103,6 +1103,7 @@ public:
|
||||
if (!mapping.is_indirect() && mapping.is_zero_reserved()) {
|
||||
SUBDEBUGT(seastore_tm, "zero reserved, mapping {}, {} remaps",
|
||||
t, mapping, remaps);
|
||||
ceph_assert(!mapping.has_shadow_val());
|
||||
//TODO: drop this assert
|
||||
assert(mapping.get_extent_type() == extent_types_t::OBJECT_DATA_BLOCK);
|
||||
auto type = mapping.get_extent_type();
|
||||
@ -1514,6 +1515,20 @@ private:
|
||||
lextent->set_laddr(laddr);
|
||||
}
|
||||
);
|
||||
if (pin.has_shadow_val()) {
|
||||
cache->retire_absent_extent_addr_by_type(
|
||||
t, pin.get_key(), pin.get_shadow_val(),
|
||||
original_len, pin.get_extent_type(),
|
||||
[laddr](auto &extent) {
|
||||
auto lextent = extent.template cast<LogicalChildNode>();
|
||||
assert(extent.is_logical());
|
||||
assert(!lextent->has_laddr());
|
||||
assert(!extent.has_been_invalidated());
|
||||
lextent->set_laddr(laddr);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -1543,6 +1558,11 @@ private:
|
||||
auto remap_len = remap.len;
|
||||
auto remap_laddr = (original_laddr + remap_offset).checked_to_laddr();
|
||||
auto remap_paddr = pin.get_val().add_offset(remap_offset);
|
||||
auto shadow_paddr = P_ADDR_NULL;
|
||||
if (pin.has_shadow_val()) {
|
||||
assert(pin.get_shadow_val() != P_ADDR_NULL);
|
||||
shadow_paddr = pin.get_shadow_val().add_offset(remap_offset);
|
||||
}
|
||||
SUBDEBUGT(seastore_tm, "remap direct pin into {}~0x{:x} {} ...",
|
||||
t, remap_laddr, remap_len, remap_paddr);
|
||||
ceph_assert(remap_len < original_len);
|
||||
@ -1557,6 +1577,17 @@ private:
|
||||
remap_offset,
|
||||
remap_len,
|
||||
original_bptr);
|
||||
if (shadow_paddr != P_ADDR_NULL) {
|
||||
SUBTRACET(seastore_tm, "remap shadow {}", t, shadow_paddr);
|
||||
auto cold_ext = cache->alloc_remapped_extent<T>(
|
||||
t,
|
||||
remap_laddr,
|
||||
shadow_paddr,
|
||||
remap_offset,
|
||||
remap_len,
|
||||
std::nullopt);
|
||||
boost::ignore_unused(cold_ext);
|
||||
}
|
||||
// user must initialize the logical extent themselves.
|
||||
remapped_extent->set_seen_by_users();
|
||||
remap.extent = remapped_extent.get();
|
||||
|
||||
@ -313,7 +313,7 @@ struct lba_btree_test : btree_test_base {
|
||||
}
|
||||
|
||||
static auto get_map_val(extent_len_t len, extent_types_t type) {
|
||||
return lba_map_val_t{0, (pladdr_t)P_ADDR_NULL, len, 0, type};
|
||||
return lba_map_val_t{0, (pladdr_t)P_ADDR_NULL, P_ADDR_NULL, len, 0, type};
|
||||
}
|
||||
|
||||
device_off_t next_off = 0;
|
||||
@ -716,7 +716,7 @@ struct btree_lba_manager_test : btree_test_base {
|
||||
*t.t,
|
||||
L_ADDR_MIN,
|
||||
L_ADDR_MAX,
|
||||
[iter=t.mappings.begin(), &t](auto l, auto p, auto len) mutable {
|
||||
[iter=t.mappings.begin(), &t](auto l, auto p, auto s, auto len) mutable {
|
||||
EXPECT_NE(iter, t.mappings.end());
|
||||
EXPECT_EQ(l, iter->first);
|
||||
EXPECT_EQ(p, iter->second.addr);
|
||||
|
||||
@ -806,7 +806,7 @@ struct transaction_manager_test_t :
|
||||
t,
|
||||
get_laddr_hint(0),
|
||||
L_ADDR_MAX,
|
||||
[iter=overlay.begin(), &overlay](auto l, auto p, auto len) mutable {
|
||||
[iter=overlay.begin(), &overlay](auto l, auto p, auto s, auto len) mutable {
|
||||
EXPECT_NE(iter, overlay.end());
|
||||
logger().debug(
|
||||
"check_mappings: scan {}",
|
||||
@ -1901,10 +1901,10 @@ TEST_P(tm_random_block_device_test_t, scatter_allocation)
|
||||
laddr_t ADDR = get_laddr_hint(0xFF * 4096);
|
||||
epm->prefill_fragmented_devices();
|
||||
auto t = create_transaction();
|
||||
for (int i = 0; i < 1974; i++) {
|
||||
for (int i = 0; i < 1958; i++) {
|
||||
auto extents = alloc_extents(t, (ADDR + i * 16384).checked_to_laddr(), 16384, 'a');
|
||||
}
|
||||
alloc_extents_deemed_fail(t, (ADDR + 1974 * 16384).checked_to_laddr(), 16384, 'a');
|
||||
alloc_extents_deemed_fail(t, (ADDR + 1958 * 16384).checked_to_laddr(), 16384, 'a');
|
||||
check_mappings(t);
|
||||
check();
|
||||
submit_transaction(std::move(t));
|
||||
|
||||
Loading…
Reference in New Issue
Block a user