diff --git a/lib/blob/blobstore.c b/lib/blob/blobstore.c index 9ec17281d..322a31200 100644 --- a/lib/blob/blobstore.c +++ b/lib/blob/blobstore.c @@ -1367,11 +1367,31 @@ spdk_bs_opts_init(struct spdk_bs_opts *opts) opts->max_channel_ops = SPDK_BLOB_OPTS_MAX_CHANNEL_OPS; } +static int +_spdk_bs_opts_verify(struct spdk_bs_opts *opts) +{ + if (opts->cluster_sz == 0 || opts->num_md_pages == 0 || opts->max_md_ops == 0 || + opts->max_channel_ops == 0) { + SPDK_ERRLOG("Blobstore options cannot be set to 0\n"); + return -1; + } + + return 0; +} + static struct spdk_blob_store * _spdk_bs_alloc(struct spdk_bs_dev *dev, struct spdk_bs_opts *opts) { struct spdk_blob_store *bs; + uint64_t dev_size; + dev_size = dev->blocklen * dev->blockcnt; + if (dev_size < opts->cluster_sz) { + /* Device size cannot be smaller than cluster size of blobstore */ + SPDK_ERRLOG("Device size %" PRIu64 " is smaller than cluster size %d\n", dev_size, + opts->cluster_sz); + return NULL; + } bs = calloc(1, sizeof(struct spdk_blob_store)); if (!bs) { return NULL; @@ -1698,6 +1718,7 @@ spdk_bs_init(struct spdk_bs_dev *dev, struct spdk_bs_opts *o, struct spdk_bs_cpl cpl; spdk_bs_sequence_t *seq; uint64_t num_md_pages; + uint64_t num_md_clusters; uint32_t i; struct spdk_bs_opts opts = {}; int rc; @@ -1718,6 +1739,12 @@ spdk_bs_init(struct spdk_bs_dev *dev, struct spdk_bs_opts *o, spdk_bs_opts_init(&opts); } + if (_spdk_bs_opts_verify(&opts) != 0) { + dev->destroy(dev); + cb_fn(cb_arg, NULL, -EINVAL); + return; + } + bs = _spdk_bs_alloc(dev, &opts); if (!bs) { dev->destroy(dev); @@ -1725,7 +1752,7 @@ spdk_bs_init(struct spdk_bs_dev *dev, struct spdk_bs_opts *o, return; } - if (opts.num_md_pages == UINT32_MAX) { + if (opts.num_md_pages == SPDK_BLOB_OPTS_NUM_MD_PAGES) { /* By default, allocate 1 page per cluster. * Technically, this over-allocates metadata * because more metadata will reduce the number @@ -1799,8 +1826,20 @@ spdk_bs_init(struct spdk_bs_dev *dev, struct spdk_bs_opts *o, num_md_pages += bs->md_len; ctx->super->crc = _spdk_blob_md_page_calc_crc(ctx->super); + + num_md_clusters = divide_round_up(num_md_pages, bs->pages_per_cluster); + if (num_md_clusters > bs->total_clusters) { + SPDK_ERRLOG("Blobstore metadata cannot use more clusters than is available, " + "please decrease number of pages reserved for metadata " + "or increase cluster size.\n"); + spdk_dma_free(ctx->super); + free(ctx); + _spdk_bs_free(bs); + cb_fn(cb_arg, NULL, -ENOMEM); + return; + } /* Claim all of the clusters used by the metadata */ - for (i = 0; i < divide_round_up(num_md_pages, bs->pages_per_cluster); i++) { + for (i = 0; i < num_md_clusters; i++) { _spdk_bs_claim_cluster(bs, i); } diff --git a/test/unit/lib/blob/blob.c/blob_ut.c b/test/unit/lib/blob/blob.c/blob_ut.c index e5fcced44..127e0dbcf 100644 --- a/test/unit/lib/blob/blob.c/blob_ut.c +++ b/test/unit/lib/blob/blob.c/blob_ut.c @@ -962,6 +962,30 @@ bs_cluster_sz(void) struct spdk_bs_opts opts; uint32_t cluster_sz; + /* Set cluster size to zero */ + dev = init_dev(); + spdk_bs_opts_init(&opts); + opts.cluster_sz = 0; + + /* Initialize a new blob store */ + spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL); + CU_ASSERT(g_bserrno == -EINVAL); + SPDK_CU_ASSERT_FATAL(g_bs == NULL); + + /* + * Set cluster size to blobstore page size, + * to work it is required to be at least twice the blobstore page size. + */ + dev = init_dev(); + spdk_bs_opts_init(&opts); + opts.cluster_sz = SPDK_BS_PAGE_SIZE; + + /* Initialize a new blob store */ + spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL); + CU_ASSERT(g_bserrno == -ENOMEM); + SPDK_CU_ASSERT_FATAL(g_bs == NULL); + + /* Set cluster size to twice the default */ dev = init_dev(); spdk_bs_opts_init(&opts); opts.cluster_sz *= 2;