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