From 8c118bf0752214e70b57ba80bb1cd29854b78f4e Mon Sep 17 00:00:00 2001 From: Niu Yawei Date: Fri, 11 Sep 2026 00:59:01 -0400 Subject: [PATCH] DAOS-19374 vos: iterator changes for multi-buckets per object - Change obj_pin_bkt() to pin all object shared buckets. - Ensure dkey bucket is pinned when iterating into dkey sub-trees. - Fix tree handle leak when nested preparation failed. Signed-off-by: Niu Yawei --- src/vos/vos_internal.h | 2 ++ src/vos/vos_obj.c | 67 ++++++++++++++++++++++++++++++++++++++--- src/vos/vos_obj.h | 1 + src/vos/vos_obj_cache.c | 55 +++++++++++++++++++++++++-------- 4 files changed, 108 insertions(+), 17 deletions(-) diff --git a/src/vos/vos_internal.h b/src/vos/vos_internal.h index a2be290db34..6c67f2659da 100644 --- a/src/vos/vos_internal.h +++ b/src/vos/vos_internal.h @@ -1303,6 +1303,8 @@ struct vos_obj_iter { daos_recx_t it_recx; /** For fake akey, save the dkey krec as well */ struct vos_krec_df *it_dkey_krec; + /** Pin held for shared and dkey buckets during nested iteration */ + struct umem_pin_handle *it_dkey_pin_hdl; /** Store the fake akey */ char it_fake_akey; }; diff --git a/src/vos/vos_obj.c b/src/vos/vos_obj.c index e10f9b6feef..e95808d96bc 100644 --- a/src/vos/vos_obj.c +++ b/src/vos/vos_obj.c @@ -1010,12 +1010,41 @@ key_ilog_prepare(struct vos_obj_iter *oiter, daos_handle_t toh, return rc; } +/* Pin single dkey bucket while holding the object shared buckets, deadlock free. */ +static inline int +dkey_bkt_iter_pin(struct vos_object *obj, struct vos_krec_df *krec, + struct umem_pin_handle **pin_hdl) +{ + struct vos_pool *pool = vos_obj2pool(obj); + struct umem_store *store = vos_pool2store(pool); + struct umem_cache_range rg; + uint32_t bkt_id; + int rc; + + D_ASSERT(*pin_hdl == NULL); + if (!vos_pool_is_evictable(pool) || !(krec->kr_bmap & KREC_BF_BKT_ID)) + return 0; + + bkt_id = *vos_krec2bkt_id(krec); + if (bkt_id == UMEM_DEFAULT_MBKT_ID) + return 0; + + rg.cr_off = umem_get_mb_base_offset(vos_pool2umm(pool), vos_bkt_id_raw(bkt_id)); + rg.cr_size = store->cache->ca_page_sz; + rc = vos_cache_pin(pool, &rg, 1, false, pin_hdl); + if (rc) + DL_ERROR(rc, "Failed to pin dkey bucket:%u for object:" DF_UOID ".", bkt_id, + DP_UOID(obj->obj_id)); + return rc; +} + static inline int key_ilog_prepare_dkey(struct vos_obj_iter *oiter, daos_key_t *key, daos_handle_t *sub_toh, struct vos_krec_df **krecp, struct vos_ts_set *ts_set) { - struct vos_object *obj = oiter->it_obj; - int flags = 0; + struct vos_object *obj = oiter->it_obj; + struct vos_krec_df *krec; + int rc, flags = 0; if (vos_obj_skip_akey_supported(obj->obj_cont, obj->obj_id)) { flags |= SUBTR_FLAT; @@ -1023,8 +1052,17 @@ key_ilog_prepare_dkey(struct vos_obj_iter *oiter, daos_key_t *key, daos_handle_t flags |= SUBTR_EVT; } - return key_ilog_prepare(oiter, obj->obj_toh, VOS_BTR_DKEY, key, flags, sub_toh, krecp, - &oiter->it_epr, &oiter->it_punched, &oiter->it_ilog_info, ts_set); + rc = key_ilog_prepare(oiter, obj->obj_toh, VOS_BTR_DKEY, key, flags, sub_toh, krecp, + &oiter->it_epr, &oiter->it_punched, &oiter->it_ilog_info, ts_set); + if (rc) + return rc; + + krec = *krecp; + rc = dkey_bkt_iter_pin(obj, krec, &oiter->it_dkey_pin_hdl); + if (rc != 0) + key_tree_release(*sub_toh, key_tree_is_evt(flags, VOS_BTR_DKEY, krec)); + + return rc; } /** @@ -1168,6 +1206,7 @@ key_iter_fetch_root(struct vos_obj_iter *oiter, vos_iter_type_t type, } krec = rbund.rb_krec; + info->ii_dkey_krec = krec; info->ii_vea_info = obj->obj_cont->vc_pool->vp_vea_info; info->ii_uma = vos_obj2uma(obj); @@ -1226,7 +1265,6 @@ key_iter_fetch_root(struct vos_obj_iter *oiter, vos_iter_type_t type, info->ii_fake_akey_flag = VOS_IT_DKEY_SV; } info->ii_ilog_info = &oiter->it_ilog_info; - info->ii_dkey_krec = krec; } return 0; @@ -2174,8 +2212,21 @@ vos_obj_akey_iter_nested_prep(vos_iter_type_t type, struct vos_iter_info *info, } rc = nested_prep_common_init(obj->obj_cont, &oiter, info); + if (rc != 0) { + if (info->ii_fake_akey_flag) + key_tree_release(info->ii_tree_hdl, + info->ii_fake_akey_flag == VOS_IT_DKEY_EV); + return rc; + } oiter->it_obj = obj; + rc = dkey_bkt_iter_pin(obj, info->ii_dkey_krec, &oiter->it_dkey_pin_hdl); + if (rc != 0) { + if (info->ii_fake_akey_flag) + key_tree_release(info->ii_tree_hdl, + info->ii_fake_akey_flag == VOS_IT_DKEY_EV); + goto failed; + } if (info->ii_fake_akey_flag) { /** In this case, we already opened the subtree so just store it @@ -2213,6 +2264,8 @@ vos_obj_akey_iter_nested_prep(vos_iter_type_t type, struct vos_iter_info *info, return 0; failed: + if (oiter->it_dkey_pin_hdl != NULL) + umem_cache_unpin(vos_pool2store(vos_obj2pool(obj)), oiter->it_dkey_pin_hdl); nested_prep_common_abort(oiter); return rc; } @@ -2374,6 +2427,10 @@ vos_obj_iter_fini(struct vos_iterator *iter) break; } out: + if (oiter->it_dkey_pin_hdl != NULL) + umem_cache_unpin(vos_pool2store(vos_obj2pool(oiter->it_obj)), + oiter->it_dkey_pin_hdl); + /* Release the object only if we didn't borrow it from the parent * iterator. The generic code reference counts the iterators * to ensure that a parent never gets removed before all nested diff --git a/src/vos/vos_obj.h b/src/vos/vos_obj.h index 64317dfd13b..630ec12d51d 100644 --- a/src/vos/vos_obj.h +++ b/src/vos/vos_obj.h @@ -70,6 +70,7 @@ struct vos_obj_bkt_node { uint8_t bn_bkt_cnt; /* valid entries in bn_bkt_ids[] */ uint8_t bn_flags; uint16_t bn_pad; + void *bn_next; }; /** diff --git a/src/vos/vos_obj_cache.c b/src/vos/vos_obj_cache.c index 4bc0fb7b619..f22083fda29 100644 --- a/src/vos/vos_obj_cache.c +++ b/src/vos/vos_obj_cache.c @@ -324,18 +324,52 @@ obj_allot_bkt(struct vos_pool *pool, struct vos_object *obj) ABT_mutex_unlock(obj->obj_mutex); } +/* Get all object shared buckets from in-memory vos_object */ +static int +obj_shared_bkts(struct vos_pool *pool, struct vos_object *obj, struct vos_bkt_array *bkts) +{ + struct vos_obj_bkt_node *node, *next = NULL; + int i, rc; + + if (obj->obj_bkt_id0 != UMEM_DEFAULT_MBKT_ID) { + rc = vos_bkt_array_add(bkts, vos_bkt_id_raw(obj->obj_bkt_id0)); + if (rc != 0) + return rc; + } + + next = obj->obj_bkt_nodes; + while (next != NULL) { + node = next; + for (i = 0; i < node->bn_bkt_cnt; i++) { + D_ASSERT(node->bn_bkt_ids[i] != UMEM_DEFAULT_MBKT_ID); + if (!vos_bkt_id_is_shared(node->bn_bkt_ids[i])) + continue; + rc = vos_bkt_array_add(bkts, vos_bkt_id_raw(node->bn_bkt_ids[i])); + if (rc != 0) + return rc; + } + next = node->bn_next; + } + return 0; +} + static int obj_pin_bkt(struct vos_pool *pool, struct vos_object *obj) { struct umem_store *store = vos_pool2store(pool); struct dtx_handle *cur_dth; - struct umem_cache_range rg; + struct vos_bkt_array bkts; int rc; - if (obj->obj_bkt_id0 == UMEM_DEFAULT_MBKT_ID) { + vos_bkt_array_init(&bkts); + rc = obj_shared_bkts(pool, obj, &bkts); + if (rc) + goto out; + + if (bkts.vba_cnt == 0) { D_ASSERT(obj->obj_pin_hdl == NULL); D_ASSERT(!obj->obj_bkt_loading); - return 0; + goto out; } if (obj->obj_bkt_loading) { @@ -349,7 +383,8 @@ obj_pin_bkt(struct vos_pool *pool, struct vos_object *obj) /* The loader failed on vos_cache_pin() */ if (obj->obj_pin_hdl == NULL) { D_ERROR("Object:"DF_UOID" isn't pinned.\n", DP_UOID(obj->obj_id)); - return -DER_BUSY; + rc = -DER_BUSY; + goto out; } } @@ -358,15 +393,11 @@ obj_pin_bkt(struct vos_pool *pool, struct vos_object *obj) if (vcm) d_tm_inc_counter(vcm->vcm_obj_hit, 1); - return 0; + goto out; } obj->obj_bkt_loading = 1; - - rg.cr_off = umem_get_mb_base_offset(vos_pool2umm(pool), obj->obj_bkt_id0); - rg.cr_size = store->cache->ca_page_sz; - - rc = vos_cache_pin(pool, &rg, 1, false, &obj->obj_pin_hdl); + rc = vos_bkt_array_pin(pool, &bkts, &obj->obj_pin_hdl); if (rc) DL_ERROR(rc, "Failed to pin object:"DF_UOID".", DP_UOID(obj->obj_id)); @@ -375,11 +406,11 @@ obj_pin_bkt(struct vos_pool *pool, struct vos_object *obj) ABT_mutex_lock(obj->obj_mutex); ABT_cond_broadcast(obj->obj_wait_loading); ABT_mutex_unlock(obj->obj_mutex); - +out: + vos_bkt_array_fini(&bkts); return rc; } -/* Support single evict-able bucket for this moment */ static inline int vos_obj_pin(struct vos_object *obj) {