]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/test/unit/lib/nvmf/subsystem.c/subsystem_ut.c
import 15.2.0 Octopus source
[ceph.git] / ceph / src / spdk / test / unit / lib / nvmf / subsystem.c / subsystem_ut.c
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), NULL);
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), NULL);
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), NULL);
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), NULL);
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 static struct spdk_nvmf_subsystem g_subsystem;
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 void
467 spdk_nvmf_ctrlr_async_event_reservation_notification(struct spdk_nvmf_ctrlr *ctrlr)
468 {
469 }
470
471 static void
472 ut_reservation_init(void)
473 {
474
475 TAILQ_INIT(&g_subsystem.ctrlrs);
476
477 memset(&g_ns, 0, sizeof(g_ns));
478 TAILQ_INIT(&g_ns.registrants);
479 g_ns.subsystem = &g_subsystem;
480
481 /* Host A has two controllers */
482 spdk_uuid_generate(&g_ctrlr1_A.hostid);
483 TAILQ_INIT(&g_ctrlr1_A.log_head);
484 g_ctrlr1_A.subsys = &g_subsystem;
485 g_ctrlr1_A.num_avail_log_pages = 0;
486 TAILQ_INSERT_TAIL(&g_subsystem.ctrlrs, &g_ctrlr1_A, link);
487 spdk_uuid_copy(&g_ctrlr2_A.hostid, &g_ctrlr1_A.hostid);
488 TAILQ_INIT(&g_ctrlr2_A.log_head);
489 g_ctrlr2_A.subsys = &g_subsystem;
490 g_ctrlr2_A.num_avail_log_pages = 0;
491 TAILQ_INSERT_TAIL(&g_subsystem.ctrlrs, &g_ctrlr2_A, link);
492
493 /* Host B has 1 controller */
494 spdk_uuid_generate(&g_ctrlr_B.hostid);
495 TAILQ_INIT(&g_ctrlr_B.log_head);
496 g_ctrlr_B.subsys = &g_subsystem;
497 g_ctrlr_B.num_avail_log_pages = 0;
498 TAILQ_INSERT_TAIL(&g_subsystem.ctrlrs, &g_ctrlr_B, link);
499
500 /* Host C has 1 controller */
501 spdk_uuid_generate(&g_ctrlr_C.hostid);
502 TAILQ_INIT(&g_ctrlr_C.log_head);
503 g_ctrlr_C.subsys = &g_subsystem;
504 g_ctrlr_C.num_avail_log_pages = 0;
505 TAILQ_INSERT_TAIL(&g_subsystem.ctrlrs, &g_ctrlr_C, link);
506 }
507
508 static void
509 ut_reservation_deinit(void)
510 {
511 struct spdk_nvmf_registrant *reg, *tmp;
512 struct spdk_nvmf_reservation_log *log, *log_tmp;
513 struct spdk_nvmf_ctrlr *ctrlr, *ctrlr_tmp;
514
515 TAILQ_FOREACH_SAFE(reg, &g_ns.registrants, link, tmp) {
516 TAILQ_REMOVE(&g_ns.registrants, reg, link);
517 free(reg);
518 }
519 TAILQ_FOREACH_SAFE(log, &g_ctrlr1_A.log_head, link, log_tmp) {
520 TAILQ_REMOVE(&g_ctrlr1_A.log_head, log, link);
521 free(log);
522 }
523 g_ctrlr1_A.num_avail_log_pages = 0;
524 TAILQ_FOREACH_SAFE(log, &g_ctrlr2_A.log_head, link, log_tmp) {
525 TAILQ_REMOVE(&g_ctrlr2_A.log_head, log, link);
526 free(log);
527 }
528 g_ctrlr2_A.num_avail_log_pages = 0;
529 TAILQ_FOREACH_SAFE(log, &g_ctrlr_B.log_head, link, log_tmp) {
530 TAILQ_REMOVE(&g_ctrlr_B.log_head, log, link);
531 free(log);
532 }
533 g_ctrlr_B.num_avail_log_pages = 0;
534 TAILQ_FOREACH_SAFE(log, &g_ctrlr_C.log_head, link, log_tmp) {
535 TAILQ_REMOVE(&g_ctrlr_C.log_head, log, link);
536 free(log);
537 }
538 g_ctrlr_C.num_avail_log_pages = 0;
539
540 TAILQ_FOREACH_SAFE(ctrlr, &g_subsystem.ctrlrs, link, ctrlr_tmp) {
541 TAILQ_REMOVE(&g_subsystem.ctrlrs, ctrlr, link);
542 }
543 }
544
545 static struct spdk_nvmf_request *
546 ut_reservation_build_req(uint32_t length)
547 {
548 struct spdk_nvmf_request *req;
549
550 req = calloc(1, sizeof(*req));
551 assert(req != NULL);
552
553 req->data = calloc(1, length);
554 assert(req->data != NULL);
555 req->length = length;
556
557 req->cmd = (union nvmf_h2c_msg *)calloc(1, sizeof(union nvmf_h2c_msg));
558 assert(req->cmd != NULL);
559
560 req->rsp = (union nvmf_c2h_msg *)calloc(1, sizeof(union nvmf_c2h_msg));
561 assert(req->rsp != NULL);
562
563 return req;
564 }
565
566 static void
567 ut_reservation_free_req(struct spdk_nvmf_request *req)
568 {
569 free(req->cmd);
570 free(req->rsp);
571 free(req->data);
572 free(req);
573 }
574
575 static void
576 ut_reservation_build_register_request(struct spdk_nvmf_request *req,
577 uint8_t rrega, uint8_t iekey,
578 uint8_t cptpl, uint64_t crkey,
579 uint64_t nrkey)
580 {
581 uint32_t cdw10;
582 struct spdk_nvme_reservation_register_data key;
583 struct spdk_nvme_cmd *cmd = &req->cmd->nvme_cmd;
584
585 cdw10 = ((cptpl << 30) | (iekey << 3) | rrega);
586 key.crkey = crkey;
587 key.nrkey = nrkey;
588 cmd->cdw10 = cdw10;
589 memcpy(req->data, &key, sizeof(key));
590 }
591
592 static void
593 ut_reservation_build_acquire_request(struct spdk_nvmf_request *req,
594 uint8_t racqa, uint8_t iekey,
595 uint8_t rtype, uint64_t crkey,
596 uint64_t prkey)
597 {
598 uint32_t cdw10;
599 struct spdk_nvme_reservation_acquire_data key;
600 struct spdk_nvme_cmd *cmd = &req->cmd->nvme_cmd;
601
602 cdw10 = ((rtype << 8) | (iekey << 3) | racqa);
603 key.crkey = crkey;
604 key.prkey = prkey;
605 cmd->cdw10 = cdw10;
606 memcpy(req->data, &key, sizeof(key));
607 }
608
609 static void
610 ut_reservation_build_release_request(struct spdk_nvmf_request *req,
611 uint8_t rrela, uint8_t iekey,
612 uint8_t rtype, uint64_t crkey)
613 {
614 uint32_t cdw10;
615 struct spdk_nvme_cmd *cmd = &req->cmd->nvme_cmd;
616
617 cdw10 = ((rtype << 8) | (iekey << 3) | rrela);
618 cmd->cdw10 = cdw10;
619 memcpy(req->data, &crkey, sizeof(crkey));
620 }
621
622 /*
623 * Construct four registrants for other test cases.
624 *
625 * g_ctrlr1_A register with key 0xa1.
626 * g_ctrlr2_A register with key 0xa1.
627 * g_ctrlr_B register with key 0xb1.
628 * g_ctrlr_C register with key 0xc1.
629 * */
630 static void
631 ut_reservation_build_registrants(void)
632 {
633 struct spdk_nvmf_request *req;
634 struct spdk_nvme_cpl *rsp;
635 struct spdk_nvmf_registrant *reg;
636 uint32_t gen;
637
638 req = ut_reservation_build_req(16);
639 rsp = &req->rsp->nvme_cpl;
640 SPDK_CU_ASSERT_FATAL(req != NULL);
641 gen = g_ns.gen;
642
643 /* TEST CASE: g_ctrlr1_A register with a new key */
644 ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_REGISTER_KEY,
645 0, 0, 0, 0xa1);
646 nvmf_ns_reservation_register(&g_ns, &g_ctrlr1_A, req);
647 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
648 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr1_A.hostid);
649 SPDK_CU_ASSERT_FATAL(reg->rkey == 0xa1);
650 SPDK_CU_ASSERT_FATAL(g_ns.gen == gen + 1);
651
652 /* TEST CASE: g_ctrlr2_A register with a new key, because it has same
653 * Host Identifier with g_ctrlr1_A, so the register key should same.
654 */
655 ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_REGISTER_KEY,
656 0, 0, 0, 0xa2);
657 nvmf_ns_reservation_register(&g_ns, &g_ctrlr2_A, req);
658 /* Reservation conflict for other key than 0xa1 */
659 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_RESERVATION_CONFLICT);
660
661 /* g_ctrlr_B register with a new key */
662 ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_REGISTER_KEY,
663 0, 0, 0, 0xb1);
664 nvmf_ns_reservation_register(&g_ns, &g_ctrlr_B, req);
665 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
666 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_B.hostid);
667 SPDK_CU_ASSERT_FATAL(reg->rkey == 0xb1);
668 SPDK_CU_ASSERT_FATAL(g_ns.gen == gen + 2);
669
670 /* g_ctrlr_C register with a new key */
671 ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_REGISTER_KEY,
672 0, 0, 0, 0xc1);
673 nvmf_ns_reservation_register(&g_ns, &g_ctrlr_C, req);
674 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
675 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_C.hostid);
676 SPDK_CU_ASSERT_FATAL(reg->rkey == 0xc1);
677 SPDK_CU_ASSERT_FATAL(g_ns.gen == gen + 3);
678
679 ut_reservation_free_req(req);
680 }
681
682 static void
683 test_reservation_register(void)
684 {
685 struct spdk_nvmf_request *req;
686 struct spdk_nvme_cpl *rsp;
687 struct spdk_nvmf_registrant *reg;
688 uint32_t gen;
689
690 ut_reservation_init();
691
692 req = ut_reservation_build_req(16);
693 rsp = &req->rsp->nvme_cpl;
694 SPDK_CU_ASSERT_FATAL(req != NULL);
695
696 ut_reservation_build_registrants();
697
698 /* TEST CASE: Replace g_ctrlr1_A with a new key */
699 ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_REPLACE_KEY,
700 0, 0, 0xa1, 0xa11);
701 nvmf_ns_reservation_register(&g_ns, &g_ctrlr1_A, req);
702 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
703 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr1_A.hostid);
704 SPDK_CU_ASSERT_FATAL(reg->rkey == 0xa11);
705
706 /* TEST CASE: Host A with g_ctrlr1_A get reservation with
707 * type SPDK_NVME_RESERVE_WRITE_EXCLUSIVE
708 */
709 ut_reservation_build_acquire_request(req, SPDK_NVME_RESERVE_ACQUIRE, 0,
710 SPDK_NVME_RESERVE_WRITE_EXCLUSIVE, 0xa11, 0x0);
711 gen = g_ns.gen;
712 nvmf_ns_reservation_acquire(&g_ns, &g_ctrlr1_A, req);
713 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
714 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr1_A.hostid);
715 SPDK_CU_ASSERT_FATAL(g_ns.rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE);
716 SPDK_CU_ASSERT_FATAL(g_ns.crkey == 0xa11);
717 SPDK_CU_ASSERT_FATAL(g_ns.holder == reg);
718 SPDK_CU_ASSERT_FATAL(g_ns.gen == gen);
719
720 /* TEST CASE: g_ctrlr_C unregister with IEKEY enabled */
721 ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_UNREGISTER_KEY,
722 1, 0, 0, 0);
723 nvmf_ns_reservation_register(&g_ns, &g_ctrlr_C, req);
724 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
725 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_C.hostid);
726 SPDK_CU_ASSERT_FATAL(reg == NULL);
727
728 /* TEST CASE: g_ctrlr_B unregister with correct key */
729 ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_UNREGISTER_KEY,
730 0, 0, 0xb1, 0);
731 nvmf_ns_reservation_register(&g_ns, &g_ctrlr_B, req);
732 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
733 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_B.hostid);
734 SPDK_CU_ASSERT_FATAL(reg == NULL);
735
736 /* TEST CASE: g_ctrlr1_A unregister with correct key,
737 * reservation should be removed as well.
738 */
739 ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_UNREGISTER_KEY,
740 0, 0, 0xa11, 0);
741 nvmf_ns_reservation_register(&g_ns, &g_ctrlr1_A, req);
742 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
743 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr1_A.hostid);
744 SPDK_CU_ASSERT_FATAL(reg == NULL);
745 SPDK_CU_ASSERT_FATAL(g_ns.rtype == 0);
746 SPDK_CU_ASSERT_FATAL(g_ns.crkey == 0);
747 SPDK_CU_ASSERT_FATAL(g_ns.holder == NULL);
748
749 ut_reservation_free_req(req);
750 ut_reservation_deinit();
751 }
752
753 static void
754 test_reservation_acquire_preempt_1(void)
755 {
756 struct spdk_nvmf_request *req;
757 struct spdk_nvme_cpl *rsp;
758 struct spdk_nvmf_registrant *reg;
759 uint32_t gen;
760
761 ut_reservation_init();
762
763 req = ut_reservation_build_req(16);
764 rsp = &req->rsp->nvme_cpl;
765 SPDK_CU_ASSERT_FATAL(req != NULL);
766
767 ut_reservation_build_registrants();
768
769 gen = g_ns.gen;
770 /* ACQUIRE: Host A with g_ctrlr1_A acquire reservation with
771 * type SPDK_NVME_RESERVE_WRITE_EXCLUSIVE.
772 */
773 ut_reservation_build_acquire_request(req, SPDK_NVME_RESERVE_ACQUIRE, 0,
774 SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY, 0xa1, 0x0);
775 nvmf_ns_reservation_acquire(&g_ns, &g_ctrlr1_A, req);
776 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
777 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr1_A.hostid);
778 SPDK_CU_ASSERT_FATAL(g_ns.rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY);
779 SPDK_CU_ASSERT_FATAL(g_ns.crkey == 0xa1);
780 SPDK_CU_ASSERT_FATAL(g_ns.holder == reg);
781 SPDK_CU_ASSERT_FATAL(g_ns.gen == gen);
782
783 /* TEST CASE: g_ctrlr1_A holds the reservation, g_ctrlr_B preempt g_ctrl1_A,
784 * g_ctrl1_A registrant is unregistred.
785 */
786 gen = g_ns.gen;
787 ut_reservation_build_acquire_request(req, SPDK_NVME_RESERVE_PREEMPT, 0,
788 SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS, 0xb1, 0xa1);
789 nvmf_ns_reservation_acquire(&g_ns, &g_ctrlr_B, req);
790 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
791 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr1_A.hostid);
792 SPDK_CU_ASSERT_FATAL(reg == NULL);
793 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_B.hostid);
794 SPDK_CU_ASSERT_FATAL(reg != NULL);
795 SPDK_CU_ASSERT_FATAL(g_ns.holder == reg);
796 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_C.hostid);
797 SPDK_CU_ASSERT_FATAL(reg != NULL);
798 SPDK_CU_ASSERT_FATAL(g_ns.rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS);
799 SPDK_CU_ASSERT_FATAL(g_ns.gen > gen);
800
801 /* TEST CASE: g_ctrlr_B holds the reservation, g_ctrlr_C preempt g_ctrlr_B
802 * with valid key and PRKEY set to 0, all registrants other the host that issued
803 * the command are unregistered.
804 */
805 gen = g_ns.gen;
806 ut_reservation_build_acquire_request(req, SPDK_NVME_RESERVE_PREEMPT, 0,
807 SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS, 0xc1, 0x0);
808 nvmf_ns_reservation_acquire(&g_ns, &g_ctrlr_C, req);
809 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
810 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr2_A.hostid);
811 SPDK_CU_ASSERT_FATAL(reg == NULL);
812 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_B.hostid);
813 SPDK_CU_ASSERT_FATAL(reg == NULL);
814 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_C.hostid);
815 SPDK_CU_ASSERT_FATAL(reg != NULL);
816 SPDK_CU_ASSERT_FATAL(g_ns.holder == reg);
817 SPDK_CU_ASSERT_FATAL(g_ns.rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS);
818 SPDK_CU_ASSERT_FATAL(g_ns.gen > gen);
819
820 ut_reservation_free_req(req);
821 ut_reservation_deinit();
822 }
823
824 static void
825 test_reservation_release(void)
826 {
827 struct spdk_nvmf_request *req;
828 struct spdk_nvme_cpl *rsp;
829 struct spdk_nvmf_registrant *reg;
830
831 ut_reservation_init();
832
833 req = ut_reservation_build_req(16);
834 rsp = &req->rsp->nvme_cpl;
835 SPDK_CU_ASSERT_FATAL(req != NULL);
836
837 ut_reservation_build_registrants();
838
839 /* ACQUIRE: Host A with g_ctrlr1_A get reservation with
840 * type SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS
841 */
842 ut_reservation_build_acquire_request(req, SPDK_NVME_RESERVE_ACQUIRE, 0,
843 SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS, 0xa1, 0x0);
844 nvmf_ns_reservation_acquire(&g_ns, &g_ctrlr1_A, req);
845 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
846 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr1_A.hostid);
847 SPDK_CU_ASSERT_FATAL(g_ns.rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS);
848 SPDK_CU_ASSERT_FATAL(g_ns.holder == reg);
849
850 /* Test Case: Host B release the reservation */
851 ut_reservation_build_release_request(req, SPDK_NVME_RESERVE_RELEASE, 0,
852 SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS, 0xb1);
853 nvmf_ns_reservation_release(&g_ns, &g_ctrlr_B, req);
854 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
855 SPDK_CU_ASSERT_FATAL(g_ns.rtype == 0);
856 SPDK_CU_ASSERT_FATAL(g_ns.crkey == 0);
857 SPDK_CU_ASSERT_FATAL(g_ns.holder == NULL);
858
859 /* Test Case: Host C clear the registrants */
860 ut_reservation_build_release_request(req, SPDK_NVME_RESERVE_CLEAR, 0,
861 0, 0xc1);
862 nvmf_ns_reservation_release(&g_ns, &g_ctrlr_C, req);
863 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
864 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr1_A.hostid);
865 SPDK_CU_ASSERT_FATAL(reg == NULL);
866 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr2_A.hostid);
867 SPDK_CU_ASSERT_FATAL(reg == NULL);
868 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_B.hostid);
869 SPDK_CU_ASSERT_FATAL(reg == NULL);
870 reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_C.hostid);
871 SPDK_CU_ASSERT_FATAL(reg == NULL);
872
873 ut_reservation_free_req(req);
874 ut_reservation_deinit();
875 }
876
877 void
878 spdk_nvmf_ctrlr_reservation_notice_log(struct spdk_nvmf_ctrlr *ctrlr,
879 struct spdk_nvmf_ns *ns,
880 enum spdk_nvme_reservation_notification_log_page_type type)
881 {
882 ctrlr->num_avail_log_pages++;
883 }
884
885 static void
886 test_reservation_unregister_notification(void)
887 {
888 struct spdk_nvmf_request *req;
889 struct spdk_nvme_cpl *rsp;
890
891 ut_reservation_init();
892
893 req = ut_reservation_build_req(16);
894 SPDK_CU_ASSERT_FATAL(req != NULL);
895 rsp = &req->rsp->nvme_cpl;
896
897 ut_reservation_build_registrants();
898
899 /* ACQUIRE: Host B with g_ctrlr_B get reservation with
900 * type SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY
901 */
902 rsp->status.sc = 0xff;
903 ut_reservation_build_acquire_request(req, SPDK_NVME_RESERVE_ACQUIRE, 0,
904 SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY, 0xb1, 0x0);
905 nvmf_ns_reservation_acquire(&g_ns, &g_ctrlr_B, req);
906 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
907 SPDK_CU_ASSERT_FATAL(g_ns.rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY);
908
909 /* Test Case : g_ctrlr_B holds the reservation, g_ctrlr_B unregister the registration.
910 * Reservation release notification sends to g_ctrlr1_A/g_ctrlr2_A/g_ctrlr_C only for
911 * SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY or SPDK_NVME_RESERVE_EXCLUSIVE_ACCESS_REG_ONLY
912 * type.
913 */
914 rsp->status.sc = 0xff;
915 g_ctrlr1_A.num_avail_log_pages = 0;
916 g_ctrlr2_A.num_avail_log_pages = 0;
917 g_ctrlr_B.num_avail_log_pages = 5;
918 g_ctrlr_C.num_avail_log_pages = 0;
919 ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_UNREGISTER_KEY,
920 0, 0, 0xb1, 0);
921 nvmf_ns_reservation_register(&g_ns, &g_ctrlr_B, req);
922 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
923 SPDK_CU_ASSERT_FATAL(g_ns.rtype == 0);
924 SPDK_CU_ASSERT_FATAL(1 == g_ctrlr1_A.num_avail_log_pages);
925 SPDK_CU_ASSERT_FATAL(1 == g_ctrlr2_A.num_avail_log_pages);
926 SPDK_CU_ASSERT_FATAL(5 == g_ctrlr_B.num_avail_log_pages);
927 SPDK_CU_ASSERT_FATAL(1 == g_ctrlr_C.num_avail_log_pages);
928
929 ut_reservation_free_req(req);
930 ut_reservation_deinit();
931 }
932
933 static void
934 test_reservation_release_notification(void)
935 {
936 struct spdk_nvmf_request *req;
937 struct spdk_nvme_cpl *rsp;
938
939 ut_reservation_init();
940
941 req = ut_reservation_build_req(16);
942 SPDK_CU_ASSERT_FATAL(req != NULL);
943 rsp = &req->rsp->nvme_cpl;
944
945 ut_reservation_build_registrants();
946
947 /* ACQUIRE: Host B with g_ctrlr_B get reservation with
948 * type SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY
949 */
950 rsp->status.sc = 0xff;
951 ut_reservation_build_acquire_request(req, SPDK_NVME_RESERVE_ACQUIRE, 0,
952 SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY, 0xb1, 0x0);
953 nvmf_ns_reservation_acquire(&g_ns, &g_ctrlr_B, req);
954 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
955 SPDK_CU_ASSERT_FATAL(g_ns.rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY);
956
957 /* Test Case : g_ctrlr_B holds the reservation, g_ctrlr_B release the reservation.
958 * Reservation release notification sends to g_ctrlr1_A/g_ctrlr2_A/g_ctrlr_C.
959 */
960 rsp->status.sc = 0xff;
961 g_ctrlr1_A.num_avail_log_pages = 0;
962 g_ctrlr2_A.num_avail_log_pages = 0;
963 g_ctrlr_B.num_avail_log_pages = 5;
964 g_ctrlr_C.num_avail_log_pages = 0;
965 ut_reservation_build_release_request(req, SPDK_NVME_RESERVE_RELEASE, 0,
966 SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY, 0xb1);
967 nvmf_ns_reservation_release(&g_ns, &g_ctrlr_B, req);
968 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
969 SPDK_CU_ASSERT_FATAL(g_ns.rtype == 0);
970 SPDK_CU_ASSERT_FATAL(1 == g_ctrlr1_A.num_avail_log_pages);
971 SPDK_CU_ASSERT_FATAL(1 == g_ctrlr2_A.num_avail_log_pages);
972 SPDK_CU_ASSERT_FATAL(5 == g_ctrlr_B.num_avail_log_pages);
973 SPDK_CU_ASSERT_FATAL(1 == g_ctrlr_C.num_avail_log_pages);
974
975 ut_reservation_free_req(req);
976 ut_reservation_deinit();
977 }
978
979 static void
980 test_reservation_release_notification_write_exclusive(void)
981 {
982 struct spdk_nvmf_request *req;
983 struct spdk_nvme_cpl *rsp;
984
985 ut_reservation_init();
986
987 req = ut_reservation_build_req(16);
988 SPDK_CU_ASSERT_FATAL(req != NULL);
989 rsp = &req->rsp->nvme_cpl;
990
991 ut_reservation_build_registrants();
992
993 /* ACQUIRE: Host B with g_ctrlr_B get reservation with
994 * type SPDK_NVME_RESERVE_WRITE_EXCLUSIVE
995 */
996 rsp->status.sc = 0xff;
997 ut_reservation_build_acquire_request(req, SPDK_NVME_RESERVE_ACQUIRE, 0,
998 SPDK_NVME_RESERVE_WRITE_EXCLUSIVE, 0xb1, 0x0);
999 nvmf_ns_reservation_acquire(&g_ns, &g_ctrlr_B, req);
1000 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
1001 SPDK_CU_ASSERT_FATAL(g_ns.rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE);
1002
1003 /* Test Case : g_ctrlr_B holds the reservation, g_ctrlr_B release the reservation.
1004 * Because the reservation type is SPDK_NVME_RESERVE_WRITE_EXCLUSIVE,
1005 * no reservation notification occurs.
1006 */
1007 rsp->status.sc = 0xff;
1008 g_ctrlr1_A.num_avail_log_pages = 5;
1009 g_ctrlr2_A.num_avail_log_pages = 5;
1010 g_ctrlr_B.num_avail_log_pages = 5;
1011 g_ctrlr_C.num_avail_log_pages = 5;
1012 ut_reservation_build_release_request(req, SPDK_NVME_RESERVE_RELEASE, 0,
1013 SPDK_NVME_RESERVE_WRITE_EXCLUSIVE, 0xb1);
1014 nvmf_ns_reservation_release(&g_ns, &g_ctrlr_B, req);
1015 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
1016 SPDK_CU_ASSERT_FATAL(g_ns.rtype == 0);
1017 SPDK_CU_ASSERT_FATAL(5 == g_ctrlr1_A.num_avail_log_pages);
1018 SPDK_CU_ASSERT_FATAL(5 == g_ctrlr2_A.num_avail_log_pages);
1019 SPDK_CU_ASSERT_FATAL(5 == g_ctrlr_B.num_avail_log_pages);
1020 SPDK_CU_ASSERT_FATAL(5 == g_ctrlr_C.num_avail_log_pages);
1021
1022 ut_reservation_free_req(req);
1023 ut_reservation_deinit();
1024 }
1025
1026 static void
1027 test_reservation_clear_notification(void)
1028 {
1029 struct spdk_nvmf_request *req;
1030 struct spdk_nvme_cpl *rsp;
1031
1032 ut_reservation_init();
1033
1034 req = ut_reservation_build_req(16);
1035 SPDK_CU_ASSERT_FATAL(req != NULL);
1036 rsp = &req->rsp->nvme_cpl;
1037
1038 ut_reservation_build_registrants();
1039
1040 /* ACQUIRE: Host B with g_ctrlr_B get reservation with
1041 * type SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY
1042 */
1043 rsp->status.sc = 0xff;
1044 ut_reservation_build_acquire_request(req, SPDK_NVME_RESERVE_ACQUIRE, 0,
1045 SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY, 0xb1, 0x0);
1046 nvmf_ns_reservation_acquire(&g_ns, &g_ctrlr_B, req);
1047 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
1048 SPDK_CU_ASSERT_FATAL(g_ns.rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY);
1049
1050 /* Test Case : g_ctrlr_B holds the reservation, g_ctrlr_B clear the reservation.
1051 * Reservation Preempted notification sends to g_ctrlr1_A/g_ctrlr2_A/g_ctrlr_C.
1052 */
1053 rsp->status.sc = 0xff;
1054 g_ctrlr1_A.num_avail_log_pages = 0;
1055 g_ctrlr2_A.num_avail_log_pages = 0;
1056 g_ctrlr_B.num_avail_log_pages = 5;
1057 g_ctrlr_C.num_avail_log_pages = 0;
1058 ut_reservation_build_release_request(req, SPDK_NVME_RESERVE_CLEAR, 0,
1059 0, 0xb1);
1060 nvmf_ns_reservation_release(&g_ns, &g_ctrlr_B, req);
1061 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
1062 SPDK_CU_ASSERT_FATAL(g_ns.rtype == 0);
1063 SPDK_CU_ASSERT_FATAL(1 == g_ctrlr1_A.num_avail_log_pages);
1064 SPDK_CU_ASSERT_FATAL(1 == g_ctrlr2_A.num_avail_log_pages);
1065 SPDK_CU_ASSERT_FATAL(5 == g_ctrlr_B.num_avail_log_pages);
1066 SPDK_CU_ASSERT_FATAL(1 == g_ctrlr_C.num_avail_log_pages);
1067
1068 ut_reservation_free_req(req);
1069 ut_reservation_deinit();
1070 }
1071
1072 static void
1073 test_reservation_preempt_notification(void)
1074 {
1075 struct spdk_nvmf_request *req;
1076 struct spdk_nvme_cpl *rsp;
1077
1078 ut_reservation_init();
1079
1080 req = ut_reservation_build_req(16);
1081 SPDK_CU_ASSERT_FATAL(req != NULL);
1082 rsp = &req->rsp->nvme_cpl;
1083
1084 ut_reservation_build_registrants();
1085
1086 /* ACQUIRE: Host B with g_ctrlr_B get reservation with
1087 * type SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY
1088 */
1089 rsp->status.sc = 0xff;
1090 ut_reservation_build_acquire_request(req, SPDK_NVME_RESERVE_ACQUIRE, 0,
1091 SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY, 0xb1, 0x0);
1092 nvmf_ns_reservation_acquire(&g_ns, &g_ctrlr_B, req);
1093 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
1094 SPDK_CU_ASSERT_FATAL(g_ns.rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY);
1095
1096 /* Test Case : g_ctrlr_B holds the reservation, g_ctrlr_C preempt g_ctrlr_B,
1097 * g_ctrlr_B registrant is unregistred, and reservation is preempted.
1098 * Registration Preempted notification sends to g_ctrlr_B.
1099 * Reservation Preempted notification sends to g_ctrlr1_A/g_ctrlr2_A.
1100 */
1101 rsp->status.sc = 0xff;
1102 g_ctrlr1_A.num_avail_log_pages = 0;
1103 g_ctrlr2_A.num_avail_log_pages = 0;
1104 g_ctrlr_B.num_avail_log_pages = 0;
1105 g_ctrlr_C.num_avail_log_pages = 5;
1106 ut_reservation_build_acquire_request(req, SPDK_NVME_RESERVE_PREEMPT, 0,
1107 SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS, 0xc1, 0xb1);
1108 nvmf_ns_reservation_acquire(&g_ns, &g_ctrlr_C, req);
1109 SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
1110 SPDK_CU_ASSERT_FATAL(g_ns.rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS);
1111 SPDK_CU_ASSERT_FATAL(1 == g_ctrlr1_A.num_avail_log_pages);
1112 SPDK_CU_ASSERT_FATAL(1 == g_ctrlr2_A.num_avail_log_pages);
1113 SPDK_CU_ASSERT_FATAL(1 == g_ctrlr_B.num_avail_log_pages);
1114 SPDK_CU_ASSERT_FATAL(5 == g_ctrlr_C.num_avail_log_pages);
1115
1116 ut_reservation_free_req(req);
1117 ut_reservation_deinit();
1118 }
1119
1120 int main(int argc, char **argv)
1121 {
1122 CU_pSuite suite = NULL;
1123 unsigned int num_failures;
1124
1125 if (CU_initialize_registry() != CUE_SUCCESS) {
1126 return CU_get_error();
1127 }
1128
1129 suite = CU_add_suite("nvmf", NULL, NULL);
1130 if (suite == NULL) {
1131 CU_cleanup_registry();
1132 return CU_get_error();
1133 }
1134
1135 if (
1136 CU_add_test(suite, "create_subsystem", nvmf_test_create_subsystem) == NULL ||
1137 CU_add_test(suite, "nvmf_subsystem_add_ns", test_spdk_nvmf_subsystem_add_ns) == NULL ||
1138 CU_add_test(suite, "nvmf_subsystem_set_sn", test_spdk_nvmf_subsystem_set_sn) == NULL ||
1139 CU_add_test(suite, "reservation_register", test_reservation_register) == NULL ||
1140 CU_add_test(suite, "reservation_acquire_preempt_1", test_reservation_acquire_preempt_1) == NULL ||
1141 CU_add_test(suite, "reservation_release", test_reservation_release) == NULL ||
1142 CU_add_test(suite, "reservation_unregister_notification",
1143 test_reservation_unregister_notification) == NULL ||
1144 CU_add_test(suite, "reservation_release_notification",
1145 test_reservation_release_notification) == NULL ||
1146 CU_add_test(suite, "reservation_release_notification_write_exclusive",
1147 test_reservation_release_notification_write_exclusive) == NULL ||
1148 CU_add_test(suite, "reservation_clear_notification", test_reservation_clear_notification) == NULL ||
1149 CU_add_test(suite, "reservation_preempt_notification",
1150 test_reservation_preempt_notification) == NULL
1151 ) {
1152 CU_cleanup_registry();
1153 return CU_get_error();
1154 }
1155
1156 allocate_threads(1);
1157 set_thread(0);
1158
1159 CU_basic_set_mode(CU_BRM_VERBOSE);
1160 CU_basic_run_tests();
1161 num_failures = CU_get_number_of_failures();
1162 CU_cleanup_registry();
1163
1164 free_threads();
1165
1166 return num_failures;
1167 }