1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE AiRE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "spdk/stdinc.h" 35 #include "spdk_cunit.h" 36 #include "spdk/env.h" 37 #include "spdk_internal/mock.h" 38 39 #include "bdev/bdev_zone.c" 40 41 DEFINE_STUB_V(bdev_io_init, (struct spdk_bdev_io *bdev_io, 42 struct spdk_bdev *bdev, void *cb_arg, 43 spdk_bdev_io_completion_cb cb)); 44 45 DEFINE_STUB_V(bdev_io_submit, (struct spdk_bdev_io *bdev_io)); 46 47 /* Construct zone_io_operation structure */ 48 struct zone_io_operation { 49 struct spdk_bdev_desc *desc; 50 struct spdk_io_channel *ch; 51 struct iovec iov; 52 union { 53 struct { 54 uint64_t zone_id; 55 size_t num_zones; 56 enum spdk_bdev_zone_action zone_action; 57 void *buf; 58 struct spdk_bdev_zone_info *info_; 59 } zone_mgmt; 60 struct { 61 void *md_buf; 62 struct iovec *iovs; 63 int iovcnt; 64 uint64_t num_blocks; 65 uint64_t offset_blocks; 66 uint64_t start_lba; 67 } bdev; 68 }; 69 spdk_bdev_io_completion_cb cb; 70 void *cb_arg; 71 enum spdk_bdev_io_type io_type; 72 }; 73 74 /* Global variables */ 75 struct zone_io_operation *g_zone_op = NULL; 76 static struct spdk_bdev *g_bdev = NULL; 77 static struct spdk_bdev_io *g_bdev_io = NULL; 78 static struct spdk_bdev_zone_info g_zone_info = {0}; 79 static enum spdk_bdev_zone_action g_zone_action = SPDK_BDEV_ZONE_OPEN; 80 static enum spdk_bdev_zone_action g_unexpected_zone_action = SPDK_BDEV_ZONE_CLOSE; 81 static enum spdk_bdev_io_type g_io_type = SPDK_BDEV_IO_TYPE_GET_ZONE_INFO; 82 83 static uint64_t g_expected_zone_id; 84 static uint64_t g_expected_num_zones; 85 static uint64_t g_unexpected_zone_id; 86 static uint64_t g_unexpected_num_zones; 87 static uint64_t g_num_blocks; 88 static uint64_t g_unexpected_num_blocks; 89 static uint64_t g_start_lba; 90 static uint64_t g_unexpected_start_lba; 91 static uint64_t g_bdev_blocklen; 92 static uint64_t g_unexpected_bdev_blocklen; 93 static bool g_append_with_md; 94 static int g_unexpected_iovcnt; 95 static void *g_md_buf; 96 static void *g_unexpetced_md_buf; 97 static void *g_buf; 98 static void *g_unexpected_buf; 99 100 static int 101 test_setup(void) 102 { 103 /* Initiate expected and unexpected value here */ 104 g_expected_zone_id = 0x1000; 105 g_expected_num_zones = 1024; 106 g_unexpected_zone_id = 0xFFFF; 107 g_unexpected_num_zones = 0; 108 g_num_blocks = 4096 * 1024; 109 g_unexpected_num_blocks = 0; 110 g_start_lba = 4096; 111 g_unexpected_start_lba = 0; 112 g_bdev_blocklen = 4096; 113 g_unexpected_bdev_blocklen = 0; 114 g_append_with_md = false; 115 g_unexpected_iovcnt = 1000; 116 g_md_buf = (void *)0xEFDCFEDE; 117 g_unexpetced_md_buf = (void *)0xFECDEFDC; 118 g_buf = (void *)0xFEEDBEEF; 119 g_unexpected_buf = (void *)0xDEADBEEF; 120 121 return 0; 122 } 123 124 static int 125 test_cleanup(void) 126 { 127 return 0; 128 } 129 130 static void 131 start_operation(void) 132 { 133 g_zone_op = calloc(1, sizeof(struct zone_io_operation)); 134 SPDK_CU_ASSERT_FATAL(g_zone_op != NULL); 135 136 switch (g_io_type) { 137 case SPDK_BDEV_IO_TYPE_ZONE_APPEND: 138 g_zone_op->bdev.iovs = &g_zone_op->iov; 139 g_zone_op->bdev.iovs[0].iov_base = g_unexpected_buf; 140 g_zone_op->bdev.iovs[0].iov_len = g_unexpected_num_blocks * g_unexpected_bdev_blocklen; 141 g_zone_op->bdev.iovcnt = g_unexpected_iovcnt; 142 g_zone_op->bdev.md_buf = g_unexpetced_md_buf; 143 g_zone_op->bdev.num_blocks = g_unexpected_num_blocks; 144 g_zone_op->bdev.offset_blocks = g_unexpected_zone_id; 145 g_zone_op->bdev.start_lba = g_unexpected_start_lba; 146 break; 147 default: 148 g_zone_op->bdev.iovcnt = 0; 149 g_zone_op->zone_mgmt.zone_id = g_unexpected_zone_id; 150 g_zone_op->zone_mgmt.num_zones = g_unexpected_num_zones; 151 g_zone_op->zone_mgmt.zone_action = g_unexpected_zone_action; 152 g_zone_op->zone_mgmt.buf = g_unexpected_buf; 153 break; 154 } 155 } 156 157 static void 158 stop_operation(void) 159 { 160 free(g_bdev_io); 161 free(g_bdev); 162 free(g_zone_op); 163 g_bdev_io = NULL; 164 g_bdev = NULL; 165 g_zone_op = NULL; 166 } 167 168 struct spdk_bdev_io * 169 bdev_channel_get_io(struct spdk_bdev_channel *channel) 170 { 171 struct spdk_bdev_io *bdev_io; 172 173 bdev_io = calloc(1, sizeof(struct spdk_bdev_io)); 174 SPDK_CU_ASSERT_FATAL(bdev_io != NULL); 175 176 bdev_io->internal.ch = channel; 177 bdev_io->type = g_io_type; 178 179 CU_ASSERT(g_zone_op != NULL); 180 181 switch (g_io_type) { 182 case SPDK_BDEV_IO_TYPE_GET_ZONE_INFO: 183 case SPDK_BDEV_IO_TYPE_ZONE_MANAGEMENT: 184 bdev_io->u.bdev.iovcnt = 0; 185 bdev_io->u.zone_mgmt.zone_id = g_zone_op->zone_mgmt.zone_id; 186 bdev_io->u.zone_mgmt.num_zones = g_zone_op->zone_mgmt.num_zones; 187 bdev_io->u.zone_mgmt.zone_action = g_zone_op->zone_mgmt.zone_action; 188 bdev_io->u.zone_mgmt.buf = g_zone_op->zone_mgmt.buf; 189 break; 190 case SPDK_BDEV_IO_TYPE_ZONE_APPEND: 191 bdev_io->u.bdev.iovs = g_zone_op->bdev.iovs; 192 bdev_io->u.bdev.iovs[0].iov_base = g_zone_op->bdev.iovs[0].iov_base; 193 bdev_io->u.bdev.iovs[0].iov_len = g_zone_op->bdev.iovs[0].iov_len; 194 bdev_io->u.bdev.iovcnt = g_zone_op->bdev.iovcnt; 195 bdev_io->u.bdev.md_buf = g_zone_op->bdev.md_buf; 196 bdev_io->u.bdev.num_blocks = g_zone_op->bdev.num_blocks; 197 bdev_io->u.bdev.offset_blocks = g_zone_op->bdev.offset_blocks; 198 break; 199 default: 200 CU_ASSERT(0); 201 } 202 203 g_bdev_io = bdev_io; 204 205 return bdev_io; 206 } 207 208 int 209 spdk_bdev_open_ext(const char *bdev_name, bool write, spdk_bdev_event_cb_t event_cb, 210 void *event_ctx, struct spdk_bdev_desc **_desc) 211 { 212 *_desc = (void *)0x1; 213 return 0; 214 } 215 216 struct spdk_io_channel * 217 spdk_bdev_get_io_channel(struct spdk_bdev_desc *desc) 218 { 219 return (struct spdk_io_channel *)0x1; 220 } 221 222 void 223 spdk_put_io_channel(struct spdk_io_channel *ch) 224 { 225 CU_ASSERT(ch == (void *)1); 226 } 227 228 struct spdk_bdev * 229 spdk_bdev_desc_get_bdev(struct spdk_bdev_desc *desc) 230 { 231 struct spdk_bdev *bdev; 232 233 bdev = calloc(1, sizeof(struct spdk_bdev)); 234 SPDK_CU_ASSERT_FATAL(bdev != NULL); 235 236 if (g_io_type == SPDK_BDEV_IO_TYPE_ZONE_APPEND) { 237 bdev->blocklen = g_bdev_blocklen; 238 } 239 240 g_bdev = bdev; 241 242 return bdev; 243 } 244 245 static void 246 test_get_zone_size(void) 247 { 248 struct spdk_bdev bdev = {}; 249 uint64_t get_zone_size; 250 251 bdev.zone_size = 1024 * 4096; 252 253 get_zone_size = spdk_bdev_get_zone_size(&bdev); 254 CU_ASSERT(get_zone_size == 1024 * 4096); 255 } 256 257 static void 258 test_get_max_open_zones(void) 259 { 260 struct spdk_bdev bdev = {}; 261 uint32_t get_max_open_zones; 262 263 bdev.max_open_zones = 8192; 264 265 get_max_open_zones = spdk_bdev_get_max_open_zones(&bdev); 266 CU_ASSERT(get_max_open_zones == 8192); 267 } 268 269 static void 270 test_get_optimal_open_zones(void) 271 { 272 struct spdk_bdev bdev = {}; 273 uint32_t get_optimal_open_zones; 274 275 bdev.optimal_open_zones = 4096; 276 277 get_optimal_open_zones = spdk_bdev_get_optimal_open_zones(&bdev); 278 CU_ASSERT(get_optimal_open_zones == 4096); 279 } 280 281 static void 282 test_bdev_io_get_append_location(void) 283 { 284 struct spdk_bdev_io bdev_io = {}; 285 uint64_t get_offset_blocks; 286 287 bdev_io.u.bdev.offset_blocks = 1024 * 10; 288 289 get_offset_blocks = spdk_bdev_io_get_append_location(&bdev_io); 290 CU_ASSERT(get_offset_blocks == 1024 * 10); 291 } 292 293 static void 294 test_zone_get_operation(void) 295 { 296 test_get_zone_size(); 297 test_get_max_open_zones(); 298 test_get_optimal_open_zones(); 299 } 300 301 #define DECLARE_VIRTUAL_BDEV_START() \ 302 struct spdk_bdev bdev; \ 303 struct spdk_io_channel *ch; \ 304 struct spdk_bdev_desc *desc = NULL; \ 305 int rc; \ 306 memset(&bdev, 0, sizeof(bdev)); \ 307 bdev.name = "bdev_zone_ut"; \ 308 rc = spdk_bdev_open_ext(bdev.name, true, NULL, NULL, &desc); \ 309 CU_ASSERT(rc == 0); \ 310 SPDK_CU_ASSERT_FATAL(desc != NULL); \ 311 ch = spdk_bdev_get_io_channel(desc); \ 312 CU_ASSERT(ch != NULL);\ 313 314 static void 315 test_bdev_zone_get_info(void) 316 { 317 DECLARE_VIRTUAL_BDEV_START(); 318 319 g_zone_info.zone_id = g_expected_zone_id; 320 g_io_type = SPDK_BDEV_IO_TYPE_GET_ZONE_INFO; 321 322 start_operation(); 323 324 rc = spdk_bdev_get_zone_info(desc, ch, g_expected_zone_id, g_expected_num_zones, &g_zone_info, NULL, 325 NULL); 326 CU_ASSERT(rc == 0); 327 CU_ASSERT(g_bdev_io->type == SPDK_BDEV_IO_TYPE_GET_ZONE_INFO); 328 CU_ASSERT(g_bdev_io->u.zone_mgmt.zone_id == g_expected_zone_id); 329 CU_ASSERT(g_bdev_io->u.zone_mgmt.num_zones == g_expected_num_zones); 330 CU_ASSERT(g_bdev_io->u.zone_mgmt.buf == &g_zone_info); 331 332 stop_operation(); 333 } 334 335 static void 336 test_bdev_zone_management(void) 337 { 338 DECLARE_VIRTUAL_BDEV_START(); 339 340 g_zone_info.zone_id = g_expected_zone_id; 341 g_io_type = SPDK_BDEV_IO_TYPE_ZONE_MANAGEMENT; 342 343 start_operation(); 344 345 rc = spdk_bdev_zone_management(desc, ch, g_expected_zone_id, g_zone_action, NULL, 346 NULL); 347 CU_ASSERT(rc == 0); 348 CU_ASSERT(g_bdev_io->type == SPDK_BDEV_IO_TYPE_ZONE_MANAGEMENT); 349 CU_ASSERT(g_bdev_io->u.zone_mgmt.zone_id == g_expected_zone_id); 350 CU_ASSERT(g_bdev_io->u.zone_mgmt.zone_action == g_zone_action); 351 CU_ASSERT(g_bdev_io->u.zone_mgmt.num_zones == 1); 352 353 stop_operation(); 354 } 355 356 static void 357 test_bdev_zone_append(void) 358 { 359 DECLARE_VIRTUAL_BDEV_START(); 360 361 g_io_type = SPDK_BDEV_IO_TYPE_ZONE_APPEND; 362 g_append_with_md = false; 363 364 start_operation(); 365 366 rc = spdk_bdev_zone_append(desc, ch, g_buf, g_start_lba, g_num_blocks, NULL, NULL); 367 368 CU_ASSERT(rc == 0); 369 CU_ASSERT(g_bdev_io->internal.desc == desc); 370 CU_ASSERT(g_bdev_io->type == SPDK_BDEV_IO_TYPE_ZONE_APPEND); 371 CU_ASSERT(g_bdev_io->u.bdev.iovs[0].iov_base == g_buf); 372 CU_ASSERT(g_bdev_io->u.bdev.iovs[0].iov_len == g_num_blocks * g_bdev_blocklen); 373 CU_ASSERT(g_bdev_io->u.bdev.iovcnt == 1); 374 CU_ASSERT(g_bdev_io->u.bdev.md_buf == NULL); 375 CU_ASSERT(g_bdev_io->u.bdev.num_blocks == g_num_blocks); 376 CU_ASSERT(g_bdev_io->u.bdev.offset_blocks == g_expected_zone_id); 377 378 stop_operation(); 379 } 380 381 static void 382 test_bdev_zone_append_with_md(void) 383 { 384 DECLARE_VIRTUAL_BDEV_START(); 385 386 g_io_type = SPDK_BDEV_IO_TYPE_ZONE_APPEND; 387 g_append_with_md = true; 388 389 start_operation(); 390 391 rc = spdk_bdev_zone_append_with_md(desc, ch, g_buf, g_md_buf, g_start_lba, g_num_blocks, NULL, 392 NULL); 393 394 CU_ASSERT(rc == 0); 395 CU_ASSERT(g_bdev_io->internal.desc == desc); 396 CU_ASSERT(g_bdev_io->type == SPDK_BDEV_IO_TYPE_ZONE_APPEND); 397 CU_ASSERT(g_bdev_io->u.bdev.iovs[0].iov_base == g_buf); 398 CU_ASSERT(g_bdev_io->u.bdev.iovs[0].iov_len == g_num_blocks * g_bdev_blocklen); 399 CU_ASSERT(g_bdev_io->u.bdev.iovcnt == 1); 400 CU_ASSERT(g_bdev_io->u.bdev.md_buf == g_md_buf); 401 CU_ASSERT(g_bdev_io->u.bdev.num_blocks == g_num_blocks); 402 CU_ASSERT(g_bdev_io->u.bdev.offset_blocks == g_expected_zone_id); 403 404 stop_operation(); 405 } 406 407 int 408 main(int argc, char **argv) 409 { 410 CU_pSuite suite = NULL; 411 unsigned int num_failures; 412 413 CU_set_error_action(CUEA_ABORT); 414 CU_initialize_registry(); 415 416 suite = CU_add_suite("zone", test_setup, test_cleanup); 417 CU_ADD_TEST(suite, test_zone_get_operation); 418 CU_ADD_TEST(suite, test_bdev_zone_get_info); 419 CU_ADD_TEST(suite, test_bdev_zone_management); 420 CU_ADD_TEST(suite, test_bdev_zone_append); 421 CU_ADD_TEST(suite, test_bdev_zone_append_with_md); 422 CU_ADD_TEST(suite, test_bdev_io_get_append_location); 423 424 CU_basic_set_mode(CU_BRM_VERBOSE); 425 CU_basic_run_tests(); 426 num_failures = CU_get_number_of_failures(); 427 CU_cleanup_registry(); 428 return num_failures; 429 } 430