1c74b8b60SMike Gerdts /* SPDX-License-Identifier: BSD-3-Clause 2c74b8b60SMike Gerdts * Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3c74b8b60SMike Gerdts */ 4c74b8b60SMike Gerdts 5c74b8b60SMike Gerdts #include "spdk/stdinc.h" 6c74b8b60SMike Gerdts 7ae431e31SKonrad Sztyber #include "spdk_internal/cunit.h" 8421fb110SMike Gerdts #include "common/lib/ut_multithread.c" 9421fb110SMike Gerdts 10421fb110SMike Gerdts static void ut_put_io_channel(struct spdk_io_channel *ch); 11421fb110SMike Gerdts 12421fb110SMike Gerdts #define spdk_put_io_channel(ch) ut_put_io_channel(ch); 13c74b8b60SMike Gerdts #include "blob/bdev/blob_bdev.c" 14c74b8b60SMike Gerdts 15c74b8b60SMike Gerdts DEFINE_STUB(spdk_bdev_io_type_supported, bool, (struct spdk_bdev *bdev, 16c74b8b60SMike Gerdts enum spdk_bdev_io_type io_type), false); 17c74b8b60SMike Gerdts DEFINE_STUB_V(spdk_bdev_free_io, (struct spdk_bdev_io *g_bdev_io)); 18c74b8b60SMike Gerdts DEFINE_STUB(spdk_bdev_queue_io_wait, int, 19c74b8b60SMike Gerdts (struct spdk_bdev *bdev, struct spdk_io_channel *ch, 20c74b8b60SMike Gerdts struct spdk_bdev_io_wait_entry *entry), 0); 21c74b8b60SMike Gerdts DEFINE_STUB(spdk_bdev_read_blocks, int, 22c74b8b60SMike Gerdts (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, void *buf, 23c74b8b60SMike Gerdts uint64_t offset_blocks, uint64_t num_blocks, spdk_bdev_io_completion_cb cb, 24c74b8b60SMike Gerdts void *cb_arg), 0); 25c74b8b60SMike Gerdts DEFINE_STUB(spdk_bdev_write_blocks, int, 26c74b8b60SMike Gerdts (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, void *buf, 27c74b8b60SMike Gerdts uint64_t offset_blocks, uint64_t num_blocks, spdk_bdev_io_completion_cb cb, 28c74b8b60SMike Gerdts void *cb_arg), 0); 29c74b8b60SMike Gerdts DEFINE_STUB(spdk_bdev_readv_blocks, int, 30c74b8b60SMike Gerdts (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, struct iovec *iov, int iovcnt, 31c74b8b60SMike Gerdts uint64_t offset_blocks, uint64_t num_blocks, spdk_bdev_io_completion_cb cb, 32c74b8b60SMike Gerdts void *cb_arg), 0); 33c74b8b60SMike Gerdts DEFINE_STUB(spdk_bdev_writev_blocks, int, 34c74b8b60SMike Gerdts (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, struct iovec *iov, int iovcnt, 35c74b8b60SMike Gerdts uint64_t offset_blocks, uint64_t num_blocks, spdk_bdev_io_completion_cb cb, 36c74b8b60SMike Gerdts void *cb_arg), 0); 37c74b8b60SMike Gerdts DEFINE_STUB(spdk_bdev_readv_blocks_ext, int, 38c74b8b60SMike Gerdts (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, struct iovec *iov, int iovcnt, 39c74b8b60SMike Gerdts uint64_t offset_blocks, uint64_t num_blocks, spdk_bdev_io_completion_cb cb, 40c74b8b60SMike Gerdts void *cb_arg, struct spdk_bdev_ext_io_opts *opts), 0); 41c74b8b60SMike Gerdts DEFINE_STUB(spdk_bdev_writev_blocks_ext, int, 42c74b8b60SMike Gerdts (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, struct iovec *iov, int iovcnt, 43c74b8b60SMike Gerdts uint64_t offset_blocks, uint64_t num_blocks, spdk_bdev_io_completion_cb cb, 44c74b8b60SMike Gerdts void *cb_arg, struct spdk_bdev_ext_io_opts *opts), 0); 45c74b8b60SMike Gerdts DEFINE_STUB(spdk_bdev_write_zeroes_blocks, int, 46c74b8b60SMike Gerdts (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, uint64_t offset_blocks, 47c74b8b60SMike Gerdts uint64_t num_blocks, spdk_bdev_io_completion_cb cb, void *cb_arg), 0); 48c74b8b60SMike Gerdts DEFINE_STUB(spdk_bdev_unmap_blocks, int, 49c74b8b60SMike Gerdts (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, uint64_t offset_blocks, 50c74b8b60SMike Gerdts uint64_t num_blocks, spdk_bdev_io_completion_cb cb, void *cb_arg), 0); 51c74b8b60SMike Gerdts DEFINE_STUB(spdk_bdev_copy_blocks, int, 52c74b8b60SMike Gerdts (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, uint64_t dst_offset_blocks, 53c74b8b60SMike Gerdts uint64_t src_offset_blocks, uint64_t num_blocks, spdk_bdev_io_completion_cb cb, 54c74b8b60SMike Gerdts void *cb_arg), 0); 55c74b8b60SMike Gerdts 56c74b8b60SMike Gerdts struct spdk_bdev { 57c74b8b60SMike Gerdts char name[16]; 58c74b8b60SMike Gerdts uint64_t blockcnt; 59c74b8b60SMike Gerdts uint32_t blocklen; 60*2dc4a231SAtul Malakar uint32_t phys_blocklen; 61c74b8b60SMike Gerdts uint32_t open_cnt; 62e52b6c0dSMike Gerdts enum spdk_bdev_claim_type claim_type; 63e52b6c0dSMike Gerdts struct spdk_bdev_module *claim_module; 64f246b2d5SMike Gerdts struct spdk_bdev_desc *claim_desc; 65c74b8b60SMike Gerdts }; 66c74b8b60SMike Gerdts 67c74b8b60SMike Gerdts struct spdk_bdev_desc { 68c74b8b60SMike Gerdts struct spdk_bdev *bdev; 69e52b6c0dSMike Gerdts bool write; 70f246b2d5SMike Gerdts enum spdk_bdev_claim_type claim_type; 71421fb110SMike Gerdts struct spdk_thread *thread; 72c74b8b60SMike Gerdts }; 73c74b8b60SMike Gerdts 74c74b8b60SMike Gerdts struct spdk_bdev *g_bdev; 75c74b8b60SMike Gerdts 76e52b6c0dSMike Gerdts static struct spdk_bdev_module g_bdev_mod = { 77e52b6c0dSMike Gerdts .name = "blob_bdev_ut" 78e52b6c0dSMike Gerdts }; 79e52b6c0dSMike Gerdts 80421fb110SMike Gerdts struct spdk_io_channel * 81421fb110SMike Gerdts spdk_bdev_get_io_channel(struct spdk_bdev_desc *desc) 82421fb110SMike Gerdts { 83421fb110SMike Gerdts if (desc != NULL) { 84421fb110SMike Gerdts return (struct spdk_io_channel *)0x1; 85421fb110SMike Gerdts } 86421fb110SMike Gerdts return NULL; 87421fb110SMike Gerdts } 88421fb110SMike Gerdts 89421fb110SMike Gerdts static void 90421fb110SMike Gerdts ut_put_io_channel(struct spdk_io_channel *ch) 91421fb110SMike Gerdts { 92421fb110SMike Gerdts } 93421fb110SMike Gerdts 94c74b8b60SMike Gerdts static struct spdk_bdev * 95c74b8b60SMike Gerdts get_bdev(const char *bdev_name) 96c74b8b60SMike Gerdts { 97c74b8b60SMike Gerdts if (g_bdev == NULL) { 98c74b8b60SMike Gerdts return NULL; 99c74b8b60SMike Gerdts } 100c74b8b60SMike Gerdts 101c74b8b60SMike Gerdts if (strcmp(bdev_name, g_bdev->name) != 0) { 102c74b8b60SMike Gerdts return NULL; 103c74b8b60SMike Gerdts } 104c74b8b60SMike Gerdts 105c74b8b60SMike Gerdts return g_bdev; 106c74b8b60SMike Gerdts } 107c74b8b60SMike Gerdts 108c74b8b60SMike Gerdts int 109c74b8b60SMike Gerdts spdk_bdev_open_ext(const char *bdev_name, bool write, spdk_bdev_event_cb_t event_cb, 110c74b8b60SMike Gerdts void *event_ctx, struct spdk_bdev_desc **_desc) 111c74b8b60SMike Gerdts { 112c74b8b60SMike Gerdts struct spdk_bdev_desc *desc; 113c74b8b60SMike Gerdts struct spdk_bdev *bdev = get_bdev(bdev_name); 114c74b8b60SMike Gerdts 115c74b8b60SMike Gerdts if (bdev == NULL) { 116c74b8b60SMike Gerdts return -ENODEV; 117c74b8b60SMike Gerdts } 118c74b8b60SMike Gerdts 119e52b6c0dSMike Gerdts if (write && bdev->claim_module != NULL) { 120e52b6c0dSMike Gerdts return -EPERM; 121e52b6c0dSMike Gerdts } 122e52b6c0dSMike Gerdts 123c74b8b60SMike Gerdts desc = calloc(1, sizeof(*desc)); 124c74b8b60SMike Gerdts desc->bdev = g_bdev; 125e52b6c0dSMike Gerdts desc->write = write; 126421fb110SMike Gerdts desc->thread = spdk_get_thread(); 127c74b8b60SMike Gerdts *_desc = desc; 128c74b8b60SMike Gerdts bdev->open_cnt++; 129c74b8b60SMike Gerdts 130c74b8b60SMike Gerdts return 0; 131c74b8b60SMike Gerdts } 132c74b8b60SMike Gerdts 133c74b8b60SMike Gerdts void 134c74b8b60SMike Gerdts spdk_bdev_close(struct spdk_bdev_desc *desc) 135c74b8b60SMike Gerdts { 136c74b8b60SMike Gerdts struct spdk_bdev *bdev = desc->bdev; 137c74b8b60SMike Gerdts 138421fb110SMike Gerdts CU_ASSERT(desc->thread == spdk_get_thread()); 139421fb110SMike Gerdts 140c74b8b60SMike Gerdts bdev->open_cnt--; 141f246b2d5SMike Gerdts if (bdev->claim_desc == desc) { 142f246b2d5SMike Gerdts bdev->claim_desc = NULL; 143f246b2d5SMike Gerdts bdev->claim_type = SPDK_BDEV_CLAIM_NONE; 144f246b2d5SMike Gerdts bdev->claim_module = NULL; 145f246b2d5SMike Gerdts } 146c74b8b60SMike Gerdts free(desc); 147c74b8b60SMike Gerdts } 148c74b8b60SMike Gerdts 149c74b8b60SMike Gerdts struct spdk_bdev * 150c74b8b60SMike Gerdts spdk_bdev_desc_get_bdev(struct spdk_bdev_desc *desc) 151c74b8b60SMike Gerdts { 152c74b8b60SMike Gerdts return desc->bdev; 153c74b8b60SMike Gerdts } 154c74b8b60SMike Gerdts 155c74b8b60SMike Gerdts uint64_t 156c74b8b60SMike Gerdts spdk_bdev_get_num_blocks(const struct spdk_bdev *bdev) 157c74b8b60SMike Gerdts { 158c74b8b60SMike Gerdts return bdev->blockcnt; 159c74b8b60SMike Gerdts } 160c74b8b60SMike Gerdts 161c74b8b60SMike Gerdts uint32_t 162c74b8b60SMike Gerdts spdk_bdev_get_block_size(const struct spdk_bdev *bdev) 163c74b8b60SMike Gerdts { 164c74b8b60SMike Gerdts return bdev->blocklen; 165c74b8b60SMike Gerdts } 166c74b8b60SMike Gerdts 167*2dc4a231SAtul Malakar uint32_t 168*2dc4a231SAtul Malakar spdk_bdev_get_physical_block_size(const struct spdk_bdev *bdev) 169*2dc4a231SAtul Malakar { 170*2dc4a231SAtul Malakar return bdev->phys_blocklen; 171*2dc4a231SAtul Malakar } 172*2dc4a231SAtul Malakar 173f246b2d5SMike Gerdts /* This is a simple approximation: it does not support shared claims */ 174e52b6c0dSMike Gerdts int 175f246b2d5SMike Gerdts spdk_bdev_module_claim_bdev_desc(struct spdk_bdev_desc *desc, enum spdk_bdev_claim_type type, 176f246b2d5SMike Gerdts struct spdk_bdev_claim_opts *opts, 177e52b6c0dSMike Gerdts struct spdk_bdev_module *module) 178e52b6c0dSMike Gerdts { 179f246b2d5SMike Gerdts struct spdk_bdev *bdev = desc->bdev; 180f246b2d5SMike Gerdts 181e52b6c0dSMike Gerdts if (bdev->claim_module != NULL) { 182e52b6c0dSMike Gerdts return -EPERM; 183e52b6c0dSMike Gerdts } 184e52b6c0dSMike Gerdts 185f246b2d5SMike Gerdts bdev->claim_type = type; 186e52b6c0dSMike Gerdts bdev->claim_module = module; 187f246b2d5SMike Gerdts bdev->claim_desc = desc; 188f246b2d5SMike Gerdts 189f246b2d5SMike Gerdts desc->claim_type = type; 190e52b6c0dSMike Gerdts 191e52b6c0dSMike Gerdts return 0; 192e52b6c0dSMike Gerdts } 193e52b6c0dSMike Gerdts 194c74b8b60SMike Gerdts static void 195c74b8b60SMike Gerdts init_bdev(struct spdk_bdev *bdev, const char *name, uint64_t num_blocks) 196c74b8b60SMike Gerdts { 197c74b8b60SMike Gerdts memset(bdev, 0, sizeof(*bdev)); 198c74b8b60SMike Gerdts snprintf(bdev->name, sizeof(bdev->name), "%s", name); 199c74b8b60SMike Gerdts bdev->blockcnt = num_blocks; 200c74b8b60SMike Gerdts } 201c74b8b60SMike Gerdts 202c74b8b60SMike Gerdts static void 203c74b8b60SMike Gerdts create_bs_dev(void) 204c74b8b60SMike Gerdts { 205c74b8b60SMike Gerdts struct spdk_bdev bdev; 206c74b8b60SMike Gerdts struct spdk_bs_dev *bs_dev = NULL; 207c74b8b60SMike Gerdts struct blob_bdev *blob_bdev; 208c74b8b60SMike Gerdts int rc; 209c74b8b60SMike Gerdts 210c74b8b60SMike Gerdts init_bdev(&bdev, "bdev0", 16); 211c74b8b60SMike Gerdts g_bdev = &bdev; 212c74b8b60SMike Gerdts 213c74b8b60SMike Gerdts rc = spdk_bdev_create_bs_dev_ext("bdev0", NULL, NULL, &bs_dev); 214c74b8b60SMike Gerdts CU_ASSERT(rc == 0); 215c74b8b60SMike Gerdts SPDK_CU_ASSERT_FATAL(bs_dev != NULL); 216c74b8b60SMike Gerdts CU_ASSERT(bdev.open_cnt == 1); 217c74b8b60SMike Gerdts 218c74b8b60SMike Gerdts blob_bdev = (struct blob_bdev *)bs_dev; 219c74b8b60SMike Gerdts CU_ASSERT(blob_bdev->desc != NULL); 220bd5a7847SMike Gerdts CU_ASSERT(blob_bdev->desc->write); 221bd5a7847SMike Gerdts CU_ASSERT(blob_bdev->desc->bdev == g_bdev); 222bd5a7847SMike Gerdts CU_ASSERT(blob_bdev->desc->claim_type == SPDK_BDEV_CLAIM_NONE); 223bd5a7847SMike Gerdts CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_NONE); 224bd5a7847SMike Gerdts 225bd5a7847SMike Gerdts bs_dev->destroy(bs_dev); 226bd5a7847SMike Gerdts CU_ASSERT(bdev.open_cnt == 0); 227bd5a7847SMike Gerdts g_bdev = NULL; 228bd5a7847SMike Gerdts } 229bd5a7847SMike Gerdts 230bd5a7847SMike Gerdts static void 231bd5a7847SMike Gerdts create_bs_dev_ro(void) 232bd5a7847SMike Gerdts { 233bd5a7847SMike Gerdts struct spdk_bdev bdev; 234bd5a7847SMike Gerdts struct spdk_bs_dev *bs_dev = NULL; 235bd5a7847SMike Gerdts struct blob_bdev *blob_bdev; 236bd5a7847SMike Gerdts struct spdk_bdev_bs_dev_opts opts = { 0 }; 237bd5a7847SMike Gerdts int rc; 238bd5a7847SMike Gerdts 239bd5a7847SMike Gerdts /* opts with the wrong size returns -EINVAL */ 240bd5a7847SMike Gerdts rc = spdk_bdev_create_bs_dev("nope", false, &opts, sizeof(opts) + 8, NULL, NULL, &bs_dev); 241bd5a7847SMike Gerdts CU_ASSERT(rc == -EINVAL); 242bd5a7847SMike Gerdts 243bd5a7847SMike Gerdts /* opts with the right size is OK, but can still fail if the device doesn't exist. */ 244bd5a7847SMike Gerdts opts.opts_size = sizeof(opts); 245bd5a7847SMike Gerdts rc = spdk_bdev_create_bs_dev("nope", false, &opts, sizeof(opts), NULL, NULL, &bs_dev); 246bd5a7847SMike Gerdts CU_ASSERT(rc == -ENODEV); 247bd5a7847SMike Gerdts 248bd5a7847SMike Gerdts init_bdev(&bdev, "bdev0", 16); 249bd5a7847SMike Gerdts g_bdev = &bdev; 250bd5a7847SMike Gerdts 251bd5a7847SMike Gerdts /* The normal way to create a read-only device */ 252bd5a7847SMike Gerdts rc = spdk_bdev_create_bs_dev("bdev0", false, NULL, 0, NULL, NULL, &bs_dev); 253bd5a7847SMike Gerdts CU_ASSERT(rc == 0); 254bd5a7847SMike Gerdts SPDK_CU_ASSERT_FATAL(bs_dev != NULL); 255bd5a7847SMike Gerdts CU_ASSERT(bdev.open_cnt == 1); 256bd5a7847SMike Gerdts 257bd5a7847SMike Gerdts blob_bdev = (struct blob_bdev *)bs_dev; 258bd5a7847SMike Gerdts CU_ASSERT(blob_bdev->desc != NULL); 259bd5a7847SMike Gerdts CU_ASSERT(!blob_bdev->desc->write); 260bd5a7847SMike Gerdts CU_ASSERT(blob_bdev->desc->bdev == g_bdev); 261bd5a7847SMike Gerdts CU_ASSERT(blob_bdev->desc->claim_type == SPDK_BDEV_CLAIM_NONE); 262bd5a7847SMike Gerdts CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_NONE); 263bd5a7847SMike Gerdts 264bd5a7847SMike Gerdts bs_dev->destroy(bs_dev); 265bd5a7847SMike Gerdts CU_ASSERT(bdev.open_cnt == 0); 266bd5a7847SMike Gerdts g_bdev = NULL; 267bd5a7847SMike Gerdts } 268bd5a7847SMike Gerdts 269bd5a7847SMike Gerdts static void 270bd5a7847SMike Gerdts create_bs_dev_rw(void) 271bd5a7847SMike Gerdts { 272bd5a7847SMike Gerdts struct spdk_bdev bdev; 273bd5a7847SMike Gerdts struct spdk_bs_dev *bs_dev = NULL; 274bd5a7847SMike Gerdts struct blob_bdev *blob_bdev; 275bd5a7847SMike Gerdts int rc; 276bd5a7847SMike Gerdts 277bd5a7847SMike Gerdts init_bdev(&bdev, "bdev0", 16); 278bd5a7847SMike Gerdts g_bdev = &bdev; 279bd5a7847SMike Gerdts 280bd5a7847SMike Gerdts /* This is equivalent to spdk_bdev_create_bs_dev_ext() */ 281bd5a7847SMike Gerdts rc = spdk_bdev_create_bs_dev("bdev0", true, NULL, 0, NULL, NULL, &bs_dev); 282bd5a7847SMike Gerdts CU_ASSERT(rc == 0); 283bd5a7847SMike Gerdts SPDK_CU_ASSERT_FATAL(bs_dev != NULL); 284bd5a7847SMike Gerdts CU_ASSERT(bdev.open_cnt == 1); 285bd5a7847SMike Gerdts 286bd5a7847SMike Gerdts blob_bdev = (struct blob_bdev *)bs_dev; 287bd5a7847SMike Gerdts CU_ASSERT(blob_bdev->desc != NULL); 288bd5a7847SMike Gerdts CU_ASSERT(blob_bdev->desc->write); 289c74b8b60SMike Gerdts CU_ASSERT(blob_bdev->desc->bdev == g_bdev); 290f246b2d5SMike Gerdts CU_ASSERT(blob_bdev->desc->claim_type == SPDK_BDEV_CLAIM_NONE); 291f246b2d5SMike Gerdts CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_NONE); 292c74b8b60SMike Gerdts 293c74b8b60SMike Gerdts bs_dev->destroy(bs_dev); 294c74b8b60SMike Gerdts CU_ASSERT(bdev.open_cnt == 0); 295c74b8b60SMike Gerdts g_bdev = NULL; 296c74b8b60SMike Gerdts } 297c74b8b60SMike Gerdts 298e52b6c0dSMike Gerdts static void 299e52b6c0dSMike Gerdts claim_bs_dev(void) 300e52b6c0dSMike Gerdts { 301e52b6c0dSMike Gerdts struct spdk_bdev bdev; 302e52b6c0dSMike Gerdts struct spdk_bs_dev *bs_dev = NULL, *bs_dev2 = NULL; 303e52b6c0dSMike Gerdts struct blob_bdev *blob_bdev; 304e52b6c0dSMike Gerdts int rc; 305e52b6c0dSMike Gerdts 306e52b6c0dSMike Gerdts init_bdev(&bdev, "bdev0", 16); 307e52b6c0dSMike Gerdts g_bdev = &bdev; 308e52b6c0dSMike Gerdts 309e52b6c0dSMike Gerdts rc = spdk_bdev_create_bs_dev_ext("bdev0", NULL, NULL, &bs_dev); 310e52b6c0dSMike Gerdts CU_ASSERT(rc == 0); 311e52b6c0dSMike Gerdts SPDK_CU_ASSERT_FATAL(bs_dev != NULL); 312e52b6c0dSMike Gerdts 313e52b6c0dSMike Gerdts blob_bdev = (struct blob_bdev *)bs_dev; 314f246b2d5SMike Gerdts CU_ASSERT(blob_bdev->desc->claim_type == SPDK_BDEV_CLAIM_NONE); 315f246b2d5SMike Gerdts CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_NONE); 316e52b6c0dSMike Gerdts CU_ASSERT(blob_bdev->desc->write); 317e52b6c0dSMike Gerdts 318e52b6c0dSMike Gerdts /* Can get an exclusive write claim */ 319e52b6c0dSMike Gerdts rc = spdk_bs_bdev_claim(bs_dev, &g_bdev_mod); 320e52b6c0dSMike Gerdts CU_ASSERT(rc == 0); 321e52b6c0dSMike Gerdts CU_ASSERT(blob_bdev->desc->write); 322f246b2d5SMike Gerdts CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_READ_MANY_WRITE_ONE); 323f246b2d5SMike Gerdts CU_ASSERT(bdev.claim_desc == blob_bdev->desc); 324e52b6c0dSMike Gerdts 325e52b6c0dSMike Gerdts /* Claim blocks a second writer without messing up the first one. */ 326e52b6c0dSMike Gerdts rc = spdk_bdev_create_bs_dev_ext("bdev0", NULL, NULL, &bs_dev2); 327e52b6c0dSMike Gerdts CU_ASSERT(rc == -EPERM); 328f246b2d5SMike Gerdts CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_READ_MANY_WRITE_ONE); 329f246b2d5SMike Gerdts CU_ASSERT(bdev.claim_desc == blob_bdev->desc); 330e52b6c0dSMike Gerdts 331e52b6c0dSMike Gerdts /* Claim blocks a second claim without messing up the first one. */ 332e52b6c0dSMike Gerdts rc = spdk_bs_bdev_claim(bs_dev, &g_bdev_mod); 333e52b6c0dSMike Gerdts CU_ASSERT(rc == -EPERM); 334f246b2d5SMike Gerdts CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_READ_MANY_WRITE_ONE); 335f246b2d5SMike Gerdts CU_ASSERT(bdev.claim_desc == blob_bdev->desc); 336e52b6c0dSMike Gerdts 337e52b6c0dSMike Gerdts bs_dev->destroy(bs_dev); 338e52b6c0dSMike Gerdts CU_ASSERT(bdev.open_cnt == 0); 339e52b6c0dSMike Gerdts CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_NONE); 340e52b6c0dSMike Gerdts CU_ASSERT(bdev.claim_module == NULL); 341f246b2d5SMike Gerdts CU_ASSERT(bdev.claim_desc == NULL); 342e52b6c0dSMike Gerdts g_bdev = NULL; 343e52b6c0dSMike Gerdts } 344e52b6c0dSMike Gerdts 345ab2eff07SMike Gerdts static void 346ab2eff07SMike Gerdts claim_bs_dev_ro(void) 347ab2eff07SMike Gerdts { 348ab2eff07SMike Gerdts struct spdk_bdev bdev; 349ab2eff07SMike Gerdts struct spdk_bs_dev *bs_dev = NULL, *bs_dev2 = NULL; 350ab2eff07SMike Gerdts struct blob_bdev *blob_bdev; 351ab2eff07SMike Gerdts int rc; 352ab2eff07SMike Gerdts 353ab2eff07SMike Gerdts init_bdev(&bdev, "bdev0", 16); 354ab2eff07SMike Gerdts g_bdev = &bdev; 355ab2eff07SMike Gerdts 356ab2eff07SMike Gerdts rc = spdk_bdev_create_bs_dev("bdev0", false, NULL, 0, NULL, NULL, &bs_dev); 357ab2eff07SMike Gerdts CU_ASSERT(rc == 0); 358ab2eff07SMike Gerdts SPDK_CU_ASSERT_FATAL(bs_dev != NULL); 359ab2eff07SMike Gerdts 360ab2eff07SMike Gerdts blob_bdev = (struct blob_bdev *)bs_dev; 361ab2eff07SMike Gerdts CU_ASSERT(blob_bdev->desc->claim_type == SPDK_BDEV_CLAIM_NONE); 362ab2eff07SMike Gerdts CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_NONE); 363ab2eff07SMike Gerdts CU_ASSERT(!blob_bdev->desc->write); 364ab2eff07SMike Gerdts 365ab2eff07SMike Gerdts /* Can get an shared reader claim */ 366ab2eff07SMike Gerdts rc = spdk_bs_bdev_claim(bs_dev, &g_bdev_mod); 367ab2eff07SMike Gerdts CU_ASSERT(rc == 0); 368ab2eff07SMike Gerdts CU_ASSERT(!blob_bdev->desc->write); 369ab2eff07SMike Gerdts CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_READ_MANY_WRITE_NONE); 370ab2eff07SMike Gerdts CU_ASSERT(bdev.claim_desc == blob_bdev->desc); 371ab2eff07SMike Gerdts 372ab2eff07SMike Gerdts /* Claim blocks a writer without messing up the claim. */ 373ab2eff07SMike Gerdts rc = spdk_bdev_create_bs_dev_ext("bdev0", NULL, NULL, &bs_dev2); 374ab2eff07SMike Gerdts CU_ASSERT(rc == -EPERM); 375ab2eff07SMike Gerdts CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_READ_MANY_WRITE_NONE); 376ab2eff07SMike Gerdts CU_ASSERT(bdev.claim_desc == blob_bdev->desc); 377ab2eff07SMike Gerdts 378ab2eff07SMike Gerdts /* Another reader is just fine */ 379ab2eff07SMike Gerdts rc = spdk_bdev_create_bs_dev("bdev0", false, NULL, 0, NULL, NULL, &bs_dev2); 380ab2eff07SMike Gerdts CU_ASSERT(rc == 0); 381ab2eff07SMike Gerdts SPDK_CU_ASSERT_FATAL(bs_dev2 != NULL); 382ab2eff07SMike Gerdts bs_dev2->destroy(bs_dev2); 383ab2eff07SMike Gerdts 384ab2eff07SMike Gerdts bs_dev->destroy(bs_dev); 385ab2eff07SMike Gerdts CU_ASSERT(bdev.open_cnt == 0); 386ab2eff07SMike Gerdts CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_NONE); 387ab2eff07SMike Gerdts CU_ASSERT(bdev.claim_module == NULL); 388ab2eff07SMike Gerdts CU_ASSERT(bdev.claim_desc == NULL); 389ab2eff07SMike Gerdts g_bdev = NULL; 390ab2eff07SMike Gerdts } 391ab2eff07SMike Gerdts 392421fb110SMike Gerdts /* 393421fb110SMike Gerdts * Verify that create_channel() and destroy_channel() increment and decrement the blob_bdev->refs. 394421fb110SMike Gerdts */ 395421fb110SMike Gerdts static void 396421fb110SMike Gerdts deferred_destroy_refs(void) 397421fb110SMike Gerdts { 398421fb110SMike Gerdts struct spdk_bdev bdev; 399421fb110SMike Gerdts struct spdk_io_channel *ch1, *ch2; 400421fb110SMike Gerdts struct spdk_bs_dev *bs_dev = NULL; 401421fb110SMike Gerdts struct blob_bdev *blob_bdev; 402421fb110SMike Gerdts int rc; 403421fb110SMike Gerdts 404421fb110SMike Gerdts set_thread(0); 405421fb110SMike Gerdts init_bdev(&bdev, "bdev0", 16); 406421fb110SMike Gerdts g_bdev = &bdev; 407421fb110SMike Gerdts 408421fb110SMike Gerdts /* Open a blob_bdev, verify reference count is 1. */ 409421fb110SMike Gerdts rc = spdk_bdev_create_bs_dev("bdev0", false, NULL, 0, NULL, NULL, &bs_dev); 410421fb110SMike Gerdts CU_ASSERT(rc == 0); 411421fb110SMike Gerdts SPDK_CU_ASSERT_FATAL(bs_dev != NULL); 412421fb110SMike Gerdts blob_bdev = (struct blob_bdev *)bs_dev; 413421fb110SMike Gerdts CU_ASSERT(blob_bdev->refs == 1); 414421fb110SMike Gerdts CU_ASSERT(blob_bdev->desc != NULL); 415421fb110SMike Gerdts 416421fb110SMike Gerdts /* Verify reference count increases with channels on the same thread. */ 417421fb110SMike Gerdts ch1 = bs_dev->create_channel(bs_dev); 418421fb110SMike Gerdts SPDK_CU_ASSERT_FATAL(ch1 != NULL); 419421fb110SMike Gerdts CU_ASSERT(blob_bdev->refs == 2); 420421fb110SMike Gerdts ch2 = bs_dev->create_channel(bs_dev); 421421fb110SMike Gerdts SPDK_CU_ASSERT_FATAL(ch2 != NULL); 422421fb110SMike Gerdts CU_ASSERT(blob_bdev->refs == 3); 423421fb110SMike Gerdts bs_dev->destroy_channel(bs_dev, ch1); 424421fb110SMike Gerdts CU_ASSERT(blob_bdev->refs == 2); 425421fb110SMike Gerdts bs_dev->destroy_channel(bs_dev, ch2); 426421fb110SMike Gerdts CU_ASSERT(blob_bdev->refs == 1); 427421fb110SMike Gerdts CU_ASSERT(blob_bdev->desc != NULL); 428421fb110SMike Gerdts 429421fb110SMike Gerdts /* Verify reference count increases with channels on different threads. */ 430421fb110SMike Gerdts ch1 = bs_dev->create_channel(bs_dev); 431421fb110SMike Gerdts SPDK_CU_ASSERT_FATAL(ch1 != NULL); 432421fb110SMike Gerdts CU_ASSERT(blob_bdev->refs == 2); 433421fb110SMike Gerdts set_thread(1); 434421fb110SMike Gerdts ch2 = bs_dev->create_channel(bs_dev); 435421fb110SMike Gerdts SPDK_CU_ASSERT_FATAL(ch2 != NULL); 436421fb110SMike Gerdts CU_ASSERT(blob_bdev->refs == 3); 437421fb110SMike Gerdts bs_dev->destroy_channel(bs_dev, ch1); 438421fb110SMike Gerdts CU_ASSERT(blob_bdev->refs == 2); 439421fb110SMike Gerdts bs_dev->destroy_channel(bs_dev, ch2); 440421fb110SMike Gerdts CU_ASSERT(blob_bdev->refs == 1); 441421fb110SMike Gerdts CU_ASSERT(blob_bdev->desc != NULL); 442421fb110SMike Gerdts 443421fb110SMike Gerdts set_thread(0); 444421fb110SMike Gerdts bs_dev->destroy(bs_dev); 445421fb110SMike Gerdts g_bdev = NULL; 446421fb110SMike Gerdts } 447421fb110SMike Gerdts 448421fb110SMike Gerdts /* 449421fb110SMike Gerdts * When a channel is open bs_dev->destroy() should not free bs_dev until after the last channel is 450421fb110SMike Gerdts * closed. Further, destroy() prevents the creation of new channels. 451421fb110SMike Gerdts */ 452421fb110SMike Gerdts static void 453421fb110SMike Gerdts deferred_destroy_channels(void) 454421fb110SMike Gerdts { 455421fb110SMike Gerdts struct spdk_bdev bdev; 456421fb110SMike Gerdts struct spdk_io_channel *ch1, *ch2; 457421fb110SMike Gerdts struct spdk_bs_dev *bs_dev = NULL; 458421fb110SMike Gerdts struct blob_bdev *blob_bdev; 459421fb110SMike Gerdts int rc; 460421fb110SMike Gerdts 461421fb110SMike Gerdts set_thread(0); 462421fb110SMike Gerdts init_bdev(&bdev, "bdev0", 16); 463421fb110SMike Gerdts 464421fb110SMike Gerdts /* Open bs_dev and sanity check */ 465421fb110SMike Gerdts g_bdev = &bdev; 466421fb110SMike Gerdts rc = spdk_bdev_create_bs_dev("bdev0", false, NULL, 0, NULL, NULL, &bs_dev); 467421fb110SMike Gerdts CU_ASSERT(rc == 0); 468421fb110SMike Gerdts SPDK_CU_ASSERT_FATAL(bs_dev != NULL); 469421fb110SMike Gerdts CU_ASSERT(bdev.open_cnt == 1); 470421fb110SMike Gerdts blob_bdev = (struct blob_bdev *)bs_dev; 471421fb110SMike Gerdts CU_ASSERT(blob_bdev->refs == 1); 472421fb110SMike Gerdts CU_ASSERT(blob_bdev->desc != NULL); 473421fb110SMike Gerdts 474421fb110SMike Gerdts /* Create a channel, destroy the bs_dev. It should not be freed yet. */ 475421fb110SMike Gerdts ch1 = bs_dev->create_channel(bs_dev); 476421fb110SMike Gerdts SPDK_CU_ASSERT_FATAL(ch1 != NULL); 477421fb110SMike Gerdts CU_ASSERT(blob_bdev->refs == 2); 478421fb110SMike Gerdts bs_dev->destroy(bs_dev); 479421fb110SMike Gerdts 480421fb110SMike Gerdts /* Destroy closes the bdev and prevents desc from being used for creating more channels. */ 481421fb110SMike Gerdts CU_ASSERT(blob_bdev->desc == NULL); 482421fb110SMike Gerdts CU_ASSERT(bdev.open_cnt == 0); 483421fb110SMike Gerdts CU_ASSERT(blob_bdev->refs == 1); 484421fb110SMike Gerdts ch2 = bs_dev->create_channel(bs_dev); 485421fb110SMike Gerdts CU_ASSERT(ch2 == NULL) 486421fb110SMike Gerdts CU_ASSERT(blob_bdev->refs == 1); 487421fb110SMike Gerdts bs_dev->destroy_channel(bs_dev, ch1); 488421fb110SMike Gerdts g_bdev = NULL; 489421fb110SMike Gerdts 490421fb110SMike Gerdts /* Now bs_dev should have been freed. Builds with asan will verify. */ 491421fb110SMike Gerdts } 492421fb110SMike Gerdts 493421fb110SMike Gerdts /* 494421fb110SMike Gerdts * Verify that deferred destroy copes well with the last channel destruction being on a thread other 495421fb110SMike Gerdts * than the thread used to obtain the bdev descriptor. 496421fb110SMike Gerdts */ 497421fb110SMike Gerdts static void 498421fb110SMike Gerdts deferred_destroy_threads(void) 499421fb110SMike Gerdts { 500421fb110SMike Gerdts struct spdk_bdev bdev; 501421fb110SMike Gerdts struct spdk_io_channel *ch1, *ch2; 502421fb110SMike Gerdts struct spdk_bs_dev *bs_dev = NULL; 503421fb110SMike Gerdts struct blob_bdev *blob_bdev; 504421fb110SMike Gerdts int rc; 505421fb110SMike Gerdts 506421fb110SMike Gerdts set_thread(0); 507421fb110SMike Gerdts init_bdev(&bdev, "bdev0", 16); 508421fb110SMike Gerdts g_bdev = &bdev; 509421fb110SMike Gerdts 510421fb110SMike Gerdts /* Open bs_dev and sanity check */ 511421fb110SMike Gerdts rc = spdk_bdev_create_bs_dev("bdev0", false, NULL, 0, NULL, NULL, &bs_dev); 512421fb110SMike Gerdts CU_ASSERT(rc == 0); 513421fb110SMike Gerdts SPDK_CU_ASSERT_FATAL(bs_dev != NULL); 514421fb110SMike Gerdts CU_ASSERT(bdev.open_cnt == 1); 515421fb110SMike Gerdts blob_bdev = (struct blob_bdev *)bs_dev; 516421fb110SMike Gerdts CU_ASSERT(blob_bdev->refs == 1); 517421fb110SMike Gerdts CU_ASSERT(blob_bdev->desc != NULL); 518421fb110SMike Gerdts 519421fb110SMike Gerdts /* Create two channels, each on their own thread. */ 520421fb110SMike Gerdts ch1 = bs_dev->create_channel(bs_dev); 521421fb110SMike Gerdts SPDK_CU_ASSERT_FATAL(ch1 != NULL); 522421fb110SMike Gerdts CU_ASSERT(blob_bdev->refs == 2); 523421fb110SMike Gerdts CU_ASSERT(spdk_get_thread() == blob_bdev->desc->thread); 524421fb110SMike Gerdts set_thread(1); 525421fb110SMike Gerdts ch2 = bs_dev->create_channel(bs_dev); 526421fb110SMike Gerdts SPDK_CU_ASSERT_FATAL(ch2 != NULL); 527421fb110SMike Gerdts CU_ASSERT(blob_bdev->refs == 3); 528421fb110SMike Gerdts 529421fb110SMike Gerdts /* Destroy the bs_dev on thread 0, the channel on thread 0, then the channel on thread 1. */ 530421fb110SMike Gerdts set_thread(0); 531421fb110SMike Gerdts bs_dev->destroy(bs_dev); 532421fb110SMike Gerdts CU_ASSERT(blob_bdev->desc == NULL); 533421fb110SMike Gerdts CU_ASSERT(bdev.open_cnt == 0); 534421fb110SMike Gerdts CU_ASSERT(blob_bdev->refs == 2); 535421fb110SMike Gerdts bs_dev->destroy_channel(bs_dev, ch1); 536421fb110SMike Gerdts CU_ASSERT(blob_bdev->refs == 1); 537421fb110SMike Gerdts set_thread(1); 538421fb110SMike Gerdts bs_dev->destroy_channel(bs_dev, ch2); 539421fb110SMike Gerdts set_thread(0); 540421fb110SMike Gerdts g_bdev = NULL; 541421fb110SMike Gerdts 542421fb110SMike Gerdts /* Now bs_dev should have been freed. Builds with asan will verify. */ 543421fb110SMike Gerdts } 544421fb110SMike Gerdts 545c74b8b60SMike Gerdts int 546c74b8b60SMike Gerdts main(int argc, char **argv) 547c74b8b60SMike Gerdts { 548c74b8b60SMike Gerdts CU_pSuite suite; 549c74b8b60SMike Gerdts unsigned int num_failures; 550c74b8b60SMike Gerdts 551c74b8b60SMike Gerdts CU_initialize_registry(); 552c74b8b60SMike Gerdts 553c74b8b60SMike Gerdts suite = CU_add_suite("blob_bdev", NULL, NULL); 554c74b8b60SMike Gerdts 555c74b8b60SMike Gerdts CU_ADD_TEST(suite, create_bs_dev); 556bd5a7847SMike Gerdts CU_ADD_TEST(suite, create_bs_dev_ro); 557bd5a7847SMike Gerdts CU_ADD_TEST(suite, create_bs_dev_rw); 558e52b6c0dSMike Gerdts CU_ADD_TEST(suite, claim_bs_dev); 559ab2eff07SMike Gerdts CU_ADD_TEST(suite, claim_bs_dev_ro); 560421fb110SMike Gerdts CU_ADD_TEST(suite, deferred_destroy_refs); 561421fb110SMike Gerdts CU_ADD_TEST(suite, deferred_destroy_channels); 562421fb110SMike Gerdts CU_ADD_TEST(suite, deferred_destroy_threads); 563421fb110SMike Gerdts 564421fb110SMike Gerdts allocate_threads(2); 565421fb110SMike Gerdts set_thread(0); 566c74b8b60SMike Gerdts 567ea941caeSKonrad Sztyber num_failures = spdk_ut_run_tests(argc, argv, NULL); 568c74b8b60SMike Gerdts CU_cleanup_registry(); 569c74b8b60SMike Gerdts 570421fb110SMike Gerdts free_threads(); 571421fb110SMike Gerdts 572c74b8b60SMike Gerdts return num_failures; 573c74b8b60SMike Gerdts } 574