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