diff --git a/src/vos/tests/vts_gc.c b/src/vos/tests/vts_gc.c index a7228cf8d40..5bd68a79b82 100644 --- a/src/vos/tests/vts_gc.c +++ b/src/vos/tests/vts_gc.c @@ -345,6 +345,86 @@ gc_obj_test(void **state) assert_rc_equal(rc, 0); } +static int +gc_obj_run_destroy(struct gc_test_args *args) +{ + daos_unit_oid_t *oids; + daos_handle_t coh; + daos_handle_t poh; + int i; + int rc; + uuid_t cont_id; + + poh = args->gc_ctx.tsc_poh; + + uuid_generate(cont_id); + + rc = vos_cont_create(poh, cont_id); + if (rc) { + print_error("failed to create container: %s\n", + d_errstr(rc)); + return rc; + } + + gc_add_stat(STAT_CONT); + rc = vos_cont_open(poh, cont_id, &coh); + if (rc) { + print_error("failed to open container: %s\n", + d_errstr(rc)); + return rc; + } + + D_ALLOC_ARRAY(oids, obj_per_cont); + if (!oids) { + print_error("failed to allocate oids\n"); + return -DER_NOMEM; + } + + rc = gc_obj_prepare(args, coh, oids); + if (rc) + goto out; + + gc_print_stat(); + + for (i = 0; i < obj_per_cont; i++) { + rc = vos_obj_delete(coh, oids[i]); + if (rc) { + print_error("failed to delete objects: %s\n", + d_errstr(rc)); + goto out; + } + } + + rc = vos_cont_close(coh); + if (rc) { + print_error("failed to close container: %s\n", + d_errstr(rc)); + return rc; + } + + rc = vos_cont_destroy(poh, cont_id); + if (rc) { + print_error("failed to destroy container: %s\n", + d_errstr(rc)); + return rc; + } + + rc = gc_wait_check(args, true); +out: + D_FREE(oids); + return rc; +} + +static void +gc_obj_test_destroy(void **state) +{ + struct gc_test_args *args = *state; + int rc; + + rc = gc_obj_run_destroy(args); + assert_rc_equal(rc, 0); +} + static void gc_obj_bio_test(void **state) { @@ -484,6 +564,8 @@ static const struct CMUnitTest gc_tests[] = { gc_obj_bio_test, gc_prepare, NULL}, { "GC04: container garbage collecting", gc_cont_test, gc_prepare, NULL}, + { "GC05: container garbage collecting with outstanding objects", + gc_obj_test_destroy, gc_prepare, NULL}, }; int diff --git a/src/vos/vos_container.c b/src/vos/vos_container.c index 4e06b39aab6..76a47fa64d6 100644 --- a/src/vos/vos_container.c +++ b/src/vos/vos_container.c @@ -100,6 +100,7 @@ cont_df_rec_alloc(struct btr_instance *tins, d_iov_t *key_iov, } dbtree_close(hdl); + gc_init_cont(&tins->ti_umm, cont_df); args->ca_cont_df = cont_df; rec->rec_off = offset; return 0; @@ -188,6 +189,9 @@ cont_free_internal(struct vos_container *cont) dbtree_close(cont->vc_btr_hdl); + if (!d_list_empty(&cont->vc_gc_link)) + d_list_del(&cont->vc_gc_link); + for (i = 0; i < VOS_IOS_CNT; i++) { if (cont->vc_hint_ctxt[i]) vea_hint_unload(cont->vc_hint_ctxt[i]); @@ -368,6 +372,7 @@ vos_cont_open(daos_handle_t poh, uuid_t co_uuid, daos_handle_t *coh) D_INIT_LIST_HEAD(&cont->vc_dtx_committed_tmp_list); cont->vc_dtx_committed_count = 0; cont->vc_dtx_committed_tmp_count = 0; + D_INIT_LIST_HEAD(&cont->vc_gc_link); /* Cache this btr object ID in container handle */ rc = dbtree_open_inplace_ex(&cont->vc_cont_df->cd_obj_root, diff --git a/src/vos/vos_gc.c b/src/vos/vos_gc.c index fe0181c5ad2..f52758dd659 100644 --- a/src/vos/vos_gc.c +++ b/src/vos/vos_gc.c @@ -55,6 +55,7 @@ struct vos_gc { */ int (*gc_drain)(struct vos_gc *gc, struct vos_pool *pool, + daos_handle_t coh, struct vos_gc_item *item, int *credits, bool *empty); /** @@ -75,14 +76,13 @@ static int gc_reclaim_pool(struct vos_pool *pool, int *credits, * or all credits are consumed (releasing a leaf record consumes one credit) */ static int -gc_drain_btr(struct vos_gc *gc, struct vos_pool *pool, +gc_drain_btr(struct vos_gc *gc, struct vos_pool *pool, daos_handle_t coh, struct btr_root *root, int *credits, bool *empty) { daos_handle_t toh; int rc; - rc = dbtree_open_inplace_ex(root, &pool->vp_uma, DAOS_HDL_INVAL, - pool, &toh); + rc = dbtree_open_inplace_ex(root, &pool->vp_uma, coh, pool, &toh); if (rc == -DER_NONEXIST) { /* empty tree */ *empty = true; return 0; @@ -111,14 +111,14 @@ gc_drain_btr(struct vos_gc *gc, struct vos_pool *pool, * or all credits are consumed (releasing a leaf record consumes one credit) */ static int -gc_drain_evt(struct vos_gc *gc, struct vos_pool *pool, +gc_drain_evt(struct vos_gc *gc, struct vos_pool *pool, daos_handle_t coh, struct evt_root *root, int *credits, bool *empty) { struct evt_desc_cbs cbs; daos_handle_t toh; int rc; - vos_evt_desc_cbs_init(&cbs, pool, DAOS_HDL_INVAL); + vos_evt_desc_cbs_init(&cbs, pool, coh); rc = evt_open(root, &pool->vp_uma, &cbs, &toh); if (rc == -DER_NONEXIST) { *empty = true; @@ -147,7 +147,7 @@ gc_drain_evt(struct vos_gc *gc, struct vos_pool *pool, * or all credits are consumed (releasing a value consumes one credit) */ static int -gc_drain_key(struct vos_gc *gc, struct vos_pool *pool, +gc_drain_key(struct vos_gc *gc, struct vos_pool *pool, daos_handle_t coh, struct vos_gc_item *item, int *credits, bool *empty) { struct vos_krec_df *key = umem_off2ptr(&pool->vp_umm, item->it_addr); @@ -155,11 +155,11 @@ gc_drain_key(struct vos_gc *gc, struct vos_pool *pool, int rc; if (key->kr_bmap & KREC_BF_BTR) { - rc = gc_drain_btr(gc, pool, &key->kr_btr, credits, empty); + rc = gc_drain_btr(gc, pool, coh, &key->kr_btr, credits, empty); } else if (key->kr_bmap & KREC_BF_EVT) { D_ASSERT(gc->gc_type == GC_AKEY); - rc = gc_drain_evt(gc, pool, &key->kr_evt, credits, empty); + rc = gc_drain_evt(gc, pool, coh, &key->kr_evt, credits, empty); } else { /* empty key generated by punch */ *empty = true; @@ -188,12 +188,44 @@ gc_drain_key(struct vos_gc *gc, struct vos_pool *pool, * or all credits are consumed (releasing a key consumes one credit) */ static int -gc_drain_obj(struct vos_gc *gc, struct vos_pool *pool, +gc_drain_obj(struct vos_gc *gc, struct vos_pool *pool, daos_handle_t coh, struct vos_gc_item *item, int *credits, bool *empty) { struct vos_obj_df *obj = umem_off2ptr(&pool->vp_umm, item->it_addr); - return gc_drain_btr(gc, pool, &obj->vo_tree, credits, empty); + return gc_drain_btr(gc, pool, coh, &obj->vo_tree, credits, empty); +} + +static int +gc_bags_move(struct vos_pool *pool, struct vos_gc_bin_df *dest_bin, + struct vos_gc_bin_df *src_bin) +{ + struct umem_instance *umm = &pool->vp_umm; + struct vos_gc_bag_df *bag; + int rc; + + rc = umem_tx_add_ptr(umm, dest_bin, sizeof(*dest_bin)); + if (rc != 0) + return rc; + + if (UMOFF_IS_NULL(dest_bin->bin_bag_last)) { + dest_bin->bin_bag_first = src_bin->bin_bag_first; + dest_bin->bin_bag_last = src_bin->bin_bag_last; + dest_bin->bin_bag_nr = src_bin->bin_bag_nr; + return 0; + } + + /** Last entry in pool list */ + bag = umem_off2ptr(umm, dest_bin->bin_bag_last); + + rc = umem_tx_add_ptr(umm, &bag->bag_next, sizeof(bag->bag_next)); + if (rc != 0) + return rc; + + bag->bag_next = src_bin->bin_bag_first; + dest_bin->bin_bag_last = src_bin->bin_bag_last; + + return 0; } /** @@ -201,12 +233,31 @@ gc_drain_obj(struct vos_gc *gc, struct vos_pool *pool, * empty, or all credits are consumed (releasing an object consumes one credit) */ static int -gc_drain_cont(struct vos_gc *gc, struct vos_pool *pool, +gc_drain_cont(struct vos_gc *gc, struct vos_pool *pool, daos_handle_t coh, struct vos_gc_item *item, int *credits, bool *empty) { - struct vos_cont_df *cont = umem_off2ptr(&pool->vp_umm, item->it_addr); + struct vos_gc_bin_df *src_bin; + struct vos_cont_df *cont = umem_off2ptr(&pool->vp_umm, + item->it_addr); + int i; + int rc; - return gc_drain_btr(gc, pool, &cont->cd_obj_root, credits, empty); + /** Move any leftover bags to the pool gc */ + for (i = GC_AKEY; i < GC_CONT; i++) { + src_bin = &cont->cd_gc_bins[i]; + + if (src_bin->bin_bag_first == UMOFF_NULL) + continue; + + rc = gc_bags_move(pool, &pool->vp_pool_df->pd_gc_bins[i], + src_bin); + if (rc != 0) + return rc; + } + + D_ASSERT(daos_handle_is_inval(coh)); + return gc_drain_btr(gc, pool, coh, &cont->cd_obj_root, + credits, empty); } static int @@ -266,10 +317,15 @@ gc_type2name(enum vos_gc_type type) } struct vos_gc_bin_df * -gc_type2bin(struct vos_pool *pool, enum vos_gc_type type) +gc_type2bin(struct vos_pool *pool, struct vos_container *cont, + enum vos_gc_type type) { D_ASSERT(type < GC_MAX); - return &pool->vp_pool_df->pd_gc_bins[type]; + if (cont == NULL) + return &pool->vp_pool_df->pd_gc_bins[type]; + + D_ASSERT(type < GC_CONT); + return &cont->vc_cont_df->cd_gc_bins[type]; } /** @@ -277,14 +333,14 @@ gc_type2bin(struct vos_pool *pool, enum vos_gc_type type) * last (newest) bag. */ static int -gc_bin_free_bag(struct umem_instance *umm, struct vos_gc_bin_df *bin, - umem_off_t bag_id) +gc_bin_free_bag(struct umem_instance *umm, struct vos_container *cont, + struct vos_gc_bin_df *bin, umem_off_t bag_id) { struct vos_gc_bag_df *bag = umem_off2ptr(umm, bag_id); int rc; D_ASSERT(bag_id == bin->bin_bag_first); - if (bag_id == bin->bin_bag_last) { + if (cont == NULL && bag_id == bin->bin_bag_last) { /* don't free the last bag, only reset it */ D_ASSERT(bin->bin_bag_nr == 1); rc = umem_tx_add_ptr(umm, bag, sizeof(*bag)); @@ -296,14 +352,21 @@ gc_bin_free_bag(struct umem_instance *umm, struct vos_gc_bin_df *bin, return rc; } - D_ASSERT(bin->bin_bag_nr > 1); - D_ASSERT(bag->bag_next != UMOFF_NULL); + if (cont != NULL) { + D_ASSERT(bin->bin_bag_nr > 0); + } else { + D_ASSERT(bin->bin_bag_nr > 1); + D_ASSERT(bag->bag_next != UMOFF_NULL); + } rc = umem_tx_add_ptr(umm, bin, sizeof(*bin)); if (rc == 0) { bin->bin_bag_first = bag->bag_next; bin->bin_bag_nr--; + if (bag->bag_next == UMOFF_NULL) + bin->bin_bag_last = UMOFF_NULL; + rc = umem_free(umm, bag_id); } @@ -392,9 +455,10 @@ gc_bin_add_item(struct umem_instance *umm, struct vos_gc_bin_df *bin, } static struct vos_gc_item * -gc_get_item(struct vos_gc *gc, struct vos_pool *pool) +gc_get_item(struct vos_gc *gc, struct vos_pool *pool, + struct vos_container *cont) { - struct vos_gc_bin_df *bin = gc_type2bin(pool, gc->gc_type); + struct vos_gc_bin_df *bin = gc_type2bin(pool, cont, gc->gc_type); struct vos_gc_bag_df *bag; bag = umem_off2ptr(&pool->vp_umm, bin->bin_bag_first); @@ -408,7 +472,7 @@ gc_get_item(struct vos_gc *gc, struct vos_pool *pool) } static int -gc_drain_item(struct vos_gc *gc, struct vos_pool *pool, +gc_drain_item(struct vos_gc *gc, struct vos_pool *pool, daos_handle_t coh, struct vos_gc_item *item, int *credits, bool *empty) { int creds; @@ -432,7 +496,7 @@ gc_drain_item(struct vos_gc *gc, struct vos_pool *pool, } D_ASSERT(item->it_addr != 0); - rc = gc->gc_drain(gc, pool, item, &creds, empty); + rc = gc->gc_drain(gc, pool, coh, item, &creds, empty); if (rc) return rc; @@ -448,9 +512,10 @@ gc_drain_item(struct vos_gc *gc, struct vos_pool *pool, } static int -gc_free_item(struct vos_gc *gc, struct vos_pool *pool, struct vos_gc_item *item) +gc_free_item(struct vos_gc *gc, struct vos_pool *pool, + struct vos_container *cont, struct vos_gc_item *item) { - struct vos_gc_bin_df *bin = gc_type2bin(pool, gc->gc_type); + struct vos_gc_bin_df *bin = gc_type2bin(pool, cont, gc->gc_type); struct vos_gc_bag_df *bag; int first; int rc = 0; @@ -466,7 +531,8 @@ gc_free_item(struct vos_gc *gc, struct vos_pool *pool, struct vos_gc_item *item) if (first == bag->bag_item_last) { /* it's going to be a empty bag */ D_ASSERT(bag->bag_item_nr == 1); - rc = gc_bin_free_bag(&pool->vp_umm, bin, bin->bin_bag_first); + rc = gc_bin_free_bag(&pool->vp_umm, cont, bin, + bin->bin_bag_first); } else { rc = umem_tx_add_ptr(&pool->vp_umm, bag, sizeof(*bag)); if (rc) @@ -507,17 +573,11 @@ gc_free_item(struct vos_gc *gc, struct vos_pool *pool, struct vos_gc_item *item) return rc; } -/** - * Add an item for garbage collection, this item and all its sub-items will - * be freed by vos_gc_run/pool(). - * - * NB: this function must be called within pmdk transaction. - */ -int -gc_add_item(struct vos_pool *pool, enum vos_gc_type type, umem_off_t item_off, - uint64_t args) +static int +gc_add_item_ex(struct vos_pool *pool, struct vos_container *cont, + enum vos_gc_type type, umem_off_t item_off, uint64_t args) { - struct vos_gc_bin_df *bin = gc_type2bin(pool, type); + struct vos_gc_bin_df *bin = gc_type2bin(pool, cont, type); struct vos_gc_item item; D_DEBUG(DB_TRACE, "Add %s addr="DF_X64"\n", @@ -550,7 +610,8 @@ gc_add_item(struct vos_pool *pool, enum vos_gc_type type, umem_off_t item_off, return rc; } - if (d_list_empty(&pool->vp_gc_link)) { + if (d_list_empty(&pool->vp_gc_link) && + d_list_empty(&pool->vp_gc_cont)) { D_CRIT("Pool="DF_UUID" is full but nothing for GC\n", DP_UUID(pool->vp_id)); return rc; @@ -571,6 +632,58 @@ gc_add_item(struct vos_pool *pool, enum vos_gc_type type, umem_off_t item_off, } } +/** + * Add an item for garbage collection, this item and all its sub-items will + * be freed by vos_gc_run/pool(). + * + * NB: this function must be called within pmdk transaction. + */ +int +gc_add_item(struct vos_pool *pool, enum vos_gc_type type, umem_off_t item_off, + uint64_t args) +{ + return gc_add_item_ex(pool, NULL, type, item_off, args); +} + +/** + * Similar to gc_add_item except specific to objects. If the container + * is not NULL, the object is added to container heaps for garbage collection. + * Otherwise, it is added to the pool heap. This enables us to remove objects + * from active containers that may be referenced elsewhere (e.g. DTX entries). + * + * NB: this function must be called within pmdk transaction. + */ +int +gc_add_obj(struct vos_pool *pool, struct vos_container *cont, + umem_off_t item_off, uint64_t args) +{ + int rc; + + if (cont == NULL) + return gc_add_item(pool, GC_OBJ, item_off, args); + + rc = gc_add_item_ex(pool, cont, GC_OBJ, item_off, args); + + if (rc != 0) + return rc; + + if (d_list_empty(&cont->vc_gc_link)) + d_list_add_tail(&cont->vc_gc_link, &pool->vp_gc_cont); + + return 0; +} + +struct vos_container * +gc_get_container(struct vos_pool *pool) +{ + /** In order to be fair to other containers, we remove this from the + * list. If we run out of credits, we will put it at the back of + * the list and give another container a turn next time. + */ + return d_list_pop_entry(&pool->vp_gc_cont, struct vos_container, + vc_gc_link); +} + /** * Run garbage collector for a pool, it returns if all @credits are consumed * or there is nothing to be reclaimed. @@ -578,9 +691,10 @@ gc_add_item(struct vos_pool *pool, enum vos_gc_type type, umem_off_t item_off, static int gc_reclaim_pool(struct vos_pool *pool, int *credits, bool *empty_ret) { - struct vos_gc *gc = &gc_table[0]; /* start from akey */ - int creds = *credits; - int rc; + struct vos_container *cont = gc_get_container(pool); + struct vos_gc *gc = &gc_table[0]; /* start from akey */ + int creds = *credits; + int rc; if (pool->vp_dying) { *empty_ret = true; @@ -599,14 +713,23 @@ gc_reclaim_pool(struct vos_pool *pool, int *credits, bool *empty_ret) struct vos_gc_item *item; bool empty = false; - D_DEBUG(DB_TRACE, "GC=%s credits=%d/%d\n", gc->gc_name, - creds, *credits); + D_DEBUG(DB_TRACE, "GC=%s cont=%p credits=%d/%d\n", gc->gc_name, + cont, creds, *credits); - item = gc_get_item(gc, pool); + item = gc_get_item(gc, pool, cont); if (item == NULL) { - if (gc->gc_type == GC_CONT) { /* top level GC */ + if (cont != NULL) { + if (gc->gc_type == GC_OBJ) { /* top level GC */ + D_DEBUG(DB_TRACE, "container %p objects" + " reclaimed\n", cont); + cont = gc_get_container(pool); + gc = &gc_table[0]; /* reset to akey */ + continue; + } + } else if (gc->gc_type == GC_CONT) { /* top level GC */ D_DEBUG(DB_TRACE, "Nothing to reclaim\n"); *empty_ret = true; + cont = NULL; break; } D_DEBUG(DB_TRACE, "GC=%s is empty\n", gc->gc_name); @@ -614,7 +737,8 @@ gc_reclaim_pool(struct vos_pool *pool, int *credits, bool *empty_ret) continue; } - rc = gc_drain_item(gc, pool, item, &creds, &empty); + rc = gc_drain_item(gc, pool, vos_cont2hdl(cont), item, &creds, + &empty); if (rc) { D_ERROR("GC=%s error=%s\n", gc->gc_name, d_errstr(rc)); break; @@ -622,7 +746,7 @@ gc_reclaim_pool(struct vos_pool *pool, int *credits, bool *empty_ret) if (empty && creds) { /* item can be released and removed from bin */ - gc_free_item(gc, pool, item); + gc_free_item(gc, pool, cont, item); creds--; } @@ -648,6 +772,13 @@ gc_reclaim_pool(struct vos_pool *pool, int *credits, bool *empty_ret) if (rc == 0) *credits = creds; + if (cont != NULL) { + /** The container may not be empty so add it back to end of + * the list. + */ + d_list_add_tail(&cont->vc_gc_link, &pool->vp_gc_cont); + } + return rc; } @@ -676,6 +807,31 @@ gc_init_pool(struct umem_instance *umm, struct vos_pool_df *pd) return 0; } +/** + * Initialize garbage bins for a pool + * + * NB: there is no need to free garbage bins, because destroy container will + * free them for free. + */ +int +gc_init_cont(struct umem_instance *umm, struct vos_cont_df *cd) +{ + int i; + + D_DEBUG(DB_IO, "Init garbage bins for cont="DF_UUID"\n", + DP_UUID(cd->cd_id)); + + for (i = 0; i < GC_CONT; i++) { + struct vos_gc_bin_df *bin = &cd->cd_gc_bins[i]; + + bin->bin_bag_first = UMOFF_NULL; + bin->bin_bag_last = UMOFF_NULL; + bin->bin_bag_size = gc_bag_size; + bin->bin_bag_nr = 0; + } + return 0; +} + /** * Attach a pool for GC, this function also pins the pool in open hash table. * GC will remove this pool from open hash if it has nothing left for GC and diff --git a/src/vos/vos_internal.h b/src/vos/vos_internal.h index 9184aef9fcd..01c833700b5 100644 --- a/src/vos/vos_internal.h +++ b/src/vos/vos_internal.h @@ -150,6 +150,8 @@ struct vos_pool { struct vos_gc_stat vp_gc_stat; /** link chain on vos_tls::vtl_gc_pools */ d_list_t vp_gc_link; + /** List of open containers with objects in gc pool */ + d_list_t vp_gc_cont; /** address of durable-format pool in SCM */ struct vos_pool_df *vp_pool_df; /** I/O context */ @@ -198,6 +200,8 @@ struct vos_container { uint32_t *vc_ts_idx; /** Direct pointer to the VOS container */ struct vos_cont_df *vc_cont_df; + /** Set if container has objects to garbage collect */ + d_list_t vc_gc_link; /** * Corresponding in-memory block allocator hints for the * durable hints in vos_cont_df @@ -1080,9 +1084,14 @@ gc_have_pool(struct vos_pool *pool); int gc_init_pool(struct umem_instance *umm, struct vos_pool_df *pd); int +gc_init_cont(struct umem_instance *umm, struct vos_cont_df *cd); +int gc_add_item(struct vos_pool *pool, enum vos_gc_type type, umem_off_t item_off, uint64_t args); int +gc_add_obj(struct vos_pool *pool, struct vos_container *cont, + umem_off_t item_off, uint64_t args); +int vos_gc_pool(daos_handle_t poh, int *credits); void gc_reserve_space(daos_size_t *rsrvd); diff --git a/src/vos/vos_layout.h b/src/vos/vos_layout.h index d181ce52cf2..37ad732dec2 100644 --- a/src/vos/vos_layout.h +++ b/src/vos/vos_layout.h @@ -88,7 +88,7 @@ enum vos_gc_type { #define POOL_DF_MAGIC 0x5ca1ab1e /** Lowest supported durable format version */ -#define POOL_DF_VER_1 13 +#define POOL_DF_VER_1 14 /** Current durable format version */ #define POOL_DF_VERSION POOL_DF_VER_1 @@ -256,6 +256,8 @@ struct vos_cont_df { umem_off_t cd_dtx_committed_tail; /** Allocation hints for block allocator. */ struct vea_hint_df cd_hint_df[VOS_IOS_CNT]; + /** GC bins for object/dkey...Don't need GC_CONT entry */ + struct vos_gc_bin_df cd_gc_bins[GC_CONT]; }; /* Assume cd_dtx_active_tail is just after cd_dtx_active_head. */ diff --git a/src/vos/vos_obj_index.c b/src/vos/vos_obj_index.c index 01dc11a0784..7d2de9adfaa 100644 --- a/src/vos/vos_obj_index.c +++ b/src/vos/vos_obj_index.c @@ -117,6 +117,7 @@ oi_rec_free(struct btr_instance *tins, struct btr_record *rec, void *args) struct umem_instance *umm = &tins->ti_umm; struct vos_obj_df *obj; struct ilog_desc_cbs cbs; + struct vos_container *cont = vos_hdl2cont(tins->ti_coh); int rc; obj = umem_off2ptr(umm, rec->rec_off); @@ -132,8 +133,9 @@ oi_rec_free(struct btr_instance *tins, struct btr_record *rec, void *args) vos_ilog_ts_evict(&obj->vo_ilog, VOS_TS_TYPE_OBJ); D_ASSERT(tins->ti_priv); - return gc_add_item((struct vos_pool *)tins->ti_priv, GC_OBJ, - rec->rec_off, 0); + + /** If container is still active, we'll add it to the container heap */ + return gc_add_obj(tins->ti_priv, cont, rec->rec_off, 0); } static int diff --git a/src/vos/vos_pool.c b/src/vos/vos_pool.c index 5631ed4a449..8b764b45682 100644 --- a/src/vos/vos_pool.c +++ b/src/vos/vos_pool.c @@ -146,6 +146,7 @@ pool_alloc(uuid_t uuid, struct vos_pool **pool_p) d_uhash_ulink_init(&pool->vp_hlink, &pool_uuid_hops); D_INIT_LIST_HEAD(&pool->vp_gc_link); + D_INIT_LIST_HEAD(&pool->vp_gc_cont); uuid_copy(pool->vp_id, uuid); memset(&uma, 0, sizeof(uma));