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 ARE 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 36 #include "common/lib/ut_multithread.c" 37 #include "spdk_cunit.h" 38 #include "spdk_internal/mock.h" 39 #include "spdk_internal/thread.h" 40 41 #include "nvmf/subsystem.c" 42 43 SPDK_LOG_REGISTER_COMPONENT("nvmf", SPDK_LOG_NVMF) 44 45 DEFINE_STUB(spdk_bdev_module_claim_bdev, 46 int, 47 (struct spdk_bdev *bdev, struct spdk_bdev_desc *desc, 48 struct spdk_bdev_module *module), 0); 49 50 DEFINE_STUB_V(spdk_bdev_module_release_bdev, 51 (struct spdk_bdev *bdev)); 52 53 DEFINE_STUB(spdk_bdev_get_block_size, uint32_t, 54 (const struct spdk_bdev *bdev), 512); 55 56 DEFINE_STUB(spdk_nvmf_transport_stop_listen, 57 int, 58 (struct spdk_nvmf_transport *transport, 59 const struct spdk_nvme_transport_id *trid), 0); 60 61 static void 62 subsystem_ns_remove_cb(struct spdk_nvmf_subsystem *subsystem, void *cb_arg, int status) 63 { 64 } 65 66 uint32_t 67 spdk_env_get_current_core(void) 68 { 69 return 0; 70 } 71 72 struct spdk_event * 73 spdk_event_allocate(uint32_t core, spdk_event_fn fn, void *arg1, void *arg2) 74 { 75 return NULL; 76 } 77 78 void 79 spdk_event_call(struct spdk_event *event) 80 { 81 82 } 83 84 int 85 spdk_nvmf_transport_listen(struct spdk_nvmf_transport *transport, 86 const struct spdk_nvme_transport_id *trid) 87 { 88 return 0; 89 } 90 91 void 92 spdk_nvmf_transport_listener_discover(struct spdk_nvmf_transport *transport, 93 struct spdk_nvme_transport_id *trid, 94 struct spdk_nvmf_discovery_log_page_entry *entry) 95 { 96 entry->trtype = 42; 97 } 98 99 static struct spdk_nvmf_transport g_transport = {}; 100 101 struct spdk_nvmf_transport * 102 spdk_nvmf_transport_create(enum spdk_nvme_transport_type type, 103 struct spdk_nvmf_transport_opts *tprt_opts) 104 { 105 if (type == SPDK_NVME_TRANSPORT_RDMA) { 106 return &g_transport; 107 } 108 109 return NULL; 110 } 111 112 struct spdk_nvmf_subsystem * 113 spdk_nvmf_tgt_find_subsystem(struct spdk_nvmf_tgt *tgt, const char *subnqn) 114 { 115 return NULL; 116 } 117 118 struct spdk_nvmf_transport * 119 spdk_nvmf_tgt_get_transport(struct spdk_nvmf_tgt *tgt, enum spdk_nvme_transport_type trtype) 120 { 121 if (trtype == SPDK_NVME_TRANSPORT_RDMA) { 122 return &g_transport; 123 } 124 125 return NULL; 126 } 127 128 int 129 spdk_nvmf_poll_group_update_subsystem(struct spdk_nvmf_poll_group *group, 130 struct spdk_nvmf_subsystem *subsystem) 131 { 132 return 0; 133 } 134 135 int 136 spdk_nvmf_poll_group_add_subsystem(struct spdk_nvmf_poll_group *group, 137 struct spdk_nvmf_subsystem *subsystem, 138 spdk_nvmf_poll_group_mod_done cb_fn, void *cb_arg) 139 { 140 return 0; 141 } 142 143 void 144 spdk_nvmf_poll_group_remove_subsystem(struct spdk_nvmf_poll_group *group, 145 struct spdk_nvmf_subsystem *subsystem, 146 spdk_nvmf_poll_group_mod_done cb_fn, void *cb_arg) 147 { 148 } 149 150 void 151 spdk_nvmf_poll_group_pause_subsystem(struct spdk_nvmf_poll_group *group, 152 struct spdk_nvmf_subsystem *subsystem, 153 spdk_nvmf_poll_group_mod_done cb_fn, void *cb_arg) 154 { 155 } 156 157 void 158 spdk_nvmf_poll_group_resume_subsystem(struct spdk_nvmf_poll_group *group, 159 struct spdk_nvmf_subsystem *subsystem, 160 spdk_nvmf_poll_group_mod_done cb_fn, void *cb_arg) 161 { 162 } 163 164 int 165 spdk_nvme_transport_id_parse_trtype(enum spdk_nvme_transport_type *trtype, const char *str) 166 { 167 if (trtype == NULL || str == NULL) { 168 return -EINVAL; 169 } 170 171 if (strcasecmp(str, "PCIe") == 0) { 172 *trtype = SPDK_NVME_TRANSPORT_PCIE; 173 } else if (strcasecmp(str, "RDMA") == 0) { 174 *trtype = SPDK_NVME_TRANSPORT_RDMA; 175 } else { 176 return -ENOENT; 177 } 178 return 0; 179 } 180 181 int 182 spdk_nvme_transport_id_compare(const struct spdk_nvme_transport_id *trid1, 183 const struct spdk_nvme_transport_id *trid2) 184 { 185 return 0; 186 } 187 188 int32_t 189 spdk_nvme_ctrlr_process_admin_completions(struct spdk_nvme_ctrlr *ctrlr) 190 { 191 return -1; 192 } 193 194 int32_t 195 spdk_nvme_qpair_process_completions(struct spdk_nvme_qpair *qpair, uint32_t max_completions) 196 { 197 return -1; 198 } 199 200 int 201 spdk_nvme_detach(struct spdk_nvme_ctrlr *ctrlr) 202 { 203 return -1; 204 } 205 206 void 207 spdk_nvmf_ctrlr_destruct(struct spdk_nvmf_ctrlr *ctrlr) 208 { 209 } 210 211 void 212 spdk_nvmf_ctrlr_ns_changed(struct spdk_nvmf_ctrlr *ctrlr, uint32_t nsid) 213 { 214 } 215 216 int 217 spdk_bdev_open(struct spdk_bdev *bdev, bool write, spdk_bdev_remove_cb_t remove_cb, 218 void *remove_ctx, struct spdk_bdev_desc **desc) 219 { 220 return 0; 221 } 222 223 void 224 spdk_bdev_close(struct spdk_bdev_desc *desc) 225 { 226 } 227 228 const char * 229 spdk_bdev_get_name(const struct spdk_bdev *bdev) 230 { 231 return "test"; 232 } 233 234 const struct spdk_uuid * 235 spdk_bdev_get_uuid(const struct spdk_bdev *bdev) 236 { 237 return &bdev->uuid; 238 } 239 240 static void 241 test_spdk_nvmf_subsystem_add_ns(void) 242 { 243 struct spdk_nvmf_tgt tgt = {}; 244 struct spdk_nvmf_subsystem subsystem = { 245 .max_nsid = 0, 246 .ns = NULL, 247 .tgt = &tgt 248 }; 249 struct spdk_bdev bdev1 = {}, bdev2 = {}; 250 struct spdk_nvmf_ns_opts ns_opts; 251 uint32_t nsid; 252 253 tgt.max_subsystems = 1024; 254 tgt.subsystems = calloc(tgt.max_subsystems, sizeof(struct spdk_nvmf_subsystem *)); 255 SPDK_CU_ASSERT_FATAL(tgt.subsystems != NULL); 256 257 /* Allow NSID to be assigned automatically */ 258 spdk_nvmf_ns_opts_get_defaults(&ns_opts, sizeof(ns_opts)); 259 nsid = spdk_nvmf_subsystem_add_ns(&subsystem, &bdev1, &ns_opts, sizeof(ns_opts)); 260 /* NSID 1 is the first unused ID */ 261 CU_ASSERT(nsid == 1); 262 CU_ASSERT(subsystem.max_nsid == 1); 263 SPDK_CU_ASSERT_FATAL(subsystem.ns != NULL); 264 SPDK_CU_ASSERT_FATAL(subsystem.ns[nsid - 1] != NULL); 265 CU_ASSERT(subsystem.ns[nsid - 1]->bdev == &bdev1); 266 267 /* Request a specific NSID */ 268 spdk_nvmf_ns_opts_get_defaults(&ns_opts, sizeof(ns_opts)); 269 ns_opts.nsid = 5; 270 nsid = spdk_nvmf_subsystem_add_ns(&subsystem, &bdev2, &ns_opts, sizeof(ns_opts)); 271 CU_ASSERT(nsid == 5); 272 CU_ASSERT(subsystem.max_nsid == 5); 273 SPDK_CU_ASSERT_FATAL(subsystem.ns[nsid - 1] != NULL); 274 CU_ASSERT(subsystem.ns[nsid - 1]->bdev == &bdev2); 275 276 /* Request an NSID that is already in use */ 277 spdk_nvmf_ns_opts_get_defaults(&ns_opts, sizeof(ns_opts)); 278 ns_opts.nsid = 5; 279 nsid = spdk_nvmf_subsystem_add_ns(&subsystem, &bdev2, &ns_opts, sizeof(ns_opts)); 280 CU_ASSERT(nsid == 0); 281 CU_ASSERT(subsystem.max_nsid == 5); 282 283 /* Request 0xFFFFFFFF (invalid NSID, reserved for broadcast) */ 284 spdk_nvmf_ns_opts_get_defaults(&ns_opts, sizeof(ns_opts)); 285 ns_opts.nsid = 0xFFFFFFFF; 286 nsid = spdk_nvmf_subsystem_add_ns(&subsystem, &bdev2, &ns_opts, sizeof(ns_opts)); 287 CU_ASSERT(nsid == 0); 288 CU_ASSERT(subsystem.max_nsid == 5); 289 290 spdk_nvmf_subsystem_remove_ns(&subsystem, 1, subsystem_ns_remove_cb, NULL); 291 poll_threads(); 292 spdk_nvmf_subsystem_remove_ns(&subsystem, 5, subsystem_ns_remove_cb, NULL); 293 poll_threads(); 294 295 free(subsystem.ns); 296 free(tgt.subsystems); 297 } 298 299 static void 300 nvmf_test_create_subsystem(void) 301 { 302 struct spdk_nvmf_tgt tgt = {}; 303 char nqn[256]; 304 struct spdk_nvmf_subsystem *subsystem; 305 306 tgt.max_subsystems = 1024; 307 tgt.subsystems = calloc(tgt.max_subsystems, sizeof(struct spdk_nvmf_subsystem *)); 308 SPDK_CU_ASSERT_FATAL(tgt.subsystems != NULL); 309 310 snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:subsystem1"); 311 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 312 SPDK_CU_ASSERT_FATAL(subsystem != NULL); 313 CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn); 314 spdk_nvmf_subsystem_destroy(subsystem); 315 316 /* valid name with complex reverse domain */ 317 snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk-full--rev-domain.name:subsystem1"); 318 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 319 SPDK_CU_ASSERT_FATAL(subsystem != NULL); 320 CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn); 321 spdk_nvmf_subsystem_destroy(subsystem); 322 323 /* Valid name discovery controller */ 324 snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:subsystem1"); 325 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 326 SPDK_CU_ASSERT_FATAL(subsystem != NULL); 327 CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn); 328 spdk_nvmf_subsystem_destroy(subsystem); 329 330 331 /* Invalid name, no user supplied string */ 332 snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:"); 333 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 334 SPDK_CU_ASSERT_FATAL(subsystem == NULL); 335 336 /* Valid name, only contains top-level domain name */ 337 snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:subsystem1"); 338 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 339 SPDK_CU_ASSERT_FATAL(subsystem != NULL); 340 CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn); 341 spdk_nvmf_subsystem_destroy(subsystem); 342 343 /* Invalid name, domain label > 63 characters */ 344 snprintf(nqn, sizeof(nqn), 345 "nqn.2016-06.io.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz:sub"); 346 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 347 SPDK_CU_ASSERT_FATAL(subsystem == NULL); 348 349 /* Invalid name, domain label starts with digit */ 350 snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.3spdk:sub"); 351 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 352 SPDK_CU_ASSERT_FATAL(subsystem == NULL); 353 354 /* Invalid name, domain label starts with - */ 355 snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.-spdk:subsystem1"); 356 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 357 SPDK_CU_ASSERT_FATAL(subsystem == NULL); 358 359 /* Invalid name, domain label ends with - */ 360 snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk-:subsystem1"); 361 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 362 SPDK_CU_ASSERT_FATAL(subsystem == NULL); 363 364 /* Invalid name, domain label with multiple consecutive periods */ 365 snprintf(nqn, sizeof(nqn), "nqn.2016-06.io..spdk:subsystem1"); 366 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 367 SPDK_CU_ASSERT_FATAL(subsystem == NULL); 368 369 /* Longest valid name */ 370 snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:"); 371 memset(nqn + strlen(nqn), 'a', 223 - strlen(nqn)); 372 nqn[223] = '\0'; 373 CU_ASSERT(strlen(nqn) == 223); 374 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 375 SPDK_CU_ASSERT_FATAL(subsystem != NULL); 376 CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn); 377 spdk_nvmf_subsystem_destroy(subsystem); 378 379 /* Invalid name, too long */ 380 snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:"); 381 memset(nqn + strlen(nqn), 'a', 224 - strlen(nqn)); 382 nqn[224] = '\0'; 383 CU_ASSERT(strlen(nqn) == 224); 384 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 385 CU_ASSERT(subsystem == NULL); 386 387 /* Valid name using uuid format */ 388 snprintf(nqn, sizeof(nqn), "nqn.2014-08.org.nvmexpress:uuid:11111111-aaaa-bbdd-FFEE-123456789abc"); 389 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 390 SPDK_CU_ASSERT_FATAL(subsystem != NULL); 391 CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn); 392 spdk_nvmf_subsystem_destroy(subsystem); 393 394 /* Invalid name user string contains an invalid utf-8 character */ 395 snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:\xFFsubsystem1"); 396 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 397 SPDK_CU_ASSERT_FATAL(subsystem == NULL); 398 399 /* Valid name with non-ascii but valid utf-8 characters */ 400 snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:\xe1\x8a\x88subsystem1\xca\x80"); 401 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 402 SPDK_CU_ASSERT_FATAL(subsystem != NULL); 403 CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn); 404 spdk_nvmf_subsystem_destroy(subsystem); 405 406 /* Invalid uuid (too long) */ 407 snprintf(nqn, sizeof(nqn), 408 "nqn.2014-08.org.nvmexpress:uuid:11111111-aaaa-bbdd-FFEE-123456789abcdef"); 409 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 410 SPDK_CU_ASSERT_FATAL(subsystem == NULL); 411 412 /* Invalid uuid (dashes placed incorrectly) */ 413 snprintf(nqn, sizeof(nqn), "nqn.2014-08.org.nvmexpress:uuid:111111-11aaaa-bbdd-FFEE-123456789abc"); 414 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 415 SPDK_CU_ASSERT_FATAL(subsystem == NULL); 416 417 /* Invalid uuid (invalid characters in uuid) */ 418 snprintf(nqn, sizeof(nqn), "nqn.2014-08.org.nvmexpress:uuid:111hg111-aaaa-bbdd-FFEE-123456789abc"); 419 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 420 SPDK_CU_ASSERT_FATAL(subsystem == NULL); 421 422 free(tgt.subsystems); 423 } 424 425 static void 426 test_spdk_nvmf_subsystem_set_sn(void) 427 { 428 struct spdk_nvmf_subsystem subsystem = {}; 429 430 /* Basic valid serial number */ 431 CU_ASSERT(spdk_nvmf_subsystem_set_sn(&subsystem, "abcd xyz") == 0); 432 CU_ASSERT(strcmp(subsystem.sn, "abcd xyz") == 0); 433 434 /* Exactly 20 characters (valid) */ 435 CU_ASSERT(spdk_nvmf_subsystem_set_sn(&subsystem, "12345678901234567890") == 0); 436 CU_ASSERT(strcmp(subsystem.sn, "12345678901234567890") == 0); 437 438 /* 21 characters (too long, invalid) */ 439 CU_ASSERT(spdk_nvmf_subsystem_set_sn(&subsystem, "123456789012345678901") < 0); 440 441 /* Non-ASCII characters (invalid) */ 442 CU_ASSERT(spdk_nvmf_subsystem_set_sn(&subsystem, "abcd\txyz") < 0); 443 } 444 445 /* 446 * Reservation Unit Test Configuration 447 * -------- -------- -------- 448 * | Host A | | Host B | | Host C | 449 * -------- -------- -------- 450 * / \ | | 451 * -------- -------- ------- ------- 452 * |Ctrlr1_A| |Ctrlr2_A| |Ctrlr_B| |Ctrlr_C| 453 * -------- -------- ------- ------- 454 * \ \ / / 455 * \ \ / / 456 * \ \ / / 457 * -------------------------------------- 458 * | NAMESPACE 1 | 459 * -------------------------------------- 460 */ 461 462 static struct spdk_nvmf_ctrlr g_ctrlr1_A, g_ctrlr2_A, g_ctrlr_B, g_ctrlr_C; 463 static struct spdk_nvmf_ns g_ns; 464 struct spdk_nvmf_subsystem_pg_ns_info g_ns_info; 465 466 static void 467 ut_reservation_init(void) 468 { 469 memset(&g_ns, 0, sizeof(g_ns)); 470 TAILQ_INIT(&g_ns.registrants); 471 472 /* Host A has two controllers */ 473 spdk_uuid_generate(&g_ctrlr1_A.hostid); 474 spdk_uuid_copy(&g_ctrlr2_A.hostid, &g_ctrlr1_A.hostid); 475 476 /* Host B has 1 controller */ 477 spdk_uuid_generate(&g_ctrlr_B.hostid); 478 479 /* Host C has 1 controller */ 480 spdk_uuid_generate(&g_ctrlr_C.hostid); 481 } 482 483 static void 484 ut_reservation_deinit(void) 485 { 486 struct spdk_nvmf_registrant *reg, *tmp; 487 488 TAILQ_FOREACH_SAFE(reg, &g_ns.registrants, link, tmp) { 489 TAILQ_REMOVE(&g_ns.registrants, reg, link); 490 free(reg); 491 } 492 } 493 494 static struct spdk_nvmf_request * 495 ut_reservation_build_req(uint32_t length) 496 { 497 struct spdk_nvmf_request *req; 498 499 req = calloc(1, sizeof(*req)); 500 assert(req != NULL); 501 502 req->data = calloc(1, length); 503 assert(req->data != NULL); 504 req->length = length; 505 506 req->cmd = (union nvmf_h2c_msg *)calloc(1, sizeof(union nvmf_h2c_msg)); 507 assert(req->cmd != NULL); 508 509 req->rsp = (union nvmf_c2h_msg *)calloc(1, sizeof(union nvmf_c2h_msg)); 510 assert(req->rsp != NULL); 511 512 return req; 513 } 514 515 static void 516 ut_reservation_free_req(struct spdk_nvmf_request *req) 517 { 518 free(req->cmd); 519 free(req->rsp); 520 free(req->data); 521 free(req); 522 } 523 524 static void 525 ut_reservation_build_register_request(struct spdk_nvmf_request *req, 526 uint8_t rrega, uint8_t iekey, 527 uint8_t cptpl, uint64_t crkey, 528 uint64_t nrkey) 529 { 530 uint32_t cdw10; 531 struct spdk_nvme_reservation_register_data key; 532 struct spdk_nvme_cmd *cmd = &req->cmd->nvme_cmd; 533 534 cdw10 = ((cptpl << 30) | (iekey << 3) | rrega); 535 key.crkey = crkey; 536 key.nrkey = nrkey; 537 cmd->cdw10 = cdw10; 538 memcpy(req->data, &key, sizeof(key)); 539 } 540 541 static void 542 ut_reservation_build_acquire_request(struct spdk_nvmf_request *req, 543 uint8_t racqa, uint8_t iekey, 544 uint8_t rtype, uint64_t crkey, 545 uint64_t prkey) 546 { 547 uint32_t cdw10; 548 struct spdk_nvme_reservation_acquire_data key; 549 struct spdk_nvme_cmd *cmd = &req->cmd->nvme_cmd; 550 551 cdw10 = ((rtype << 8) | (iekey << 3) | racqa); 552 key.crkey = crkey; 553 key.prkey = prkey; 554 cmd->cdw10 = cdw10; 555 memcpy(req->data, &key, sizeof(key)); 556 } 557 558 static void 559 ut_reservation_build_release_request(struct spdk_nvmf_request *req, 560 uint8_t rrela, uint8_t iekey, 561 uint8_t rtype, uint64_t crkey) 562 { 563 uint32_t cdw10; 564 struct spdk_nvme_cmd *cmd = &req->cmd->nvme_cmd; 565 566 cdw10 = ((rtype << 8) | (iekey << 3) | rrela); 567 cmd->cdw10 = cdw10; 568 memcpy(req->data, &crkey, sizeof(crkey)); 569 } 570 571 /* 572 * Construct four registrants for other test cases. 573 * 574 * g_ctrlr1_A register with key 0xa1. 575 * g_ctrlr2_A register with key 0xa1. 576 * g_ctrlr_B register with key 0xb1. 577 * g_ctrlr_C register with key 0xc1. 578 * */ 579 static void 580 ut_reservation_build_registrants(void) 581 { 582 struct spdk_nvmf_request *req; 583 struct spdk_nvme_cpl *rsp; 584 struct spdk_nvmf_registrant *reg; 585 uint32_t gen; 586 587 req = ut_reservation_build_req(16); 588 rsp = &req->rsp->nvme_cpl; 589 SPDK_CU_ASSERT_FATAL(req != NULL); 590 gen = g_ns.gen; 591 592 /* TEST CASE: g_ctrlr1_A register with a new key */ 593 ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_REGISTER_KEY, 594 0, 0, 0, 0xa1); 595 nvmf_ns_reservation_register(&g_ns, &g_ctrlr1_A, req); 596 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS); 597 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr1_A.hostid); 598 SPDK_CU_ASSERT_FATAL(reg->rkey == 0xa1); 599 SPDK_CU_ASSERT_FATAL(g_ns.gen == gen + 1); 600 601 /* TEST CASE: g_ctrlr2_A register with a new key, because it has same 602 * Host Identifier with g_ctrlr1_A, so the register key should same. 603 */ 604 ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_REGISTER_KEY, 605 0, 0, 0, 0xa2); 606 nvmf_ns_reservation_register(&g_ns, &g_ctrlr2_A, req); 607 /* Reservation conflict for other key than 0xa1 */ 608 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_RESERVATION_CONFLICT); 609 610 /* g_ctrlr_B register with a new key */ 611 ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_REGISTER_KEY, 612 0, 0, 0, 0xb1); 613 nvmf_ns_reservation_register(&g_ns, &g_ctrlr_B, req); 614 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS); 615 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_B.hostid); 616 SPDK_CU_ASSERT_FATAL(reg->rkey == 0xb1); 617 SPDK_CU_ASSERT_FATAL(g_ns.gen == gen + 2); 618 619 /* g_ctrlr_C register with a new key */ 620 ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_REGISTER_KEY, 621 0, 0, 0, 0xc1); 622 nvmf_ns_reservation_register(&g_ns, &g_ctrlr_C, req); 623 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS); 624 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_C.hostid); 625 SPDK_CU_ASSERT_FATAL(reg->rkey == 0xc1); 626 SPDK_CU_ASSERT_FATAL(g_ns.gen == gen + 3); 627 628 ut_reservation_free_req(req); 629 } 630 631 static void 632 test_reservation_register(void) 633 { 634 struct spdk_nvmf_request *req; 635 struct spdk_nvme_cpl *rsp; 636 struct spdk_nvmf_registrant *reg; 637 uint32_t gen; 638 639 ut_reservation_init(); 640 641 req = ut_reservation_build_req(16); 642 rsp = &req->rsp->nvme_cpl; 643 SPDK_CU_ASSERT_FATAL(req != NULL); 644 645 ut_reservation_build_registrants(); 646 647 /* TEST CASE: Replace g_ctrlr1_A with a new key */ 648 ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_REPLACE_KEY, 649 0, 0, 0xa1, 0xa11); 650 nvmf_ns_reservation_register(&g_ns, &g_ctrlr1_A, req); 651 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS); 652 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr1_A.hostid); 653 SPDK_CU_ASSERT_FATAL(reg->rkey == 0xa11); 654 655 /* TEST CASE: Host A with g_ctrlr1_A get reservation with 656 * type SPDK_NVME_RESERVE_WRITE_EXCLUSIVE 657 */ 658 ut_reservation_build_acquire_request(req, SPDK_NVME_RESERVE_ACQUIRE, 0, 659 SPDK_NVME_RESERVE_WRITE_EXCLUSIVE, 0xa11, 0x0); 660 gen = g_ns.gen; 661 nvmf_ns_reservation_acquire(&g_ns, &g_ctrlr1_A, req); 662 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS); 663 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr1_A.hostid); 664 SPDK_CU_ASSERT_FATAL(g_ns.rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE); 665 SPDK_CU_ASSERT_FATAL(g_ns.crkey == 0xa11); 666 SPDK_CU_ASSERT_FATAL(g_ns.holder == reg); 667 SPDK_CU_ASSERT_FATAL(g_ns.gen == gen); 668 669 /* TEST CASE: g_ctrlr_C unregister with IEKEY enabled */ 670 ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_UNREGISTER_KEY, 671 1, 0, 0, 0); 672 nvmf_ns_reservation_register(&g_ns, &g_ctrlr_C, req); 673 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS); 674 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_C.hostid); 675 SPDK_CU_ASSERT_FATAL(reg == NULL); 676 677 /* TEST CASE: g_ctrlr_B unregister with correct key */ 678 ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_UNREGISTER_KEY, 679 0, 0, 0xb1, 0); 680 nvmf_ns_reservation_register(&g_ns, &g_ctrlr_B, req); 681 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS); 682 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_B.hostid); 683 SPDK_CU_ASSERT_FATAL(reg == NULL); 684 685 /* TEST CASE: g_ctrlr1_A unregister with correct key, 686 * reservation should be removed as well. 687 */ 688 ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_UNREGISTER_KEY, 689 0, 0, 0xa11, 0); 690 nvmf_ns_reservation_register(&g_ns, &g_ctrlr1_A, req); 691 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS); 692 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr1_A.hostid); 693 SPDK_CU_ASSERT_FATAL(reg == NULL); 694 SPDK_CU_ASSERT_FATAL(g_ns.rtype == 0); 695 SPDK_CU_ASSERT_FATAL(g_ns.crkey == 0); 696 SPDK_CU_ASSERT_FATAL(g_ns.holder == NULL); 697 698 ut_reservation_free_req(req); 699 ut_reservation_deinit(); 700 } 701 702 static void 703 test_reservation_acquire_preempt_1(void) 704 { 705 struct spdk_nvmf_request *req; 706 struct spdk_nvme_cpl *rsp; 707 struct spdk_nvmf_registrant *reg; 708 uint32_t gen; 709 710 ut_reservation_init(); 711 712 req = ut_reservation_build_req(16); 713 rsp = &req->rsp->nvme_cpl; 714 SPDK_CU_ASSERT_FATAL(req != NULL); 715 716 ut_reservation_build_registrants(); 717 718 gen = g_ns.gen; 719 /* ACQUIRE: Host A with g_ctrlr1_A acquire reservation with 720 * type SPDK_NVME_RESERVE_WRITE_EXCLUSIVE. 721 */ 722 ut_reservation_build_acquire_request(req, SPDK_NVME_RESERVE_ACQUIRE, 0, 723 SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY, 0xa1, 0x0); 724 nvmf_ns_reservation_acquire(&g_ns, &g_ctrlr1_A, req); 725 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS); 726 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr1_A.hostid); 727 SPDK_CU_ASSERT_FATAL(g_ns.rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY); 728 SPDK_CU_ASSERT_FATAL(g_ns.crkey == 0xa1); 729 SPDK_CU_ASSERT_FATAL(g_ns.holder == reg); 730 SPDK_CU_ASSERT_FATAL(g_ns.gen == gen); 731 732 /* TEST CASE: g_ctrlr1_A holds the reservation, g_ctrlr_B preempt g_ctrl1_A, 733 * g_ctrl1_A registrant is unregistred. 734 */ 735 gen = g_ns.gen; 736 ut_reservation_build_acquire_request(req, SPDK_NVME_RESERVE_PREEMPT, 0, 737 SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS, 0xb1, 0xa1); 738 nvmf_ns_reservation_acquire(&g_ns, &g_ctrlr_B, req); 739 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS); 740 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr1_A.hostid); 741 SPDK_CU_ASSERT_FATAL(reg == NULL); 742 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_B.hostid); 743 SPDK_CU_ASSERT_FATAL(reg != NULL); 744 SPDK_CU_ASSERT_FATAL(g_ns.holder == reg); 745 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_C.hostid); 746 SPDK_CU_ASSERT_FATAL(reg != NULL); 747 SPDK_CU_ASSERT_FATAL(g_ns.rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS); 748 SPDK_CU_ASSERT_FATAL(g_ns.gen > gen); 749 750 /* TEST CASE: g_ctrlr_B holds the reservation, g_ctrlr_C preempt g_ctrlr_B 751 * with valid key and PRKEY set to 0, all registrants other the host that issued 752 * the command are unregistered. 753 */ 754 gen = g_ns.gen; 755 ut_reservation_build_acquire_request(req, SPDK_NVME_RESERVE_PREEMPT, 0, 756 SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS, 0xc1, 0x0); 757 nvmf_ns_reservation_acquire(&g_ns, &g_ctrlr_C, req); 758 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS); 759 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr2_A.hostid); 760 SPDK_CU_ASSERT_FATAL(reg == NULL); 761 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_B.hostid); 762 SPDK_CU_ASSERT_FATAL(reg == NULL); 763 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_C.hostid); 764 SPDK_CU_ASSERT_FATAL(reg != NULL); 765 SPDK_CU_ASSERT_FATAL(g_ns.holder == reg); 766 SPDK_CU_ASSERT_FATAL(g_ns.rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS); 767 SPDK_CU_ASSERT_FATAL(g_ns.gen > gen); 768 769 ut_reservation_free_req(req); 770 ut_reservation_deinit(); 771 } 772 773 static void 774 test_reservation_release(void) 775 { 776 struct spdk_nvmf_request *req; 777 struct spdk_nvme_cpl *rsp; 778 struct spdk_nvmf_registrant *reg; 779 780 ut_reservation_init(); 781 782 req = ut_reservation_build_req(16); 783 rsp = &req->rsp->nvme_cpl; 784 SPDK_CU_ASSERT_FATAL(req != NULL); 785 786 ut_reservation_build_registrants(); 787 788 /* ACQUIRE: Host A with g_ctrlr1_A get reservation with 789 * type SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS 790 */ 791 ut_reservation_build_acquire_request(req, SPDK_NVME_RESERVE_ACQUIRE, 0, 792 SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS, 0xa1, 0x0); 793 nvmf_ns_reservation_acquire(&g_ns, &g_ctrlr1_A, req); 794 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS); 795 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr1_A.hostid); 796 SPDK_CU_ASSERT_FATAL(g_ns.rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS); 797 SPDK_CU_ASSERT_FATAL(g_ns.holder == reg); 798 799 /* Test Case: Host B release the reservation */ 800 ut_reservation_build_release_request(req, SPDK_NVME_RESERVE_RELEASE, 0, 801 SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS, 0xb1); 802 nvmf_ns_reservation_release(&g_ns, &g_ctrlr_B, req); 803 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS); 804 SPDK_CU_ASSERT_FATAL(g_ns.rtype == 0); 805 SPDK_CU_ASSERT_FATAL(g_ns.crkey == 0); 806 SPDK_CU_ASSERT_FATAL(g_ns.holder == NULL); 807 808 /* Test Case: Host C clear the registrants */ 809 ut_reservation_build_release_request(req, SPDK_NVME_RESERVE_CLEAR, 0, 810 0, 0xc1); 811 nvmf_ns_reservation_release(&g_ns, &g_ctrlr_C, req); 812 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS); 813 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr1_A.hostid); 814 SPDK_CU_ASSERT_FATAL(reg == NULL); 815 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr2_A.hostid); 816 SPDK_CU_ASSERT_FATAL(reg == NULL); 817 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_B.hostid); 818 SPDK_CU_ASSERT_FATAL(reg == NULL); 819 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_C.hostid); 820 SPDK_CU_ASSERT_FATAL(reg == NULL); 821 822 ut_reservation_free_req(req); 823 ut_reservation_deinit(); 824 } 825 826 int main(int argc, char **argv) 827 { 828 CU_pSuite suite = NULL; 829 unsigned int num_failures; 830 831 if (CU_initialize_registry() != CUE_SUCCESS) { 832 return CU_get_error(); 833 } 834 835 suite = CU_add_suite("nvmf", NULL, NULL); 836 if (suite == NULL) { 837 CU_cleanup_registry(); 838 return CU_get_error(); 839 } 840 841 if ( 842 CU_add_test(suite, "create_subsystem", nvmf_test_create_subsystem) == NULL || 843 CU_add_test(suite, "nvmf_subsystem_add_ns", test_spdk_nvmf_subsystem_add_ns) == NULL || 844 CU_add_test(suite, "nvmf_subsystem_set_sn", test_spdk_nvmf_subsystem_set_sn) == NULL || 845 CU_add_test(suite, "reservation_register", test_reservation_register) == NULL || 846 CU_add_test(suite, "reservation_acquire_preempt_1", test_reservation_acquire_preempt_1) == NULL || 847 CU_add_test(suite, "reservation_release", test_reservation_release) == NULL 848 ) { 849 CU_cleanup_registry(); 850 return CU_get_error(); 851 } 852 853 allocate_threads(1); 854 set_thread(0); 855 856 CU_basic_set_mode(CU_BRM_VERBOSE); 857 CU_basic_run_tests(); 858 num_failures = CU_get_number_of_failures(); 859 CU_cleanup_registry(); 860 861 free_threads(); 862 863 return num_failures; 864 } 865