xref: /spdk/lib/nvmf/subsystem.c (revision 97cb1713ffd23594904e38b2636aa491b7d9ab51)
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 
45 #include "spdk_internal/bdev.h"
46 #include "spdk_internal/log.h"
47 #include "spdk_internal/utf.h"
48 
49 #include <uuid/uuid.h>
50 
51 /*
52  * States for parsing valid domains in NQNs according to RFC 1034
53  */
54 enum spdk_nvmf_nqn_domain_states {
55 	/* First character of a domain must be a letter */
56 	SPDK_NVMF_DOMAIN_ACCEPT_LETTER = 0,
57 
58 	/* Subsequent characters can be any of letter, digit, or hyphen */
59 	SPDK_NVMF_DOMAIN_ACCEPT_LDH = 1,
60 
61 	/* A domain label must end with either a letter or digit */
62 	SPDK_NVMF_DOMAIN_ACCEPT_ANY = 2
63 };
64 
65 static bool
66 spdk_nvmf_valid_nqn(const char *nqn)
67 {
68 	size_t len;
69 	uuid_t uuid_value;
70 	uint i;
71 	int bytes_consumed;
72 	uint domain_label_length;
73 	char *reverse_domain_end;
74 	uint reverse_domain_end_index;
75 	enum spdk_nvmf_nqn_domain_states domain_state = SPDK_NVMF_DOMAIN_ACCEPT_LETTER;
76 
77 	/* Check for length requirements */
78 	len = strlen(nqn);
79 	if (len > SPDK_NVMF_NQN_MAX_LEN) {
80 		SPDK_ERRLOG("Invalid NQN \"%s\": length %zu > max %d\n", nqn, len, SPDK_NVMF_NQN_MAX_LEN);
81 		return false;
82 	}
83 
84 	/* The nqn must be at least as long as SPDK_NVMF_NQN_MIN_LEN to contain the necessary prefix. */
85 	if (len < SPDK_NVMF_NQN_MIN_LEN) {
86 		SPDK_ERRLOG("Invalid NQN \"%s\": length %zu < min %d\n", nqn, len, SPDK_NVMF_NQN_MIN_LEN);
87 		return false;
88 	}
89 
90 	/* Check for discovery controller nqn */
91 	if (!strcmp(nqn, SPDK_NVMF_DISCOVERY_NQN)) {
92 		return true;
93 	}
94 
95 	/* Check for equality with the generic nqn structure of the form "nqn.2014-08.org.nvmexpress:uuid:11111111-2222-3333-4444-555555555555" */
96 	if (!strncmp(nqn, SPDK_NVMF_NQN_UUID_PRE, SPDK_NVMF_NQN_UUID_PRE_LEN)) {
97 		if (len != SPDK_NVMF_NQN_UUID_PRE_LEN + SPDK_NVMF_UUID_STRING_LEN) {
98 			SPDK_ERRLOG("Invalid NQN \"%s\": uuid is not the correct length\n", nqn);
99 			return false;
100 		}
101 
102 		if (uuid_parse(&nqn[SPDK_NVMF_NQN_UUID_PRE_LEN], uuid_value) == -1) {
103 			SPDK_ERRLOG("Invalid NQN \"%s\": uuid is not formatted correctly\n", nqn);
104 			return false;
105 		}
106 		return true;
107 	}
108 
109 	/* If the nqn does not match the uuid structure, the next several checks validate the form "nqn.yyyy-mm.reverse.domain:user-string" */
110 
111 	if (strncmp(nqn, "nqn.", 4) != 0) {
112 		SPDK_ERRLOG("Invalid NQN \"%s\": NQN must begin with \"nqn.\".\n", nqn);
113 		return false;
114 	}
115 
116 	/* Check for yyyy-mm. */
117 	if (!(isdigit(nqn[4]) && isdigit(nqn[5]) && isdigit(nqn[6]) && isdigit(nqn[7]) &&
118 	      nqn[8] == '-' && isdigit(nqn[9]) && isdigit(nqn[10]) && nqn[11] == '.')) {
119 		SPDK_ERRLOG("Invalid date code in NQN \"%s\"\n", nqn);
120 		return false;
121 	}
122 
123 	reverse_domain_end = strchr(nqn, ':');
124 	if (reverse_domain_end != NULL && (reverse_domain_end_index = reverse_domain_end - nqn) < len - 1) {
125 	} else {
126 		SPDK_ERRLOG("Invalid NQN \"%s\". NQN must contain user specified name with a ':' as a prefix.\n",
127 			    nqn);
128 		return false;
129 	}
130 
131 	/* Check for valid reverse domain */
132 	domain_label_length = 0;
133 	for (i = 12; i < reverse_domain_end_index; i++) {
134 		if (domain_label_length > SPDK_DOMAIN_LABEL_MAX_LEN) {
135 			SPDK_ERRLOG("Invalid domain name in NQN \"%s\". At least one Label is too long.\n", nqn);
136 			return false;
137 		}
138 
139 		switch (domain_state) {
140 
141 		case SPDK_NVMF_DOMAIN_ACCEPT_LETTER: {
142 			if (isalpha(nqn[i])) {
143 				domain_state = SPDK_NVMF_DOMAIN_ACCEPT_ANY;
144 				domain_label_length++;
145 				break;
146 			} else {
147 				SPDK_ERRLOG("Invalid domain name in NQN \"%s\". Label names must start with a letter.\n", nqn);
148 				return false;
149 			}
150 		}
151 
152 		case SPDK_NVMF_DOMAIN_ACCEPT_LDH: {
153 			if (isalpha(nqn[i]) || isdigit(nqn[i])) {
154 				domain_state = SPDK_NVMF_DOMAIN_ACCEPT_ANY;
155 				domain_label_length++;
156 				break;
157 			} else if (nqn[i] == '-') {
158 				if (i == reverse_domain_end_index - 1) {
159 					SPDK_ERRLOG("Invalid domain name in NQN \"%s\". Label names must end with an alphanumeric symbol.\n",
160 						    nqn);
161 					return false;
162 				}
163 				domain_state = SPDK_NVMF_DOMAIN_ACCEPT_LDH;
164 				domain_label_length++;
165 				break;
166 			} else if (nqn[i] == '.') {
167 				SPDK_ERRLOG("Invalid domain name in NQN \"%s\". Label names must end with an alphanumeric symbol.\n",
168 					    nqn);
169 				return false;
170 			} else {
171 				SPDK_ERRLOG("Invalid domain name in NQN \"%s\". Label names must contain only [a-z,A-Z,0-9,'-','.'].\n",
172 					    nqn);
173 				return false;
174 			}
175 		}
176 
177 		case SPDK_NVMF_DOMAIN_ACCEPT_ANY: {
178 			if (isalpha(nqn[i]) || isdigit(nqn[i])) {
179 				domain_state = SPDK_NVMF_DOMAIN_ACCEPT_ANY;
180 				domain_label_length++;
181 				break;
182 			} else if (nqn[i] == '-') {
183 				if (i == reverse_domain_end_index - 1) {
184 					SPDK_ERRLOG("Invalid domain name in NQN \"%s\". Label names must end with an alphanumeric symbol.\n",
185 						    nqn);
186 					return false;
187 				}
188 				domain_state = SPDK_NVMF_DOMAIN_ACCEPT_LDH;
189 				domain_label_length++;
190 				break;
191 			} else if (nqn[i] == '.') {
192 				domain_state = SPDK_NVMF_DOMAIN_ACCEPT_LETTER;
193 				domain_label_length = 0;
194 				break;
195 			} else {
196 				SPDK_ERRLOG("Invalid domain name in NQN \"%s\". Label names must contain only [a-z,A-Z,0-9,'-','.'].\n",
197 					    nqn);
198 				return false;
199 			}
200 		}
201 		}
202 	}
203 
204 	i = reverse_domain_end_index + 1;
205 	while (i < len) {
206 		bytes_consumed = utf8_valid(&nqn[i], &nqn[len]);
207 		if (bytes_consumed <= 0) {
208 			SPDK_ERRLOG("Invalid domain name in NQN \"%s\". Label names must contain only valid utf-8.\n", nqn);
209 			return false;
210 		}
211 
212 		i += bytes_consumed;
213 	}
214 	return true;
215 }
216 
217 struct spdk_nvmf_subsystem *
218 spdk_nvmf_subsystem_create(struct spdk_nvmf_tgt *tgt,
219 			   const char *nqn,
220 			   enum spdk_nvmf_subtype type,
221 			   uint32_t num_ns)
222 {
223 	struct spdk_nvmf_subsystem	*subsystem;
224 	uint32_t			sid;
225 
226 	if (!spdk_nvmf_valid_nqn(nqn)) {
227 		return NULL;
228 	}
229 
230 	if (type == SPDK_NVMF_SUBTYPE_DISCOVERY && num_ns != 0) {
231 		SPDK_ERRLOG("Discovery subsystem cannot have namespaces.\n");
232 		return NULL;
233 	}
234 
235 	/* Find a free subsystem id (sid) */
236 	for (sid = 0; sid < tgt->max_sid; sid++) {
237 		if (tgt->subsystems[sid] == NULL) {
238 			break;
239 		}
240 	}
241 	if (sid == tgt->max_sid) {
242 		struct spdk_nvmf_subsystem **subsys_array;
243 		/* No free slots. Add more. */
244 		tgt->max_sid++;
245 		subsys_array = realloc(tgt->subsystems, tgt->max_sid * sizeof(struct spdk_nvmf_subsystem *));
246 		if (!subsys_array) {
247 			tgt->max_sid--;
248 			return NULL;
249 		}
250 		tgt->subsystems = subsys_array;
251 	}
252 
253 	subsystem = calloc(1, sizeof(struct spdk_nvmf_subsystem));
254 	if (subsystem == NULL) {
255 		return NULL;
256 	}
257 
258 	subsystem->state = SPDK_NVMF_SUBSYSTEM_INACTIVE;
259 	subsystem->tgt = tgt;
260 	subsystem->id = sid;
261 	subsystem->subtype = type;
262 	subsystem->max_nsid = num_ns;
263 	subsystem->num_allocated_nsid = 0;
264 	subsystem->next_cntlid = 0;
265 	snprintf(subsystem->subnqn, sizeof(subsystem->subnqn), "%s", nqn);
266 	TAILQ_INIT(&subsystem->listeners);
267 	TAILQ_INIT(&subsystem->hosts);
268 	TAILQ_INIT(&subsystem->ctrlrs);
269 
270 	if (num_ns != 0) {
271 		subsystem->ns = calloc(num_ns, sizeof(struct spdk_nvmf_ns *));
272 		if (subsystem->ns == NULL) {
273 			SPDK_ERRLOG("Namespace memory allocation failed\n");
274 			free(subsystem);
275 			return NULL;
276 		}
277 	}
278 
279 	tgt->subsystems[sid] = subsystem;
280 	tgt->discovery_genctr++;
281 
282 	return subsystem;
283 }
284 
285 void
286 spdk_nvmf_subsystem_destroy(struct spdk_nvmf_subsystem *subsystem)
287 {
288 	struct spdk_nvmf_listener	*listener, *listener_tmp;
289 	struct spdk_nvmf_host		*host, *host_tmp;
290 	struct spdk_nvmf_ctrlr		*ctrlr, *ctrlr_tmp;
291 	struct spdk_nvmf_ns		*ns;
292 
293 	if (!subsystem) {
294 		return;
295 	}
296 
297 	assert(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE);
298 
299 	SPDK_DEBUGLOG(SPDK_LOG_NVMF, "subsystem is %p\n", subsystem);
300 
301 	TAILQ_FOREACH_SAFE(listener, &subsystem->listeners, link, listener_tmp) {
302 		TAILQ_REMOVE(&subsystem->listeners, listener, link);
303 		free(listener);
304 	}
305 
306 	TAILQ_FOREACH_SAFE(host, &subsystem->hosts, link, host_tmp) {
307 		TAILQ_REMOVE(&subsystem->hosts, host, link);
308 		free(host->nqn);
309 		free(host);
310 	}
311 
312 	TAILQ_FOREACH_SAFE(ctrlr, &subsystem->ctrlrs, link, ctrlr_tmp) {
313 		spdk_nvmf_ctrlr_destruct(ctrlr);
314 	}
315 
316 	ns = spdk_nvmf_subsystem_get_first_ns(subsystem);
317 	while (ns != NULL) {
318 		struct spdk_nvmf_ns *next_ns = spdk_nvmf_subsystem_get_next_ns(subsystem, ns);
319 
320 		spdk_nvmf_subsystem_remove_ns(subsystem, ns->opts.nsid);
321 		ns = next_ns;
322 	}
323 
324 	free(subsystem->ns);
325 
326 	subsystem->tgt->subsystems[subsystem->id] = NULL;
327 	subsystem->tgt->discovery_genctr++;
328 
329 	free(subsystem);
330 }
331 
332 static int
333 spdk_nvmf_subsystem_set_state(struct spdk_nvmf_subsystem *subsystem,
334 			      enum spdk_nvmf_subsystem_state state)
335 {
336 	enum spdk_nvmf_subsystem_state actual_old_state, expected_old_state;
337 
338 	switch (state) {
339 	case SPDK_NVMF_SUBSYSTEM_INACTIVE:
340 		expected_old_state = SPDK_NVMF_SUBSYSTEM_DEACTIVATING;
341 		break;
342 	case SPDK_NVMF_SUBSYSTEM_ACTIVATING:
343 		expected_old_state = SPDK_NVMF_SUBSYSTEM_INACTIVE;
344 		break;
345 	case SPDK_NVMF_SUBSYSTEM_ACTIVE:
346 		expected_old_state = SPDK_NVMF_SUBSYSTEM_ACTIVATING;
347 		break;
348 	case SPDK_NVMF_SUBSYSTEM_PAUSING:
349 		expected_old_state = SPDK_NVMF_SUBSYSTEM_ACTIVE;
350 		break;
351 	case SPDK_NVMF_SUBSYSTEM_PAUSED:
352 		expected_old_state = SPDK_NVMF_SUBSYSTEM_PAUSING;
353 		break;
354 	case SPDK_NVMF_SUBSYSTEM_RESUMING:
355 		expected_old_state = SPDK_NVMF_SUBSYSTEM_PAUSED;
356 		break;
357 	case SPDK_NVMF_SUBSYSTEM_DEACTIVATING:
358 		expected_old_state = SPDK_NVMF_SUBSYSTEM_ACTIVE;
359 		break;
360 	default:
361 		assert(false);
362 		return -1;
363 	}
364 
365 	actual_old_state = __sync_val_compare_and_swap(&subsystem->state, expected_old_state, state);
366 	if (actual_old_state != expected_old_state) {
367 		if (actual_old_state == SPDK_NVMF_SUBSYSTEM_RESUMING &&
368 		    state == SPDK_NVMF_SUBSYSTEM_ACTIVE) {
369 			expected_old_state = SPDK_NVMF_SUBSYSTEM_RESUMING;
370 		}
371 		actual_old_state = __sync_val_compare_and_swap(&subsystem->state, expected_old_state, state);
372 	}
373 	assert(actual_old_state == expected_old_state);
374 	return actual_old_state - expected_old_state;
375 }
376 
377 struct subsystem_state_change_ctx {
378 	struct spdk_nvmf_subsystem *subsystem;
379 
380 	enum spdk_nvmf_subsystem_state requested_state;
381 
382 	spdk_nvmf_subsystem_state_change_done cb_fn;
383 	void *cb_arg;
384 };
385 
386 static void
387 subsystem_state_change_done(struct spdk_io_channel_iter *i, int status)
388 {
389 	struct subsystem_state_change_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
390 
391 	if (status == 0) {
392 		status = spdk_nvmf_subsystem_set_state(ctx->subsystem, ctx->requested_state);
393 		if (status) {
394 			status = -1;
395 		}
396 	}
397 
398 	if (ctx->cb_fn) {
399 		ctx->cb_fn(ctx->subsystem, ctx->cb_arg, status);
400 	}
401 	free(ctx);
402 }
403 
404 static void
405 subsystem_state_change_on_pg(struct spdk_io_channel_iter *i)
406 {
407 	struct subsystem_state_change_ctx *ctx;
408 	struct spdk_io_channel *ch;
409 	struct spdk_nvmf_poll_group *group;
410 	int rc = -1;
411 
412 	ctx = spdk_io_channel_iter_get_ctx(i);
413 	ch = spdk_io_channel_iter_get_channel(i);
414 	group = spdk_io_channel_get_ctx(ch);
415 
416 	switch (ctx->requested_state) {
417 	case SPDK_NVMF_SUBSYSTEM_INACTIVE:
418 		rc = spdk_nvmf_poll_group_remove_subsystem(group, ctx->subsystem);
419 		break;
420 	case SPDK_NVMF_SUBSYSTEM_ACTIVE:
421 		if (ctx->subsystem->state == SPDK_NVMF_SUBSYSTEM_ACTIVATING) {
422 			rc = spdk_nvmf_poll_group_add_subsystem(group, ctx->subsystem);
423 		} else if (ctx->subsystem->state == SPDK_NVMF_SUBSYSTEM_RESUMING) {
424 			rc = spdk_nvmf_poll_group_resume_subsystem(group, ctx->subsystem);
425 		}
426 		break;
427 	case SPDK_NVMF_SUBSYSTEM_PAUSED:
428 		rc = spdk_nvmf_poll_group_pause_subsystem(group, ctx->subsystem);
429 		break;
430 	default:
431 		assert(false);
432 		break;
433 	}
434 
435 	spdk_for_each_channel_continue(i, rc);
436 }
437 
438 static int
439 spdk_nvmf_subsystem_state_change(struct spdk_nvmf_subsystem *subsystem,
440 				 enum spdk_nvmf_subsystem_state requested_state,
441 				 spdk_nvmf_subsystem_state_change_done cb_fn,
442 				 void *cb_arg)
443 {
444 	struct subsystem_state_change_ctx *ctx;
445 	enum spdk_nvmf_subsystem_state intermediate_state;
446 	int rc;
447 
448 	switch (requested_state) {
449 	case SPDK_NVMF_SUBSYSTEM_INACTIVE:
450 		intermediate_state = SPDK_NVMF_SUBSYSTEM_DEACTIVATING;
451 		break;
452 	case SPDK_NVMF_SUBSYSTEM_ACTIVE:
453 		if (subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED) {
454 			intermediate_state = SPDK_NVMF_SUBSYSTEM_RESUMING;
455 		} else {
456 			intermediate_state = SPDK_NVMF_SUBSYSTEM_ACTIVATING;
457 		}
458 		break;
459 	case SPDK_NVMF_SUBSYSTEM_PAUSED:
460 		intermediate_state = SPDK_NVMF_SUBSYSTEM_PAUSING;
461 		break;
462 	default:
463 		assert(false);
464 		return -EINVAL;
465 	}
466 
467 	ctx = calloc(1, sizeof(*ctx));
468 	if (!ctx) {
469 		return -ENOMEM;
470 	}
471 
472 	rc = spdk_nvmf_subsystem_set_state(subsystem, intermediate_state);
473 	if (rc) {
474 		free(ctx);
475 		return rc;
476 	}
477 
478 	ctx->subsystem = subsystem;
479 	ctx->requested_state = requested_state;
480 	ctx->cb_fn = cb_fn;
481 	ctx->cb_arg = cb_arg;
482 
483 	spdk_for_each_channel(subsystem->tgt,
484 			      subsystem_state_change_on_pg,
485 			      ctx,
486 			      subsystem_state_change_done);
487 
488 	return 0;
489 }
490 
491 int
492 spdk_nvmf_subsystem_start(struct spdk_nvmf_subsystem *subsystem,
493 			  spdk_nvmf_subsystem_state_change_done cb_fn,
494 			  void *cb_arg)
495 {
496 	return spdk_nvmf_subsystem_state_change(subsystem, SPDK_NVMF_SUBSYSTEM_ACTIVE, cb_fn, cb_arg);
497 }
498 
499 int
500 spdk_nvmf_subsystem_stop(struct spdk_nvmf_subsystem *subsystem,
501 			 spdk_nvmf_subsystem_state_change_done cb_fn,
502 			 void *cb_arg)
503 {
504 	return spdk_nvmf_subsystem_state_change(subsystem, SPDK_NVMF_SUBSYSTEM_INACTIVE, cb_fn, cb_arg);
505 }
506 
507 int
508 spdk_nvmf_subsystem_pause(struct spdk_nvmf_subsystem *subsystem,
509 			  spdk_nvmf_subsystem_state_change_done cb_fn,
510 			  void *cb_arg)
511 {
512 	return spdk_nvmf_subsystem_state_change(subsystem, SPDK_NVMF_SUBSYSTEM_PAUSED, cb_fn, cb_arg);
513 }
514 
515 int
516 spdk_nvmf_subsystem_resume(struct spdk_nvmf_subsystem *subsystem,
517 			   spdk_nvmf_subsystem_state_change_done cb_fn,
518 			   void *cb_arg)
519 {
520 	return spdk_nvmf_subsystem_state_change(subsystem, SPDK_NVMF_SUBSYSTEM_ACTIVE, cb_fn, cb_arg);
521 }
522 
523 struct spdk_nvmf_subsystem *
524 spdk_nvmf_subsystem_get_first(struct spdk_nvmf_tgt *tgt)
525 {
526 	struct spdk_nvmf_subsystem	*subsystem;
527 	uint32_t sid;
528 
529 	for (sid = 0; sid < tgt->max_sid; sid++) {
530 		subsystem = tgt->subsystems[sid];
531 		if (subsystem) {
532 			return subsystem;
533 		}
534 	}
535 
536 	return NULL;
537 }
538 
539 struct spdk_nvmf_subsystem *
540 spdk_nvmf_subsystem_get_next(struct spdk_nvmf_subsystem *subsystem)
541 {
542 	uint32_t sid;
543 	struct spdk_nvmf_tgt *tgt;
544 
545 	if (!subsystem) {
546 		return NULL;
547 	}
548 
549 	tgt = subsystem->tgt;
550 
551 	for (sid = subsystem->id + 1; sid < tgt->max_sid; sid++) {
552 		subsystem = tgt->subsystems[sid];
553 		if (subsystem) {
554 			return subsystem;
555 		}
556 	}
557 
558 	return NULL;
559 }
560 
561 int
562 spdk_nvmf_subsystem_add_host(struct spdk_nvmf_subsystem *subsystem, const char *hostnqn)
563 {
564 	struct spdk_nvmf_host *host;
565 
566 	if (!spdk_nvmf_valid_nqn(hostnqn)) {
567 		return -EINVAL;
568 	}
569 
570 	if (!(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
571 	      subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED)) {
572 		return -EAGAIN;
573 	}
574 
575 	host = calloc(1, sizeof(*host));
576 	if (!host) {
577 		return -ENOMEM;
578 	}
579 	host->nqn = strdup(hostnqn);
580 	if (!host->nqn) {
581 		free(host);
582 		return -ENOMEM;
583 	}
584 
585 	TAILQ_INSERT_HEAD(&subsystem->hosts, host, link);
586 	subsystem->tgt->discovery_genctr++;
587 
588 	return 0;
589 }
590 
591 int
592 spdk_nvmf_subsystem_set_allow_any_host(struct spdk_nvmf_subsystem *subsystem, bool allow_any_host)
593 {
594 	if (!(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
595 	      subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED)) {
596 		return -EAGAIN;
597 	}
598 
599 	subsystem->allow_any_host = allow_any_host;
600 
601 	return 0;
602 }
603 
604 bool
605 spdk_nvmf_subsystem_get_allow_any_host(const struct spdk_nvmf_subsystem *subsystem)
606 {
607 	return subsystem->allow_any_host;
608 }
609 
610 bool
611 spdk_nvmf_subsystem_host_allowed(struct spdk_nvmf_subsystem *subsystem, const char *hostnqn)
612 {
613 	struct spdk_nvmf_host *host;
614 
615 	if (!hostnqn) {
616 		return false;
617 	}
618 
619 	if (subsystem->allow_any_host) {
620 		return true;
621 	}
622 
623 	TAILQ_FOREACH(host, &subsystem->hosts, link) {
624 		if (strcmp(hostnqn, host->nqn) == 0) {
625 			return true;
626 		}
627 	}
628 
629 	return false;
630 }
631 
632 struct spdk_nvmf_host *
633 spdk_nvmf_subsystem_get_first_host(struct spdk_nvmf_subsystem *subsystem)
634 {
635 	return TAILQ_FIRST(&subsystem->hosts);
636 }
637 
638 
639 struct spdk_nvmf_host *
640 spdk_nvmf_subsystem_get_next_host(struct spdk_nvmf_subsystem *subsystem,
641 				  struct spdk_nvmf_host *prev_host)
642 {
643 	return TAILQ_NEXT(prev_host, link);
644 }
645 
646 const char *
647 spdk_nvmf_host_get_nqn(struct spdk_nvmf_host *host)
648 {
649 	return host->nqn;
650 }
651 
652 static struct spdk_nvmf_listener *
653 _spdk_nvmf_subsystem_find_listener(struct spdk_nvmf_subsystem *subsystem,
654 				   const struct spdk_nvme_transport_id *trid)
655 {
656 	struct spdk_nvmf_listener *listener;
657 
658 	TAILQ_FOREACH(listener, &subsystem->listeners, link) {
659 		if (spdk_nvme_transport_id_compare(&listener->trid, trid) == 0) {
660 			return listener;
661 		}
662 	}
663 
664 	return NULL;
665 }
666 
667 int
668 spdk_nvmf_subsystem_add_listener(struct spdk_nvmf_subsystem *subsystem,
669 				 struct spdk_nvme_transport_id *trid)
670 {
671 	struct spdk_nvmf_transport *transport;
672 	struct spdk_nvmf_listener *listener;
673 
674 	if (!(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
675 	      subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED)) {
676 		return -EAGAIN;
677 	}
678 
679 	if (_spdk_nvmf_subsystem_find_listener(subsystem, trid)) {
680 		/* Listener already exists in this subsystem */
681 		return 0;
682 	}
683 
684 	transport = spdk_nvmf_tgt_get_transport(subsystem->tgt, trid->trtype);
685 	if (transport == NULL) {
686 		SPDK_ERRLOG("Unknown transport type %d\n", trid->trtype);
687 		return -EINVAL;
688 	}
689 
690 	listener = calloc(1, sizeof(*listener));
691 	if (!listener) {
692 		return -ENOMEM;
693 	}
694 
695 	listener->trid = *trid;
696 	listener->transport = transport;
697 
698 	TAILQ_INSERT_HEAD(&subsystem->listeners, listener, link);
699 
700 	return 0;
701 }
702 
703 int
704 spdk_nvmf_subsystem_remove_listener(struct spdk_nvmf_subsystem *subsystem,
705 				    const struct spdk_nvme_transport_id *trid)
706 {
707 	struct spdk_nvmf_listener *listener;
708 
709 	if (!(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
710 	      subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED)) {
711 		return -EAGAIN;
712 	}
713 
714 	listener = _spdk_nvmf_subsystem_find_listener(subsystem, trid);
715 	if (listener == NULL) {
716 		return -ENOENT;
717 	}
718 
719 	TAILQ_REMOVE(&subsystem->listeners, listener, link);
720 	free(listener);
721 
722 	return 0;
723 }
724 
725 /*
726  * TODO: this is the whitelist and will be called during connection setup
727  */
728 bool
729 spdk_nvmf_subsystem_listener_allowed(struct spdk_nvmf_subsystem *subsystem,
730 				     struct spdk_nvme_transport_id *trid)
731 {
732 	struct spdk_nvmf_listener *listener;
733 
734 	if (TAILQ_EMPTY(&subsystem->listeners)) {
735 		return true;
736 	}
737 
738 	TAILQ_FOREACH(listener, &subsystem->listeners, link) {
739 		if (spdk_nvme_transport_id_compare(&listener->trid, trid) == 0) {
740 			return true;
741 		}
742 	}
743 
744 	return false;
745 }
746 
747 struct spdk_nvmf_listener *
748 spdk_nvmf_subsystem_get_first_listener(struct spdk_nvmf_subsystem *subsystem)
749 {
750 	return TAILQ_FIRST(&subsystem->listeners);
751 }
752 
753 struct spdk_nvmf_listener *
754 spdk_nvmf_subsystem_get_next_listener(struct spdk_nvmf_subsystem *subsystem,
755 				      struct spdk_nvmf_listener *prev_listener)
756 {
757 	return TAILQ_NEXT(prev_listener, link);
758 }
759 
760 
761 const struct spdk_nvme_transport_id *
762 spdk_nvmf_listener_get_trid(struct spdk_nvmf_listener *listener)
763 {
764 	return &listener->trid;
765 }
766 
767 int
768 spdk_nvmf_subsystem_remove_ns(struct spdk_nvmf_subsystem *subsystem, uint32_t nsid)
769 {
770 	struct spdk_nvmf_ns *ns;
771 
772 	assert(subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED ||
773 	       subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE);
774 
775 	if (nsid == 0 || nsid > subsystem->max_nsid) {
776 		return -1;
777 	}
778 
779 	if (!(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
780 	      subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED)) {
781 		return -1;
782 	}
783 
784 	ns = subsystem->ns[nsid - 1];
785 	if (!ns) {
786 		return -1;
787 	}
788 
789 	subsystem->ns[nsid - 1] = NULL;
790 
791 	spdk_bdev_close(ns->desc);
792 	free(ns);
793 	subsystem->num_allocated_nsid--;
794 
795 	return 0;
796 }
797 
798 static void
799 _spdk_nvmf_ns_hot_remove(struct spdk_nvmf_subsystem *subsystem,
800 			 void *cb_arg, int status)
801 {
802 	struct spdk_nvmf_ns *ns = cb_arg;
803 
804 	spdk_nvmf_subsystem_remove_ns(subsystem, ns->opts.nsid);
805 
806 	spdk_nvmf_subsystem_resume(subsystem, NULL, NULL);
807 }
808 
809 static void
810 spdk_nvmf_ns_hot_remove(void *remove_ctx)
811 {
812 	struct spdk_nvmf_ns *ns = remove_ctx;
813 	int rc;
814 
815 	rc = spdk_nvmf_subsystem_pause(ns->subsystem, _spdk_nvmf_ns_hot_remove, ns);
816 	if (rc) {
817 		SPDK_ERRLOG("Unable to pause subsystem to process namespace removal!\n");
818 	}
819 }
820 
821 void
822 spdk_nvmf_ns_opts_get_defaults(struct spdk_nvmf_ns_opts *opts, size_t opts_size)
823 {
824 	/* All current fields are set to 0 by default. */
825 	memset(opts, 0, opts_size);
826 }
827 
828 uint32_t
829 spdk_nvmf_subsystem_add_ns(struct spdk_nvmf_subsystem *subsystem, struct spdk_bdev *bdev,
830 			   const struct spdk_nvmf_ns_opts *user_opts, size_t opts_size)
831 {
832 	struct spdk_nvmf_ns_opts opts;
833 	struct spdk_nvmf_ns *ns;
834 	uint32_t i;
835 	int rc;
836 
837 	if (!(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
838 	      subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED)) {
839 		return 0;
840 	}
841 
842 	spdk_nvmf_ns_opts_get_defaults(&opts, sizeof(opts));
843 	if (user_opts) {
844 		memcpy(&opts, user_opts, spdk_min(sizeof(opts), opts_size));
845 	}
846 
847 	if (opts.nsid == SPDK_NVME_GLOBAL_NS_TAG) {
848 		SPDK_ERRLOG("Invalid NSID %" PRIu32 "\n", opts.nsid);
849 		return 0;
850 	}
851 
852 	if (opts.nsid > subsystem->max_nsid ||
853 	    (opts.nsid == 0 && subsystem->num_allocated_nsid == subsystem->max_nsid)) {
854 		struct spdk_nvmf_ns **new_ns_array;
855 		uint32_t new_max_nsid;
856 
857 		if (opts.nsid > subsystem->max_nsid) {
858 			new_max_nsid = opts.nsid;
859 		} else {
860 			new_max_nsid = subsystem->max_nsid + 1;
861 		}
862 
863 		if (!TAILQ_EMPTY(&subsystem->ctrlrs)) {
864 			SPDK_ERRLOG("Can't extend NSID range with active connections\n");
865 			return 0;
866 		}
867 
868 		new_ns_array = realloc(subsystem->ns, sizeof(struct spdk_nvmf_ns *) * new_max_nsid);
869 		if (new_ns_array == NULL) {
870 			SPDK_ERRLOG("Memory allocation error while resizing namespace array.\n");
871 			return 0;
872 		}
873 
874 		memset(new_ns_array + subsystem->max_nsid, 0,
875 		       sizeof(struct spdk_nvmf_ns *) * (new_max_nsid - subsystem->max_nsid));
876 		subsystem->ns = new_ns_array;
877 		subsystem->max_nsid = new_max_nsid;
878 	}
879 
880 	if (opts.nsid == 0) {
881 		/* NSID not specified - find a free index */
882 		for (i = 0; i < subsystem->max_nsid; i++) {
883 			if (_spdk_nvmf_subsystem_get_ns(subsystem, i + 1) == NULL) {
884 				opts.nsid = i + 1;
885 				break;
886 			}
887 		}
888 		if (opts.nsid == 0) {
889 			SPDK_ERRLOG("All available NSIDs in use\n");
890 			return 0;
891 		}
892 	} else {
893 		/* Specific NSID requested */
894 		if (_spdk_nvmf_subsystem_get_ns(subsystem, opts.nsid)) {
895 			SPDK_ERRLOG("Requested NSID %" PRIu32 " already in use\n", opts.nsid);
896 			return 0;
897 		}
898 	}
899 
900 	ns = calloc(1, sizeof(*ns));
901 	if (ns == NULL) {
902 		SPDK_ERRLOG("Namespace allocation failed\n");
903 		return 0;
904 	}
905 
906 	ns->bdev = bdev;
907 	ns->opts = opts;
908 	ns->subsystem = subsystem;
909 	rc = spdk_bdev_open(bdev, true, spdk_nvmf_ns_hot_remove, ns, &ns->desc);
910 	if (rc != 0) {
911 		SPDK_ERRLOG("Subsystem %s: bdev %s cannot be opened, error=%d\n",
912 			    subsystem->subnqn, spdk_bdev_get_name(bdev), rc);
913 		free(ns);
914 		return 0;
915 	}
916 	subsystem->ns[opts.nsid - 1] = ns;
917 
918 	SPDK_DEBUGLOG(SPDK_LOG_NVMF, "Subsystem %s: bdev %s assigned nsid %" PRIu32 "\n",
919 		      spdk_nvmf_subsystem_get_nqn(subsystem),
920 		      spdk_bdev_get_name(bdev),
921 		      opts.nsid);
922 
923 	subsystem->max_nsid = spdk_max(subsystem->max_nsid, opts.nsid);
924 	subsystem->num_allocated_nsid++;
925 
926 	return opts.nsid;
927 }
928 
929 static uint32_t
930 spdk_nvmf_subsystem_get_next_allocated_nsid(struct spdk_nvmf_subsystem *subsystem,
931 		uint32_t prev_nsid)
932 {
933 	uint32_t nsid;
934 
935 	if (prev_nsid >= subsystem->max_nsid) {
936 		return 0;
937 	}
938 
939 	for (nsid = prev_nsid + 1; nsid <= subsystem->max_nsid; nsid++) {
940 		if (subsystem->ns[nsid - 1]) {
941 			return nsid;
942 		}
943 	}
944 
945 	return 0;
946 }
947 
948 struct spdk_nvmf_ns *
949 spdk_nvmf_subsystem_get_first_ns(struct spdk_nvmf_subsystem *subsystem)
950 {
951 	uint32_t first_nsid;
952 
953 	first_nsid = spdk_nvmf_subsystem_get_next_allocated_nsid(subsystem, 0);
954 	return _spdk_nvmf_subsystem_get_ns(subsystem, first_nsid);
955 }
956 
957 struct spdk_nvmf_ns *
958 spdk_nvmf_subsystem_get_next_ns(struct spdk_nvmf_subsystem *subsystem,
959 				struct spdk_nvmf_ns *prev_ns)
960 {
961 	uint32_t next_nsid;
962 
963 	next_nsid = spdk_nvmf_subsystem_get_next_allocated_nsid(subsystem, prev_ns->opts.nsid);
964 	return _spdk_nvmf_subsystem_get_ns(subsystem, next_nsid);
965 }
966 
967 struct spdk_nvmf_ns *
968 spdk_nvmf_subsystem_get_ns(struct spdk_nvmf_subsystem *subsystem, uint32_t nsid)
969 {
970 	return _spdk_nvmf_subsystem_get_ns(subsystem, nsid);
971 }
972 
973 uint32_t
974 spdk_nvmf_ns_get_id(const struct spdk_nvmf_ns *ns)
975 {
976 	return ns->opts.nsid;
977 }
978 
979 struct spdk_bdev *
980 spdk_nvmf_ns_get_bdev(struct spdk_nvmf_ns *ns)
981 {
982 	return ns->bdev;
983 }
984 
985 void
986 spdk_nvmf_ns_get_opts(const struct spdk_nvmf_ns *ns, struct spdk_nvmf_ns_opts *opts,
987 		      size_t opts_size)
988 {
989 	memset(opts, 0, opts_size);
990 	memcpy(opts, &ns->opts, spdk_min(sizeof(ns->opts), opts_size));
991 }
992 
993 const char *
994 spdk_nvmf_subsystem_get_sn(const struct spdk_nvmf_subsystem *subsystem)
995 {
996 	return subsystem->sn;
997 }
998 
999 int
1000 spdk_nvmf_subsystem_set_sn(struct spdk_nvmf_subsystem *subsystem, const char *sn)
1001 {
1002 	size_t len, max_len;
1003 
1004 	max_len = sizeof(subsystem->sn) - 1;
1005 	len = strlen(sn);
1006 	if (len > max_len) {
1007 		SPDK_DEBUGLOG(SPDK_LOG_NVMF, "Invalid sn \"%s\": length %zu > max %zu\n",
1008 			      sn, len, max_len);
1009 		return -1;
1010 	}
1011 
1012 	snprintf(subsystem->sn, sizeof(subsystem->sn), "%s", sn);
1013 
1014 	return 0;
1015 }
1016 
1017 const char *
1018 spdk_nvmf_subsystem_get_nqn(struct spdk_nvmf_subsystem *subsystem)
1019 {
1020 	return subsystem->subnqn;
1021 }
1022 
1023 /* Workaround for astyle formatting bug */
1024 typedef enum spdk_nvmf_subtype nvmf_subtype_t;
1025 
1026 nvmf_subtype_t
1027 spdk_nvmf_subsystem_get_type(struct spdk_nvmf_subsystem *subsystem)
1028 {
1029 	return subsystem->subtype;
1030 }
1031 
1032 static uint16_t
1033 spdk_nvmf_subsystem_gen_cntlid(struct spdk_nvmf_subsystem *subsystem)
1034 {
1035 	int count;
1036 
1037 	/*
1038 	 * In the worst case, we might have to try all CNTLID values between 1 and 0xFFF0 - 1
1039 	 * before we find one that is unused (or find that all values are in use).
1040 	 */
1041 	for (count = 0; count < 0xFFF0 - 1; count++) {
1042 		subsystem->next_cntlid++;
1043 		if (subsystem->next_cntlid >= 0xFFF0) {
1044 			/* The spec reserves cntlid values in the range FFF0h to FFFFh. */
1045 			subsystem->next_cntlid = 1;
1046 		}
1047 
1048 		/* Check if a controller with this cntlid currently exists. */
1049 		if (spdk_nvmf_subsystem_get_ctrlr(subsystem, subsystem->next_cntlid) == NULL) {
1050 			/* Found unused cntlid */
1051 			return subsystem->next_cntlid;
1052 		}
1053 	}
1054 
1055 	/* All valid cntlid values are in use. */
1056 	return 0xFFFF;
1057 }
1058 
1059 int
1060 spdk_nvmf_subsystem_add_ctrlr(struct spdk_nvmf_subsystem *subsystem, struct spdk_nvmf_ctrlr *ctrlr)
1061 {
1062 	ctrlr->cntlid = spdk_nvmf_subsystem_gen_cntlid(subsystem);
1063 	if (ctrlr->cntlid == 0xFFFF) {
1064 		/* Unable to get a cntlid */
1065 		SPDK_ERRLOG("Reached max simultaneous ctrlrs\n");
1066 		return -EBUSY;
1067 	}
1068 
1069 	TAILQ_INSERT_TAIL(&subsystem->ctrlrs, ctrlr, link);
1070 
1071 	return 0;
1072 }
1073 
1074 void
1075 spdk_nvmf_subsystem_remove_ctrlr(struct spdk_nvmf_subsystem *subsystem,
1076 				 struct spdk_nvmf_ctrlr *ctrlr)
1077 {
1078 	assert(subsystem == ctrlr->subsys);
1079 	TAILQ_REMOVE(&subsystem->ctrlrs, ctrlr, link);
1080 }
1081 
1082 struct spdk_nvmf_ctrlr *
1083 spdk_nvmf_subsystem_get_ctrlr(struct spdk_nvmf_subsystem *subsystem, uint16_t cntlid)
1084 {
1085 	struct spdk_nvmf_ctrlr *ctrlr;
1086 
1087 	TAILQ_FOREACH(ctrlr, &subsystem->ctrlrs, link) {
1088 		if (ctrlr->cntlid == cntlid) {
1089 			return ctrlr;
1090 		}
1091 	}
1092 
1093 	return NULL;
1094 }
1095