1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 */ 4 5 #include "spdk/stdinc.h" 6 7 #include "spdk_cunit.h" 8 #include "common/lib/test_env.c" 9 #include "blob/bdev/blob_bdev.c" 10 11 DEFINE_STUB(spdk_bdev_io_type_supported, bool, (struct spdk_bdev *bdev, 12 enum spdk_bdev_io_type io_type), false); 13 DEFINE_STUB_V(spdk_bdev_free_io, (struct spdk_bdev_io *g_bdev_io)); 14 DEFINE_STUB(spdk_bdev_queue_io_wait, int, 15 (struct spdk_bdev *bdev, struct spdk_io_channel *ch, 16 struct spdk_bdev_io_wait_entry *entry), 0); 17 DEFINE_STUB(spdk_bdev_read_blocks, int, 18 (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, void *buf, 19 uint64_t offset_blocks, uint64_t num_blocks, spdk_bdev_io_completion_cb cb, 20 void *cb_arg), 0); 21 DEFINE_STUB(spdk_bdev_write_blocks, int, 22 (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, void *buf, 23 uint64_t offset_blocks, uint64_t num_blocks, spdk_bdev_io_completion_cb cb, 24 void *cb_arg), 0); 25 DEFINE_STUB(spdk_bdev_readv_blocks, int, 26 (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, struct iovec *iov, int iovcnt, 27 uint64_t offset_blocks, uint64_t num_blocks, spdk_bdev_io_completion_cb cb, 28 void *cb_arg), 0); 29 DEFINE_STUB(spdk_bdev_writev_blocks, int, 30 (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, struct iovec *iov, int iovcnt, 31 uint64_t offset_blocks, uint64_t num_blocks, spdk_bdev_io_completion_cb cb, 32 void *cb_arg), 0); 33 DEFINE_STUB(spdk_bdev_readv_blocks_ext, int, 34 (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, struct iovec *iov, int iovcnt, 35 uint64_t offset_blocks, uint64_t num_blocks, spdk_bdev_io_completion_cb cb, 36 void *cb_arg, struct spdk_bdev_ext_io_opts *opts), 0); 37 DEFINE_STUB(spdk_bdev_writev_blocks_ext, int, 38 (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, struct iovec *iov, int iovcnt, 39 uint64_t offset_blocks, uint64_t num_blocks, spdk_bdev_io_completion_cb cb, 40 void *cb_arg, struct spdk_bdev_ext_io_opts *opts), 0); 41 DEFINE_STUB(spdk_bdev_write_zeroes_blocks, int, 42 (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, uint64_t offset_blocks, 43 uint64_t num_blocks, spdk_bdev_io_completion_cb cb, void *cb_arg), 0); 44 DEFINE_STUB(spdk_bdev_unmap_blocks, int, 45 (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, uint64_t offset_blocks, 46 uint64_t num_blocks, spdk_bdev_io_completion_cb cb, void *cb_arg), 0); 47 DEFINE_STUB(spdk_bdev_copy_blocks, int, 48 (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, uint64_t dst_offset_blocks, 49 uint64_t src_offset_blocks, uint64_t num_blocks, spdk_bdev_io_completion_cb cb, 50 void *cb_arg), 0); 51 DEFINE_STUB(spdk_bdev_get_io_channel, struct spdk_io_channel *, 52 (struct spdk_bdev_desc *desc), NULL); 53 54 struct spdk_bdev { 55 char name[16]; 56 uint64_t blockcnt; 57 uint32_t blocklen; 58 uint32_t open_cnt; 59 enum spdk_bdev_claim_type claim_type; 60 struct spdk_bdev_module *claim_module; 61 struct spdk_bdev_desc *claim_desc; 62 }; 63 64 struct spdk_bdev_desc { 65 struct spdk_bdev *bdev; 66 bool write; 67 enum spdk_bdev_claim_type claim_type; 68 }; 69 70 struct spdk_bdev *g_bdev; 71 72 static struct spdk_bdev_module g_bdev_mod = { 73 .name = "blob_bdev_ut" 74 }; 75 76 static struct spdk_bdev * 77 get_bdev(const char *bdev_name) 78 { 79 if (g_bdev == NULL) { 80 return NULL; 81 } 82 83 if (strcmp(bdev_name, g_bdev->name) != 0) { 84 return NULL; 85 } 86 87 return g_bdev; 88 } 89 90 int 91 spdk_bdev_open_ext(const char *bdev_name, bool write, spdk_bdev_event_cb_t event_cb, 92 void *event_ctx, struct spdk_bdev_desc **_desc) 93 { 94 struct spdk_bdev_desc *desc; 95 struct spdk_bdev *bdev = get_bdev(bdev_name); 96 97 if (bdev == NULL) { 98 return -ENODEV; 99 } 100 101 if (write && bdev->claim_module != NULL) { 102 return -EPERM; 103 } 104 105 desc = calloc(1, sizeof(*desc)); 106 desc->bdev = g_bdev; 107 desc->write = write; 108 *_desc = desc; 109 bdev->open_cnt++; 110 111 return 0; 112 } 113 114 void 115 spdk_bdev_close(struct spdk_bdev_desc *desc) 116 { 117 struct spdk_bdev *bdev = desc->bdev; 118 119 bdev->open_cnt--; 120 if (bdev->claim_desc == desc) { 121 bdev->claim_desc = NULL; 122 bdev->claim_type = SPDK_BDEV_CLAIM_NONE; 123 bdev->claim_module = NULL; 124 } 125 free(desc); 126 } 127 128 struct spdk_bdev * 129 spdk_bdev_desc_get_bdev(struct spdk_bdev_desc *desc) 130 { 131 return desc->bdev; 132 } 133 134 uint64_t 135 spdk_bdev_get_num_blocks(const struct spdk_bdev *bdev) 136 { 137 return bdev->blockcnt; 138 } 139 140 uint32_t 141 spdk_bdev_get_block_size(const struct spdk_bdev *bdev) 142 { 143 return bdev->blocklen; 144 } 145 146 /* This is a simple approximation: it does not support shared claims */ 147 int 148 spdk_bdev_module_claim_bdev_desc(struct spdk_bdev_desc *desc, enum spdk_bdev_claim_type type, 149 struct spdk_bdev_claim_opts *opts, 150 struct spdk_bdev_module *module) 151 { 152 struct spdk_bdev *bdev = desc->bdev; 153 154 if (bdev->claim_module != NULL) { 155 return -EPERM; 156 } 157 158 bdev->claim_type = type; 159 bdev->claim_module = module; 160 bdev->claim_desc = desc; 161 162 desc->claim_type = type; 163 164 return 0; 165 } 166 167 static void 168 init_bdev(struct spdk_bdev *bdev, const char *name, uint64_t num_blocks) 169 { 170 memset(bdev, 0, sizeof(*bdev)); 171 snprintf(bdev->name, sizeof(bdev->name), "%s", name); 172 bdev->blockcnt = num_blocks; 173 } 174 175 static void 176 create_bs_dev(void) 177 { 178 struct spdk_bdev bdev; 179 struct spdk_bs_dev *bs_dev = NULL; 180 struct blob_bdev *blob_bdev; 181 int rc; 182 183 init_bdev(&bdev, "bdev0", 16); 184 g_bdev = &bdev; 185 186 rc = spdk_bdev_create_bs_dev_ext("bdev0", NULL, NULL, &bs_dev); 187 CU_ASSERT(rc == 0); 188 SPDK_CU_ASSERT_FATAL(bs_dev != NULL); 189 CU_ASSERT(bdev.open_cnt == 1); 190 191 blob_bdev = (struct blob_bdev *)bs_dev; 192 CU_ASSERT(blob_bdev->desc != NULL); 193 CU_ASSERT(blob_bdev->desc->bdev == g_bdev); 194 CU_ASSERT(blob_bdev->desc->claim_type == SPDK_BDEV_CLAIM_NONE); 195 CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_NONE); 196 197 bs_dev->destroy(bs_dev); 198 CU_ASSERT(bdev.open_cnt == 0); 199 g_bdev = NULL; 200 } 201 202 static void 203 claim_bs_dev(void) 204 { 205 struct spdk_bdev bdev; 206 struct spdk_bs_dev *bs_dev = NULL, *bs_dev2 = NULL; 207 struct blob_bdev *blob_bdev; 208 int rc; 209 210 init_bdev(&bdev, "bdev0", 16); 211 g_bdev = &bdev; 212 213 rc = spdk_bdev_create_bs_dev_ext("bdev0", NULL, NULL, &bs_dev); 214 CU_ASSERT(rc == 0); 215 SPDK_CU_ASSERT_FATAL(bs_dev != NULL); 216 217 blob_bdev = (struct blob_bdev *)bs_dev; 218 CU_ASSERT(blob_bdev->desc->claim_type == SPDK_BDEV_CLAIM_NONE); 219 CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_NONE); 220 CU_ASSERT(blob_bdev->desc->write); 221 222 /* Can get an exclusive write claim */ 223 rc = spdk_bs_bdev_claim(bs_dev, &g_bdev_mod); 224 CU_ASSERT(rc == 0); 225 CU_ASSERT(blob_bdev->desc->write); 226 CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_READ_MANY_WRITE_ONE); 227 CU_ASSERT(bdev.claim_desc == blob_bdev->desc); 228 229 /* Claim blocks a second writer without messing up the first one. */ 230 rc = spdk_bdev_create_bs_dev_ext("bdev0", NULL, NULL, &bs_dev2); 231 CU_ASSERT(rc == -EPERM); 232 CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_READ_MANY_WRITE_ONE); 233 CU_ASSERT(bdev.claim_desc == blob_bdev->desc); 234 235 /* Claim blocks a second claim without messing up the first one. */ 236 rc = spdk_bs_bdev_claim(bs_dev, &g_bdev_mod); 237 CU_ASSERT(rc == -EPERM); 238 CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_READ_MANY_WRITE_ONE); 239 CU_ASSERT(bdev.claim_desc == blob_bdev->desc); 240 241 bs_dev->destroy(bs_dev); 242 CU_ASSERT(bdev.open_cnt == 0); 243 CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_NONE); 244 CU_ASSERT(bdev.claim_module == NULL); 245 CU_ASSERT(bdev.claim_desc == NULL); 246 g_bdev = NULL; 247 } 248 249 int 250 main(int argc, char **argv) 251 { 252 CU_pSuite suite; 253 unsigned int num_failures; 254 255 CU_set_error_action(CUEA_ABORT); 256 CU_initialize_registry(); 257 258 suite = CU_add_suite("blob_bdev", NULL, NULL); 259 260 CU_ADD_TEST(suite, create_bs_dev); 261 CU_ADD_TEST(suite, claim_bs_dev); 262 263 CU_basic_set_mode(CU_BRM_VERBOSE); 264 CU_basic_run_tests(); 265 num_failures = CU_get_number_of_failures(); 266 CU_cleanup_registry(); 267 268 return num_failures; 269 } 270