diff --git a/include/spdk/blob.h b/include/spdk/blob.h index f55b13f17..9dcc87fba 100644 --- a/include/spdk/blob.h +++ b/include/spdk/blob.h @@ -196,6 +196,9 @@ uint64_t spdk_bs_get_page_size(struct spdk_blob_store *bs); /* Get the number of free clusters. */ uint64_t spdk_bs_free_cluster_count(struct spdk_blob_store *bs); +/* Get the total number of clusters accessible by user. */ +uint64_t spdk_bs_total_data_cluster_count(struct spdk_blob_store *bs); + /* Register the current thread as the metadata thread. All functions beginning with * the prefix "spdk_bs_md" must be called only from this thread. */ diff --git a/lib/blob/blobstore.c b/lib/blob/blobstore.c index c1c6c7e25..2d1c3efe0 100644 --- a/lib/blob/blobstore.c +++ b/lib/blob/blobstore.c @@ -1926,6 +1926,8 @@ _spdk_bs_load_super_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno) ctx->bs->pages_per_cluster = ctx->bs->cluster_sz / SPDK_BS_PAGE_SIZE; ctx->bs->md_start = ctx->super->md_start; ctx->bs->md_len = ctx->super->md_len; + ctx->bs->total_data_clusters = ctx->bs->total_clusters - divide_round_up( + ctx->bs->md_start + ctx->bs->md_len, ctx->bs->pages_per_cluster); ctx->bs->super_blob = ctx->super->super_blob; memcpy(&ctx->bs->bstype, &ctx->super->bstype, sizeof(ctx->super->bstype)); @@ -2169,6 +2171,8 @@ spdk_bs_init(struct spdk_bs_dev *dev, struct spdk_bs_opts *o, _spdk_bs_claim_cluster(bs, i); } + bs->total_data_clusters = bs->num_free_clusters; + cpl.type = SPDK_BS_CPL_TYPE_BS_HANDLE; cpl.u.bs_handle.cb_fn = cb_fn; cpl.u.bs_handle.cb_arg = cb_arg; @@ -2404,6 +2408,12 @@ spdk_bs_free_cluster_count(struct spdk_blob_store *bs) return bs->num_free_clusters; } +uint64_t +spdk_bs_total_data_cluster_count(struct spdk_blob_store *bs) +{ + return bs->total_data_clusters; +} + int spdk_bs_register_md_thread(struct spdk_blob_store *bs) { bs->md_target.md_channel = spdk_get_io_channel(&bs->md_target); diff --git a/lib/blob/blobstore.h b/lib/blob/blobstore.h index 259437a06..174667f48 100644 --- a/lib/blob/blobstore.h +++ b/lib/blob/blobstore.h @@ -154,6 +154,7 @@ struct spdk_blob_store { uint32_t cluster_sz; uint64_t total_clusters; + uint64_t total_data_clusters; uint64_t num_free_clusters; uint32_t pages_per_cluster; diff --git a/test/unit/lib/blob/blob.c/blob_ut.c b/test/unit/lib/blob/blob.c/blob_ut.c index 54f8efe8e..4af8b1368 100644 --- a/test/unit/lib/blob/blob.c/blob_ut.c +++ b/test/unit/lib/blob/blob.c/blob_ut.c @@ -1234,6 +1234,82 @@ bs_cluster_sz(void) g_bs = NULL; } +/* + * Create a blobstore, reload it and ensure total usable cluster count + * stays the same. + */ +static void +bs_usable_clusters(void) +{ + struct spdk_bs_dev *dev; + struct spdk_bs_opts opts; + uint32_t clusters; + int i, rc; + + /* Init blobstore */ + dev = init_dev(); + spdk_bs_opts_init(&opts); + + spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL); + CU_ASSERT(g_bserrno == 0); + SPDK_CU_ASSERT_FATAL(g_bs != NULL); + + clusters = spdk_bs_total_data_cluster_count(g_bs); + + /* Unload the blob store */ + spdk_bs_unload(g_bs, bs_op_complete, NULL); + CU_ASSERT(g_bserrno == 0); + g_bs = NULL; + + dev = init_dev(); + /* Load an existing blob store */ + spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL); + CU_ASSERT(g_bserrno == 0); + SPDK_CU_ASSERT_FATAL(g_bs != NULL); + + CU_ASSERT(spdk_bs_total_data_cluster_count(g_bs) == clusters); + + /* Create and resize blobs to make sure that useable cluster count won't change */ + for (i = 0; i < 4; i++) { + g_bserrno = -1; + g_blobid = SPDK_BLOBID_INVALID; + spdk_bs_md_create_blob(g_bs, blob_op_with_id_complete, NULL); + CU_ASSERT(g_bserrno == 0); + CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID); + + g_bserrno = -1; + g_blob = NULL; + spdk_bs_md_open_blob(g_bs, g_blobid, blob_op_with_handle_complete, NULL); + CU_ASSERT(g_bserrno == 0); + CU_ASSERT(g_blob != NULL); + + rc = spdk_bs_md_resize_blob(g_blob, 10); + CU_ASSERT(rc == 0); + + g_bserrno = -1; + spdk_bs_md_close_blob(&g_blob, blob_op_complete, NULL); + CU_ASSERT(g_bserrno == 0); + + CU_ASSERT(spdk_bs_total_data_cluster_count(g_bs) == clusters); + } + + /* Reload the blob store to make sure that nothing changed */ + spdk_bs_unload(g_bs, bs_op_complete, NULL); + CU_ASSERT(g_bserrno == 0); + g_bs = NULL; + + dev = init_dev(); + spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL); + CU_ASSERT(g_bserrno == 0); + SPDK_CU_ASSERT_FATAL(g_bs != NULL); + + CU_ASSERT(spdk_bs_total_data_cluster_count(g_bs) == clusters); + + spdk_bs_unload(g_bs, bs_op_complete, NULL); + CU_ASSERT(g_bserrno == 0); + g_bs = NULL; +} + /* * Test resizing of the metadata blob. This requires creating enough blobs * so that one cluster is not enough to fit the metadata for those blobs. @@ -1845,6 +1921,7 @@ int main(int argc, char **argv) CU_add_test(suite, "bs_load", bs_load) == NULL || CU_add_test(suite, "bs_unload", bs_unload) == NULL || CU_add_test(suite, "bs_cluster_sz", bs_cluster_sz) == NULL || + CU_add_test(suite, "bs_usable_clusters", bs_usable_clusters) == NULL || CU_add_test(suite, "bs_resize_md", bs_resize_md) == NULL || CU_add_test(suite, "bs_destroy", bs_destroy) == NULL || CU_add_test(suite, "bs_type", bs_type) == NULL ||