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