xref: /spdk/lib/nvmf/subsystem.c (revision 8a0a98d35e21f282088edf28b9e8da66ec390e3a)
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->opts.max_subsystems; sid++) {
257 		if (tgt->subsystems[sid] == NULL) {
258 			break;
259 		}
260 	}
261 	if (sid >= tgt->opts.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 	tgt->subsystems[sid] = subsystem;
293 	tgt->discovery_genctr++;
294 
295 	return subsystem;
296 }
297 
298 static void
299 _spdk_nvmf_subsystem_remove_host(struct spdk_nvmf_subsystem *subsystem, struct spdk_nvmf_host *host)
300 {
301 	TAILQ_REMOVE(&subsystem->hosts, host, link);
302 	free(host->nqn);
303 	free(host);
304 }
305 
306 static int _spdk_nvmf_subsystem_remove_ns(struct spdk_nvmf_subsystem *subsystem, uint32_t nsid);
307 
308 void
309 spdk_nvmf_subsystem_destroy(struct spdk_nvmf_subsystem *subsystem)
310 {
311 	struct spdk_nvmf_listener	*listener, *listener_tmp;
312 	struct spdk_nvmf_host		*host, *host_tmp;
313 	struct spdk_nvmf_ctrlr		*ctrlr, *ctrlr_tmp;
314 	struct spdk_nvmf_ns		*ns;
315 
316 	if (!subsystem) {
317 		return;
318 	}
319 
320 	assert(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE);
321 
322 	SPDK_DEBUGLOG(SPDK_LOG_NVMF, "subsystem is %p\n", subsystem);
323 
324 	TAILQ_FOREACH_SAFE(listener, &subsystem->listeners, link, listener_tmp) {
325 		TAILQ_REMOVE(&subsystem->listeners, listener, link);
326 		free(listener);
327 	}
328 
329 	TAILQ_FOREACH_SAFE(host, &subsystem->hosts, link, host_tmp) {
330 		_spdk_nvmf_subsystem_remove_host(subsystem, host);
331 	}
332 
333 	TAILQ_FOREACH_SAFE(ctrlr, &subsystem->ctrlrs, link, ctrlr_tmp) {
334 		spdk_nvmf_ctrlr_destruct(ctrlr);
335 	}
336 
337 	ns = spdk_nvmf_subsystem_get_first_ns(subsystem);
338 	while (ns != NULL) {
339 		struct spdk_nvmf_ns *next_ns = spdk_nvmf_subsystem_get_next_ns(subsystem, ns);
340 
341 		_spdk_nvmf_subsystem_remove_ns(subsystem, ns->opts.nsid);
342 		ns = next_ns;
343 	}
344 
345 	free(subsystem->ns);
346 
347 	subsystem->tgt->subsystems[subsystem->id] = NULL;
348 	subsystem->tgt->discovery_genctr++;
349 
350 	free(subsystem);
351 }
352 
353 static int
354 spdk_nvmf_subsystem_set_state(struct spdk_nvmf_subsystem *subsystem,
355 			      enum spdk_nvmf_subsystem_state state)
356 {
357 	enum spdk_nvmf_subsystem_state actual_old_state, expected_old_state;
358 
359 	switch (state) {
360 	case SPDK_NVMF_SUBSYSTEM_INACTIVE:
361 		expected_old_state = SPDK_NVMF_SUBSYSTEM_DEACTIVATING;
362 		break;
363 	case SPDK_NVMF_SUBSYSTEM_ACTIVATING:
364 		expected_old_state = SPDK_NVMF_SUBSYSTEM_INACTIVE;
365 		break;
366 	case SPDK_NVMF_SUBSYSTEM_ACTIVE:
367 		expected_old_state = SPDK_NVMF_SUBSYSTEM_ACTIVATING;
368 		break;
369 	case SPDK_NVMF_SUBSYSTEM_PAUSING:
370 		expected_old_state = SPDK_NVMF_SUBSYSTEM_ACTIVE;
371 		break;
372 	case SPDK_NVMF_SUBSYSTEM_PAUSED:
373 		expected_old_state = SPDK_NVMF_SUBSYSTEM_PAUSING;
374 		break;
375 	case SPDK_NVMF_SUBSYSTEM_RESUMING:
376 		expected_old_state = SPDK_NVMF_SUBSYSTEM_PAUSED;
377 		break;
378 	case SPDK_NVMF_SUBSYSTEM_DEACTIVATING:
379 		expected_old_state = SPDK_NVMF_SUBSYSTEM_ACTIVE;
380 		break;
381 	default:
382 		assert(false);
383 		return -1;
384 	}
385 
386 	actual_old_state = __sync_val_compare_and_swap(&subsystem->state, expected_old_state, state);
387 	if (actual_old_state != expected_old_state) {
388 		if (actual_old_state == SPDK_NVMF_SUBSYSTEM_RESUMING &&
389 		    state == SPDK_NVMF_SUBSYSTEM_ACTIVE) {
390 			expected_old_state = SPDK_NVMF_SUBSYSTEM_RESUMING;
391 		}
392 		actual_old_state = __sync_val_compare_and_swap(&subsystem->state, expected_old_state, state);
393 	}
394 	assert(actual_old_state == expected_old_state);
395 	return actual_old_state - expected_old_state;
396 }
397 
398 struct subsystem_state_change_ctx {
399 	struct spdk_nvmf_subsystem *subsystem;
400 
401 	enum spdk_nvmf_subsystem_state requested_state;
402 
403 	spdk_nvmf_subsystem_state_change_done cb_fn;
404 	void *cb_arg;
405 };
406 
407 static void
408 subsystem_state_change_done(struct spdk_io_channel_iter *i, int status)
409 {
410 	struct subsystem_state_change_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
411 
412 	if (status == 0) {
413 		status = spdk_nvmf_subsystem_set_state(ctx->subsystem, ctx->requested_state);
414 		if (status) {
415 			status = -1;
416 		}
417 	}
418 
419 	if (ctx->cb_fn) {
420 		ctx->cb_fn(ctx->subsystem, ctx->cb_arg, status);
421 	}
422 	free(ctx);
423 }
424 
425 static void
426 subsystem_state_change_on_pg(struct spdk_io_channel_iter *i)
427 {
428 	struct subsystem_state_change_ctx *ctx;
429 	struct spdk_io_channel *ch;
430 	struct spdk_nvmf_poll_group *group;
431 	int rc = -1;
432 
433 	ctx = spdk_io_channel_iter_get_ctx(i);
434 	ch = spdk_io_channel_iter_get_channel(i);
435 	group = spdk_io_channel_get_ctx(ch);
436 
437 	switch (ctx->requested_state) {
438 	case SPDK_NVMF_SUBSYSTEM_INACTIVE:
439 		rc = spdk_nvmf_poll_group_remove_subsystem(group, ctx->subsystem);
440 		break;
441 	case SPDK_NVMF_SUBSYSTEM_ACTIVE:
442 		if (ctx->subsystem->state == SPDK_NVMF_SUBSYSTEM_ACTIVATING) {
443 			rc = spdk_nvmf_poll_group_add_subsystem(group, ctx->subsystem);
444 		} else if (ctx->subsystem->state == SPDK_NVMF_SUBSYSTEM_RESUMING) {
445 			rc = spdk_nvmf_poll_group_resume_subsystem(group, ctx->subsystem);
446 		}
447 		break;
448 	case SPDK_NVMF_SUBSYSTEM_PAUSED:
449 		rc = spdk_nvmf_poll_group_pause_subsystem(group, ctx->subsystem);
450 		break;
451 	default:
452 		assert(false);
453 		break;
454 	}
455 
456 	spdk_for_each_channel_continue(i, rc);
457 }
458 
459 static int
460 spdk_nvmf_subsystem_state_change(struct spdk_nvmf_subsystem *subsystem,
461 				 enum spdk_nvmf_subsystem_state requested_state,
462 				 spdk_nvmf_subsystem_state_change_done cb_fn,
463 				 void *cb_arg)
464 {
465 	struct subsystem_state_change_ctx *ctx;
466 	enum spdk_nvmf_subsystem_state intermediate_state;
467 	int rc;
468 
469 	switch (requested_state) {
470 	case SPDK_NVMF_SUBSYSTEM_INACTIVE:
471 		intermediate_state = SPDK_NVMF_SUBSYSTEM_DEACTIVATING;
472 		break;
473 	case SPDK_NVMF_SUBSYSTEM_ACTIVE:
474 		if (subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED) {
475 			intermediate_state = SPDK_NVMF_SUBSYSTEM_RESUMING;
476 		} else {
477 			intermediate_state = SPDK_NVMF_SUBSYSTEM_ACTIVATING;
478 		}
479 		break;
480 	case SPDK_NVMF_SUBSYSTEM_PAUSED:
481 		intermediate_state = SPDK_NVMF_SUBSYSTEM_PAUSING;
482 		break;
483 	default:
484 		assert(false);
485 		return -EINVAL;
486 	}
487 
488 	ctx = calloc(1, sizeof(*ctx));
489 	if (!ctx) {
490 		return -ENOMEM;
491 	}
492 
493 	rc = spdk_nvmf_subsystem_set_state(subsystem, intermediate_state);
494 	if (rc) {
495 		free(ctx);
496 		return rc;
497 	}
498 
499 	ctx->subsystem = subsystem;
500 	ctx->requested_state = requested_state;
501 	ctx->cb_fn = cb_fn;
502 	ctx->cb_arg = cb_arg;
503 
504 	spdk_for_each_channel(subsystem->tgt,
505 			      subsystem_state_change_on_pg,
506 			      ctx,
507 			      subsystem_state_change_done);
508 
509 	return 0;
510 }
511 
512 int
513 spdk_nvmf_subsystem_start(struct spdk_nvmf_subsystem *subsystem,
514 			  spdk_nvmf_subsystem_state_change_done cb_fn,
515 			  void *cb_arg)
516 {
517 	return spdk_nvmf_subsystem_state_change(subsystem, SPDK_NVMF_SUBSYSTEM_ACTIVE, cb_fn, cb_arg);
518 }
519 
520 int
521 spdk_nvmf_subsystem_stop(struct spdk_nvmf_subsystem *subsystem,
522 			 spdk_nvmf_subsystem_state_change_done cb_fn,
523 			 void *cb_arg)
524 {
525 	return spdk_nvmf_subsystem_state_change(subsystem, SPDK_NVMF_SUBSYSTEM_INACTIVE, cb_fn, cb_arg);
526 }
527 
528 int
529 spdk_nvmf_subsystem_pause(struct spdk_nvmf_subsystem *subsystem,
530 			  spdk_nvmf_subsystem_state_change_done cb_fn,
531 			  void *cb_arg)
532 {
533 	return spdk_nvmf_subsystem_state_change(subsystem, SPDK_NVMF_SUBSYSTEM_PAUSED, cb_fn, cb_arg);
534 }
535 
536 int
537 spdk_nvmf_subsystem_resume(struct spdk_nvmf_subsystem *subsystem,
538 			   spdk_nvmf_subsystem_state_change_done cb_fn,
539 			   void *cb_arg)
540 {
541 	return spdk_nvmf_subsystem_state_change(subsystem, SPDK_NVMF_SUBSYSTEM_ACTIVE, cb_fn, cb_arg);
542 }
543 
544 struct spdk_nvmf_subsystem *
545 spdk_nvmf_subsystem_get_first(struct spdk_nvmf_tgt *tgt)
546 {
547 	struct spdk_nvmf_subsystem	*subsystem;
548 	uint32_t sid;
549 
550 	for (sid = 0; sid < tgt->opts.max_subsystems; sid++) {
551 		subsystem = tgt->subsystems[sid];
552 		if (subsystem) {
553 			return subsystem;
554 		}
555 	}
556 
557 	return NULL;
558 }
559 
560 struct spdk_nvmf_subsystem *
561 spdk_nvmf_subsystem_get_next(struct spdk_nvmf_subsystem *subsystem)
562 {
563 	uint32_t sid;
564 	struct spdk_nvmf_tgt *tgt;
565 
566 	if (!subsystem) {
567 		return NULL;
568 	}
569 
570 	tgt = subsystem->tgt;
571 
572 	for (sid = subsystem->id + 1; sid < tgt->opts.max_subsystems; sid++) {
573 		subsystem = tgt->subsystems[sid];
574 		if (subsystem) {
575 			return subsystem;
576 		}
577 	}
578 
579 	return NULL;
580 }
581 
582 static struct spdk_nvmf_host *
583 _spdk_nvmf_subsystem_find_host(struct spdk_nvmf_subsystem *subsystem, const char *hostnqn)
584 {
585 	struct spdk_nvmf_host *host = NULL;
586 
587 	TAILQ_FOREACH(host, &subsystem->hosts, link) {
588 		if (strcmp(hostnqn, host->nqn) == 0) {
589 			return host;
590 		}
591 	}
592 
593 	return NULL;
594 }
595 
596 int
597 spdk_nvmf_subsystem_add_host(struct spdk_nvmf_subsystem *subsystem, const char *hostnqn)
598 {
599 	struct spdk_nvmf_host *host;
600 
601 	if (!spdk_nvmf_valid_nqn(hostnqn)) {
602 		return -EINVAL;
603 	}
604 
605 	if (!(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
606 	      subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED)) {
607 		return -EAGAIN;
608 	}
609 
610 	if (_spdk_nvmf_subsystem_find_host(subsystem, hostnqn)) {
611 		/* This subsystem already allows the specified host. */
612 		return 0;
613 	}
614 
615 	host = calloc(1, sizeof(*host));
616 	if (!host) {
617 		return -ENOMEM;
618 	}
619 	host->nqn = strdup(hostnqn);
620 	if (!host->nqn) {
621 		free(host);
622 		return -ENOMEM;
623 	}
624 
625 	TAILQ_INSERT_HEAD(&subsystem->hosts, host, link);
626 	subsystem->tgt->discovery_genctr++;
627 
628 	return 0;
629 }
630 
631 int
632 spdk_nvmf_subsystem_remove_host(struct spdk_nvmf_subsystem *subsystem, const char *hostnqn)
633 {
634 	struct spdk_nvmf_host *host;
635 
636 	if (!(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
637 	      subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED)) {
638 		return -EAGAIN;
639 	}
640 
641 	host = _spdk_nvmf_subsystem_find_host(subsystem, hostnqn);
642 	if (host == NULL) {
643 		return -ENOENT;
644 	}
645 
646 	_spdk_nvmf_subsystem_remove_host(subsystem, host);
647 	return 0;
648 }
649 
650 int
651 spdk_nvmf_subsystem_set_allow_any_host(struct spdk_nvmf_subsystem *subsystem, bool allow_any_host)
652 {
653 	if (!(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
654 	      subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED)) {
655 		return -EAGAIN;
656 	}
657 
658 	subsystem->allow_any_host = allow_any_host;
659 
660 	return 0;
661 }
662 
663 bool
664 spdk_nvmf_subsystem_get_allow_any_host(const struct spdk_nvmf_subsystem *subsystem)
665 {
666 	return subsystem->allow_any_host;
667 }
668 
669 bool
670 spdk_nvmf_subsystem_host_allowed(struct spdk_nvmf_subsystem *subsystem, const char *hostnqn)
671 {
672 	if (!hostnqn) {
673 		return false;
674 	}
675 
676 	if (subsystem->allow_any_host) {
677 		return true;
678 	}
679 
680 	return _spdk_nvmf_subsystem_find_host(subsystem, hostnqn) != NULL;
681 }
682 
683 struct spdk_nvmf_host *
684 spdk_nvmf_subsystem_get_first_host(struct spdk_nvmf_subsystem *subsystem)
685 {
686 	return TAILQ_FIRST(&subsystem->hosts);
687 }
688 
689 
690 struct spdk_nvmf_host *
691 spdk_nvmf_subsystem_get_next_host(struct spdk_nvmf_subsystem *subsystem,
692 				  struct spdk_nvmf_host *prev_host)
693 {
694 	return TAILQ_NEXT(prev_host, link);
695 }
696 
697 const char *
698 spdk_nvmf_host_get_nqn(struct spdk_nvmf_host *host)
699 {
700 	return host->nqn;
701 }
702 
703 static struct spdk_nvmf_listener *
704 _spdk_nvmf_subsystem_find_listener(struct spdk_nvmf_subsystem *subsystem,
705 				   const struct spdk_nvme_transport_id *trid)
706 {
707 	struct spdk_nvmf_listener *listener;
708 
709 	TAILQ_FOREACH(listener, &subsystem->listeners, link) {
710 		if (spdk_nvme_transport_id_compare(&listener->trid, trid) == 0) {
711 			return listener;
712 		}
713 	}
714 
715 	return NULL;
716 }
717 
718 int
719 spdk_nvmf_subsystem_add_listener(struct spdk_nvmf_subsystem *subsystem,
720 				 struct spdk_nvme_transport_id *trid)
721 {
722 	struct spdk_nvmf_transport *transport;
723 	struct spdk_nvmf_listener *listener;
724 
725 	if (!(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
726 	      subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED)) {
727 		return -EAGAIN;
728 	}
729 
730 	if (_spdk_nvmf_subsystem_find_listener(subsystem, trid)) {
731 		/* Listener already exists in this subsystem */
732 		return 0;
733 	}
734 
735 	transport = spdk_nvmf_tgt_get_transport(subsystem->tgt, trid->trtype);
736 	if (transport == NULL) {
737 		SPDK_ERRLOG("Unknown transport type %d\n", trid->trtype);
738 		return -EINVAL;
739 	}
740 
741 	listener = calloc(1, sizeof(*listener));
742 	if (!listener) {
743 		return -ENOMEM;
744 	}
745 
746 	listener->trid = *trid;
747 	listener->transport = transport;
748 
749 	TAILQ_INSERT_HEAD(&subsystem->listeners, listener, link);
750 
751 	return 0;
752 }
753 
754 int
755 spdk_nvmf_subsystem_remove_listener(struct spdk_nvmf_subsystem *subsystem,
756 				    const struct spdk_nvme_transport_id *trid)
757 {
758 	struct spdk_nvmf_listener *listener;
759 
760 	if (!(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
761 	      subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED)) {
762 		return -EAGAIN;
763 	}
764 
765 	listener = _spdk_nvmf_subsystem_find_listener(subsystem, trid);
766 	if (listener == NULL) {
767 		return -ENOENT;
768 	}
769 
770 	TAILQ_REMOVE(&subsystem->listeners, listener, link);
771 	free(listener);
772 
773 	return 0;
774 }
775 
776 /*
777  * TODO: this is the whitelist and will be called during connection setup
778  */
779 bool
780 spdk_nvmf_subsystem_listener_allowed(struct spdk_nvmf_subsystem *subsystem,
781 				     struct spdk_nvme_transport_id *trid)
782 {
783 	struct spdk_nvmf_listener *listener;
784 
785 	if (TAILQ_EMPTY(&subsystem->listeners)) {
786 		return true;
787 	}
788 
789 	TAILQ_FOREACH(listener, &subsystem->listeners, link) {
790 		if (spdk_nvme_transport_id_compare(&listener->trid, trid) == 0) {
791 			return true;
792 		}
793 	}
794 
795 	return false;
796 }
797 
798 struct spdk_nvmf_listener *
799 spdk_nvmf_subsystem_get_first_listener(struct spdk_nvmf_subsystem *subsystem)
800 {
801 	return TAILQ_FIRST(&subsystem->listeners);
802 }
803 
804 struct spdk_nvmf_listener *
805 spdk_nvmf_subsystem_get_next_listener(struct spdk_nvmf_subsystem *subsystem,
806 				      struct spdk_nvmf_listener *prev_listener)
807 {
808 	return TAILQ_NEXT(prev_listener, link);
809 }
810 
811 const struct spdk_nvme_transport_id *
812 spdk_nvmf_listener_get_trid(struct spdk_nvmf_listener *listener)
813 {
814 	return &listener->trid;
815 }
816 
817 struct subsystem_update_ns_ctx {
818 	struct spdk_nvmf_subsystem *subsystem;
819 
820 	spdk_nvmf_subsystem_state_change_done cb_fn;
821 	void *cb_arg;
822 };
823 
824 static void
825 subsystem_update_ns_done(struct spdk_io_channel_iter *i, int status)
826 {
827 	struct subsystem_update_ns_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
828 
829 	if (ctx->cb_fn) {
830 		ctx->cb_fn(ctx->subsystem, ctx->cb_arg, status);
831 	}
832 	free(ctx);
833 }
834 
835 static void
836 subsystem_update_ns_on_pg(struct spdk_io_channel_iter *i)
837 {
838 	int rc;
839 	struct subsystem_update_ns_ctx *ctx;
840 	struct spdk_nvmf_poll_group *group;
841 	struct spdk_nvmf_subsystem *subsystem;
842 
843 	ctx = spdk_io_channel_iter_get_ctx(i);
844 	group = spdk_io_channel_get_ctx(spdk_io_channel_iter_get_channel(i));
845 	subsystem = ctx->subsystem;
846 
847 	rc = spdk_nvmf_poll_group_update_subsystem(group, subsystem);
848 	spdk_for_each_channel_continue(i, rc);
849 }
850 
851 static int
852 spdk_nvmf_subsystem_update_ns(struct spdk_nvmf_subsystem *subsystem, spdk_channel_for_each_cpl cpl,
853 			      void *ctx)
854 {
855 	spdk_for_each_channel(subsystem->tgt,
856 			      subsystem_update_ns_on_pg,
857 			      ctx,
858 			      cpl);
859 
860 	return 0;
861 }
862 
863 static void
864 spdk_nvmf_subsystem_ns_changed(struct spdk_nvmf_subsystem *subsystem, uint32_t nsid)
865 {
866 	struct spdk_nvmf_ctrlr *ctrlr;
867 
868 	TAILQ_FOREACH(ctrlr, &subsystem->ctrlrs, link) {
869 		spdk_nvmf_ctrlr_ns_changed(ctrlr, nsid);
870 	}
871 }
872 
873 static int
874 _spdk_nvmf_subsystem_remove_ns(struct spdk_nvmf_subsystem *subsystem, uint32_t nsid)
875 {
876 	struct spdk_nvmf_ns *ns;
877 
878 	assert(subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED ||
879 	       subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE);
880 
881 	if (nsid == 0 || nsid > subsystem->max_nsid) {
882 		return -1;
883 	}
884 
885 	if (!(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
886 	      subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED)) {
887 		return -1;
888 	}
889 
890 	ns = subsystem->ns[nsid - 1];
891 	if (!ns) {
892 		return -1;
893 	}
894 
895 	subsystem->ns[nsid - 1] = NULL;
896 
897 	spdk_bdev_close(ns->desc);
898 	free(ns);
899 
900 	spdk_nvmf_subsystem_ns_changed(subsystem, nsid);
901 
902 	return 0;
903 }
904 
905 int
906 spdk_nvmf_subsystem_remove_ns(struct spdk_nvmf_subsystem *subsystem, uint32_t nsid,
907 			      spdk_nvmf_subsystem_state_change_done cb_fn, void *cb_arg)
908 {
909 	int rc;
910 	struct subsystem_update_ns_ctx *ctx;
911 
912 	rc = _spdk_nvmf_subsystem_remove_ns(subsystem, nsid);
913 	if (rc < 0) {
914 		return rc;
915 	}
916 
917 	ctx = calloc(1, sizeof(*ctx));
918 
919 	if (ctx == NULL) {
920 		return -ENOMEM;
921 	}
922 
923 	ctx->subsystem = subsystem;
924 	ctx->cb_fn = cb_fn;
925 	ctx->cb_arg = cb_arg;
926 
927 	spdk_nvmf_subsystem_update_ns(subsystem, subsystem_update_ns_done, ctx);
928 
929 	return 0;
930 }
931 
932 static void
933 _spdk_nvmf_ns_hot_remove_done(struct spdk_nvmf_subsystem *subsystem, void *cb_arg, int status)
934 {
935 	if (status != 0) {
936 		SPDK_ERRLOG("Failed to make changes to NVMe-oF subsystem with id %u\n", subsystem->id);
937 	}
938 	spdk_nvmf_subsystem_resume(subsystem, NULL, NULL);
939 }
940 
941 static void
942 _spdk_nvmf_ns_hot_remove(struct spdk_nvmf_subsystem *subsystem,
943 			 void *cb_arg, int status)
944 {
945 	struct spdk_nvmf_ns *ns = cb_arg;
946 
947 	spdk_nvmf_subsystem_remove_ns(subsystem, ns->opts.nsid, _spdk_nvmf_ns_hot_remove_done,
948 				      subsystem);
949 }
950 
951 static void
952 spdk_nvmf_ns_hot_remove(void *remove_ctx)
953 {
954 	struct spdk_nvmf_ns *ns = remove_ctx;
955 	int rc;
956 
957 	rc = spdk_nvmf_subsystem_pause(ns->subsystem, _spdk_nvmf_ns_hot_remove, ns);
958 	if (rc) {
959 		SPDK_ERRLOG("Unable to pause subsystem to process namespace removal!\n");
960 	}
961 }
962 
963 void
964 spdk_nvmf_ns_opts_get_defaults(struct spdk_nvmf_ns_opts *opts, size_t opts_size)
965 {
966 	/* All current fields are set to 0 by default. */
967 	memset(opts, 0, opts_size);
968 }
969 
970 uint32_t
971 spdk_nvmf_subsystem_add_ns(struct spdk_nvmf_subsystem *subsystem, struct spdk_bdev *bdev,
972 			   const struct spdk_nvmf_ns_opts *user_opts, size_t opts_size)
973 {
974 	struct spdk_nvmf_ns_opts opts;
975 	struct spdk_nvmf_ns *ns;
976 	int rc;
977 
978 	if (!(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
979 	      subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED)) {
980 		return 0;
981 	}
982 
983 	spdk_nvmf_ns_opts_get_defaults(&opts, sizeof(opts));
984 	if (user_opts) {
985 		memcpy(&opts, user_opts, spdk_min(sizeof(opts), opts_size));
986 	}
987 
988 	if (spdk_mem_all_zero(&opts.uuid, sizeof(opts.uuid))) {
989 		opts.uuid = *spdk_bdev_get_uuid(bdev);
990 	}
991 
992 	if (opts.nsid == SPDK_NVME_GLOBAL_NS_TAG) {
993 		SPDK_ERRLOG("Invalid NSID %" PRIu32 "\n", opts.nsid);
994 		return 0;
995 	}
996 
997 	if (opts.nsid == 0) {
998 		/*
999 		 * NSID not specified - find a free index.
1000 		 *
1001 		 * If no free slots are found, opts.nsid will be subsystem->max_nsid + 1, which will
1002 		 * expand max_nsid if possible.
1003 		 */
1004 		for (opts.nsid = 1; opts.nsid <= subsystem->max_nsid; opts.nsid++) {
1005 			if (_spdk_nvmf_subsystem_get_ns(subsystem, opts.nsid) == NULL) {
1006 				break;
1007 			}
1008 		}
1009 	}
1010 
1011 	if (_spdk_nvmf_subsystem_get_ns(subsystem, opts.nsid)) {
1012 		SPDK_ERRLOG("Requested NSID %" PRIu32 " already in use\n", opts.nsid);
1013 		return 0;
1014 	}
1015 
1016 	if (opts.nsid > subsystem->max_nsid) {
1017 		struct spdk_nvmf_ns **new_ns_array;
1018 
1019 		/* If MaxNamespaces was specified, we can't extend max_nsid beyond it. */
1020 		if (subsystem->max_allowed_nsid > 0 && opts.nsid > subsystem->max_allowed_nsid) {
1021 			SPDK_ERRLOG("Can't extend NSID range above MaxNamespaces\n");
1022 			return 0;
1023 		}
1024 
1025 		/* If a controller is connected, we can't change NN. */
1026 		if (!TAILQ_EMPTY(&subsystem->ctrlrs)) {
1027 			SPDK_ERRLOG("Can't extend NSID range while controllers are connected\n");
1028 			return 0;
1029 		}
1030 
1031 		new_ns_array = realloc(subsystem->ns, sizeof(struct spdk_nvmf_ns *) * opts.nsid);
1032 		if (new_ns_array == NULL) {
1033 			SPDK_ERRLOG("Memory allocation error while resizing namespace array.\n");
1034 			return 0;
1035 		}
1036 
1037 		memset(new_ns_array + subsystem->max_nsid, 0,
1038 		       sizeof(struct spdk_nvmf_ns *) * (opts.nsid - subsystem->max_nsid));
1039 		subsystem->ns = new_ns_array;
1040 		subsystem->max_nsid = opts.nsid;
1041 	}
1042 
1043 	ns = calloc(1, sizeof(*ns));
1044 	if (ns == NULL) {
1045 		SPDK_ERRLOG("Namespace allocation failed\n");
1046 		return 0;
1047 	}
1048 
1049 	ns->bdev = bdev;
1050 	ns->opts = opts;
1051 	ns->subsystem = subsystem;
1052 	rc = spdk_bdev_open(bdev, true, spdk_nvmf_ns_hot_remove, ns, &ns->desc);
1053 	if (rc != 0) {
1054 		SPDK_ERRLOG("Subsystem %s: bdev %s cannot be opened, error=%d\n",
1055 			    subsystem->subnqn, spdk_bdev_get_name(bdev), rc);
1056 		free(ns);
1057 		return 0;
1058 	}
1059 	subsystem->ns[opts.nsid - 1] = ns;
1060 
1061 	SPDK_DEBUGLOG(SPDK_LOG_NVMF, "Subsystem %s: bdev %s assigned nsid %" PRIu32 "\n",
1062 		      spdk_nvmf_subsystem_get_nqn(subsystem),
1063 		      spdk_bdev_get_name(bdev),
1064 		      opts.nsid);
1065 
1066 	spdk_nvmf_subsystem_ns_changed(subsystem, opts.nsid);
1067 
1068 	return opts.nsid;
1069 }
1070 
1071 static uint32_t
1072 spdk_nvmf_subsystem_get_next_allocated_nsid(struct spdk_nvmf_subsystem *subsystem,
1073 		uint32_t prev_nsid)
1074 {
1075 	uint32_t nsid;
1076 
1077 	if (prev_nsid >= subsystem->max_nsid) {
1078 		return 0;
1079 	}
1080 
1081 	for (nsid = prev_nsid + 1; nsid <= subsystem->max_nsid; nsid++) {
1082 		if (subsystem->ns[nsid - 1]) {
1083 			return nsid;
1084 		}
1085 	}
1086 
1087 	return 0;
1088 }
1089 
1090 struct spdk_nvmf_ns *
1091 spdk_nvmf_subsystem_get_first_ns(struct spdk_nvmf_subsystem *subsystem)
1092 {
1093 	uint32_t first_nsid;
1094 
1095 	first_nsid = spdk_nvmf_subsystem_get_next_allocated_nsid(subsystem, 0);
1096 	return _spdk_nvmf_subsystem_get_ns(subsystem, first_nsid);
1097 }
1098 
1099 struct spdk_nvmf_ns *
1100 spdk_nvmf_subsystem_get_next_ns(struct spdk_nvmf_subsystem *subsystem,
1101 				struct spdk_nvmf_ns *prev_ns)
1102 {
1103 	uint32_t next_nsid;
1104 
1105 	next_nsid = spdk_nvmf_subsystem_get_next_allocated_nsid(subsystem, prev_ns->opts.nsid);
1106 	return _spdk_nvmf_subsystem_get_ns(subsystem, next_nsid);
1107 }
1108 
1109 struct spdk_nvmf_ns *
1110 spdk_nvmf_subsystem_get_ns(struct spdk_nvmf_subsystem *subsystem, uint32_t nsid)
1111 {
1112 	return _spdk_nvmf_subsystem_get_ns(subsystem, nsid);
1113 }
1114 
1115 uint32_t
1116 spdk_nvmf_ns_get_id(const struct spdk_nvmf_ns *ns)
1117 {
1118 	return ns->opts.nsid;
1119 }
1120 
1121 struct spdk_bdev *
1122 spdk_nvmf_ns_get_bdev(struct spdk_nvmf_ns *ns)
1123 {
1124 	return ns->bdev;
1125 }
1126 
1127 void
1128 spdk_nvmf_ns_get_opts(const struct spdk_nvmf_ns *ns, struct spdk_nvmf_ns_opts *opts,
1129 		      size_t opts_size)
1130 {
1131 	memset(opts, 0, opts_size);
1132 	memcpy(opts, &ns->opts, spdk_min(sizeof(ns->opts), opts_size));
1133 }
1134 
1135 const char *
1136 spdk_nvmf_subsystem_get_sn(const struct spdk_nvmf_subsystem *subsystem)
1137 {
1138 	return subsystem->sn;
1139 }
1140 
1141 int
1142 spdk_nvmf_subsystem_set_sn(struct spdk_nvmf_subsystem *subsystem, const char *sn)
1143 {
1144 	size_t len, max_len;
1145 
1146 	max_len = sizeof(subsystem->sn) - 1;
1147 	len = strlen(sn);
1148 	if (len > max_len) {
1149 		SPDK_DEBUGLOG(SPDK_LOG_NVMF, "Invalid sn \"%s\": length %zu > max %zu\n",
1150 			      sn, len, max_len);
1151 		return -1;
1152 	}
1153 
1154 	if (!spdk_nvmf_valid_ascii_string(sn, len)) {
1155 		SPDK_DEBUGLOG(SPDK_LOG_NVMF, "Non-ASCII sn\n");
1156 		SPDK_TRACEDUMP(SPDK_LOG_NVMF, "sn", sn, len);
1157 		return -1;
1158 	}
1159 
1160 	snprintf(subsystem->sn, sizeof(subsystem->sn), "%s", sn);
1161 
1162 	return 0;
1163 }
1164 
1165 const char *
1166 spdk_nvmf_subsystem_get_nqn(struct spdk_nvmf_subsystem *subsystem)
1167 {
1168 	return subsystem->subnqn;
1169 }
1170 
1171 /* Workaround for astyle formatting bug */
1172 typedef enum spdk_nvmf_subtype nvmf_subtype_t;
1173 
1174 nvmf_subtype_t
1175 spdk_nvmf_subsystem_get_type(struct spdk_nvmf_subsystem *subsystem)
1176 {
1177 	return subsystem->subtype;
1178 }
1179 
1180 static uint16_t
1181 spdk_nvmf_subsystem_gen_cntlid(struct spdk_nvmf_subsystem *subsystem)
1182 {
1183 	int count;
1184 
1185 	/*
1186 	 * In the worst case, we might have to try all CNTLID values between 1 and 0xFFF0 - 1
1187 	 * before we find one that is unused (or find that all values are in use).
1188 	 */
1189 	for (count = 0; count < 0xFFF0 - 1; count++) {
1190 		subsystem->next_cntlid++;
1191 		if (subsystem->next_cntlid >= 0xFFF0) {
1192 			/* The spec reserves cntlid values in the range FFF0h to FFFFh. */
1193 			subsystem->next_cntlid = 1;
1194 		}
1195 
1196 		/* Check if a controller with this cntlid currently exists. */
1197 		if (spdk_nvmf_subsystem_get_ctrlr(subsystem, subsystem->next_cntlid) == NULL) {
1198 			/* Found unused cntlid */
1199 			return subsystem->next_cntlid;
1200 		}
1201 	}
1202 
1203 	/* All valid cntlid values are in use. */
1204 	return 0xFFFF;
1205 }
1206 
1207 int
1208 spdk_nvmf_subsystem_add_ctrlr(struct spdk_nvmf_subsystem *subsystem, struct spdk_nvmf_ctrlr *ctrlr)
1209 {
1210 	ctrlr->cntlid = spdk_nvmf_subsystem_gen_cntlid(subsystem);
1211 	if (ctrlr->cntlid == 0xFFFF) {
1212 		/* Unable to get a cntlid */
1213 		SPDK_ERRLOG("Reached max simultaneous ctrlrs\n");
1214 		return -EBUSY;
1215 	}
1216 
1217 	TAILQ_INSERT_TAIL(&subsystem->ctrlrs, ctrlr, link);
1218 
1219 	return 0;
1220 }
1221 
1222 void
1223 spdk_nvmf_subsystem_remove_ctrlr(struct spdk_nvmf_subsystem *subsystem,
1224 				 struct spdk_nvmf_ctrlr *ctrlr)
1225 {
1226 	assert(subsystem == ctrlr->subsys);
1227 	TAILQ_REMOVE(&subsystem->ctrlrs, ctrlr, link);
1228 }
1229 
1230 struct spdk_nvmf_ctrlr *
1231 spdk_nvmf_subsystem_get_ctrlr(struct spdk_nvmf_subsystem *subsystem, uint16_t cntlid)
1232 {
1233 	struct spdk_nvmf_ctrlr *ctrlr;
1234 
1235 	TAILQ_FOREACH(ctrlr, &subsystem->ctrlrs, link) {
1236 		if (ctrlr->cntlid == cntlid) {
1237 			return ctrlr;
1238 		}
1239 	}
1240 
1241 	return NULL;
1242 }
1243 
1244 uint32_t
1245 spdk_nvmf_subsystem_get_max_namespaces(const struct spdk_nvmf_subsystem *subsystem)
1246 {
1247 	return subsystem->max_allowed_nsid;
1248 }
1249