xref: /spdk/lib/nvmf/subsystem.c (revision 97f3104bc7b8f305409105d19b7e6d6d87d56da5)
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/likely.h"
40 #include "spdk/string.h"
41 #include "spdk/trace.h"
42 #include "spdk/nvmf_spec.h"
43 
44 #include "spdk_internal/bdev.h"
45 #include "spdk_internal/log.h"
46 
47 int
48 spdk_nvmf_subsystem_start(struct spdk_nvmf_subsystem *subsystem)
49 {
50 	return spdk_nvmf_subsystem_bdev_attach(subsystem);
51 }
52 
53 void
54 spdk_nvmf_subsystem_poll(struct spdk_nvmf_subsystem *subsystem)
55 {
56 	struct spdk_nvmf_ctrlr *ctrlr;
57 
58 	TAILQ_FOREACH(ctrlr, &subsystem->ctrlrs, link) {
59 		/* For each connection in the ctrlr, check for completions */
60 		spdk_nvmf_ctrlr_poll(ctrlr);
61 	}
62 }
63 
64 static bool
65 spdk_nvmf_valid_nqn(const char *nqn)
66 {
67 	size_t len;
68 
69 	len = strlen(nqn);
70 	if (len > SPDK_NVMF_NQN_MAX_LEN) {
71 		SPDK_ERRLOG("Invalid NQN \"%s\": length %zu > max %d\n", nqn, len, SPDK_NVMF_NQN_MAX_LEN);
72 		return false;
73 	}
74 
75 	if (strncmp(nqn, "nqn.", 4) != 0) {
76 		SPDK_ERRLOG("Invalid NQN \"%s\": NQN must begin with \"nqn.\".\n", nqn);
77 		return false;
78 	}
79 
80 	/* yyyy-mm. */
81 	if (!(isdigit(nqn[4]) && isdigit(nqn[5]) && isdigit(nqn[6]) && isdigit(nqn[7]) &&
82 	      nqn[8] == '-' && isdigit(nqn[9]) && isdigit(nqn[10]) && nqn[11] == '.')) {
83 		SPDK_ERRLOG("Invalid date code in NQN \"%s\"\n", nqn);
84 		return false;
85 	}
86 
87 	return true;
88 }
89 
90 struct spdk_nvmf_subsystem *
91 spdk_nvmf_create_subsystem(struct spdk_nvmf_tgt *tgt,
92 			   const char *nqn,
93 			   enum spdk_nvmf_subtype type,
94 			   uint32_t num_ns)
95 {
96 	struct spdk_nvmf_subsystem	*subsystem;
97 	uint32_t			sid;
98 
99 	if (!spdk_nvmf_valid_nqn(nqn)) {
100 		return NULL;
101 	}
102 
103 	if (type == SPDK_NVMF_SUBTYPE_DISCOVERY && num_ns != 0) {
104 		SPDK_ERRLOG("Discovery subsystem cannot have namespaces.\n");
105 		return NULL;
106 	}
107 
108 	/* Find a free subsystem id (sid) */
109 	for (sid = 0; sid < tgt->max_sid; sid++) {
110 		if (tgt->subsystems[sid] == NULL) {
111 			break;
112 		}
113 	}
114 	if (sid == tgt->max_sid) {
115 		struct spdk_nvmf_subsystem **subsys_array;
116 		/* No free slots. Add more. */
117 		tgt->max_sid++;
118 		subsys_array = realloc(tgt->subsystems, tgt->max_sid * sizeof(struct spdk_nvmf_subsystem *));
119 		if (!subsys_array) {
120 			tgt->max_sid--;
121 			return NULL;
122 		}
123 		tgt->subsystems = subsys_array;
124 	}
125 
126 	subsystem = calloc(1, sizeof(struct spdk_nvmf_subsystem));
127 	if (subsystem == NULL) {
128 		return NULL;
129 	}
130 
131 	subsystem->tgt = tgt;
132 	subsystem->id = sid;
133 	subsystem->subtype = type;
134 	subsystem->max_nsid = num_ns;
135 	subsystem->num_allocated_nsid = 0;
136 	subsystem->next_cntlid = 0;
137 	snprintf(subsystem->subnqn, sizeof(subsystem->subnqn), "%s", nqn);
138 	TAILQ_INIT(&subsystem->listeners);
139 	TAILQ_INIT(&subsystem->hosts);
140 	TAILQ_INIT(&subsystem->ctrlrs);
141 
142 	if (num_ns != 0) {
143 		subsystem->ns = calloc(num_ns, sizeof(struct spdk_nvmf_ns));
144 		if (subsystem->ns == NULL) {
145 			SPDK_ERRLOG("Namespace memory allocation failed\n");
146 			free(subsystem);
147 			return NULL;
148 		}
149 	}
150 
151 	tgt->subsystems[sid] = subsystem;
152 	tgt->discovery_genctr++;
153 
154 	return subsystem;
155 }
156 
157 void
158 spdk_nvmf_delete_subsystem(struct spdk_nvmf_subsystem *subsystem)
159 {
160 	struct spdk_nvmf_listener	*listener, *listener_tmp;
161 	struct spdk_nvmf_host		*host, *host_tmp;
162 	struct spdk_nvmf_ctrlr		*ctrlr, *ctrlr_tmp;
163 
164 	if (!subsystem) {
165 		return;
166 	}
167 
168 	SPDK_DEBUGLOG(SPDK_TRACE_NVMF, "subsystem is %p\n", subsystem);
169 
170 	TAILQ_FOREACH_SAFE(listener, &subsystem->listeners, link, listener_tmp) {
171 		TAILQ_REMOVE(&subsystem->listeners, listener, link);
172 		free(listener);
173 	}
174 
175 	TAILQ_FOREACH_SAFE(host, &subsystem->hosts, link, host_tmp) {
176 		TAILQ_REMOVE(&subsystem->hosts, host, link);
177 		free(host->nqn);
178 		free(host);
179 	}
180 
181 	TAILQ_FOREACH_SAFE(ctrlr, &subsystem->ctrlrs, link, ctrlr_tmp) {
182 		spdk_nvmf_ctrlr_destruct(ctrlr);
183 	}
184 
185 	spdk_nvmf_subsystem_bdev_detach(subsystem);
186 
187 	free(subsystem->ns);
188 
189 	subsystem->tgt->subsystems[subsystem->id] = NULL;
190 	subsystem->tgt->discovery_genctr++;
191 
192 	free(subsystem);
193 }
194 
195 
196 int
197 spdk_nvmf_subsystem_add_host(struct spdk_nvmf_subsystem *subsystem, const char *hostnqn)
198 {
199 	struct spdk_nvmf_host *host;
200 
201 	if (!spdk_nvmf_valid_nqn(hostnqn)) {
202 		return -1;
203 	}
204 
205 	host = calloc(1, sizeof(*host));
206 	if (!host) {
207 		return -1;
208 	}
209 	host->nqn = strdup(hostnqn);
210 	if (!host->nqn) {
211 		free(host);
212 		return -1;
213 	}
214 
215 	TAILQ_INSERT_HEAD(&subsystem->hosts, host, link);
216 	subsystem->tgt->discovery_genctr++;
217 
218 	return 0;
219 }
220 
221 void
222 spdk_nvmf_subsystem_set_allow_any_host(struct spdk_nvmf_subsystem *subsystem, bool allow_any_host)
223 {
224 	subsystem->allow_any_host = allow_any_host;
225 }
226 
227 bool
228 spdk_nvmf_subsystem_get_allow_any_host(const struct spdk_nvmf_subsystem *subsystem)
229 {
230 	return subsystem->allow_any_host;
231 }
232 
233 bool
234 spdk_nvmf_subsystem_host_allowed(struct spdk_nvmf_subsystem *subsystem, const char *hostnqn)
235 {
236 	struct spdk_nvmf_host *host;
237 
238 	if (!hostnqn) {
239 		return false;
240 	}
241 
242 	if (subsystem->allow_any_host) {
243 		return true;
244 	}
245 
246 	TAILQ_FOREACH(host, &subsystem->hosts, link) {
247 		if (strcmp(hostnqn, host->nqn) == 0) {
248 			return true;
249 		}
250 	}
251 
252 	return false;
253 }
254 
255 struct spdk_nvmf_host *
256 spdk_nvmf_subsystem_get_first_host(struct spdk_nvmf_subsystem *subsystem)
257 {
258 	return TAILQ_FIRST(&subsystem->hosts);
259 }
260 
261 
262 struct spdk_nvmf_host *
263 spdk_nvmf_subsystem_get_next_host(struct spdk_nvmf_subsystem *subsystem,
264 				  struct spdk_nvmf_host *prev_host)
265 {
266 	return TAILQ_NEXT(prev_host, link);
267 }
268 
269 const char *
270 spdk_nvmf_host_get_nqn(struct spdk_nvmf_host *host)
271 {
272 	return host->nqn;
273 }
274 
275 int
276 spdk_nvmf_subsystem_add_listener(struct spdk_nvmf_subsystem *subsystem,
277 				 struct spdk_nvme_transport_id *trid)
278 {
279 	struct spdk_nvmf_transport *transport;
280 	struct spdk_nvmf_listener *listener;
281 
282 	transport = spdk_nvmf_tgt_get_transport(subsystem->tgt, trid->trtype);
283 	if (transport == NULL) {
284 		SPDK_ERRLOG("Unknown transport type %d\n", trid->trtype);
285 		return -1;
286 	}
287 
288 	listener = calloc(1, sizeof(*listener));
289 	if (!listener) {
290 		return -1;
291 	}
292 
293 	listener->trid = *trid;
294 	listener->transport = transport;
295 
296 	TAILQ_INSERT_HEAD(&subsystem->listeners, listener, link);
297 
298 	return 0;
299 }
300 
301 /*
302  * TODO: this is the whitelist and will be called during connection setup
303  */
304 bool
305 spdk_nvmf_subsystem_listener_allowed(struct spdk_nvmf_subsystem *subsystem,
306 				     struct spdk_nvme_transport_id *trid)
307 {
308 	struct spdk_nvmf_listener *listener;
309 
310 	if (TAILQ_EMPTY(&subsystem->listeners)) {
311 		return true;
312 	}
313 
314 	TAILQ_FOREACH(listener, &subsystem->listeners, link) {
315 		if (spdk_nvme_transport_id_compare(&listener->trid, trid) == 0) {
316 			return true;
317 		}
318 	}
319 
320 	return false;
321 }
322 
323 struct spdk_nvmf_listener *
324 spdk_nvmf_subsystem_get_first_listener(struct spdk_nvmf_subsystem *subsystem)
325 {
326 	return TAILQ_FIRST(&subsystem->listeners);
327 }
328 
329 struct spdk_nvmf_listener *
330 spdk_nvmf_subsystem_get_next_listener(struct spdk_nvmf_subsystem *subsystem,
331 				      struct spdk_nvmf_listener *prev_listener)
332 {
333 	return TAILQ_NEXT(prev_listener, link);
334 }
335 
336 
337 const struct spdk_nvme_transport_id *
338 spdk_nvmf_listener_get_trid(struct spdk_nvmf_listener *listener)
339 {
340 	return &listener->trid;
341 }
342 
343 uint32_t
344 spdk_nvmf_subsystem_add_ns(struct spdk_nvmf_subsystem *subsystem, struct spdk_bdev *bdev,
345 			   uint32_t nsid)
346 {
347 	struct spdk_nvmf_ns *ns;
348 	uint32_t i;
349 	int rc;
350 
351 	if (nsid == SPDK_NVME_GLOBAL_NS_TAG) {
352 		SPDK_ERRLOG("Invalid NSID %" PRIu32 "\n", nsid);
353 		return 0;
354 	}
355 
356 	if (nsid > subsystem->max_nsid ||
357 	    (nsid == 0 && subsystem->num_allocated_nsid == subsystem->max_nsid)) {
358 		struct spdk_nvmf_ns *new_ns_array;
359 		uint32_t new_max_nsid;
360 
361 		if (nsid > subsystem->max_nsid) {
362 			new_max_nsid = nsid;
363 		} else {
364 			new_max_nsid = subsystem->max_nsid + 1;
365 		}
366 
367 		if (!TAILQ_EMPTY(&subsystem->ctrlrs)) {
368 			SPDK_ERRLOG("Can't extend NSID range with active connections\n");
369 			return 0;
370 		}
371 
372 		new_ns_array = realloc(subsystem->ns, sizeof(struct spdk_nvmf_ns) * new_max_nsid);
373 		if (new_ns_array == NULL) {
374 			SPDK_ERRLOG("Memory allocation error while resizing namespace array.\n");
375 			return 0;
376 		}
377 
378 		memset(new_ns_array + subsystem->max_nsid, 0,
379 		       sizeof(struct spdk_nvmf_ns) * (new_max_nsid - subsystem->max_nsid));
380 		subsystem->ns = new_ns_array;
381 		subsystem->max_nsid = new_max_nsid;
382 	}
383 
384 	if (nsid == 0) {
385 		/* NSID not specified - find a free index */
386 		for (i = 0; i < subsystem->max_nsid; i++) {
387 			if (_spdk_nvmf_subsystem_get_ns(subsystem, i + 1) == NULL) {
388 				nsid = i + 1;
389 				break;
390 			}
391 		}
392 		if (nsid == 0) {
393 			SPDK_ERRLOG("All available NSIDs in use\n");
394 			return 0;
395 		}
396 	} else {
397 		/* Specific NSID requested */
398 		if (_spdk_nvmf_subsystem_get_ns(subsystem, nsid)) {
399 			SPDK_ERRLOG("Requested NSID %" PRIu32 " already in use\n", nsid);
400 			return 0;
401 		}
402 	}
403 
404 	ns = &subsystem->ns[nsid - 1];
405 	memset(ns, 0, sizeof(*ns));
406 	ns->bdev = bdev;
407 	ns->id = nsid;
408 	rc = spdk_bdev_open(bdev, true, NULL, NULL, &ns->desc);
409 	if (rc != 0) {
410 		SPDK_ERRLOG("Subsystem %s: bdev %s cannot be opened, error=%d\n",
411 			    subsystem->subnqn, spdk_bdev_get_name(bdev), rc);
412 		return 0;
413 	}
414 	ns->allocated = true;
415 
416 	SPDK_DEBUGLOG(SPDK_TRACE_NVMF, "Subsystem %s: bdev %s assigned nsid %" PRIu32 "\n",
417 		      spdk_nvmf_subsystem_get_nqn(subsystem),
418 		      spdk_bdev_get_name(bdev),
419 		      nsid);
420 
421 	subsystem->max_nsid = spdk_max(subsystem->max_nsid, nsid);
422 	subsystem->num_allocated_nsid++;
423 	return nsid;
424 }
425 
426 static uint32_t
427 spdk_nvmf_subsystem_get_next_allocated_nsid(struct spdk_nvmf_subsystem *subsystem,
428 		uint32_t prev_nsid)
429 {
430 	uint32_t nsid;
431 
432 	if (prev_nsid >= subsystem->max_nsid) {
433 		return 0;
434 	}
435 
436 	for (nsid = prev_nsid + 1; nsid <= subsystem->max_nsid; nsid++) {
437 		if (subsystem->ns[nsid - 1].allocated) {
438 			return nsid;
439 		}
440 	}
441 
442 	return 0;
443 }
444 
445 struct spdk_nvmf_ns *
446 spdk_nvmf_subsystem_get_first_ns(struct spdk_nvmf_subsystem *subsystem)
447 {
448 	uint32_t first_nsid;
449 
450 	first_nsid = spdk_nvmf_subsystem_get_next_allocated_nsid(subsystem, 0);
451 	return _spdk_nvmf_subsystem_get_ns(subsystem, first_nsid);
452 }
453 
454 struct spdk_nvmf_ns *
455 spdk_nvmf_subsystem_get_next_ns(struct spdk_nvmf_subsystem *subsystem,
456 				struct spdk_nvmf_ns *prev_ns)
457 {
458 	uint32_t next_nsid;
459 
460 	next_nsid = spdk_nvmf_subsystem_get_next_allocated_nsid(subsystem, prev_ns->id);
461 	return _spdk_nvmf_subsystem_get_ns(subsystem, next_nsid);
462 }
463 
464 struct spdk_nvmf_ns *
465 spdk_nvmf_subsystem_get_ns(struct spdk_nvmf_subsystem *subsystem, uint32_t nsid)
466 {
467 	return _spdk_nvmf_subsystem_get_ns(subsystem, nsid);
468 }
469 
470 uint32_t
471 spdk_nvmf_ns_get_id(const struct spdk_nvmf_ns *ns)
472 {
473 	return ns->id;
474 }
475 
476 struct spdk_bdev *
477 spdk_nvmf_ns_get_bdev(struct spdk_nvmf_ns *ns)
478 {
479 	return ns->bdev;
480 }
481 
482 const char *
483 spdk_nvmf_subsystem_get_sn(const struct spdk_nvmf_subsystem *subsystem)
484 {
485 	return subsystem->sn;
486 }
487 
488 int
489 spdk_nvmf_subsystem_set_sn(struct spdk_nvmf_subsystem *subsystem, const char *sn)
490 {
491 	size_t len, max_len;
492 
493 	max_len = sizeof(subsystem->sn) - 1;
494 	len = strlen(sn);
495 	if (len > max_len) {
496 		SPDK_DEBUGLOG(SPDK_TRACE_NVMF, "Invalid sn \"%s\": length %zu > max %zu\n",
497 			      sn, len, max_len);
498 		return -1;
499 	}
500 
501 	snprintf(subsystem->sn, sizeof(subsystem->sn), "%s", sn);
502 
503 	return 0;
504 }
505 
506 const char *
507 spdk_nvmf_subsystem_get_nqn(struct spdk_nvmf_subsystem *subsystem)
508 {
509 	return subsystem->subnqn;
510 }
511 
512 /* Workaround for astyle formatting bug */
513 typedef enum spdk_nvmf_subtype nvmf_subtype_t;
514 
515 nvmf_subtype_t
516 spdk_nvmf_subsystem_get_type(struct spdk_nvmf_subsystem *subsystem)
517 {
518 	return subsystem->subtype;
519 }
520 
521 static uint16_t
522 spdk_nvmf_subsystem_gen_cntlid(struct spdk_nvmf_subsystem *subsystem)
523 {
524 	int count;
525 
526 	/*
527 	 * In the worst case, we might have to try all CNTLID values between 1 and 0xFFF0 - 1
528 	 * before we find one that is unused (or find that all values are in use).
529 	 */
530 	for (count = 0; count < 0xFFF0 - 1; count++) {
531 		subsystem->next_cntlid++;
532 		if (subsystem->next_cntlid >= 0xFFF0) {
533 			/* The spec reserves cntlid values in the range FFF0h to FFFFh. */
534 			subsystem->next_cntlid = 1;
535 		}
536 
537 		/* Check if a controller with this cntlid currently exists. */
538 		if (spdk_nvmf_subsystem_get_ctrlr(subsystem, subsystem->next_cntlid) == NULL) {
539 			/* Found unused cntlid */
540 			return subsystem->next_cntlid;
541 		}
542 	}
543 
544 	/* All valid cntlid values are in use. */
545 	return 0xFFFF;
546 }
547 
548 int
549 spdk_nvmf_subsystem_add_ctrlr(struct spdk_nvmf_subsystem *subsystem, struct spdk_nvmf_ctrlr *ctrlr)
550 {
551 	ctrlr->cntlid = spdk_nvmf_subsystem_gen_cntlid(subsystem);
552 	if (ctrlr->cntlid == 0xFFFF) {
553 		/* Unable to get a cntlid */
554 		SPDK_ERRLOG("Reached max simultaneous ctrlrs\n");
555 		return -EBUSY;
556 	}
557 
558 	TAILQ_INSERT_TAIL(&subsystem->ctrlrs, ctrlr, link);
559 
560 	return 0;
561 }
562 
563 void
564 spdk_nvmf_subsystem_remove_ctrlr(struct spdk_nvmf_subsystem *subsystem,
565 				 struct spdk_nvmf_ctrlr *ctrlr)
566 {
567 	assert(subsystem == ctrlr->subsys);
568 	TAILQ_REMOVE(&subsystem->ctrlrs, ctrlr, link);
569 }
570 
571 struct spdk_nvmf_ctrlr *
572 spdk_nvmf_subsystem_get_ctrlr(struct spdk_nvmf_subsystem *subsystem, uint16_t cntlid)
573 {
574 	struct spdk_nvmf_ctrlr *ctrlr;
575 
576 	TAILQ_FOREACH(ctrlr, &subsystem->ctrlrs, link) {
577 		if (ctrlr->cntlid == cntlid) {
578 			return ctrlr;
579 		}
580 	}
581 
582 	return NULL;
583 }
584