xref: /spdk/test/unit/lib/nvmf/subsystem.c/subsystem_ut.c (revision c4d9daeb7bf491bc0eb6e8d417b75d44773cb009)
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 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 }
1168