1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 */ 4 #include "spdk/stdinc.h" 5 6 #include "spdk_cunit.h" 7 #include "spdk/blob.h" 8 9 /* 10 * This creates a bs_dev that does not depend on a bdev. Typical use without assertions looks like: 11 * 12 * struct spdk_bs_dev *dev; 13 * struct spdk_bs_opts bs_opts; 14 * struct spdk_blob_opts blob_opts; 15 * struct ut_snap_opts esnap_opts; 16 * 17 * Create the blobstore with external snapshot support. 18 * dev = init_dev(); 19 * memset(g_dev_buffer, 0, DEV_BUFFER_SIZE); 20 * spdk_bs_opts_init(&bs_opts, sizeof(bs_opts)); 21 * bs_opts.esnap_bs_dev_create = ut_esnap_create; 22 * 23 * Create an esnap clone blob. 24 * ut_spdk_blob_opts_init(&blob_opts); 25 * ut_esnap_opts_init(512, 2048, "name", &esnap_opts); 26 * blob_opts.esnap_id = &esnap_opts; 27 * blob_opts.esnap_id_len = sizeof(esnap_opts); 28 * opts.num_clusters = 4; 29 * blob = ut_blob_create_and_open(bs, &opts); 30 * 31 * At this point the blob can be used like any other blob. 32 */ 33 34 #define UT_ESNAP_OPTS_MAGIC 0xbadf1ea5 35 struct ut_esnap_opts { 36 /* 37 * This structure gets stored in an xattr. The magic number is used to give some assurance 38 * that we got the right thing before trying to use the other fields. 39 */ 40 uint32_t magic; 41 uint32_t block_size; 42 uint64_t num_blocks; 43 char name[32]; 44 }; 45 46 struct ut_esnap_dev { 47 struct spdk_bs_dev bs_dev; 48 struct ut_esnap_opts ut_opts; 49 spdk_blob_id blob_id; 50 uint32_t num_channels; 51 }; 52 53 static void 54 ut_esnap_opts_init(uint32_t block_size, uint32_t num_blocks, const char *name, 55 struct ut_esnap_opts *opts) 56 { 57 memset(opts, 0, sizeof(*opts)); 58 opts->magic = UT_ESNAP_OPTS_MAGIC; 59 opts->block_size = block_size; 60 opts->num_blocks = num_blocks; 61 spdk_strcpy_pad(opts->name, name, sizeof(opts->name) - 1, '\0'); 62 } 63 64 static void 65 ut_esnap_destroy(struct spdk_bs_dev *bs_dev) 66 { 67 free(bs_dev); 68 } 69 70 static struct spdk_bs_dev * 71 ut_esnap_dev_alloc(const struct ut_esnap_opts *opts) 72 { 73 struct ut_esnap_dev *ut_dev; 74 struct spdk_bs_dev *bs_dev; 75 76 assert(opts->magic == UT_ESNAP_OPTS_MAGIC); 77 78 ut_dev = calloc(1, sizeof(*ut_dev)); 79 if (ut_dev == NULL) { 80 return NULL; 81 } 82 83 ut_dev->ut_opts = *opts; 84 bs_dev = &ut_dev->bs_dev; 85 86 bs_dev->blocklen = opts->block_size; 87 bs_dev->blockcnt = opts->num_blocks; 88 89 bs_dev->destroy = ut_esnap_destroy; 90 91 return bs_dev; 92 } 93 94 static int 95 ut_esnap_create(void *bs_ctx, struct spdk_blob *blob, const void *id, uint32_t id_len, 96 struct spdk_bs_dev **bs_devp) 97 { 98 struct spdk_bs_dev *bs_dev = NULL; 99 100 /* With any blobstore that will use bs_ctx, wrap this function and pass NULL as bs_ctx. */ 101 CU_ASSERT(bs_ctx == NULL); 102 103 SPDK_CU_ASSERT_FATAL(id != NULL); 104 SPDK_CU_ASSERT_FATAL(sizeof(struct ut_esnap_opts) == id_len); 105 106 bs_dev = ut_esnap_dev_alloc(id); 107 SPDK_CU_ASSERT_FATAL(bs_dev != NULL); 108 109 *bs_devp = bs_dev; 110 return 0; 111 } 112 113 static int 114 ut_esnap_create_with_count(void *bs_ctx, struct spdk_blob *blob, 115 const void *id, uint32_t id_len, struct spdk_bs_dev **bs_devp) 116 { 117 uint32_t *bs_ctx_count = bs_ctx; 118 119 SPDK_CU_ASSERT_FATAL(bs_ctx != NULL); 120 121 (*bs_ctx_count)++; 122 return ut_esnap_create(NULL, blob, id, id_len, bs_devp); 123 } 124