@@ -260,6 +260,8 @@ class TransactionManager : public ExtentCallbackInterface {
260260 static_assert (is_logical_type (T::TYPE));
261261 assert (is_aligned (partial_off, get_block_size ()));
262262 assert (is_aligned (partial_len, get_block_size ()));
263+ // must be user-oriented required by maybe_init
264+ assert (is_user_transaction (t.get_src ()));
263265
264266 extent_len_t direct_partial_off = partial_off;
265267 bool is_clone = pin->is_clone ();
@@ -302,9 +304,12 @@ class TransactionManager : public ExtentCallbackInterface {
302304 return cache->read_extent_maybe_partial (
303305 t, std::move (extent), direct_partial_off, partial_len);
304306 }).si_then ([maybe_init=std::move (maybe_init)](auto extent) {
305- maybe_init (*extent);
306- return extent;
307- });
307+ if (!extent->is_seen_by_users ()) {
308+ maybe_init (*extent);
309+ extent->set_seen_by_users ();
310+ }
311+ return std::move (extent);
312+ });
308313 } else {
309314 return this ->pin_to_extent <T>(
310315 t, std::move (std::get<0 >(ret)),
@@ -381,6 +386,7 @@ class TransactionManager : public ExtentCallbackInterface {
381386 laddr_t laddr_hint,
382387 extent_len_t len,
383388 placement_hint_t placement_hint = placement_hint_t ::HOT) {
389+ static_assert (is_logical_metadata_type (T::TYPE));
384390 LOG_PREFIX (TransactionManager::alloc_non_data_extent);
385391 SUBDEBUGT (seastore_tm, " {} hint {}~0x{:x} phint={} ..." ,
386392 t, T::TYPE, laddr_hint, len, placement_hint);
@@ -389,6 +395,9 @@ class TransactionManager : public ExtentCallbackInterface {
389395 len,
390396 placement_hint,
391397 INIT_GENERATION);
398+ // user must initialize the logical extent themselves.
399+ assert (is_user_transaction (t.get_src ()));
400+ ext->set_seen_by_users ();
392401 return lba_manager->alloc_extent (
393402 t,
394403 laddr_hint,
@@ -416,6 +425,7 @@ class TransactionManager : public ExtentCallbackInterface {
416425 laddr_t laddr_hint,
417426 extent_len_t len,
418427 placement_hint_t placement_hint = placement_hint_t ::HOT) {
428+ static_assert (is_data_type (T::TYPE));
419429 LOG_PREFIX (TransactionManager::alloc_data_extents);
420430 SUBDEBUGT (seastore_tm, " {} hint {}~0x{:x} phint={} ..." ,
421431 t, T::TYPE, laddr_hint, len, placement_hint);
@@ -424,6 +434,11 @@ class TransactionManager : public ExtentCallbackInterface {
424434 len,
425435 placement_hint,
426436 INIT_GENERATION);
437+ // user must initialize the logical extent themselves
438+ assert (is_user_transaction (t.get_src ()));
439+ for (auto & ext : exts) {
440+ ext->set_seen_by_users ();
441+ }
427442 return lba_manager->alloc_extents (
428443 t,
429444 laddr_hint,
@@ -479,6 +494,10 @@ class TransactionManager : public ExtentCallbackInterface {
479494 LBAMappingRef &&pin,
480495 std::array<remap_entry, N> remaps) {
481496 static_assert (std::is_base_of_v<LogicalChildNode, T>);
497+ // data extents don't need maybe_init yet, currently,
498+ static_assert (is_data_type (T::TYPE));
499+ // must be user-oriented required by (the potential) maybe_init
500+ assert (is_user_transaction (t.get_src ()));
482501
483502#ifndef NDEBUG
484503 std::sort (remaps.begin (), remaps.end (),
@@ -550,7 +569,14 @@ class TransactionManager : public ExtentCallbackInterface {
550569 } else {
551570 auto ret = get_extent_if_linked<T>(t, pin->duplicate ());
552571 if (ret.index () == 1 ) {
553- return std::move (std::get<1 >(ret));
572+ return std::get<1 >(ret
573+ ).si_then ([](auto extent) {
574+ if (!extent->is_seen_by_users ()) {
575+ // Note, no maybe_init available for data extents
576+ extent->set_seen_by_users ();
577+ }
578+ return std::move (extent);
579+ });
554580 } else {
555581 // absent
556582 return base_iertr::make_ready_future<TCachedExtentRef<T>>();
@@ -571,6 +597,7 @@ class TransactionManager : public ExtentCallbackInterface {
571597 original_bptr = ext->get_bptr ();
572598 }
573599 if (ext) {
600+ assert (ext->is_seen_by_users ());
574601 cache->retire_extent (t, ext);
575602 } else {
576603 cache->retire_absent_extent_addr (t, original_paddr, original_len);
@@ -594,6 +621,8 @@ class TransactionManager : public ExtentCallbackInterface {
594621 remap_len,
595622 original_laddr,
596623 original_bptr);
624+ // user must initialize the logical extent themselves.
625+ extent->set_seen_by_users ();
597626 extents.emplace_back (std::move (extent));
598627 }
599628 });
@@ -1034,6 +1063,8 @@ class TransactionManager : public ExtentCallbackInterface {
10341063 extent_len_t partial_len,
10351064 lextent_init_func_t <T> &&maybe_init) {
10361065 static_assert (is_logical_type (T::TYPE));
1066+ // must be user-oriented required by maybe_init
1067+ assert (is_user_transaction (t.get_src ()));
10371068 using ret = pin_to_extent_ret<T>;
10381069 auto &pref = *pin;
10391070 auto direct_length = pref.is_indirect () ?
@@ -1062,6 +1093,7 @@ class TransactionManager : public ExtentCallbackInterface {
10621093 pref.link_child (&extent);
10631094 extent.maybe_set_intermediate_laddr (pref);
10641095 maybe_init (extent);
1096+ extent.set_seen_by_users ();
10651097 }
10661098 ).si_then ([FNAME, &t, pin=std::move (pin), this ](auto ref) mutable -> ret {
10671099 if (ref->is_fully_loaded ()) {
@@ -1114,6 +1146,7 @@ class TransactionManager : public ExtentCallbackInterface {
11141146 SUBTRACET (seastore_tm, " getting absent extent from pin {} type {} ..." ,
11151147 t, *pin, type);
11161148 assert (is_logical_type (type));
1149+ assert (is_background_transaction (t.get_src ()));
11171150 auto &pref = *pin;
11181151 laddr_t direct_key;
11191152 extent_len_t direct_length;
@@ -1140,6 +1173,8 @@ class TransactionManager : public ExtentCallbackInterface {
11401173 assert (!pref.get_parent ()->is_pending ());
11411174 pref.link_child (&lextent);
11421175 lextent.maybe_set_intermediate_laddr (pref);
1176+ // No change to extent::seen_by_user because this path is only
1177+ // for background cleaning.
11431178 }
11441179 ).si_then ([FNAME, &t, pin=std::move (pin), this ](auto ref) {
11451180 auto crc = ref->calc_crc32c ();
0 commit comments