xref: /spdk/test/unit/lib/nvmf/subsystem.c/subsystem_ut.c (revision ae7b5890ef728af40bd233a5011b924c482603bf)
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_bdev_get_md_size, uint32_t,
57 	    (const struct spdk_bdev *bdev), 0);
58 
59 DEFINE_STUB(spdk_bdev_is_md_interleaved, bool,
60 	    (const struct spdk_bdev *bdev), false);
61 
62 DEFINE_STUB(spdk_nvmf_transport_stop_listen,
63 	    int,
64 	    (struct spdk_nvmf_transport *transport,
65 	     const struct spdk_nvme_transport_id *trid), 0);
66 
67 struct spdk_event *
68 spdk_event_allocate(uint32_t core, spdk_event_fn fn, void *arg1, void *arg2)
69 {
70 	return NULL;
71 }
72 
73 void
74 spdk_event_call(struct spdk_event *event)
75 {
76 
77 }
78 
79 int
80 spdk_nvmf_transport_listen(struct spdk_nvmf_transport *transport,
81 			   const struct spdk_nvme_transport_id *trid)
82 {
83 	return 0;
84 }
85 
86 void
87 spdk_nvmf_transport_listener_discover(struct spdk_nvmf_transport *transport,
88 				      struct spdk_nvme_transport_id *trid,
89 				      struct spdk_nvmf_discovery_log_page_entry *entry)
90 {
91 	entry->trtype = 42;
92 }
93 
94 static struct spdk_nvmf_transport g_transport = {};
95 
96 struct spdk_nvmf_transport *
97 spdk_nvmf_transport_create(enum spdk_nvme_transport_type type,
98 			   struct spdk_nvmf_transport_opts *tprt_opts)
99 {
100 	if (type == SPDK_NVME_TRANSPORT_RDMA) {
101 		return &g_transport;
102 	}
103 
104 	return NULL;
105 }
106 
107 struct spdk_nvmf_subsystem *
108 spdk_nvmf_tgt_find_subsystem(struct spdk_nvmf_tgt *tgt, const char *subnqn)
109 {
110 	return NULL;
111 }
112 
113 struct spdk_nvmf_transport *
114 spdk_nvmf_tgt_get_transport(struct spdk_nvmf_tgt *tgt, enum spdk_nvme_transport_type trtype)
115 {
116 	if (trtype == SPDK_NVME_TRANSPORT_RDMA) {
117 		return &g_transport;
118 	}
119 
120 	return NULL;
121 }
122 
123 int
124 spdk_nvmf_poll_group_update_subsystem(struct spdk_nvmf_poll_group *group,
125 				      struct spdk_nvmf_subsystem *subsystem)
126 {
127 	return 0;
128 }
129 
130 int
131 spdk_nvmf_poll_group_add_subsystem(struct spdk_nvmf_poll_group *group,
132 				   struct spdk_nvmf_subsystem *subsystem,
133 				   spdk_nvmf_poll_group_mod_done cb_fn, void *cb_arg)
134 {
135 	return 0;
136 }
137 
138 void
139 spdk_nvmf_poll_group_remove_subsystem(struct spdk_nvmf_poll_group *group,
140 				      struct spdk_nvmf_subsystem *subsystem,
141 				      spdk_nvmf_poll_group_mod_done cb_fn, void *cb_arg)
142 {
143 }
144 
145 void
146 spdk_nvmf_poll_group_pause_subsystem(struct spdk_nvmf_poll_group *group,
147 				     struct spdk_nvmf_subsystem *subsystem,
148 				     spdk_nvmf_poll_group_mod_done cb_fn, void *cb_arg)
149 {
150 }
151 
152 void
153 spdk_nvmf_poll_group_resume_subsystem(struct spdk_nvmf_poll_group *group,
154 				      struct spdk_nvmf_subsystem *subsystem,
155 				      spdk_nvmf_poll_group_mod_done cb_fn, void *cb_arg)
156 {
157 }
158 
159 int
160 spdk_nvme_transport_id_parse_trtype(enum spdk_nvme_transport_type *trtype, const char *str)
161 {
162 	if (trtype == NULL || str == NULL) {
163 		return -EINVAL;
164 	}
165 
166 	if (strcasecmp(str, "PCIe") == 0) {
167 		*trtype = SPDK_NVME_TRANSPORT_PCIE;
168 	} else if (strcasecmp(str, "RDMA") == 0) {
169 		*trtype = SPDK_NVME_TRANSPORT_RDMA;
170 	} else {
171 		return -ENOENT;
172 	}
173 	return 0;
174 }
175 
176 int
177 spdk_nvme_transport_id_compare(const struct spdk_nvme_transport_id *trid1,
178 			       const struct spdk_nvme_transport_id *trid2)
179 {
180 	return 0;
181 }
182 
183 int32_t
184 spdk_nvme_ctrlr_process_admin_completions(struct spdk_nvme_ctrlr *ctrlr)
185 {
186 	return -1;
187 }
188 
189 int32_t
190 spdk_nvme_qpair_process_completions(struct spdk_nvme_qpair *qpair, uint32_t max_completions)
191 {
192 	return -1;
193 }
194 
195 int
196 spdk_nvme_detach(struct spdk_nvme_ctrlr *ctrlr)
197 {
198 	return -1;
199 }
200 
201 void
202 spdk_nvmf_ctrlr_destruct(struct spdk_nvmf_ctrlr *ctrlr)
203 {
204 }
205 
206 void
207 spdk_nvmf_ctrlr_ns_changed(struct spdk_nvmf_ctrlr *ctrlr, uint32_t nsid)
208 {
209 }
210 
211 int
212 spdk_bdev_open(struct spdk_bdev *bdev, bool write, spdk_bdev_remove_cb_t remove_cb,
213 	       void *remove_ctx, struct spdk_bdev_desc **desc)
214 {
215 	return 0;
216 }
217 
218 void
219 spdk_bdev_close(struct spdk_bdev_desc *desc)
220 {
221 }
222 
223 const char *
224 spdk_bdev_get_name(const struct spdk_bdev *bdev)
225 {
226 	return "test";
227 }
228 
229 const struct spdk_uuid *
230 spdk_bdev_get_uuid(const struct spdk_bdev *bdev)
231 {
232 	return &bdev->uuid;
233 }
234 
235 static void
236 test_spdk_nvmf_subsystem_add_ns(void)
237 {
238 	struct spdk_nvmf_tgt tgt = {};
239 	struct spdk_nvmf_subsystem subsystem = {
240 		.max_nsid = 0,
241 		.ns = NULL,
242 		.tgt = &tgt
243 	};
244 	struct spdk_bdev bdev1 = {}, bdev2 = {};
245 	struct spdk_nvmf_ns_opts ns_opts;
246 	uint32_t nsid;
247 	int rc;
248 
249 	tgt.max_subsystems = 1024;
250 	tgt.subsystems = calloc(tgt.max_subsystems, sizeof(struct spdk_nvmf_subsystem *));
251 	SPDK_CU_ASSERT_FATAL(tgt.subsystems != NULL);
252 
253 	/* Allow NSID to be assigned automatically */
254 	spdk_nvmf_ns_opts_get_defaults(&ns_opts, sizeof(ns_opts));
255 	nsid = spdk_nvmf_subsystem_add_ns(&subsystem, &bdev1, &ns_opts, sizeof(ns_opts), NULL);
256 	/* NSID 1 is the first unused ID */
257 	CU_ASSERT(nsid == 1);
258 	CU_ASSERT(subsystem.max_nsid == 1);
259 	SPDK_CU_ASSERT_FATAL(subsystem.ns != NULL);
260 	SPDK_CU_ASSERT_FATAL(subsystem.ns[nsid - 1] != NULL);
261 	CU_ASSERT(subsystem.ns[nsid - 1]->bdev == &bdev1);
262 
263 	/* Request a specific NSID */
264 	spdk_nvmf_ns_opts_get_defaults(&ns_opts, sizeof(ns_opts));
265 	ns_opts.nsid = 5;
266 	nsid = spdk_nvmf_subsystem_add_ns(&subsystem, &bdev2, &ns_opts, sizeof(ns_opts), NULL);
267 	CU_ASSERT(nsid == 5);
268 	CU_ASSERT(subsystem.max_nsid == 5);
269 	SPDK_CU_ASSERT_FATAL(subsystem.ns[nsid - 1] != NULL);
270 	CU_ASSERT(subsystem.ns[nsid - 1]->bdev == &bdev2);
271 
272 	/* Request an NSID that is already in use */
273 	spdk_nvmf_ns_opts_get_defaults(&ns_opts, sizeof(ns_opts));
274 	ns_opts.nsid = 5;
275 	nsid = spdk_nvmf_subsystem_add_ns(&subsystem, &bdev2, &ns_opts, sizeof(ns_opts), NULL);
276 	CU_ASSERT(nsid == 0);
277 	CU_ASSERT(subsystem.max_nsid == 5);
278 
279 	/* Request 0xFFFFFFFF (invalid NSID, reserved for broadcast) */
280 	spdk_nvmf_ns_opts_get_defaults(&ns_opts, sizeof(ns_opts));
281 	ns_opts.nsid = 0xFFFFFFFF;
282 	nsid = spdk_nvmf_subsystem_add_ns(&subsystem, &bdev2, &ns_opts, sizeof(ns_opts), NULL);
283 	CU_ASSERT(nsid == 0);
284 	CU_ASSERT(subsystem.max_nsid == 5);
285 
286 	rc = spdk_nvmf_subsystem_remove_ns(&subsystem, 1);
287 	CU_ASSERT(rc == 0);
288 	rc = spdk_nvmf_subsystem_remove_ns(&subsystem, 5);
289 	CU_ASSERT(rc == 0);
290 
291 	free(subsystem.ns);
292 	free(tgt.subsystems);
293 }
294 
295 static void
296 nvmf_test_create_subsystem(void)
297 {
298 	struct spdk_nvmf_tgt tgt = {};
299 	char nqn[256];
300 	struct spdk_nvmf_subsystem *subsystem;
301 
302 	tgt.max_subsystems = 1024;
303 	tgt.subsystems = calloc(tgt.max_subsystems, sizeof(struct spdk_nvmf_subsystem *));
304 	SPDK_CU_ASSERT_FATAL(tgt.subsystems != NULL);
305 
306 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:subsystem1");
307 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
308 	SPDK_CU_ASSERT_FATAL(subsystem != NULL);
309 	CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn);
310 	spdk_nvmf_subsystem_destroy(subsystem);
311 
312 	/* valid name with complex reverse domain */
313 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk-full--rev-domain.name:subsystem1");
314 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
315 	SPDK_CU_ASSERT_FATAL(subsystem != NULL);
316 	CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn);
317 	spdk_nvmf_subsystem_destroy(subsystem);
318 
319 	/* Valid name discovery controller */
320 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:subsystem1");
321 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
322 	SPDK_CU_ASSERT_FATAL(subsystem != NULL);
323 	CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn);
324 	spdk_nvmf_subsystem_destroy(subsystem);
325 
326 
327 	/* Invalid name, no user supplied string */
328 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:");
329 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
330 	SPDK_CU_ASSERT_FATAL(subsystem == NULL);
331 
332 	/* Valid name, only contains top-level domain name */
333 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:subsystem1");
334 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
335 	SPDK_CU_ASSERT_FATAL(subsystem != NULL);
336 	CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn);
337 	spdk_nvmf_subsystem_destroy(subsystem);
338 
339 	/* Invalid name, domain label > 63 characters */
340 	snprintf(nqn, sizeof(nqn),
341 		 "nqn.2016-06.io.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz:sub");
342 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
343 	SPDK_CU_ASSERT_FATAL(subsystem == NULL);
344 
345 	/* Invalid name, domain label starts with digit */
346 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.3spdk:sub");
347 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
348 	SPDK_CU_ASSERT_FATAL(subsystem == NULL);
349 
350 	/* Invalid name, domain label starts with - */
351 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.-spdk:subsystem1");
352 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
353 	SPDK_CU_ASSERT_FATAL(subsystem == NULL);
354 
355 	/* Invalid name, domain label ends with - */
356 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk-:subsystem1");
357 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
358 	SPDK_CU_ASSERT_FATAL(subsystem == NULL);
359 
360 	/* Invalid name, domain label with multiple consecutive periods */
361 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io..spdk:subsystem1");
362 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
363 	SPDK_CU_ASSERT_FATAL(subsystem == NULL);
364 
365 	/* Longest valid name */
366 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:");
367 	memset(nqn + strlen(nqn), 'a', 223 - strlen(nqn));
368 	nqn[223] = '\0';
369 	CU_ASSERT(strlen(nqn) == 223);
370 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
371 	SPDK_CU_ASSERT_FATAL(subsystem != NULL);
372 	CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn);
373 	spdk_nvmf_subsystem_destroy(subsystem);
374 
375 	/* Invalid name, too long */
376 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:");
377 	memset(nqn + strlen(nqn), 'a', 224 - strlen(nqn));
378 	nqn[224] = '\0';
379 	CU_ASSERT(strlen(nqn) == 224);
380 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
381 	CU_ASSERT(subsystem == NULL);
382 
383 	/* Valid name using uuid format */
384 	snprintf(nqn, sizeof(nqn), "nqn.2014-08.org.nvmexpress:uuid:11111111-aaaa-bbdd-FFEE-123456789abc");
385 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
386 	SPDK_CU_ASSERT_FATAL(subsystem != NULL);
387 	CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn);
388 	spdk_nvmf_subsystem_destroy(subsystem);
389 
390 	/* Invalid name user string contains an invalid utf-8 character */
391 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:\xFFsubsystem1");
392 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
393 	SPDK_CU_ASSERT_FATAL(subsystem == NULL);
394 
395 	/* Valid name with non-ascii but valid utf-8 characters */
396 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:\xe1\x8a\x88subsystem1\xca\x80");
397 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
398 	SPDK_CU_ASSERT_FATAL(subsystem != NULL);
399 	CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn);
400 	spdk_nvmf_subsystem_destroy(subsystem);
401 
402 	/* Invalid uuid (too long) */
403 	snprintf(nqn, sizeof(nqn),
404 		 "nqn.2014-08.org.nvmexpress:uuid:11111111-aaaa-bbdd-FFEE-123456789abcdef");
405 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
406 	SPDK_CU_ASSERT_FATAL(subsystem == NULL);
407 
408 	/* Invalid uuid (dashes placed incorrectly) */
409 	snprintf(nqn, sizeof(nqn), "nqn.2014-08.org.nvmexpress:uuid:111111-11aaaa-bbdd-FFEE-123456789abc");
410 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
411 	SPDK_CU_ASSERT_FATAL(subsystem == NULL);
412 
413 	/* Invalid uuid (invalid characters in uuid) */
414 	snprintf(nqn, sizeof(nqn), "nqn.2014-08.org.nvmexpress:uuid:111hg111-aaaa-bbdd-FFEE-123456789abc");
415 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
416 	SPDK_CU_ASSERT_FATAL(subsystem == NULL);
417 
418 	free(tgt.subsystems);
419 }
420 
421 static void
422 test_spdk_nvmf_subsystem_set_sn(void)
423 {
424 	struct spdk_nvmf_subsystem subsystem = {};
425 
426 	/* Basic valid serial number */
427 	CU_ASSERT(spdk_nvmf_subsystem_set_sn(&subsystem, "abcd xyz") == 0);
428 	CU_ASSERT(strcmp(subsystem.sn, "abcd xyz") == 0);
429 
430 	/* Exactly 20 characters (valid) */
431 	CU_ASSERT(spdk_nvmf_subsystem_set_sn(&subsystem, "12345678901234567890") == 0);
432 	CU_ASSERT(strcmp(subsystem.sn, "12345678901234567890") == 0);
433 
434 	/* 21 characters (too long, invalid) */
435 	CU_ASSERT(spdk_nvmf_subsystem_set_sn(&subsystem, "123456789012345678901") < 0);
436 
437 	/* Non-ASCII characters (invalid) */
438 	CU_ASSERT(spdk_nvmf_subsystem_set_sn(&subsystem, "abcd\txyz") < 0);
439 }
440 
441 /*
442  * Reservation Unit Test Configuration
443  *       --------             --------    --------
444  *      | Host A |           | Host B |  | Host C |
445  *       --------             --------    --------
446  *      /        \               |           |
447  *  --------   --------       -------     -------
448  * |Ctrlr1_A| |Ctrlr2_A|     |Ctrlr_B|   |Ctrlr_C|
449  *  --------   --------       -------     -------
450  *    \           \              /           /
451  *     \           \            /           /
452  *      \           \          /           /
453  *      --------------------------------------
454  *     |            NAMESPACE 1               |
455  *      --------------------------------------
456  */
457 static struct spdk_nvmf_subsystem g_subsystem;
458 static struct spdk_nvmf_ctrlr g_ctrlr1_A, g_ctrlr2_A, g_ctrlr_B, g_ctrlr_C;
459 static struct spdk_nvmf_ns g_ns;
460 static struct spdk_bdev g_bdev;
461 struct spdk_nvmf_subsystem_pg_ns_info g_ns_info;
462 
463 void
464 spdk_nvmf_ctrlr_async_event_reservation_notification(struct spdk_nvmf_ctrlr *ctrlr)
465 {
466 }
467 
468 static void
469 ut_reservation_init(void)
470 {
471 
472 	TAILQ_INIT(&g_subsystem.ctrlrs);
473 
474 	memset(&g_ns, 0, sizeof(g_ns));
475 	TAILQ_INIT(&g_ns.registrants);
476 	g_ns.subsystem = &g_subsystem;
477 	g_ns.ptpl_file = NULL;
478 	g_ns.ptpl_activated = false;
479 	spdk_uuid_generate(&g_bdev.uuid);
480 	g_ns.bdev = &g_bdev;
481 
482 	/* Host A has two controllers */
483 	spdk_uuid_generate(&g_ctrlr1_A.hostid);
484 	TAILQ_INIT(&g_ctrlr1_A.log_head);
485 	g_ctrlr1_A.subsys = &g_subsystem;
486 	g_ctrlr1_A.num_avail_log_pages = 0;
487 	TAILQ_INSERT_TAIL(&g_subsystem.ctrlrs, &g_ctrlr1_A, link);
488 	spdk_uuid_copy(&g_ctrlr2_A.hostid, &g_ctrlr1_A.hostid);
489 	TAILQ_INIT(&g_ctrlr2_A.log_head);
490 	g_ctrlr2_A.subsys = &g_subsystem;
491 	g_ctrlr2_A.num_avail_log_pages = 0;
492 	TAILQ_INSERT_TAIL(&g_subsystem.ctrlrs, &g_ctrlr2_A, link);
493 
494 	/* Host B has 1 controller */
495 	spdk_uuid_generate(&g_ctrlr_B.hostid);
496 	TAILQ_INIT(&g_ctrlr_B.log_head);
497 	g_ctrlr_B.subsys = &g_subsystem;
498 	g_ctrlr_B.num_avail_log_pages = 0;
499 	TAILQ_INSERT_TAIL(&g_subsystem.ctrlrs, &g_ctrlr_B, link);
500 
501 	/* Host C has 1 controller */
502 	spdk_uuid_generate(&g_ctrlr_C.hostid);
503 	TAILQ_INIT(&g_ctrlr_C.log_head);
504 	g_ctrlr_C.subsys = &g_subsystem;
505 	g_ctrlr_C.num_avail_log_pages = 0;
506 	TAILQ_INSERT_TAIL(&g_subsystem.ctrlrs, &g_ctrlr_C, link);
507 }
508 
509 static void
510 ut_reservation_deinit(void)
511 {
512 	struct spdk_nvmf_registrant *reg, *tmp;
513 	struct spdk_nvmf_reservation_log *log, *log_tmp;
514 	struct spdk_nvmf_ctrlr *ctrlr, *ctrlr_tmp;
515 
516 	TAILQ_FOREACH_SAFE(reg, &g_ns.registrants, link, tmp) {
517 		TAILQ_REMOVE(&g_ns.registrants, reg, link);
518 		free(reg);
519 	}
520 	TAILQ_FOREACH_SAFE(log, &g_ctrlr1_A.log_head, link, log_tmp) {
521 		TAILQ_REMOVE(&g_ctrlr1_A.log_head, log, link);
522 		free(log);
523 	}
524 	g_ctrlr1_A.num_avail_log_pages = 0;
525 	TAILQ_FOREACH_SAFE(log, &g_ctrlr2_A.log_head, link, log_tmp) {
526 		TAILQ_REMOVE(&g_ctrlr2_A.log_head, log, link);
527 		free(log);
528 	}
529 	g_ctrlr2_A.num_avail_log_pages = 0;
530 	TAILQ_FOREACH_SAFE(log, &g_ctrlr_B.log_head, link, log_tmp) {
531 		TAILQ_REMOVE(&g_ctrlr_B.log_head, log, link);
532 		free(log);
533 	}
534 	g_ctrlr_B.num_avail_log_pages = 0;
535 	TAILQ_FOREACH_SAFE(log, &g_ctrlr_C.log_head, link, log_tmp) {
536 		TAILQ_REMOVE(&g_ctrlr_C.log_head, log, link);
537 		free(log);
538 	}
539 	g_ctrlr_C.num_avail_log_pages = 0;
540 
541 	TAILQ_FOREACH_SAFE(ctrlr, &g_subsystem.ctrlrs, link, ctrlr_tmp) {
542 		TAILQ_REMOVE(&g_subsystem.ctrlrs, ctrlr, link);
543 	}
544 }
545 
546 static struct spdk_nvmf_request *
547 ut_reservation_build_req(uint32_t length)
548 {
549 	struct spdk_nvmf_request *req;
550 
551 	req = calloc(1, sizeof(*req));
552 	assert(req != NULL);
553 
554 	req->data = calloc(1, length);
555 	assert(req->data != NULL);
556 	req->length = length;
557 
558 	req->cmd = (union nvmf_h2c_msg *)calloc(1, sizeof(union nvmf_h2c_msg));
559 	assert(req->cmd != NULL);
560 
561 	req->rsp = (union nvmf_c2h_msg *)calloc(1, sizeof(union nvmf_c2h_msg));
562 	assert(req->rsp != NULL);
563 
564 	return req;
565 }
566 
567 static void
568 ut_reservation_free_req(struct spdk_nvmf_request *req)
569 {
570 	free(req->cmd);
571 	free(req->rsp);
572 	free(req->data);
573 	free(req);
574 }
575 
576 static void
577 ut_reservation_build_register_request(struct spdk_nvmf_request *req,
578 				      uint8_t rrega, uint8_t iekey,
579 				      uint8_t cptpl, uint64_t crkey,
580 				      uint64_t nrkey)
581 {
582 	uint32_t cdw10;
583 	struct spdk_nvme_reservation_register_data key;
584 	struct spdk_nvme_cmd *cmd = &req->cmd->nvme_cmd;
585 
586 	cdw10 = (((uint32_t)cptpl << 30) | ((uint32_t)iekey << 3) | rrega);
587 	key.crkey = crkey;
588 	key.nrkey = nrkey;
589 	cmd->cdw10 = cdw10;
590 	memcpy(req->data, &key, sizeof(key));
591 }
592 
593 static void
594 ut_reservation_build_acquire_request(struct spdk_nvmf_request *req,
595 				     uint8_t racqa, uint8_t iekey,
596 				     uint8_t rtype, uint64_t crkey,
597 				     uint64_t prkey)
598 {
599 	uint32_t cdw10;
600 	struct spdk_nvme_reservation_acquire_data key;
601 	struct spdk_nvme_cmd *cmd = &req->cmd->nvme_cmd;
602 
603 	cdw10 = ((rtype << 8) | (iekey << 3) | racqa);
604 	key.crkey = crkey;
605 	key.prkey = prkey;
606 	cmd->cdw10 = cdw10;
607 	memcpy(req->data, &key, sizeof(key));
608 }
609 
610 static void
611 ut_reservation_build_release_request(struct spdk_nvmf_request *req,
612 				     uint8_t rrela, uint8_t iekey,
613 				     uint8_t rtype, uint64_t crkey)
614 {
615 	uint32_t cdw10;
616 	struct spdk_nvme_cmd *cmd = &req->cmd->nvme_cmd;
617 
618 	cdw10 = ((rtype << 8) | (iekey << 3) | rrela);
619 	cmd->cdw10 = cdw10;
620 	memcpy(req->data, &crkey, sizeof(crkey));
621 }
622 
623 /*
624  * Construct four registrants for other test cases.
625  *
626  * g_ctrlr1_A register with key 0xa1.
627  * g_ctrlr2_A register with key 0xa1.
628  * g_ctrlr_B register with key 0xb1.
629  * g_ctrlr_C register with key 0xc1.
630  * */
631 static void
632 ut_reservation_build_registrants(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 	req = ut_reservation_build_req(16);
640 	rsp = &req->rsp->nvme_cpl;
641 	SPDK_CU_ASSERT_FATAL(req != NULL);
642 	gen = g_ns.gen;
643 
644 	/* TEST CASE: g_ctrlr1_A register with a new key */
645 	ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_REGISTER_KEY,
646 					      0, 0, 0, 0xa1);
647 	nvmf_ns_reservation_register(&g_ns, &g_ctrlr1_A, req);
648 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
649 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr1_A.hostid);
650 	SPDK_CU_ASSERT_FATAL(reg->rkey == 0xa1);
651 	SPDK_CU_ASSERT_FATAL(g_ns.gen == gen + 1);
652 
653 	/* TEST CASE: g_ctrlr2_A register with a new key, because it has same
654 	 * Host Identifier with g_ctrlr1_A, so the register key should same.
655 	 */
656 	ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_REGISTER_KEY,
657 					      0, 0, 0, 0xa2);
658 	nvmf_ns_reservation_register(&g_ns, &g_ctrlr2_A, req);
659 	/* Reservation conflict for other key than 0xa1 */
660 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_RESERVATION_CONFLICT);
661 
662 	/* g_ctrlr_B register with a new key */
663 	ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_REGISTER_KEY,
664 					      0, 0, 0, 0xb1);
665 	nvmf_ns_reservation_register(&g_ns, &g_ctrlr_B, req);
666 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
667 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_B.hostid);
668 	SPDK_CU_ASSERT_FATAL(reg->rkey == 0xb1);
669 	SPDK_CU_ASSERT_FATAL(g_ns.gen == gen + 2);
670 
671 	/* g_ctrlr_C register with a new key */
672 	ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_REGISTER_KEY,
673 					      0, 0, 0, 0xc1);
674 	nvmf_ns_reservation_register(&g_ns, &g_ctrlr_C, req);
675 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
676 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_C.hostid);
677 	SPDK_CU_ASSERT_FATAL(reg->rkey == 0xc1);
678 	SPDK_CU_ASSERT_FATAL(g_ns.gen == gen + 3);
679 
680 	ut_reservation_free_req(req);
681 }
682 
683 static void
684 test_reservation_register(void)
685 {
686 	struct spdk_nvmf_request *req;
687 	struct spdk_nvme_cpl *rsp;
688 	struct spdk_nvmf_registrant *reg;
689 	uint32_t gen;
690 
691 	ut_reservation_init();
692 
693 	req = ut_reservation_build_req(16);
694 	rsp = &req->rsp->nvme_cpl;
695 	SPDK_CU_ASSERT_FATAL(req != NULL);
696 
697 	ut_reservation_build_registrants();
698 
699 	/* TEST CASE: Replace g_ctrlr1_A with a new key */
700 	ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_REPLACE_KEY,
701 					      0, 0, 0xa1, 0xa11);
702 	nvmf_ns_reservation_register(&g_ns, &g_ctrlr1_A, req);
703 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
704 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr1_A.hostid);
705 	SPDK_CU_ASSERT_FATAL(reg->rkey == 0xa11);
706 
707 	/* TEST CASE: Host A with g_ctrlr1_A get reservation with
708 	 * type SPDK_NVME_RESERVE_WRITE_EXCLUSIVE
709 	 */
710 	ut_reservation_build_acquire_request(req, SPDK_NVME_RESERVE_ACQUIRE, 0,
711 					     SPDK_NVME_RESERVE_WRITE_EXCLUSIVE, 0xa11, 0x0);
712 	gen = g_ns.gen;
713 	nvmf_ns_reservation_acquire(&g_ns, &g_ctrlr1_A, req);
714 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
715 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr1_A.hostid);
716 	SPDK_CU_ASSERT_FATAL(g_ns.rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE);
717 	SPDK_CU_ASSERT_FATAL(g_ns.crkey == 0xa11);
718 	SPDK_CU_ASSERT_FATAL(g_ns.holder == reg);
719 	SPDK_CU_ASSERT_FATAL(g_ns.gen == gen);
720 
721 	/* TEST CASE: g_ctrlr_C unregister with IEKEY enabled */
722 	ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_UNREGISTER_KEY,
723 					      1, 0, 0, 0);
724 	nvmf_ns_reservation_register(&g_ns, &g_ctrlr_C, req);
725 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
726 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_C.hostid);
727 	SPDK_CU_ASSERT_FATAL(reg == NULL);
728 
729 	/* TEST CASE: g_ctrlr_B unregister with correct key */
730 	ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_UNREGISTER_KEY,
731 					      0, 0, 0xb1, 0);
732 	nvmf_ns_reservation_register(&g_ns, &g_ctrlr_B, req);
733 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
734 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_B.hostid);
735 	SPDK_CU_ASSERT_FATAL(reg == NULL);
736 
737 	/* TEST CASE: g_ctrlr1_A unregister with correct key,
738 	 * reservation should be removed as well.
739 	 */
740 	ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_UNREGISTER_KEY,
741 					      0, 0, 0xa11, 0);
742 	nvmf_ns_reservation_register(&g_ns, &g_ctrlr1_A, req);
743 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
744 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr1_A.hostid);
745 	SPDK_CU_ASSERT_FATAL(reg == NULL);
746 	SPDK_CU_ASSERT_FATAL(g_ns.rtype == 0);
747 	SPDK_CU_ASSERT_FATAL(g_ns.crkey == 0);
748 	SPDK_CU_ASSERT_FATAL(g_ns.holder == NULL);
749 
750 	ut_reservation_free_req(req);
751 	ut_reservation_deinit();
752 }
753 
754 static void
755 test_reservation_register_with_ptpl(void)
756 {
757 	struct spdk_nvmf_request *req;
758 	struct spdk_nvme_cpl *rsp;
759 	struct spdk_nvmf_registrant *reg;
760 	bool update_sgroup = false;
761 	int rc;
762 	struct spdk_nvmf_reservation_info info;
763 
764 	ut_reservation_init();
765 
766 	req = ut_reservation_build_req(16);
767 	rsp = &req->rsp->nvme_cpl;
768 	SPDK_CU_ASSERT_FATAL(req != NULL);
769 
770 	/* TEST CASE: No persistent file, register with PTPL enabled will fail */
771 	g_ns.ptpl_file = NULL;
772 	ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_REGISTER_KEY, 0,
773 					      SPDK_NVME_RESERVE_PTPL_PERSIST_POWER_LOSS, 0, 0xa1);
774 	update_sgroup = nvmf_ns_reservation_register(&g_ns, &g_ctrlr1_A, req);
775 	SPDK_CU_ASSERT_FATAL(update_sgroup == false);
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(reg == NULL);
779 
780 	/* TEST CASE: Enable PTPL */
781 	g_ns.ptpl_file = "/tmp/Ns1PR.cfg";
782 	ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_REGISTER_KEY, 0,
783 					      SPDK_NVME_RESERVE_PTPL_PERSIST_POWER_LOSS, 0, 0xa1);
784 	update_sgroup = nvmf_ns_reservation_register(&g_ns, &g_ctrlr1_A, req);
785 	SPDK_CU_ASSERT_FATAL(update_sgroup == true);
786 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
787 	SPDK_CU_ASSERT_FATAL(g_ns.ptpl_activated == true);
788 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr1_A.hostid);
789 	SPDK_CU_ASSERT_FATAL(reg != NULL);
790 	SPDK_CU_ASSERT_FATAL(!spdk_uuid_compare(&g_ctrlr1_A.hostid, &reg->hostid));
791 	/* Load reservation information from configuration file */
792 	memset(&info, 0, sizeof(info));
793 	rc = spdk_nvmf_ns_load_reservation(g_ns.ptpl_file, &info);
794 	SPDK_CU_ASSERT_FATAL(rc == 0);
795 	SPDK_CU_ASSERT_FATAL(info.ptpl_activated == true);
796 
797 	/* TEST CASE: Disable PTPL */
798 	rsp->status.sc = SPDK_NVME_SC_INVALID_FIELD;
799 	ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_REGISTER_KEY, 0,
800 					      SPDK_NVME_RESERVE_PTPL_CLEAR_POWER_ON, 0, 0xa1);
801 	update_sgroup = nvmf_ns_reservation_register(&g_ns, &g_ctrlr1_A, req);
802 	SPDK_CU_ASSERT_FATAL(update_sgroup == true);
803 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
804 	SPDK_CU_ASSERT_FATAL(g_ns.ptpl_activated == false);
805 	rc = spdk_nvmf_ns_load_reservation(g_ns.ptpl_file, &info);
806 	SPDK_CU_ASSERT_FATAL(rc < 0);
807 	unlink(g_ns.ptpl_file);
808 
809 	ut_reservation_free_req(req);
810 	ut_reservation_deinit();
811 }
812 
813 static void
814 test_reservation_acquire_preempt_1(void)
815 {
816 	struct spdk_nvmf_request *req;
817 	struct spdk_nvme_cpl *rsp;
818 	struct spdk_nvmf_registrant *reg;
819 	uint32_t gen;
820 
821 	ut_reservation_init();
822 
823 	req = ut_reservation_build_req(16);
824 	rsp = &req->rsp->nvme_cpl;
825 	SPDK_CU_ASSERT_FATAL(req != NULL);
826 
827 	ut_reservation_build_registrants();
828 
829 	gen = g_ns.gen;
830 	/* ACQUIRE: Host A with g_ctrlr1_A acquire reservation with
831 	 * type SPDK_NVME_RESERVE_WRITE_EXCLUSIVE.
832 	 */
833 	ut_reservation_build_acquire_request(req, SPDK_NVME_RESERVE_ACQUIRE, 0,
834 					     SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY, 0xa1, 0x0);
835 	nvmf_ns_reservation_acquire(&g_ns, &g_ctrlr1_A, req);
836 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
837 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr1_A.hostid);
838 	SPDK_CU_ASSERT_FATAL(g_ns.rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY);
839 	SPDK_CU_ASSERT_FATAL(g_ns.crkey == 0xa1);
840 	SPDK_CU_ASSERT_FATAL(g_ns.holder == reg);
841 	SPDK_CU_ASSERT_FATAL(g_ns.gen == gen);
842 
843 	/* TEST CASE: g_ctrlr1_A holds the reservation, g_ctrlr_B preempt g_ctrl1_A,
844 	 * g_ctrl1_A registrant is unregistred.
845 	 */
846 	gen = g_ns.gen;
847 	ut_reservation_build_acquire_request(req, SPDK_NVME_RESERVE_PREEMPT, 0,
848 					     SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS, 0xb1, 0xa1);
849 	nvmf_ns_reservation_acquire(&g_ns, &g_ctrlr_B, req);
850 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
851 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr1_A.hostid);
852 	SPDK_CU_ASSERT_FATAL(reg == NULL);
853 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_B.hostid);
854 	SPDK_CU_ASSERT_FATAL(reg != NULL);
855 	SPDK_CU_ASSERT_FATAL(g_ns.holder == reg);
856 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_C.hostid);
857 	SPDK_CU_ASSERT_FATAL(reg != NULL);
858 	SPDK_CU_ASSERT_FATAL(g_ns.rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS);
859 	SPDK_CU_ASSERT_FATAL(g_ns.gen > gen);
860 
861 	/* TEST CASE: g_ctrlr_B holds the reservation, g_ctrlr_C preempt g_ctrlr_B
862 	 * with valid key and PRKEY set to 0, all registrants other the host that issued
863 	 * the command are unregistered.
864 	 */
865 	gen = g_ns.gen;
866 	ut_reservation_build_acquire_request(req, SPDK_NVME_RESERVE_PREEMPT, 0,
867 					     SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS, 0xc1, 0x0);
868 	nvmf_ns_reservation_acquire(&g_ns, &g_ctrlr_C, req);
869 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
870 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr2_A.hostid);
871 	SPDK_CU_ASSERT_FATAL(reg == NULL);
872 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_B.hostid);
873 	SPDK_CU_ASSERT_FATAL(reg == NULL);
874 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_C.hostid);
875 	SPDK_CU_ASSERT_FATAL(reg != NULL);
876 	SPDK_CU_ASSERT_FATAL(g_ns.holder == reg);
877 	SPDK_CU_ASSERT_FATAL(g_ns.rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS);
878 	SPDK_CU_ASSERT_FATAL(g_ns.gen > gen);
879 
880 	ut_reservation_free_req(req);
881 	ut_reservation_deinit();
882 }
883 
884 static void
885 test_reservation_acquire_release_with_ptpl(void)
886 {
887 	struct spdk_nvmf_request *req;
888 	struct spdk_nvme_cpl *rsp;
889 	struct spdk_nvmf_registrant *reg;
890 	bool update_sgroup = false;
891 	struct spdk_uuid holder_uuid;
892 	int rc;
893 	struct spdk_nvmf_reservation_info info;
894 
895 	ut_reservation_init();
896 
897 	req = ut_reservation_build_req(16);
898 	rsp = &req->rsp->nvme_cpl;
899 	SPDK_CU_ASSERT_FATAL(req != NULL);
900 
901 	/* TEST CASE: Enable PTPL */
902 	g_ns.ptpl_file = "/tmp/Ns1PR.cfg";
903 	ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_REGISTER_KEY, 0,
904 					      SPDK_NVME_RESERVE_PTPL_PERSIST_POWER_LOSS, 0, 0xa1);
905 	update_sgroup = nvmf_ns_reservation_register(&g_ns, &g_ctrlr1_A, req);
906 	SPDK_CU_ASSERT_FATAL(update_sgroup == true);
907 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
908 	SPDK_CU_ASSERT_FATAL(g_ns.ptpl_activated == true);
909 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr1_A.hostid);
910 	SPDK_CU_ASSERT_FATAL(reg != NULL);
911 	SPDK_CU_ASSERT_FATAL(!spdk_uuid_compare(&g_ctrlr1_A.hostid, &reg->hostid));
912 	/* Load reservation information from configuration file */
913 	memset(&info, 0, sizeof(info));
914 	rc = spdk_nvmf_ns_load_reservation(g_ns.ptpl_file, &info);
915 	SPDK_CU_ASSERT_FATAL(rc == 0);
916 	SPDK_CU_ASSERT_FATAL(info.ptpl_activated == true);
917 
918 	/* TEST CASE: Acquire the reservation */
919 	rsp->status.sc = SPDK_NVME_SC_INVALID_FIELD;
920 	ut_reservation_build_acquire_request(req, SPDK_NVME_RESERVE_ACQUIRE, 0,
921 					     SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY, 0xa1, 0x0);
922 	update_sgroup = nvmf_ns_reservation_acquire(&g_ns, &g_ctrlr1_A, req);
923 	SPDK_CU_ASSERT_FATAL(update_sgroup == true);
924 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
925 	memset(&info, 0, sizeof(info));
926 	rc = spdk_nvmf_ns_load_reservation(g_ns.ptpl_file, &info);
927 	SPDK_CU_ASSERT_FATAL(rc == 0);
928 	SPDK_CU_ASSERT_FATAL(info.ptpl_activated == true);
929 	SPDK_CU_ASSERT_FATAL(info.rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY);
930 	SPDK_CU_ASSERT_FATAL(info.crkey == 0xa1);
931 	spdk_uuid_parse(&holder_uuid, info.holder_uuid);
932 	SPDK_CU_ASSERT_FATAL(!spdk_uuid_compare(&g_ctrlr1_A.hostid, &holder_uuid));
933 
934 	/* TEST CASE: Release the reservation */
935 	rsp->status.sc = SPDK_NVME_SC_INVALID_FIELD;
936 	ut_reservation_build_release_request(req, SPDK_NVME_RESERVE_RELEASE, 0,
937 					     SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY, 0xa1);
938 	update_sgroup = nvmf_ns_reservation_release(&g_ns, &g_ctrlr1_A, req);
939 	SPDK_CU_ASSERT_FATAL(update_sgroup == true);
940 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
941 	memset(&info, 0, sizeof(info));
942 	rc = spdk_nvmf_ns_load_reservation(g_ns.ptpl_file, &info);
943 	SPDK_CU_ASSERT_FATAL(rc == 0);
944 	SPDK_CU_ASSERT_FATAL(info.rtype == 0);
945 	SPDK_CU_ASSERT_FATAL(info.crkey == 0);
946 	SPDK_CU_ASSERT_FATAL(info.ptpl_activated == true);
947 	unlink(g_ns.ptpl_file);
948 
949 	ut_reservation_free_req(req);
950 	ut_reservation_deinit();
951 }
952 
953 static void
954 test_reservation_release(void)
955 {
956 	struct spdk_nvmf_request *req;
957 	struct spdk_nvme_cpl *rsp;
958 	struct spdk_nvmf_registrant *reg;
959 
960 	ut_reservation_init();
961 
962 	req = ut_reservation_build_req(16);
963 	rsp = &req->rsp->nvme_cpl;
964 	SPDK_CU_ASSERT_FATAL(req != NULL);
965 
966 	ut_reservation_build_registrants();
967 
968 	/* ACQUIRE: Host A with g_ctrlr1_A get reservation with
969 	 * type SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS
970 	 */
971 	ut_reservation_build_acquire_request(req, SPDK_NVME_RESERVE_ACQUIRE, 0,
972 					     SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS, 0xa1, 0x0);
973 	nvmf_ns_reservation_acquire(&g_ns, &g_ctrlr1_A, req);
974 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
975 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr1_A.hostid);
976 	SPDK_CU_ASSERT_FATAL(g_ns.rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS);
977 	SPDK_CU_ASSERT_FATAL(g_ns.holder == reg);
978 
979 	/* Test Case: Host B release the reservation */
980 	ut_reservation_build_release_request(req, SPDK_NVME_RESERVE_RELEASE, 0,
981 					     SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS, 0xb1);
982 	nvmf_ns_reservation_release(&g_ns, &g_ctrlr_B, req);
983 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
984 	SPDK_CU_ASSERT_FATAL(g_ns.rtype == 0);
985 	SPDK_CU_ASSERT_FATAL(g_ns.crkey == 0);
986 	SPDK_CU_ASSERT_FATAL(g_ns.holder == NULL);
987 
988 	/* Test Case: Host C clear the registrants */
989 	ut_reservation_build_release_request(req, SPDK_NVME_RESERVE_CLEAR, 0,
990 					     0, 0xc1);
991 	nvmf_ns_reservation_release(&g_ns, &g_ctrlr_C, req);
992 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
993 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr1_A.hostid);
994 	SPDK_CU_ASSERT_FATAL(reg == NULL);
995 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr2_A.hostid);
996 	SPDK_CU_ASSERT_FATAL(reg == NULL);
997 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_B.hostid);
998 	SPDK_CU_ASSERT_FATAL(reg == NULL);
999 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_C.hostid);
1000 	SPDK_CU_ASSERT_FATAL(reg == NULL);
1001 
1002 	ut_reservation_free_req(req);
1003 	ut_reservation_deinit();
1004 }
1005 
1006 void
1007 spdk_nvmf_ctrlr_reservation_notice_log(struct spdk_nvmf_ctrlr *ctrlr,
1008 				       struct spdk_nvmf_ns *ns,
1009 				       enum spdk_nvme_reservation_notification_log_page_type type)
1010 {
1011 	ctrlr->num_avail_log_pages++;
1012 }
1013 
1014 static void
1015 test_reservation_unregister_notification(void)
1016 {
1017 	struct spdk_nvmf_request *req;
1018 	struct spdk_nvme_cpl *rsp;
1019 
1020 	ut_reservation_init();
1021 
1022 	req = ut_reservation_build_req(16);
1023 	SPDK_CU_ASSERT_FATAL(req != NULL);
1024 	rsp = &req->rsp->nvme_cpl;
1025 
1026 	ut_reservation_build_registrants();
1027 
1028 	/* ACQUIRE: Host B with g_ctrlr_B get reservation with
1029 	 * type SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY
1030 	 */
1031 	rsp->status.sc = 0xff;
1032 	ut_reservation_build_acquire_request(req, SPDK_NVME_RESERVE_ACQUIRE, 0,
1033 					     SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY, 0xb1, 0x0);
1034 	nvmf_ns_reservation_acquire(&g_ns, &g_ctrlr_B, req);
1035 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
1036 	SPDK_CU_ASSERT_FATAL(g_ns.rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY);
1037 
1038 	/* Test Case : g_ctrlr_B holds the reservation, g_ctrlr_B unregister the registration.
1039 	 * Reservation release notification sends to g_ctrlr1_A/g_ctrlr2_A/g_ctrlr_C only for
1040 	 * SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY or SPDK_NVME_RESERVE_EXCLUSIVE_ACCESS_REG_ONLY
1041 	 * type.
1042 	 */
1043 	rsp->status.sc = 0xff;
1044 	g_ctrlr1_A.num_avail_log_pages = 0;
1045 	g_ctrlr2_A.num_avail_log_pages = 0;
1046 	g_ctrlr_B.num_avail_log_pages = 5;
1047 	g_ctrlr_C.num_avail_log_pages = 0;
1048 	ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_UNREGISTER_KEY,
1049 					      0, 0, 0xb1, 0);
1050 	nvmf_ns_reservation_register(&g_ns, &g_ctrlr_B, req);
1051 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
1052 	SPDK_CU_ASSERT_FATAL(g_ns.rtype == 0);
1053 	SPDK_CU_ASSERT_FATAL(1 == g_ctrlr1_A.num_avail_log_pages);
1054 	SPDK_CU_ASSERT_FATAL(1 == g_ctrlr2_A.num_avail_log_pages);
1055 	SPDK_CU_ASSERT_FATAL(5 == g_ctrlr_B.num_avail_log_pages);
1056 	SPDK_CU_ASSERT_FATAL(1 == g_ctrlr_C.num_avail_log_pages);
1057 
1058 	ut_reservation_free_req(req);
1059 	ut_reservation_deinit();
1060 }
1061 
1062 static void
1063 test_reservation_release_notification(void)
1064 {
1065 	struct spdk_nvmf_request *req;
1066 	struct spdk_nvme_cpl *rsp;
1067 
1068 	ut_reservation_init();
1069 
1070 	req = ut_reservation_build_req(16);
1071 	SPDK_CU_ASSERT_FATAL(req != NULL);
1072 	rsp = &req->rsp->nvme_cpl;
1073 
1074 	ut_reservation_build_registrants();
1075 
1076 	/* ACQUIRE: Host B with g_ctrlr_B get reservation with
1077 	 * type SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY
1078 	 */
1079 	rsp->status.sc = 0xff;
1080 	ut_reservation_build_acquire_request(req, SPDK_NVME_RESERVE_ACQUIRE, 0,
1081 					     SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY, 0xb1, 0x0);
1082 	nvmf_ns_reservation_acquire(&g_ns, &g_ctrlr_B, req);
1083 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
1084 	SPDK_CU_ASSERT_FATAL(g_ns.rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY);
1085 
1086 	/* Test Case : g_ctrlr_B holds the reservation, g_ctrlr_B release the reservation.
1087 	 * Reservation release notification sends to g_ctrlr1_A/g_ctrlr2_A/g_ctrlr_C.
1088 	 */
1089 	rsp->status.sc = 0xff;
1090 	g_ctrlr1_A.num_avail_log_pages = 0;
1091 	g_ctrlr2_A.num_avail_log_pages = 0;
1092 	g_ctrlr_B.num_avail_log_pages = 5;
1093 	g_ctrlr_C.num_avail_log_pages = 0;
1094 	ut_reservation_build_release_request(req, SPDK_NVME_RESERVE_RELEASE, 0,
1095 					     SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY, 0xb1);
1096 	nvmf_ns_reservation_release(&g_ns, &g_ctrlr_B, req);
1097 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
1098 	SPDK_CU_ASSERT_FATAL(g_ns.rtype == 0);
1099 	SPDK_CU_ASSERT_FATAL(1 == g_ctrlr1_A.num_avail_log_pages);
1100 	SPDK_CU_ASSERT_FATAL(1 == g_ctrlr2_A.num_avail_log_pages);
1101 	SPDK_CU_ASSERT_FATAL(5 == g_ctrlr_B.num_avail_log_pages);
1102 	SPDK_CU_ASSERT_FATAL(1 == g_ctrlr_C.num_avail_log_pages);
1103 
1104 	ut_reservation_free_req(req);
1105 	ut_reservation_deinit();
1106 }
1107 
1108 static void
1109 test_reservation_release_notification_write_exclusive(void)
1110 {
1111 	struct spdk_nvmf_request *req;
1112 	struct spdk_nvme_cpl *rsp;
1113 
1114 	ut_reservation_init();
1115 
1116 	req = ut_reservation_build_req(16);
1117 	SPDK_CU_ASSERT_FATAL(req != NULL);
1118 	rsp = &req->rsp->nvme_cpl;
1119 
1120 	ut_reservation_build_registrants();
1121 
1122 	/* ACQUIRE: Host B with g_ctrlr_B get reservation with
1123 	 * type SPDK_NVME_RESERVE_WRITE_EXCLUSIVE
1124 	 */
1125 	rsp->status.sc = 0xff;
1126 	ut_reservation_build_acquire_request(req, SPDK_NVME_RESERVE_ACQUIRE, 0,
1127 					     SPDK_NVME_RESERVE_WRITE_EXCLUSIVE, 0xb1, 0x0);
1128 	nvmf_ns_reservation_acquire(&g_ns, &g_ctrlr_B, req);
1129 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
1130 	SPDK_CU_ASSERT_FATAL(g_ns.rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE);
1131 
1132 	/* Test Case : g_ctrlr_B holds the reservation, g_ctrlr_B release the reservation.
1133 	 * Because the reservation type is SPDK_NVME_RESERVE_WRITE_EXCLUSIVE,
1134 	 * no reservation notification occurs.
1135 	 */
1136 	rsp->status.sc = 0xff;
1137 	g_ctrlr1_A.num_avail_log_pages = 5;
1138 	g_ctrlr2_A.num_avail_log_pages = 5;
1139 	g_ctrlr_B.num_avail_log_pages = 5;
1140 	g_ctrlr_C.num_avail_log_pages = 5;
1141 	ut_reservation_build_release_request(req, SPDK_NVME_RESERVE_RELEASE, 0,
1142 					     SPDK_NVME_RESERVE_WRITE_EXCLUSIVE, 0xb1);
1143 	nvmf_ns_reservation_release(&g_ns, &g_ctrlr_B, req);
1144 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
1145 	SPDK_CU_ASSERT_FATAL(g_ns.rtype == 0);
1146 	SPDK_CU_ASSERT_FATAL(5 == g_ctrlr1_A.num_avail_log_pages);
1147 	SPDK_CU_ASSERT_FATAL(5 == g_ctrlr2_A.num_avail_log_pages);
1148 	SPDK_CU_ASSERT_FATAL(5 == g_ctrlr_B.num_avail_log_pages);
1149 	SPDK_CU_ASSERT_FATAL(5 == g_ctrlr_C.num_avail_log_pages);
1150 
1151 	ut_reservation_free_req(req);
1152 	ut_reservation_deinit();
1153 }
1154 
1155 static void
1156 test_reservation_clear_notification(void)
1157 {
1158 	struct spdk_nvmf_request *req;
1159 	struct spdk_nvme_cpl *rsp;
1160 
1161 	ut_reservation_init();
1162 
1163 	req = ut_reservation_build_req(16);
1164 	SPDK_CU_ASSERT_FATAL(req != NULL);
1165 	rsp = &req->rsp->nvme_cpl;
1166 
1167 	ut_reservation_build_registrants();
1168 
1169 	/* ACQUIRE: Host B with g_ctrlr_B get reservation with
1170 	 * type SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY
1171 	 */
1172 	rsp->status.sc = 0xff;
1173 	ut_reservation_build_acquire_request(req, SPDK_NVME_RESERVE_ACQUIRE, 0,
1174 					     SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY, 0xb1, 0x0);
1175 	nvmf_ns_reservation_acquire(&g_ns, &g_ctrlr_B, req);
1176 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
1177 	SPDK_CU_ASSERT_FATAL(g_ns.rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY);
1178 
1179 	/* Test Case : g_ctrlr_B holds the reservation, g_ctrlr_B clear the reservation.
1180 	 * Reservation Preempted notification sends to g_ctrlr1_A/g_ctrlr2_A/g_ctrlr_C.
1181 	 */
1182 	rsp->status.sc = 0xff;
1183 	g_ctrlr1_A.num_avail_log_pages = 0;
1184 	g_ctrlr2_A.num_avail_log_pages = 0;
1185 	g_ctrlr_B.num_avail_log_pages = 5;
1186 	g_ctrlr_C.num_avail_log_pages = 0;
1187 	ut_reservation_build_release_request(req, SPDK_NVME_RESERVE_CLEAR, 0,
1188 					     0, 0xb1);
1189 	nvmf_ns_reservation_release(&g_ns, &g_ctrlr_B, req);
1190 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
1191 	SPDK_CU_ASSERT_FATAL(g_ns.rtype == 0);
1192 	SPDK_CU_ASSERT_FATAL(1 == g_ctrlr1_A.num_avail_log_pages);
1193 	SPDK_CU_ASSERT_FATAL(1 == g_ctrlr2_A.num_avail_log_pages);
1194 	SPDK_CU_ASSERT_FATAL(5 == g_ctrlr_B.num_avail_log_pages);
1195 	SPDK_CU_ASSERT_FATAL(1 == g_ctrlr_C.num_avail_log_pages);
1196 
1197 	ut_reservation_free_req(req);
1198 	ut_reservation_deinit();
1199 }
1200 
1201 static void
1202 test_reservation_preempt_notification(void)
1203 {
1204 	struct spdk_nvmf_request *req;
1205 	struct spdk_nvme_cpl *rsp;
1206 
1207 	ut_reservation_init();
1208 
1209 	req = ut_reservation_build_req(16);
1210 	SPDK_CU_ASSERT_FATAL(req != NULL);
1211 	rsp = &req->rsp->nvme_cpl;
1212 
1213 	ut_reservation_build_registrants();
1214 
1215 	/* ACQUIRE: Host B with g_ctrlr_B get reservation with
1216 	 * type SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY
1217 	 */
1218 	rsp->status.sc = 0xff;
1219 	ut_reservation_build_acquire_request(req, SPDK_NVME_RESERVE_ACQUIRE, 0,
1220 					     SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY, 0xb1, 0x0);
1221 	nvmf_ns_reservation_acquire(&g_ns, &g_ctrlr_B, req);
1222 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
1223 	SPDK_CU_ASSERT_FATAL(g_ns.rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY);
1224 
1225 	/* Test Case : g_ctrlr_B holds the reservation, g_ctrlr_C preempt g_ctrlr_B,
1226 	 * g_ctrlr_B registrant is unregistred, and reservation is preempted.
1227 	 * Registration Preempted notification sends to g_ctrlr_B.
1228 	 * Reservation Preempted notification sends to g_ctrlr1_A/g_ctrlr2_A.
1229 	 */
1230 	rsp->status.sc = 0xff;
1231 	g_ctrlr1_A.num_avail_log_pages = 0;
1232 	g_ctrlr2_A.num_avail_log_pages = 0;
1233 	g_ctrlr_B.num_avail_log_pages = 0;
1234 	g_ctrlr_C.num_avail_log_pages = 5;
1235 	ut_reservation_build_acquire_request(req, SPDK_NVME_RESERVE_PREEMPT, 0,
1236 					     SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS, 0xc1, 0xb1);
1237 	nvmf_ns_reservation_acquire(&g_ns, &g_ctrlr_C, req);
1238 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
1239 	SPDK_CU_ASSERT_FATAL(g_ns.rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS);
1240 	SPDK_CU_ASSERT_FATAL(1 == g_ctrlr1_A.num_avail_log_pages);
1241 	SPDK_CU_ASSERT_FATAL(1 == g_ctrlr2_A.num_avail_log_pages);
1242 	SPDK_CU_ASSERT_FATAL(1 == g_ctrlr_B.num_avail_log_pages);
1243 	SPDK_CU_ASSERT_FATAL(5 == g_ctrlr_C.num_avail_log_pages);
1244 
1245 	ut_reservation_free_req(req);
1246 	ut_reservation_deinit();
1247 }
1248 
1249 int main(int argc, char **argv)
1250 {
1251 	CU_pSuite	suite = NULL;
1252 	unsigned int	num_failures;
1253 
1254 	if (CU_initialize_registry() != CUE_SUCCESS) {
1255 		return CU_get_error();
1256 	}
1257 
1258 	suite = CU_add_suite("nvmf", NULL, NULL);
1259 	if (suite == NULL) {
1260 		CU_cleanup_registry();
1261 		return CU_get_error();
1262 	}
1263 
1264 	if (
1265 		CU_add_test(suite, "create_subsystem", nvmf_test_create_subsystem) == NULL ||
1266 		CU_add_test(suite, "nvmf_subsystem_add_ns", test_spdk_nvmf_subsystem_add_ns) == NULL ||
1267 		CU_add_test(suite, "nvmf_subsystem_set_sn", test_spdk_nvmf_subsystem_set_sn) == NULL ||
1268 		CU_add_test(suite, "reservation_register", test_reservation_register) == NULL ||
1269 		CU_add_test(suite, "reservation_register_with_ptpl", test_reservation_register_with_ptpl) == NULL ||
1270 		CU_add_test(suite, "reservation_acquire_preempt_1", test_reservation_acquire_preempt_1) == NULL ||
1271 		CU_add_test(suite, "reservation_acquire_release_with_ptpl",
1272 			    test_reservation_acquire_release_with_ptpl) == NULL ||
1273 		CU_add_test(suite, "reservation_release", test_reservation_release) == NULL ||
1274 		CU_add_test(suite, "reservation_unregister_notification",
1275 			    test_reservation_unregister_notification) == NULL ||
1276 		CU_add_test(suite, "reservation_release_notification",
1277 			    test_reservation_release_notification) == NULL ||
1278 		CU_add_test(suite, "reservation_release_notification_write_exclusive",
1279 			    test_reservation_release_notification_write_exclusive) == NULL ||
1280 		CU_add_test(suite, "reservation_clear_notification", test_reservation_clear_notification) == NULL ||
1281 		CU_add_test(suite, "reservation_preempt_notification",
1282 			    test_reservation_preempt_notification) == NULL
1283 	) {
1284 		CU_cleanup_registry();
1285 		return CU_get_error();
1286 	}
1287 
1288 	allocate_threads(1);
1289 	set_thread(0);
1290 
1291 	CU_basic_set_mode(CU_BRM_VERBOSE);
1292 	CU_basic_run_tests();
1293 	num_failures = CU_get_number_of_failures();
1294 	CU_cleanup_registry();
1295 
1296 	free_threads();
1297 
1298 	return num_failures;
1299 }
1300