xref: /spdk/lib/nvmf/subsystem.c (revision bb64a7e5118f36b264b0de2a9ef77f22f8d0dbd7)
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 "nvmf_internal.h"
37 #include "transport.h"
38 
39 #include "spdk/event.h"
40 #include "spdk/likely.h"
41 #include "spdk/string.h"
42 #include "spdk/trace.h"
43 #include "spdk/nvmf_spec.h"
44 #include "spdk/uuid.h"
45 
46 #include "spdk/bdev_module.h"
47 #include "spdk_internal/log.h"
48 #include "spdk_internal/utf.h"
49 
50 /*
51  * States for parsing valid domains in NQNs according to RFC 1034
52  */
53 enum spdk_nvmf_nqn_domain_states {
54 	/* First character of a domain must be a letter */
55 	SPDK_NVMF_DOMAIN_ACCEPT_LETTER = 0,
56 
57 	/* Subsequent characters can be any of letter, digit, or hyphen */
58 	SPDK_NVMF_DOMAIN_ACCEPT_LDH = 1,
59 
60 	/* A domain label must end with either a letter or digit */
61 	SPDK_NVMF_DOMAIN_ACCEPT_ANY = 2
62 };
63 
64 /* Returns true if is a valid ASCII string as defined by the NVMe spec */
65 static bool
66 spdk_nvmf_valid_ascii_string(const void *buf, size_t size)
67 {
68 	const uint8_t *str = buf;
69 	size_t i;
70 
71 	for (i = 0; i < size; i++) {
72 		if (str[i] < 0x20 || str[i] > 0x7E) {
73 			return false;
74 		}
75 	}
76 
77 	return true;
78 }
79 
80 static bool
81 spdk_nvmf_valid_nqn(const char *nqn)
82 {
83 	size_t len;
84 	struct spdk_uuid uuid_value;
85 	uint32_t i;
86 	int bytes_consumed;
87 	uint32_t domain_label_length;
88 	char *reverse_domain_end;
89 	uint32_t reverse_domain_end_index;
90 	enum spdk_nvmf_nqn_domain_states domain_state = SPDK_NVMF_DOMAIN_ACCEPT_LETTER;
91 
92 	/* Check for length requirements */
93 	len = strlen(nqn);
94 	if (len > SPDK_NVMF_NQN_MAX_LEN) {
95 		SPDK_ERRLOG("Invalid NQN \"%s\": length %zu > max %d\n", nqn, len, SPDK_NVMF_NQN_MAX_LEN);
96 		return false;
97 	}
98 
99 	/* The nqn must be at least as long as SPDK_NVMF_NQN_MIN_LEN to contain the necessary prefix. */
100 	if (len < SPDK_NVMF_NQN_MIN_LEN) {
101 		SPDK_ERRLOG("Invalid NQN \"%s\": length %zu < min %d\n", nqn, len, SPDK_NVMF_NQN_MIN_LEN);
102 		return false;
103 	}
104 
105 	/* Check for discovery controller nqn */
106 	if (!strcmp(nqn, SPDK_NVMF_DISCOVERY_NQN)) {
107 		return true;
108 	}
109 
110 	/* Check for equality with the generic nqn structure of the form "nqn.2014-08.org.nvmexpress:uuid:11111111-2222-3333-4444-555555555555" */
111 	if (!strncmp(nqn, SPDK_NVMF_NQN_UUID_PRE, SPDK_NVMF_NQN_UUID_PRE_LEN)) {
112 		if (len != SPDK_NVMF_NQN_UUID_PRE_LEN + SPDK_NVMF_UUID_STRING_LEN) {
113 			SPDK_ERRLOG("Invalid NQN \"%s\": uuid is not the correct length\n", nqn);
114 			return false;
115 		}
116 
117 		if (spdk_uuid_parse(&uuid_value, &nqn[SPDK_NVMF_NQN_UUID_PRE_LEN])) {
118 			SPDK_ERRLOG("Invalid NQN \"%s\": uuid is not formatted correctly\n", nqn);
119 			return false;
120 		}
121 		return true;
122 	}
123 
124 	/* If the nqn does not match the uuid structure, the next several checks validate the form "nqn.yyyy-mm.reverse.domain:user-string" */
125 
126 	if (strncmp(nqn, "nqn.", 4) != 0) {
127 		SPDK_ERRLOG("Invalid NQN \"%s\": NQN must begin with \"nqn.\".\n", nqn);
128 		return false;
129 	}
130 
131 	/* Check for yyyy-mm. */
132 	if (!(isdigit(nqn[4]) && isdigit(nqn[5]) && isdigit(nqn[6]) && isdigit(nqn[7]) &&
133 	      nqn[8] == '-' && isdigit(nqn[9]) && isdigit(nqn[10]) && nqn[11] == '.')) {
134 		SPDK_ERRLOG("Invalid date code in NQN \"%s\"\n", nqn);
135 		return false;
136 	}
137 
138 	reverse_domain_end = strchr(nqn, ':');
139 	if (reverse_domain_end != NULL && (reverse_domain_end_index = reverse_domain_end - nqn) < len - 1) {
140 	} else {
141 		SPDK_ERRLOG("Invalid NQN \"%s\". NQN must contain user specified name with a ':' as a prefix.\n",
142 			    nqn);
143 		return false;
144 	}
145 
146 	/* Check for valid reverse domain */
147 	domain_label_length = 0;
148 	for (i = 12; i < reverse_domain_end_index; i++) {
149 		if (domain_label_length > SPDK_DOMAIN_LABEL_MAX_LEN) {
150 			SPDK_ERRLOG("Invalid domain name in NQN \"%s\". At least one Label is too long.\n", nqn);
151 			return false;
152 		}
153 
154 		switch (domain_state) {
155 
156 		case SPDK_NVMF_DOMAIN_ACCEPT_LETTER: {
157 			if (isalpha(nqn[i])) {
158 				domain_state = SPDK_NVMF_DOMAIN_ACCEPT_ANY;
159 				domain_label_length++;
160 				break;
161 			} else {
162 				SPDK_ERRLOG("Invalid domain name in NQN \"%s\". Label names must start with a letter.\n", nqn);
163 				return false;
164 			}
165 		}
166 
167 		case SPDK_NVMF_DOMAIN_ACCEPT_LDH: {
168 			if (isalpha(nqn[i]) || isdigit(nqn[i])) {
169 				domain_state = SPDK_NVMF_DOMAIN_ACCEPT_ANY;
170 				domain_label_length++;
171 				break;
172 			} else if (nqn[i] == '-') {
173 				if (i == reverse_domain_end_index - 1) {
174 					SPDK_ERRLOG("Invalid domain name in NQN \"%s\". Label names must end with an alphanumeric symbol.\n",
175 						    nqn);
176 					return false;
177 				}
178 				domain_state = SPDK_NVMF_DOMAIN_ACCEPT_LDH;
179 				domain_label_length++;
180 				break;
181 			} else if (nqn[i] == '.') {
182 				SPDK_ERRLOG("Invalid domain name in NQN \"%s\". Label names must end with an alphanumeric symbol.\n",
183 					    nqn);
184 				return false;
185 			} else {
186 				SPDK_ERRLOG("Invalid domain name in NQN \"%s\". Label names must contain only [a-z,A-Z,0-9,'-','.'].\n",
187 					    nqn);
188 				return false;
189 			}
190 		}
191 
192 		case SPDK_NVMF_DOMAIN_ACCEPT_ANY: {
193 			if (isalpha(nqn[i]) || isdigit(nqn[i])) {
194 				domain_state = SPDK_NVMF_DOMAIN_ACCEPT_ANY;
195 				domain_label_length++;
196 				break;
197 			} else if (nqn[i] == '-') {
198 				if (i == reverse_domain_end_index - 1) {
199 					SPDK_ERRLOG("Invalid domain name in NQN \"%s\". Label names must end with an alphanumeric symbol.\n",
200 						    nqn);
201 					return false;
202 				}
203 				domain_state = SPDK_NVMF_DOMAIN_ACCEPT_LDH;
204 				domain_label_length++;
205 				break;
206 			} else if (nqn[i] == '.') {
207 				domain_state = SPDK_NVMF_DOMAIN_ACCEPT_LETTER;
208 				domain_label_length = 0;
209 				break;
210 			} else {
211 				SPDK_ERRLOG("Invalid domain name in NQN \"%s\". Label names must contain only [a-z,A-Z,0-9,'-','.'].\n",
212 					    nqn);
213 				return false;
214 			}
215 		}
216 		}
217 	}
218 
219 	i = reverse_domain_end_index + 1;
220 	while (i < len) {
221 		bytes_consumed = utf8_valid(&nqn[i], &nqn[len]);
222 		if (bytes_consumed <= 0) {
223 			SPDK_ERRLOG("Invalid domain name in NQN \"%s\". Label names must contain only valid utf-8.\n", nqn);
224 			return false;
225 		}
226 
227 		i += bytes_consumed;
228 	}
229 	return true;
230 }
231 
232 struct spdk_nvmf_subsystem *
233 spdk_nvmf_subsystem_create(struct spdk_nvmf_tgt *tgt,
234 			   const char *nqn,
235 			   enum spdk_nvmf_subtype type,
236 			   uint32_t num_ns)
237 {
238 	struct spdk_nvmf_subsystem	*subsystem;
239 	uint32_t			sid;
240 
241 	if (spdk_nvmf_tgt_find_subsystem(tgt, nqn)) {
242 		SPDK_ERRLOG("Subsystem NQN '%s' already exists\n", nqn);
243 		return NULL;
244 	}
245 
246 	if (!spdk_nvmf_valid_nqn(nqn)) {
247 		return NULL;
248 	}
249 
250 	if (type == SPDK_NVMF_SUBTYPE_DISCOVERY && num_ns != 0) {
251 		SPDK_ERRLOG("Discovery subsystem cannot have namespaces.\n");
252 		return NULL;
253 	}
254 
255 	/* Find a free subsystem id (sid) */
256 	for (sid = 0; sid < tgt->max_subsystems; sid++) {
257 		if (tgt->subsystems[sid] == NULL) {
258 			break;
259 		}
260 	}
261 	if (sid >= tgt->max_subsystems) {
262 		return NULL;
263 	}
264 
265 	subsystem = calloc(1, sizeof(struct spdk_nvmf_subsystem));
266 	if (subsystem == NULL) {
267 		return NULL;
268 	}
269 
270 	subsystem->thread = spdk_get_thread();
271 	subsystem->state = SPDK_NVMF_SUBSYSTEM_INACTIVE;
272 	subsystem->tgt = tgt;
273 	subsystem->id = sid;
274 	subsystem->subtype = type;
275 	subsystem->max_nsid = num_ns;
276 	subsystem->max_allowed_nsid = num_ns;
277 	subsystem->next_cntlid = 0;
278 	snprintf(subsystem->subnqn, sizeof(subsystem->subnqn), "%s", nqn);
279 	TAILQ_INIT(&subsystem->listeners);
280 	TAILQ_INIT(&subsystem->hosts);
281 	TAILQ_INIT(&subsystem->ctrlrs);
282 
283 	if (num_ns != 0) {
284 		subsystem->ns = calloc(num_ns, sizeof(struct spdk_nvmf_ns *));
285 		if (subsystem->ns == NULL) {
286 			SPDK_ERRLOG("Namespace memory allocation failed\n");
287 			free(subsystem);
288 			return NULL;
289 		}
290 	}
291 
292 	memset(subsystem->sn, '0', sizeof(subsystem->sn) - 1);
293 	subsystem->sn[sizeof(subsystem->sn) - 1] = '\0';
294 
295 	tgt->subsystems[sid] = subsystem;
296 	tgt->discovery_genctr++;
297 
298 	return subsystem;
299 }
300 
301 static void
302 _spdk_nvmf_subsystem_remove_host(struct spdk_nvmf_subsystem *subsystem, struct spdk_nvmf_host *host)
303 {
304 	TAILQ_REMOVE(&subsystem->hosts, host, link);
305 	free(host->nqn);
306 	free(host);
307 }
308 
309 static int _spdk_nvmf_subsystem_remove_ns(struct spdk_nvmf_subsystem *subsystem, uint32_t nsid);
310 
311 static void
312 _nvmf_subsystem_remove_listener(struct spdk_nvmf_subsystem *subsystem,
313 				struct spdk_nvmf_listener *listener)
314 {
315 	struct spdk_nvmf_transport *transport;
316 
317 	transport = spdk_nvmf_tgt_get_transport(subsystem->tgt, listener->trid.trtype);
318 	if (transport != NULL) {
319 		spdk_nvmf_transport_stop_listen(transport, &listener->trid);
320 	}
321 
322 	TAILQ_REMOVE(&subsystem->listeners, listener, link);
323 	free(listener);
324 }
325 
326 void
327 spdk_nvmf_subsystem_destroy(struct spdk_nvmf_subsystem *subsystem)
328 {
329 	struct spdk_nvmf_listener	*listener, *listener_tmp;
330 	struct spdk_nvmf_host		*host, *host_tmp;
331 	struct spdk_nvmf_ctrlr		*ctrlr, *ctrlr_tmp;
332 	struct spdk_nvmf_ns		*ns;
333 
334 	if (!subsystem) {
335 		return;
336 	}
337 
338 	assert(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE);
339 
340 	SPDK_DEBUGLOG(SPDK_LOG_NVMF, "subsystem is %p\n", subsystem);
341 
342 	TAILQ_FOREACH_SAFE(listener, &subsystem->listeners, link, listener_tmp) {
343 		_nvmf_subsystem_remove_listener(subsystem, listener);
344 	}
345 
346 	TAILQ_FOREACH_SAFE(host, &subsystem->hosts, link, host_tmp) {
347 		_spdk_nvmf_subsystem_remove_host(subsystem, host);
348 	}
349 
350 	TAILQ_FOREACH_SAFE(ctrlr, &subsystem->ctrlrs, link, ctrlr_tmp) {
351 		spdk_nvmf_ctrlr_destruct(ctrlr);
352 	}
353 
354 	ns = spdk_nvmf_subsystem_get_first_ns(subsystem);
355 	while (ns != NULL) {
356 		struct spdk_nvmf_ns *next_ns = spdk_nvmf_subsystem_get_next_ns(subsystem, ns);
357 
358 		_spdk_nvmf_subsystem_remove_ns(subsystem, ns->opts.nsid);
359 		ns = next_ns;
360 	}
361 
362 	free(subsystem->ns);
363 
364 	subsystem->tgt->subsystems[subsystem->id] = NULL;
365 	subsystem->tgt->discovery_genctr++;
366 
367 	free(subsystem);
368 }
369 
370 static int
371 spdk_nvmf_subsystem_set_state(struct spdk_nvmf_subsystem *subsystem,
372 			      enum spdk_nvmf_subsystem_state state)
373 {
374 	enum spdk_nvmf_subsystem_state actual_old_state, expected_old_state;
375 
376 	switch (state) {
377 	case SPDK_NVMF_SUBSYSTEM_INACTIVE:
378 		expected_old_state = SPDK_NVMF_SUBSYSTEM_DEACTIVATING;
379 		break;
380 	case SPDK_NVMF_SUBSYSTEM_ACTIVATING:
381 		expected_old_state = SPDK_NVMF_SUBSYSTEM_INACTIVE;
382 		break;
383 	case SPDK_NVMF_SUBSYSTEM_ACTIVE:
384 		expected_old_state = SPDK_NVMF_SUBSYSTEM_ACTIVATING;
385 		break;
386 	case SPDK_NVMF_SUBSYSTEM_PAUSING:
387 		expected_old_state = SPDK_NVMF_SUBSYSTEM_ACTIVE;
388 		break;
389 	case SPDK_NVMF_SUBSYSTEM_PAUSED:
390 		expected_old_state = SPDK_NVMF_SUBSYSTEM_PAUSING;
391 		break;
392 	case SPDK_NVMF_SUBSYSTEM_RESUMING:
393 		expected_old_state = SPDK_NVMF_SUBSYSTEM_PAUSED;
394 		break;
395 	case SPDK_NVMF_SUBSYSTEM_DEACTIVATING:
396 		expected_old_state = SPDK_NVMF_SUBSYSTEM_ACTIVE;
397 		break;
398 	default:
399 		assert(false);
400 		return -1;
401 	}
402 
403 	actual_old_state = __sync_val_compare_and_swap(&subsystem->state, expected_old_state, state);
404 	if (actual_old_state != expected_old_state) {
405 		if (actual_old_state == SPDK_NVMF_SUBSYSTEM_RESUMING &&
406 		    state == SPDK_NVMF_SUBSYSTEM_ACTIVE) {
407 			expected_old_state = SPDK_NVMF_SUBSYSTEM_RESUMING;
408 		}
409 		/* This is for the case when activating the subsystem fails. */
410 		if (actual_old_state == SPDK_NVMF_SUBSYSTEM_ACTIVATING &&
411 		    state == SPDK_NVMF_SUBSYSTEM_DEACTIVATING) {
412 			expected_old_state = SPDK_NVMF_SUBSYSTEM_ACTIVATING;
413 		}
414 		actual_old_state = __sync_val_compare_and_swap(&subsystem->state, expected_old_state, state);
415 	}
416 	assert(actual_old_state == expected_old_state);
417 	return actual_old_state - expected_old_state;
418 }
419 
420 struct subsystem_state_change_ctx {
421 	struct spdk_nvmf_subsystem *subsystem;
422 
423 	enum spdk_nvmf_subsystem_state requested_state;
424 
425 	spdk_nvmf_subsystem_state_change_done cb_fn;
426 	void *cb_arg;
427 };
428 
429 static void
430 subsystem_state_change_done(struct spdk_io_channel_iter *i, int status)
431 {
432 	struct subsystem_state_change_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
433 
434 	if (status == 0) {
435 		status = spdk_nvmf_subsystem_set_state(ctx->subsystem, ctx->requested_state);
436 		if (status) {
437 			status = -1;
438 		}
439 	}
440 
441 	if (ctx->cb_fn) {
442 		ctx->cb_fn(ctx->subsystem, ctx->cb_arg, status);
443 	}
444 	free(ctx);
445 }
446 
447 static void
448 subsystem_state_change_continue(void *ctx, int status)
449 {
450 	struct spdk_io_channel_iter *i = ctx;
451 	spdk_for_each_channel_continue(i, status);
452 }
453 
454 static void
455 subsystem_state_change_on_pg(struct spdk_io_channel_iter *i)
456 {
457 	struct subsystem_state_change_ctx *ctx;
458 	struct spdk_io_channel *ch;
459 	struct spdk_nvmf_poll_group *group;
460 
461 	ctx = spdk_io_channel_iter_get_ctx(i);
462 	ch = spdk_io_channel_iter_get_channel(i);
463 	group = spdk_io_channel_get_ctx(ch);
464 
465 	switch (ctx->requested_state) {
466 	case SPDK_NVMF_SUBSYSTEM_INACTIVE:
467 		spdk_nvmf_poll_group_remove_subsystem(group, ctx->subsystem, subsystem_state_change_continue, i);
468 		break;
469 	case SPDK_NVMF_SUBSYSTEM_ACTIVE:
470 		if (ctx->subsystem->state == SPDK_NVMF_SUBSYSTEM_ACTIVATING) {
471 			spdk_nvmf_poll_group_add_subsystem(group, ctx->subsystem, subsystem_state_change_continue, i);
472 		} else if (ctx->subsystem->state == SPDK_NVMF_SUBSYSTEM_RESUMING) {
473 			spdk_nvmf_poll_group_resume_subsystem(group, ctx->subsystem, subsystem_state_change_continue, i);
474 		}
475 		break;
476 	case SPDK_NVMF_SUBSYSTEM_PAUSED:
477 		spdk_nvmf_poll_group_pause_subsystem(group, ctx->subsystem, subsystem_state_change_continue, i);
478 		break;
479 	default:
480 		assert(false);
481 		break;
482 	}
483 }
484 
485 static int
486 spdk_nvmf_subsystem_state_change(struct spdk_nvmf_subsystem *subsystem,
487 				 enum spdk_nvmf_subsystem_state requested_state,
488 				 spdk_nvmf_subsystem_state_change_done cb_fn,
489 				 void *cb_arg)
490 {
491 	struct subsystem_state_change_ctx *ctx;
492 	enum spdk_nvmf_subsystem_state intermediate_state;
493 	int rc;
494 
495 	switch (requested_state) {
496 	case SPDK_NVMF_SUBSYSTEM_INACTIVE:
497 		intermediate_state = SPDK_NVMF_SUBSYSTEM_DEACTIVATING;
498 		break;
499 	case SPDK_NVMF_SUBSYSTEM_ACTIVE:
500 		if (subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED) {
501 			intermediate_state = SPDK_NVMF_SUBSYSTEM_RESUMING;
502 		} else {
503 			intermediate_state = SPDK_NVMF_SUBSYSTEM_ACTIVATING;
504 		}
505 		break;
506 	case SPDK_NVMF_SUBSYSTEM_PAUSED:
507 		intermediate_state = SPDK_NVMF_SUBSYSTEM_PAUSING;
508 		break;
509 	default:
510 		assert(false);
511 		return -EINVAL;
512 	}
513 
514 	ctx = calloc(1, sizeof(*ctx));
515 	if (!ctx) {
516 		return -ENOMEM;
517 	}
518 
519 	rc = spdk_nvmf_subsystem_set_state(subsystem, intermediate_state);
520 	if (rc) {
521 		free(ctx);
522 		return rc;
523 	}
524 
525 	ctx->subsystem = subsystem;
526 	ctx->requested_state = requested_state;
527 	ctx->cb_fn = cb_fn;
528 	ctx->cb_arg = cb_arg;
529 
530 	spdk_for_each_channel(subsystem->tgt,
531 			      subsystem_state_change_on_pg,
532 			      ctx,
533 			      subsystem_state_change_done);
534 
535 	return 0;
536 }
537 
538 int
539 spdk_nvmf_subsystem_start(struct spdk_nvmf_subsystem *subsystem,
540 			  spdk_nvmf_subsystem_state_change_done cb_fn,
541 			  void *cb_arg)
542 {
543 	return spdk_nvmf_subsystem_state_change(subsystem, SPDK_NVMF_SUBSYSTEM_ACTIVE, cb_fn, cb_arg);
544 }
545 
546 int
547 spdk_nvmf_subsystem_stop(struct spdk_nvmf_subsystem *subsystem,
548 			 spdk_nvmf_subsystem_state_change_done cb_fn,
549 			 void *cb_arg)
550 {
551 	return spdk_nvmf_subsystem_state_change(subsystem, SPDK_NVMF_SUBSYSTEM_INACTIVE, cb_fn, cb_arg);
552 }
553 
554 int
555 spdk_nvmf_subsystem_pause(struct spdk_nvmf_subsystem *subsystem,
556 			  spdk_nvmf_subsystem_state_change_done cb_fn,
557 			  void *cb_arg)
558 {
559 	return spdk_nvmf_subsystem_state_change(subsystem, SPDK_NVMF_SUBSYSTEM_PAUSED, cb_fn, cb_arg);
560 }
561 
562 int
563 spdk_nvmf_subsystem_resume(struct spdk_nvmf_subsystem *subsystem,
564 			   spdk_nvmf_subsystem_state_change_done cb_fn,
565 			   void *cb_arg)
566 {
567 	return spdk_nvmf_subsystem_state_change(subsystem, SPDK_NVMF_SUBSYSTEM_ACTIVE, cb_fn, cb_arg);
568 }
569 
570 struct spdk_nvmf_subsystem *
571 spdk_nvmf_subsystem_get_first(struct spdk_nvmf_tgt *tgt)
572 {
573 	struct spdk_nvmf_subsystem	*subsystem;
574 	uint32_t sid;
575 
576 	for (sid = 0; sid < tgt->max_subsystems; sid++) {
577 		subsystem = tgt->subsystems[sid];
578 		if (subsystem) {
579 			return subsystem;
580 		}
581 	}
582 
583 	return NULL;
584 }
585 
586 struct spdk_nvmf_subsystem *
587 spdk_nvmf_subsystem_get_next(struct spdk_nvmf_subsystem *subsystem)
588 {
589 	uint32_t sid;
590 	struct spdk_nvmf_tgt *tgt;
591 
592 	if (!subsystem) {
593 		return NULL;
594 	}
595 
596 	tgt = subsystem->tgt;
597 
598 	for (sid = subsystem->id + 1; sid < tgt->max_subsystems; sid++) {
599 		subsystem = tgt->subsystems[sid];
600 		if (subsystem) {
601 			return subsystem;
602 		}
603 	}
604 
605 	return NULL;
606 }
607 
608 static struct spdk_nvmf_host *
609 _spdk_nvmf_subsystem_find_host(struct spdk_nvmf_subsystem *subsystem, const char *hostnqn)
610 {
611 	struct spdk_nvmf_host *host = NULL;
612 
613 	TAILQ_FOREACH(host, &subsystem->hosts, link) {
614 		if (strcmp(hostnqn, host->nqn) == 0) {
615 			return host;
616 		}
617 	}
618 
619 	return NULL;
620 }
621 
622 int
623 spdk_nvmf_subsystem_add_host(struct spdk_nvmf_subsystem *subsystem, const char *hostnqn)
624 {
625 	struct spdk_nvmf_host *host;
626 
627 	if (!spdk_nvmf_valid_nqn(hostnqn)) {
628 		return -EINVAL;
629 	}
630 
631 	if (!(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
632 	      subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED)) {
633 		return -EAGAIN;
634 	}
635 
636 	if (_spdk_nvmf_subsystem_find_host(subsystem, hostnqn)) {
637 		/* This subsystem already allows the specified host. */
638 		return 0;
639 	}
640 
641 	host = calloc(1, sizeof(*host));
642 	if (!host) {
643 		return -ENOMEM;
644 	}
645 	host->nqn = strdup(hostnqn);
646 	if (!host->nqn) {
647 		free(host);
648 		return -ENOMEM;
649 	}
650 
651 	TAILQ_INSERT_HEAD(&subsystem->hosts, host, link);
652 	subsystem->tgt->discovery_genctr++;
653 
654 	return 0;
655 }
656 
657 int
658 spdk_nvmf_subsystem_remove_host(struct spdk_nvmf_subsystem *subsystem, const char *hostnqn)
659 {
660 	struct spdk_nvmf_host *host;
661 
662 	if (!(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
663 	      subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED)) {
664 		return -EAGAIN;
665 	}
666 
667 	host = _spdk_nvmf_subsystem_find_host(subsystem, hostnqn);
668 	if (host == NULL) {
669 		return -ENOENT;
670 	}
671 
672 	_spdk_nvmf_subsystem_remove_host(subsystem, host);
673 	return 0;
674 }
675 
676 int
677 spdk_nvmf_subsystem_set_allow_any_host(struct spdk_nvmf_subsystem *subsystem, bool allow_any_host)
678 {
679 	if (!(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
680 	      subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED)) {
681 		return -EAGAIN;
682 	}
683 
684 	subsystem->allow_any_host = allow_any_host;
685 
686 	return 0;
687 }
688 
689 bool
690 spdk_nvmf_subsystem_get_allow_any_host(const struct spdk_nvmf_subsystem *subsystem)
691 {
692 	return subsystem->allow_any_host;
693 }
694 
695 bool
696 spdk_nvmf_subsystem_host_allowed(struct spdk_nvmf_subsystem *subsystem, const char *hostnqn)
697 {
698 	if (!hostnqn) {
699 		return false;
700 	}
701 
702 	if (subsystem->allow_any_host) {
703 		return true;
704 	}
705 
706 	return _spdk_nvmf_subsystem_find_host(subsystem, hostnqn) != NULL;
707 }
708 
709 struct spdk_nvmf_host *
710 spdk_nvmf_subsystem_get_first_host(struct spdk_nvmf_subsystem *subsystem)
711 {
712 	return TAILQ_FIRST(&subsystem->hosts);
713 }
714 
715 
716 struct spdk_nvmf_host *
717 spdk_nvmf_subsystem_get_next_host(struct spdk_nvmf_subsystem *subsystem,
718 				  struct spdk_nvmf_host *prev_host)
719 {
720 	return TAILQ_NEXT(prev_host, link);
721 }
722 
723 const char *
724 spdk_nvmf_host_get_nqn(struct spdk_nvmf_host *host)
725 {
726 	return host->nqn;
727 }
728 
729 static struct spdk_nvmf_listener *
730 _spdk_nvmf_subsystem_find_listener(struct spdk_nvmf_subsystem *subsystem,
731 				   const struct spdk_nvme_transport_id *trid)
732 {
733 	struct spdk_nvmf_listener *listener;
734 
735 	TAILQ_FOREACH(listener, &subsystem->listeners, link) {
736 		if (spdk_nvme_transport_id_compare(&listener->trid, trid) == 0) {
737 			return listener;
738 		}
739 	}
740 
741 	return NULL;
742 }
743 
744 int
745 spdk_nvmf_subsystem_add_listener(struct spdk_nvmf_subsystem *subsystem,
746 				 struct spdk_nvme_transport_id *trid)
747 {
748 	struct spdk_nvmf_transport *transport;
749 	struct spdk_nvmf_listener *listener;
750 
751 	if (!(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
752 	      subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED)) {
753 		return -EAGAIN;
754 	}
755 
756 	if (_spdk_nvmf_subsystem_find_listener(subsystem, trid)) {
757 		/* Listener already exists in this subsystem */
758 		return 0;
759 	}
760 
761 	transport = spdk_nvmf_tgt_get_transport(subsystem->tgt, trid->trtype);
762 	if (transport == NULL) {
763 		SPDK_ERRLOG("Unknown transport type %d\n", trid->trtype);
764 		return -EINVAL;
765 	}
766 
767 	listener = calloc(1, sizeof(*listener));
768 	if (!listener) {
769 		return -ENOMEM;
770 	}
771 
772 	listener->trid = *trid;
773 	listener->transport = transport;
774 
775 	TAILQ_INSERT_HEAD(&subsystem->listeners, listener, link);
776 
777 	return 0;
778 }
779 
780 int
781 spdk_nvmf_subsystem_remove_listener(struct spdk_nvmf_subsystem *subsystem,
782 				    const struct spdk_nvme_transport_id *trid)
783 {
784 	struct spdk_nvmf_listener *listener;
785 
786 	if (!(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
787 	      subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED)) {
788 		return -EAGAIN;
789 	}
790 
791 	listener = _spdk_nvmf_subsystem_find_listener(subsystem, trid);
792 	if (listener == NULL) {
793 		return -ENOENT;
794 	}
795 
796 	_nvmf_subsystem_remove_listener(subsystem, listener);
797 
798 	return 0;
799 }
800 
801 bool
802 spdk_nvmf_subsystem_listener_allowed(struct spdk_nvmf_subsystem *subsystem,
803 				     struct spdk_nvme_transport_id *trid)
804 {
805 	struct spdk_nvmf_listener *listener;
806 
807 	if (!strcmp(subsystem->subnqn, SPDK_NVMF_DISCOVERY_NQN)) {
808 		return true;
809 	}
810 
811 	TAILQ_FOREACH(listener, &subsystem->listeners, link) {
812 		if (spdk_nvme_transport_id_compare(&listener->trid, trid) == 0) {
813 			return true;
814 		}
815 	}
816 
817 	return false;
818 }
819 
820 struct spdk_nvmf_listener *
821 spdk_nvmf_subsystem_get_first_listener(struct spdk_nvmf_subsystem *subsystem)
822 {
823 	return TAILQ_FIRST(&subsystem->listeners);
824 }
825 
826 struct spdk_nvmf_listener *
827 spdk_nvmf_subsystem_get_next_listener(struct spdk_nvmf_subsystem *subsystem,
828 				      struct spdk_nvmf_listener *prev_listener)
829 {
830 	return TAILQ_NEXT(prev_listener, link);
831 }
832 
833 const struct spdk_nvme_transport_id *
834 spdk_nvmf_listener_get_trid(struct spdk_nvmf_listener *listener)
835 {
836 	return &listener->trid;
837 }
838 
839 struct subsystem_update_ns_ctx {
840 	struct spdk_nvmf_subsystem *subsystem;
841 
842 	spdk_nvmf_subsystem_state_change_done cb_fn;
843 	void *cb_arg;
844 };
845 
846 static void
847 subsystem_update_ns_done(struct spdk_io_channel_iter *i, int status)
848 {
849 	struct subsystem_update_ns_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
850 
851 	if (ctx->cb_fn) {
852 		ctx->cb_fn(ctx->subsystem, ctx->cb_arg, status);
853 	}
854 	free(ctx);
855 }
856 
857 static void
858 subsystem_update_ns_on_pg(struct spdk_io_channel_iter *i)
859 {
860 	int rc;
861 	struct subsystem_update_ns_ctx *ctx;
862 	struct spdk_nvmf_poll_group *group;
863 	struct spdk_nvmf_subsystem *subsystem;
864 
865 	ctx = spdk_io_channel_iter_get_ctx(i);
866 	group = spdk_io_channel_get_ctx(spdk_io_channel_iter_get_channel(i));
867 	subsystem = ctx->subsystem;
868 
869 	rc = spdk_nvmf_poll_group_update_subsystem(group, subsystem);
870 	spdk_for_each_channel_continue(i, rc);
871 }
872 
873 static int
874 spdk_nvmf_subsystem_update_ns(struct spdk_nvmf_subsystem *subsystem, spdk_channel_for_each_cpl cpl,
875 			      void *ctx)
876 {
877 	spdk_for_each_channel(subsystem->tgt,
878 			      subsystem_update_ns_on_pg,
879 			      ctx,
880 			      cpl);
881 
882 	return 0;
883 }
884 
885 static void
886 spdk_nvmf_subsystem_ns_changed(struct spdk_nvmf_subsystem *subsystem, uint32_t nsid)
887 {
888 	struct spdk_nvmf_ctrlr *ctrlr;
889 
890 	TAILQ_FOREACH(ctrlr, &subsystem->ctrlrs, link) {
891 		spdk_nvmf_ctrlr_ns_changed(ctrlr, nsid);
892 	}
893 }
894 
895 static int
896 _spdk_nvmf_subsystem_remove_ns(struct spdk_nvmf_subsystem *subsystem, uint32_t nsid)
897 {
898 	struct spdk_nvmf_ns *ns;
899 	struct spdk_nvmf_registrant *reg, *reg_tmp;
900 
901 	assert(subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED ||
902 	       subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE);
903 
904 	if (nsid == 0 || nsid > subsystem->max_nsid) {
905 		return -1;
906 	}
907 
908 	if (!(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
909 	      subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED)) {
910 		return -1;
911 	}
912 
913 	ns = subsystem->ns[nsid - 1];
914 	if (!ns) {
915 		return -1;
916 	}
917 
918 	subsystem->ns[nsid - 1] = NULL;
919 
920 	TAILQ_FOREACH_SAFE(reg, &ns->registrants, link, reg_tmp) {
921 		TAILQ_REMOVE(&ns->registrants, reg, link);
922 		free(reg);
923 	}
924 	spdk_bdev_module_release_bdev(ns->bdev);
925 	spdk_bdev_close(ns->desc);
926 	free(ns);
927 
928 	spdk_nvmf_subsystem_ns_changed(subsystem, nsid);
929 
930 	return 0;
931 }
932 
933 int
934 spdk_nvmf_subsystem_remove_ns(struct spdk_nvmf_subsystem *subsystem, uint32_t nsid,
935 			      spdk_nvmf_subsystem_state_change_done cb_fn, void *cb_arg)
936 {
937 	int rc;
938 	struct subsystem_update_ns_ctx *ctx;
939 
940 	rc = _spdk_nvmf_subsystem_remove_ns(subsystem, nsid);
941 	if (rc < 0) {
942 		return rc;
943 	}
944 
945 	ctx = calloc(1, sizeof(*ctx));
946 
947 	if (ctx == NULL) {
948 		return -ENOMEM;
949 	}
950 
951 	ctx->subsystem = subsystem;
952 	ctx->cb_fn = cb_fn;
953 	ctx->cb_arg = cb_arg;
954 
955 	spdk_nvmf_subsystem_update_ns(subsystem, subsystem_update_ns_done, ctx);
956 
957 	return 0;
958 }
959 
960 static void
961 _spdk_nvmf_ns_hot_remove_done(struct spdk_nvmf_subsystem *subsystem, void *cb_arg, int status)
962 {
963 	if (status != 0) {
964 		SPDK_ERRLOG("Failed to make changes to NVMe-oF subsystem with id %u\n", subsystem->id);
965 	}
966 	spdk_nvmf_subsystem_resume(subsystem, NULL, NULL);
967 }
968 
969 static void
970 _spdk_nvmf_ns_hot_remove(struct spdk_nvmf_subsystem *subsystem,
971 			 void *cb_arg, int status)
972 {
973 	struct spdk_nvmf_ns *ns = cb_arg;
974 
975 	spdk_nvmf_subsystem_remove_ns(subsystem, ns->opts.nsid, _spdk_nvmf_ns_hot_remove_done,
976 				      subsystem);
977 }
978 
979 static void
980 spdk_nvmf_ns_hot_remove(void *remove_ctx)
981 {
982 	struct spdk_nvmf_ns *ns = remove_ctx;
983 	int rc;
984 
985 	rc = spdk_nvmf_subsystem_pause(ns->subsystem, _spdk_nvmf_ns_hot_remove, ns);
986 	if (rc) {
987 		SPDK_ERRLOG("Unable to pause subsystem to process namespace removal!\n");
988 	}
989 }
990 
991 void
992 spdk_nvmf_ns_opts_get_defaults(struct spdk_nvmf_ns_opts *opts, size_t opts_size)
993 {
994 	/* All current fields are set to 0 by default. */
995 	memset(opts, 0, opts_size);
996 }
997 
998 /* Dummy bdev module used to to claim bdevs. */
999 static struct spdk_bdev_module ns_bdev_module = {
1000 	.name	= "NVMe-oF Target",
1001 };
1002 
1003 uint32_t
1004 spdk_nvmf_subsystem_add_ns(struct spdk_nvmf_subsystem *subsystem, struct spdk_bdev *bdev,
1005 			   const struct spdk_nvmf_ns_opts *user_opts, size_t opts_size)
1006 {
1007 	struct spdk_nvmf_ns_opts opts;
1008 	struct spdk_nvmf_ns *ns;
1009 	int rc;
1010 
1011 	if (!(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
1012 	      subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED)) {
1013 		return 0;
1014 	}
1015 
1016 	spdk_nvmf_ns_opts_get_defaults(&opts, sizeof(opts));
1017 	if (user_opts) {
1018 		memcpy(&opts, user_opts, spdk_min(sizeof(opts), opts_size));
1019 	}
1020 
1021 	if (spdk_mem_all_zero(&opts.uuid, sizeof(opts.uuid))) {
1022 		opts.uuid = *spdk_bdev_get_uuid(bdev);
1023 	}
1024 
1025 	if (opts.nsid == SPDK_NVME_GLOBAL_NS_TAG) {
1026 		SPDK_ERRLOG("Invalid NSID %" PRIu32 "\n", opts.nsid);
1027 		return 0;
1028 	}
1029 
1030 	if (opts.nsid == 0) {
1031 		/*
1032 		 * NSID not specified - find a free index.
1033 		 *
1034 		 * If no free slots are found, opts.nsid will be subsystem->max_nsid + 1, which will
1035 		 * expand max_nsid if possible.
1036 		 */
1037 		for (opts.nsid = 1; opts.nsid <= subsystem->max_nsid; opts.nsid++) {
1038 			if (_spdk_nvmf_subsystem_get_ns(subsystem, opts.nsid) == NULL) {
1039 				break;
1040 			}
1041 		}
1042 	}
1043 
1044 	if (_spdk_nvmf_subsystem_get_ns(subsystem, opts.nsid)) {
1045 		SPDK_ERRLOG("Requested NSID %" PRIu32 " already in use\n", opts.nsid);
1046 		return 0;
1047 	}
1048 
1049 	if (opts.nsid > subsystem->max_nsid) {
1050 		struct spdk_nvmf_ns **new_ns_array;
1051 
1052 		/* If MaxNamespaces was specified, we can't extend max_nsid beyond it. */
1053 		if (subsystem->max_allowed_nsid > 0 && opts.nsid > subsystem->max_allowed_nsid) {
1054 			SPDK_ERRLOG("Can't extend NSID range above MaxNamespaces\n");
1055 			return 0;
1056 		}
1057 
1058 		/* If a controller is connected, we can't change NN. */
1059 		if (!TAILQ_EMPTY(&subsystem->ctrlrs)) {
1060 			SPDK_ERRLOG("Can't extend NSID range while controllers are connected\n");
1061 			return 0;
1062 		}
1063 
1064 		new_ns_array = realloc(subsystem->ns, sizeof(struct spdk_nvmf_ns *) * opts.nsid);
1065 		if (new_ns_array == NULL) {
1066 			SPDK_ERRLOG("Memory allocation error while resizing namespace array.\n");
1067 			return 0;
1068 		}
1069 
1070 		memset(new_ns_array + subsystem->max_nsid, 0,
1071 		       sizeof(struct spdk_nvmf_ns *) * (opts.nsid - subsystem->max_nsid));
1072 		subsystem->ns = new_ns_array;
1073 		subsystem->max_nsid = opts.nsid;
1074 	}
1075 
1076 	ns = calloc(1, sizeof(*ns));
1077 	if (ns == NULL) {
1078 		SPDK_ERRLOG("Namespace allocation failed\n");
1079 		return 0;
1080 	}
1081 
1082 	ns->bdev = bdev;
1083 	ns->opts = opts;
1084 	ns->subsystem = subsystem;
1085 	rc = spdk_bdev_open(bdev, true, spdk_nvmf_ns_hot_remove, ns, &ns->desc);
1086 	if (rc != 0) {
1087 		SPDK_ERRLOG("Subsystem %s: bdev %s cannot be opened, error=%d\n",
1088 			    subsystem->subnqn, spdk_bdev_get_name(bdev), rc);
1089 		free(ns);
1090 		return 0;
1091 	}
1092 	rc = spdk_bdev_module_claim_bdev(bdev, ns->desc, &ns_bdev_module);
1093 	if (rc != 0) {
1094 		spdk_bdev_close(ns->desc);
1095 		free(ns);
1096 		return 0;
1097 	}
1098 	subsystem->ns[opts.nsid - 1] = ns;
1099 	ns->nsid = opts.nsid;
1100 	TAILQ_INIT(&ns->registrants);
1101 
1102 	SPDK_DEBUGLOG(SPDK_LOG_NVMF, "Subsystem %s: bdev %s assigned nsid %" PRIu32 "\n",
1103 		      spdk_nvmf_subsystem_get_nqn(subsystem),
1104 		      spdk_bdev_get_name(bdev),
1105 		      opts.nsid);
1106 
1107 	spdk_nvmf_subsystem_ns_changed(subsystem, opts.nsid);
1108 
1109 	return opts.nsid;
1110 }
1111 
1112 static uint32_t
1113 spdk_nvmf_subsystem_get_next_allocated_nsid(struct spdk_nvmf_subsystem *subsystem,
1114 		uint32_t prev_nsid)
1115 {
1116 	uint32_t nsid;
1117 
1118 	if (prev_nsid >= subsystem->max_nsid) {
1119 		return 0;
1120 	}
1121 
1122 	for (nsid = prev_nsid + 1; nsid <= subsystem->max_nsid; nsid++) {
1123 		if (subsystem->ns[nsid - 1]) {
1124 			return nsid;
1125 		}
1126 	}
1127 
1128 	return 0;
1129 }
1130 
1131 struct spdk_nvmf_ns *
1132 spdk_nvmf_subsystem_get_first_ns(struct spdk_nvmf_subsystem *subsystem)
1133 {
1134 	uint32_t first_nsid;
1135 
1136 	first_nsid = spdk_nvmf_subsystem_get_next_allocated_nsid(subsystem, 0);
1137 	return _spdk_nvmf_subsystem_get_ns(subsystem, first_nsid);
1138 }
1139 
1140 struct spdk_nvmf_ns *
1141 spdk_nvmf_subsystem_get_next_ns(struct spdk_nvmf_subsystem *subsystem,
1142 				struct spdk_nvmf_ns *prev_ns)
1143 {
1144 	uint32_t next_nsid;
1145 
1146 	next_nsid = spdk_nvmf_subsystem_get_next_allocated_nsid(subsystem, prev_ns->opts.nsid);
1147 	return _spdk_nvmf_subsystem_get_ns(subsystem, next_nsid);
1148 }
1149 
1150 struct spdk_nvmf_ns *
1151 spdk_nvmf_subsystem_get_ns(struct spdk_nvmf_subsystem *subsystem, uint32_t nsid)
1152 {
1153 	return _spdk_nvmf_subsystem_get_ns(subsystem, nsid);
1154 }
1155 
1156 uint32_t
1157 spdk_nvmf_ns_get_id(const struct spdk_nvmf_ns *ns)
1158 {
1159 	return ns->opts.nsid;
1160 }
1161 
1162 struct spdk_bdev *
1163 spdk_nvmf_ns_get_bdev(struct spdk_nvmf_ns *ns)
1164 {
1165 	return ns->bdev;
1166 }
1167 
1168 void
1169 spdk_nvmf_ns_get_opts(const struct spdk_nvmf_ns *ns, struct spdk_nvmf_ns_opts *opts,
1170 		      size_t opts_size)
1171 {
1172 	memset(opts, 0, opts_size);
1173 	memcpy(opts, &ns->opts, spdk_min(sizeof(ns->opts), opts_size));
1174 }
1175 
1176 const char *
1177 spdk_nvmf_subsystem_get_sn(const struct spdk_nvmf_subsystem *subsystem)
1178 {
1179 	return subsystem->sn;
1180 }
1181 
1182 int
1183 spdk_nvmf_subsystem_set_sn(struct spdk_nvmf_subsystem *subsystem, const char *sn)
1184 {
1185 	size_t len, max_len;
1186 
1187 	max_len = sizeof(subsystem->sn) - 1;
1188 	len = strlen(sn);
1189 	if (len > max_len) {
1190 		SPDK_DEBUGLOG(SPDK_LOG_NVMF, "Invalid sn \"%s\": length %zu > max %zu\n",
1191 			      sn, len, max_len);
1192 		return -1;
1193 	}
1194 
1195 	if (!spdk_nvmf_valid_ascii_string(sn, len)) {
1196 		SPDK_DEBUGLOG(SPDK_LOG_NVMF, "Non-ASCII sn\n");
1197 		SPDK_LOGDUMP(SPDK_LOG_NVMF, "sn", sn, len);
1198 		return -1;
1199 	}
1200 
1201 	snprintf(subsystem->sn, sizeof(subsystem->sn), "%s", sn);
1202 
1203 	return 0;
1204 }
1205 
1206 const char *
1207 spdk_nvmf_subsystem_get_nqn(struct spdk_nvmf_subsystem *subsystem)
1208 {
1209 	return subsystem->subnqn;
1210 }
1211 
1212 /* Workaround for astyle formatting bug */
1213 typedef enum spdk_nvmf_subtype nvmf_subtype_t;
1214 
1215 nvmf_subtype_t
1216 spdk_nvmf_subsystem_get_type(struct spdk_nvmf_subsystem *subsystem)
1217 {
1218 	return subsystem->subtype;
1219 }
1220 
1221 static uint16_t
1222 spdk_nvmf_subsystem_gen_cntlid(struct spdk_nvmf_subsystem *subsystem)
1223 {
1224 	int count;
1225 
1226 	/*
1227 	 * In the worst case, we might have to try all CNTLID values between 1 and 0xFFF0 - 1
1228 	 * before we find one that is unused (or find that all values are in use).
1229 	 */
1230 	for (count = 0; count < 0xFFF0 - 1; count++) {
1231 		subsystem->next_cntlid++;
1232 		if (subsystem->next_cntlid >= 0xFFF0) {
1233 			/* The spec reserves cntlid values in the range FFF0h to FFFFh. */
1234 			subsystem->next_cntlid = 1;
1235 		}
1236 
1237 		/* Check if a controller with this cntlid currently exists. */
1238 		if (spdk_nvmf_subsystem_get_ctrlr(subsystem, subsystem->next_cntlid) == NULL) {
1239 			/* Found unused cntlid */
1240 			return subsystem->next_cntlid;
1241 		}
1242 	}
1243 
1244 	/* All valid cntlid values are in use. */
1245 	return 0xFFFF;
1246 }
1247 
1248 int
1249 spdk_nvmf_subsystem_add_ctrlr(struct spdk_nvmf_subsystem *subsystem, struct spdk_nvmf_ctrlr *ctrlr)
1250 {
1251 	ctrlr->cntlid = spdk_nvmf_subsystem_gen_cntlid(subsystem);
1252 	if (ctrlr->cntlid == 0xFFFF) {
1253 		/* Unable to get a cntlid */
1254 		SPDK_ERRLOG("Reached max simultaneous ctrlrs\n");
1255 		return -EBUSY;
1256 	}
1257 
1258 	TAILQ_INSERT_TAIL(&subsystem->ctrlrs, ctrlr, link);
1259 
1260 	return 0;
1261 }
1262 
1263 void
1264 spdk_nvmf_subsystem_remove_ctrlr(struct spdk_nvmf_subsystem *subsystem,
1265 				 struct spdk_nvmf_ctrlr *ctrlr)
1266 {
1267 	assert(subsystem == ctrlr->subsys);
1268 	TAILQ_REMOVE(&subsystem->ctrlrs, ctrlr, link);
1269 }
1270 
1271 struct spdk_nvmf_ctrlr *
1272 spdk_nvmf_subsystem_get_ctrlr(struct spdk_nvmf_subsystem *subsystem, uint16_t cntlid)
1273 {
1274 	struct spdk_nvmf_ctrlr *ctrlr;
1275 
1276 	TAILQ_FOREACH(ctrlr, &subsystem->ctrlrs, link) {
1277 		if (ctrlr->cntlid == cntlid) {
1278 			return ctrlr;
1279 		}
1280 	}
1281 
1282 	return NULL;
1283 }
1284 
1285 uint32_t
1286 spdk_nvmf_subsystem_get_max_namespaces(const struct spdk_nvmf_subsystem *subsystem)
1287 {
1288 	return subsystem->max_allowed_nsid;
1289 }
1290 
1291 static struct spdk_nvmf_registrant *
1292 nvmf_ns_reservation_get_registrant(struct spdk_nvmf_ns *ns,
1293 				   struct spdk_uuid *uuid)
1294 {
1295 	struct spdk_nvmf_registrant *reg, *tmp;
1296 
1297 	TAILQ_FOREACH_SAFE(reg, &ns->registrants, link, tmp) {
1298 		if (spdk_uuid_compare(&reg->hostid, uuid) == 0) {
1299 			return reg;
1300 		}
1301 	}
1302 
1303 	return NULL;
1304 }
1305 
1306 /* current reservation type is all registrants or not */
1307 static bool
1308 nvmf_ns_reservation_all_registrants_type(struct spdk_nvmf_ns *ns)
1309 {
1310 	return (ns->rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS ||
1311 		ns->rtype == SPDK_NVME_RESERVE_EXCLUSIVE_ACCESS_ALL_REGS);
1312 }
1313 
1314 /* current registrant is reservation holder or not */
1315 static bool
1316 nvmf_ns_reservation_registrant_is_holder(struct spdk_nvmf_ns *ns,
1317 		struct spdk_nvmf_registrant *reg)
1318 {
1319 	if (!reg) {
1320 		return false;
1321 	}
1322 
1323 	if (nvmf_ns_reservation_all_registrants_type(ns)) {
1324 		return true;
1325 	}
1326 
1327 	return (ns->holder == reg);
1328 }
1329 
1330 static int
1331 nvmf_ns_reservation_add_registrant(struct spdk_nvmf_ns *ns,
1332 				   struct spdk_nvmf_ctrlr *ctrlr,
1333 				   uint64_t nrkey)
1334 {
1335 	struct spdk_nvmf_registrant *reg;
1336 
1337 	reg = calloc(1, sizeof(*reg));
1338 	if (!reg) {
1339 		return -ENOMEM;
1340 	}
1341 
1342 	reg->rkey = nrkey;
1343 	/* set hostid for the registrant */
1344 	spdk_uuid_copy(&reg->hostid, &ctrlr->hostid);
1345 	TAILQ_INSERT_TAIL(&ns->registrants, reg, link);
1346 	ns->gen++;
1347 
1348 	return 0;
1349 }
1350 
1351 static void
1352 nvmf_ns_reservation_release_reservation(struct spdk_nvmf_ns *ns)
1353 {
1354 	ns->rtype = 0;
1355 	ns->crkey = 0;
1356 	ns->holder = NULL;
1357 }
1358 
1359 /* release the reservation if the last registrant was removed */
1360 static void
1361 nvmf_ns_reservation_check_release_on_remove_registrant(struct spdk_nvmf_ns *ns,
1362 		struct spdk_nvmf_registrant *reg)
1363 {
1364 	struct spdk_nvmf_registrant *next_reg;
1365 
1366 	/* no reservation holder */
1367 	if (!ns->holder) {
1368 		assert(ns->rtype == 0);
1369 		return;
1370 	}
1371 
1372 	next_reg = TAILQ_FIRST(&ns->registrants);
1373 	if (next_reg && nvmf_ns_reservation_all_registrants_type(ns)) {
1374 		/* the next valid registrant is the new holder now */
1375 		ns->holder = next_reg;
1376 	} else if (nvmf_ns_reservation_registrant_is_holder(ns, reg)) {
1377 		/* release the reservation */
1378 		nvmf_ns_reservation_release_reservation(ns);
1379 	}
1380 }
1381 
1382 static void
1383 nvmf_ns_reservation_remove_registrant(struct spdk_nvmf_ns *ns,
1384 				      struct spdk_nvmf_registrant *reg)
1385 {
1386 	TAILQ_REMOVE(&ns->registrants, reg, link);
1387 	nvmf_ns_reservation_check_release_on_remove_registrant(ns, reg);
1388 	free(reg);
1389 	ns->gen++;
1390 	return;
1391 }
1392 
1393 static uint32_t
1394 nvmf_ns_reservation_remove_registrants_by_key(struct spdk_nvmf_ns *ns,
1395 		uint64_t rkey)
1396 {
1397 	struct spdk_nvmf_registrant *reg, *tmp;
1398 	uint32_t count = 0;
1399 
1400 	TAILQ_FOREACH_SAFE(reg, &ns->registrants, link, tmp) {
1401 		if (reg->rkey == rkey) {
1402 			nvmf_ns_reservation_remove_registrant(ns, reg);
1403 			count++;
1404 		}
1405 	}
1406 	return count;
1407 }
1408 
1409 static uint32_t
1410 nvmf_ns_reservation_remove_all_other_registrants(struct spdk_nvmf_ns *ns,
1411 		struct spdk_nvmf_registrant *reg)
1412 {
1413 	struct spdk_nvmf_registrant *reg_tmp, *reg_tmp2;
1414 	uint32_t count = 0;
1415 
1416 	TAILQ_FOREACH_SAFE(reg_tmp, &ns->registrants, link, reg_tmp2) {
1417 		if (reg_tmp != reg) {
1418 			nvmf_ns_reservation_remove_registrant(ns, reg_tmp);
1419 			count++;
1420 		}
1421 	}
1422 	return count;
1423 }
1424 
1425 static uint32_t
1426 nvmf_ns_reservation_clear_all_registrants(struct spdk_nvmf_ns *ns)
1427 {
1428 	struct spdk_nvmf_registrant *reg, *reg_tmp;
1429 	uint32_t count = 0;
1430 
1431 	TAILQ_FOREACH_SAFE(reg, &ns->registrants, link, reg_tmp) {
1432 		nvmf_ns_reservation_remove_registrant(ns, reg);
1433 		count++;
1434 	}
1435 	return count;
1436 }
1437 
1438 static void
1439 nvmf_ns_reservation_acquire_reservation(struct spdk_nvmf_ns *ns, uint64_t rkey,
1440 					enum spdk_nvme_reservation_type rtype,
1441 					struct spdk_nvmf_registrant *holder)
1442 {
1443 	ns->rtype = rtype;
1444 	ns->crkey = rkey;
1445 	assert(ns->holder == NULL);
1446 	ns->holder = holder;
1447 }
1448 
1449 static bool
1450 nvmf_ns_reservation_register(struct spdk_nvmf_ns *ns,
1451 			     struct spdk_nvmf_ctrlr *ctrlr,
1452 			     struct spdk_nvmf_request *req)
1453 {
1454 	struct spdk_nvme_cmd *cmd = &req->cmd->nvme_cmd;
1455 	uint8_t rrega, iekey, cptpl;
1456 	struct spdk_nvme_reservation_register_data key;
1457 	struct spdk_nvmf_registrant *reg;
1458 	uint8_t status = SPDK_NVME_SC_SUCCESS;
1459 	bool update_sgroup = false;
1460 	int rc;
1461 
1462 	rrega = cmd->cdw10 & 0x7u;
1463 	iekey = (cmd->cdw10 >> 3) & 0x1u;
1464 	cptpl = (cmd->cdw10 >> 30) & 0x3u;
1465 	memcpy(&key, req->data, sizeof(key));
1466 
1467 	SPDK_DEBUGLOG(SPDK_LOG_NVMF, "REGISTER: RREGA %u, IEKEY %u, CPTPL %u, "
1468 		      "NRKEY 0x%"PRIx64", NRKEY 0x%"PRIx64"\n",
1469 		      rrega, iekey, cptpl, key.crkey, key.nrkey);
1470 
1471 	/* TODO: doesn't support for now */
1472 	if (cptpl == SPDK_NVME_RESERVE_PTPL_PERSIST_POWER_LOSS) {
1473 		SPDK_ERRLOG("Can't change persist through power loss for now\n");
1474 		status = SPDK_NVME_SC_INVALID_FIELD;
1475 		goto exit;
1476 	}
1477 
1478 	/* current Host Identifier has registrant or not */
1479 	reg = nvmf_ns_reservation_get_registrant(ns, &ctrlr->hostid);
1480 
1481 	switch (rrega) {
1482 	case SPDK_NVME_RESERVE_REGISTER_KEY:
1483 		if (!reg) {
1484 			/* register new controller */
1485 			if (key.nrkey == 0) {
1486 				SPDK_ERRLOG("Can't register zeroed new key\n");
1487 				status = SPDK_NVME_SC_INVALID_FIELD;
1488 				goto exit;
1489 			}
1490 			rc = nvmf_ns_reservation_add_registrant(ns, ctrlr, key.nrkey);
1491 			if (rc < 0) {
1492 				status = SPDK_NVME_SC_INTERNAL_DEVICE_ERROR;
1493 				goto exit;
1494 			}
1495 		} else {
1496 			/* register with same key is not an error */
1497 			if (reg->rkey != key.nrkey) {
1498 				SPDK_ERRLOG("The same host already register a "
1499 					    "key with 0x%"PRIx64"\n",
1500 					    reg->rkey);
1501 				status = SPDK_NVME_SC_RESERVATION_CONFLICT;
1502 				goto exit;
1503 			}
1504 		}
1505 		break;
1506 	case SPDK_NVME_RESERVE_UNREGISTER_KEY:
1507 		if (!reg || (!iekey && reg->rkey != key.crkey)) {
1508 			SPDK_ERRLOG("No registrant or current key doesn't match "
1509 				    "with existing registrant key\n");
1510 			status = SPDK_NVME_SC_RESERVATION_CONFLICT;
1511 			goto exit;
1512 		}
1513 		nvmf_ns_reservation_remove_registrant(ns, reg);
1514 		update_sgroup = true;
1515 		break;
1516 	case SPDK_NVME_RESERVE_REPLACE_KEY:
1517 		if (!reg || (!iekey && reg->rkey != key.crkey)) {
1518 			SPDK_ERRLOG("No registrant or current key doesn't match "
1519 				    "with existing registrant key\n");
1520 			status = SPDK_NVME_SC_RESERVATION_CONFLICT;
1521 			goto exit;
1522 		}
1523 		if (key.nrkey == 0) {
1524 			SPDK_ERRLOG("Can't register zeroed new key\n");
1525 			status = SPDK_NVME_SC_INVALID_FIELD;
1526 			goto exit;
1527 		}
1528 		reg->rkey = key.nrkey;
1529 		break;
1530 	default:
1531 		status = SPDK_NVME_SC_INVALID_FIELD;
1532 		goto exit;
1533 	}
1534 
1535 exit:
1536 	req->rsp->nvme_cpl.status.sct = SPDK_NVME_SCT_GENERIC;
1537 	req->rsp->nvme_cpl.status.sc = status;
1538 	return update_sgroup;
1539 }
1540 
1541 static bool
1542 nvmf_ns_reservation_acquire(struct spdk_nvmf_ns *ns,
1543 			    struct spdk_nvmf_ctrlr *ctrlr,
1544 			    struct spdk_nvmf_request *req)
1545 {
1546 	struct spdk_nvme_cmd *cmd = &req->cmd->nvme_cmd;
1547 	uint8_t racqa, iekey, rtype;
1548 	struct spdk_nvme_reservation_acquire_data key;
1549 	struct spdk_nvmf_registrant *reg;
1550 	bool all_regs = false;
1551 	uint32_t count = 0;
1552 	bool update_sgroup = true;
1553 	uint8_t status = SPDK_NVME_SC_SUCCESS;
1554 
1555 	racqa = cmd->cdw10 & 0x7u;
1556 	iekey = (cmd->cdw10 >> 3) & 0x1u;
1557 	rtype = (cmd->cdw10 >> 8) & 0xffu;
1558 	memcpy(&key, req->data, sizeof(key));
1559 
1560 	SPDK_DEBUGLOG(SPDK_LOG_NVMF, "ACQUIRE: RACQA %u, IEKEY %u, RTYPE %u, "
1561 		      "NRKEY 0x%"PRIx64", PRKEY 0x%"PRIx64"\n",
1562 		      racqa, iekey, rtype, key.crkey, key.prkey);
1563 
1564 	if (iekey) {
1565 		SPDK_ERRLOG("Ignore existing key field set to 1\n");
1566 		status = SPDK_NVME_SC_INVALID_FIELD;
1567 		update_sgroup = false;
1568 		goto exit;
1569 	}
1570 
1571 	reg = nvmf_ns_reservation_get_registrant(ns, &ctrlr->hostid);
1572 	/* must be registrant and CRKEY must match */
1573 	if (!reg || reg->rkey != key.crkey) {
1574 		SPDK_ERRLOG("No registrant or current key doesn't match "
1575 			    "with existing registrant key\n");
1576 		status = SPDK_NVME_SC_RESERVATION_CONFLICT;
1577 		update_sgroup = false;
1578 		goto exit;
1579 	}
1580 
1581 	all_regs = nvmf_ns_reservation_all_registrants_type(ns);
1582 
1583 	switch (racqa) {
1584 	case SPDK_NVME_RESERVE_ACQUIRE:
1585 		/* it's not an error for the holder to acquire same reservation type again */
1586 		if (nvmf_ns_reservation_registrant_is_holder(ns, reg) && ns->rtype == rtype) {
1587 			/* do nothing */
1588 			update_sgroup = false;
1589 		} else if (ns->holder == NULL) {
1590 			/* fisrt time to acquire the reservation */
1591 			nvmf_ns_reservation_acquire_reservation(ns, key.crkey, rtype, reg);
1592 		} else {
1593 			SPDK_ERRLOG("Invalid rtype or current registrant is not holder\n");
1594 			status = SPDK_NVME_SC_RESERVATION_CONFLICT;
1595 			update_sgroup = false;
1596 			goto exit;
1597 		}
1598 		break;
1599 	case SPDK_NVME_RESERVE_PREEMPT:
1600 		/* no reservation holder */
1601 		if (!ns->holder) {
1602 			/* unregister with PRKEY */
1603 			nvmf_ns_reservation_remove_registrants_by_key(ns, key.prkey);
1604 			break;
1605 		}
1606 		/* only 1 reservation holder and reservation key is valid */
1607 		if (!all_regs) {
1608 			/* preempt itself */
1609 			if (nvmf_ns_reservation_registrant_is_holder(ns, reg) &&
1610 			    ns->crkey == key.prkey) {
1611 				ns->rtype = rtype;
1612 				break;
1613 			}
1614 
1615 			if (ns->crkey == key.prkey) {
1616 				nvmf_ns_reservation_remove_registrant(ns, ns->holder);
1617 				nvmf_ns_reservation_acquire_reservation(ns, key.crkey, rtype, reg);
1618 			} else if (key.prkey != 0) {
1619 				nvmf_ns_reservation_remove_registrants_by_key(ns, key.prkey);
1620 			} else {
1621 				/* PRKEY is zero */
1622 				SPDK_ERRLOG("Current PRKEY is zero\n");
1623 				status = SPDK_NVME_SC_RESERVATION_CONFLICT;
1624 				update_sgroup = false;
1625 				goto exit;
1626 			}
1627 		} else {
1628 			/* release all other registrants except for the current one */
1629 			if (key.prkey == 0) {
1630 				nvmf_ns_reservation_remove_all_other_registrants(ns, reg);
1631 				assert(ns->holder == reg);
1632 			} else {
1633 				count = nvmf_ns_reservation_remove_registrants_by_key(ns, key.prkey);
1634 				if (count == 0) {
1635 					SPDK_ERRLOG("PRKEY doesn't match any registrant\n");
1636 					status = SPDK_NVME_SC_RESERVATION_CONFLICT;
1637 					update_sgroup = false;
1638 					goto exit;
1639 				}
1640 			}
1641 		}
1642 		break;
1643 	default:
1644 		update_sgroup = false;
1645 		break;
1646 	}
1647 
1648 exit:
1649 	req->rsp->nvme_cpl.status.sct = SPDK_NVME_SCT_GENERIC;
1650 	req->rsp->nvme_cpl.status.sc = status;
1651 	return update_sgroup;
1652 }
1653 
1654 static bool
1655 nvmf_ns_reservation_release(struct spdk_nvmf_ns *ns,
1656 			    struct spdk_nvmf_ctrlr *ctrlr,
1657 			    struct spdk_nvmf_request *req)
1658 {
1659 	struct spdk_nvme_cmd *cmd = &req->cmd->nvme_cmd;
1660 	uint8_t rrela, iekey, rtype;
1661 	struct spdk_nvmf_registrant *reg;
1662 	uint64_t crkey;
1663 	uint8_t status = SPDK_NVME_SC_SUCCESS;
1664 	bool update_sgroup = true;
1665 
1666 	rrela = cmd->cdw10 & 0x7u;
1667 	iekey = (cmd->cdw10 >> 3) & 0x1u;
1668 	rtype = (cmd->cdw10 >> 8) & 0xffu;
1669 	memcpy(&crkey, req->data, sizeof(crkey));
1670 
1671 	SPDK_DEBUGLOG(SPDK_LOG_NVMF, "RELEASE: RRELA %u, IEKEY %u, RTYPE %u, "
1672 		      "CRKEY 0x%"PRIx64"\n",  rrela, iekey, rtype, crkey);
1673 
1674 	if (iekey) {
1675 		SPDK_ERRLOG("Ignore existing key field set to 1\n");
1676 		status = SPDK_NVME_SC_INVALID_FIELD;
1677 		update_sgroup = false;
1678 		goto exit;
1679 	}
1680 
1681 	reg = nvmf_ns_reservation_get_registrant(ns, &ctrlr->hostid);
1682 	if (!reg || reg->rkey != crkey) {
1683 		SPDK_ERRLOG("No registrant or current key doesn't match "
1684 			    "with existing registrant key\n");
1685 		status = SPDK_NVME_SC_RESERVATION_CONFLICT;
1686 		update_sgroup = false;
1687 		goto exit;
1688 	}
1689 
1690 	switch (rrela) {
1691 	case SPDK_NVME_RESERVE_RELEASE:
1692 		if (!ns->holder) {
1693 			SPDK_DEBUGLOG(SPDK_LOG_NVMF, "RELEASE: no holder\n");
1694 			update_sgroup = false;
1695 			goto exit;
1696 		}
1697 		if (ns->rtype != rtype) {
1698 			SPDK_ERRLOG("Type doesn't match\n");
1699 			status = SPDK_NVME_SC_INVALID_FIELD;
1700 			update_sgroup = false;
1701 			goto exit;
1702 		}
1703 		if (!nvmf_ns_reservation_registrant_is_holder(ns, reg)) {
1704 			/* not the reservation holder, this isn't an error */
1705 			update_sgroup = false;
1706 			goto exit;
1707 		}
1708 		nvmf_ns_reservation_release_reservation(ns);
1709 		break;
1710 	case SPDK_NVME_RESERVE_CLEAR:
1711 		nvmf_ns_reservation_clear_all_registrants(ns);
1712 		break;
1713 	default:
1714 		status = SPDK_NVME_SC_INVALID_FIELD;
1715 		update_sgroup = false;
1716 		goto exit;
1717 	}
1718 
1719 exit:
1720 	req->rsp->nvme_cpl.status.sct = SPDK_NVME_SCT_GENERIC;
1721 	req->rsp->nvme_cpl.status.sc = status;
1722 	return update_sgroup;
1723 }
1724 
1725 static void
1726 nvmf_ns_reservation_report(struct spdk_nvmf_ns *ns,
1727 			   struct spdk_nvmf_ctrlr *ctrlr,
1728 			   struct spdk_nvmf_request *req)
1729 {
1730 	struct spdk_nvme_cmd *cmd = &req->cmd->nvme_cmd;
1731 	struct spdk_nvmf_subsystem *subsystem = ctrlr->subsys;
1732 	struct spdk_nvmf_ctrlr *ctrlr_tmp;
1733 	struct spdk_nvmf_registrant *reg, *tmp;
1734 	struct spdk_nvme_reservation_status_extended_data *status_data;
1735 	struct spdk_nvme_registered_ctrlr_extended_data *ctrlr_data;
1736 	uint8_t *payload;
1737 	uint32_t len, count = 0;
1738 	uint32_t regctl = 0;
1739 	uint8_t status = SPDK_NVME_SC_SUCCESS;
1740 
1741 	/* NVMeoF uses Extended Data Structure */
1742 	if ((cmd->cdw11 & 0x00000001u) == 0) {
1743 		SPDK_ERRLOG("NVMeoF uses extended controller data structure, "
1744 			    "please set EDS bit in cdw11 and try again\n");
1745 		status = SPDK_NVME_SC_INVALID_FIELD;
1746 		goto exit;
1747 	}
1748 
1749 	/* Get number of registerd controllers, one Host may have more than
1750 	 * one controller based on different ports.
1751 	 */
1752 	TAILQ_FOREACH(ctrlr_tmp, &subsystem->ctrlrs, link) {
1753 		reg = nvmf_ns_reservation_get_registrant(ns, &ctrlr_tmp->hostid);
1754 		if (reg) {
1755 			regctl++;
1756 		}
1757 	}
1758 
1759 	len = sizeof(*status_data) + sizeof(*ctrlr_data) * regctl;
1760 	payload = calloc(1, len);
1761 	if (!payload) {
1762 		status = SPDK_NVME_SC_INTERNAL_DEVICE_ERROR;
1763 		goto exit;
1764 	}
1765 
1766 	status_data = (struct spdk_nvme_reservation_status_extended_data *)payload;
1767 	status_data->data.gen = ns->gen;
1768 	status_data->data.rtype = ns->rtype;
1769 	status_data->data.regctl = regctl;
1770 	/* TODO: Don't support Persist Through Power Loss State for now */
1771 	status_data->data.ptpls = 0;
1772 
1773 	TAILQ_FOREACH_SAFE(reg, &ns->registrants, link, tmp) {
1774 		assert(count <= regctl);
1775 		ctrlr_data = (struct spdk_nvme_registered_ctrlr_extended_data *)
1776 			     (payload + sizeof(*status_data) + sizeof(*ctrlr_data) * count);
1777 		/* Set to 0xffffh for dynamic controller */
1778 		ctrlr_data->cntlid = 0xffff;
1779 		ctrlr_data->rcsts.status = (ns->holder == reg) ? true : false;
1780 		ctrlr_data->rkey = reg->rkey;
1781 		spdk_uuid_copy((struct spdk_uuid *)ctrlr_data->hostid, &reg->hostid);
1782 		count++;
1783 	}
1784 
1785 	memcpy(req->data, payload, spdk_min(len, (cmd->cdw10 + 1) * sizeof(uint32_t)));
1786 	free(payload);
1787 
1788 exit:
1789 	req->rsp->nvme_cpl.status.sct = SPDK_NVME_SCT_GENERIC;
1790 	req->rsp->nvme_cpl.status.sc = status;
1791 	return;
1792 }
1793 
1794 static void
1795 spdk_nvmf_ns_reservation_complete(void *ctx)
1796 {
1797 	struct spdk_nvmf_request *req = ctx;
1798 
1799 	spdk_nvmf_request_complete(req);
1800 }
1801 
1802 static void
1803 _nvmf_ns_reservation_update_done(struct spdk_nvmf_subsystem *subsystem,
1804 				 void *cb_arg, int status)
1805 {
1806 	struct spdk_nvmf_request *req = (struct spdk_nvmf_request *)cb_arg;
1807 	struct spdk_nvmf_poll_group *group = req->qpair->group;
1808 
1809 	spdk_thread_send_msg(group->thread, spdk_nvmf_ns_reservation_complete, req);
1810 }
1811 
1812 void
1813 spdk_nvmf_ns_reservation_request(void *ctx)
1814 {
1815 	struct spdk_nvmf_request *req = (struct spdk_nvmf_request *)ctx;
1816 	struct spdk_nvme_cmd *cmd = &req->cmd->nvme_cmd;
1817 	struct spdk_nvmf_ctrlr *ctrlr = req->qpair->ctrlr;
1818 	struct subsystem_update_ns_ctx *update_ctx;
1819 	uint32_t nsid;
1820 	struct spdk_nvmf_ns *ns;
1821 	bool update_sgroup = false;
1822 
1823 	nsid = cmd->nsid;
1824 	ns = _spdk_nvmf_subsystem_get_ns(ctrlr->subsys, nsid);
1825 	assert(ns != NULL);
1826 
1827 	switch (cmd->opc) {
1828 	case SPDK_NVME_OPC_RESERVATION_REGISTER:
1829 		update_sgroup = nvmf_ns_reservation_register(ns, ctrlr, req);
1830 		break;
1831 	case SPDK_NVME_OPC_RESERVATION_ACQUIRE:
1832 		update_sgroup = nvmf_ns_reservation_acquire(ns, ctrlr, req);
1833 		break;
1834 	case SPDK_NVME_OPC_RESERVATION_RELEASE:
1835 		update_sgroup = nvmf_ns_reservation_release(ns, ctrlr, req);
1836 		break;
1837 	case SPDK_NVME_OPC_RESERVATION_REPORT:
1838 		nvmf_ns_reservation_report(ns, ctrlr, req);
1839 		break;
1840 	default:
1841 		break;
1842 	}
1843 
1844 	/* update reservation information to subsystem's poll group */
1845 	if (update_sgroup) {
1846 		update_ctx = calloc(1, sizeof(*update_ctx));
1847 		if (update_ctx == NULL) {
1848 			SPDK_ERRLOG("Can't alloc subsystem poll group update context\n");
1849 			goto update_done;
1850 		}
1851 		update_ctx->subsystem = ctrlr->subsys;
1852 		update_ctx->cb_fn = _nvmf_ns_reservation_update_done;
1853 		update_ctx->cb_arg = req;
1854 
1855 		spdk_nvmf_subsystem_update_ns(ctrlr->subsys, subsystem_update_ns_done, update_ctx);
1856 		return;
1857 	}
1858 
1859 update_done:
1860 	_nvmf_ns_reservation_update_done(ctrlr->subsys, (void *)req, 0);
1861 }
1862