xref: /spdk/lib/ftl/ftl_io.c (revision 9889ab2dc80e40dae92dcef361d53dcba722043d)
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 #include "spdk/ftl.h"
36 #include "spdk/likely.h"
37 #include "spdk/util.h"
38 
39 #include "ftl_io.h"
40 #include "ftl_core.h"
41 #include "ftl_rwb.h"
42 #include "ftl_band.h"
43 #include "ftl_debug.h"
44 
45 void
46 ftl_io_inc_req(struct ftl_io *io)
47 {
48 	struct ftl_band *band = io->band;
49 
50 	if (!(io->flags & FTL_IO_CACHE) && io->type != FTL_IO_READ && io->type != FTL_IO_ERASE) {
51 		ftl_band_acquire_lba_map(band);
52 	}
53 
54 	__atomic_fetch_add(&io->dev->num_inflight, 1, __ATOMIC_SEQ_CST);
55 
56 	++io->req_cnt;
57 }
58 
59 void
60 ftl_io_dec_req(struct ftl_io *io)
61 {
62 	struct ftl_band *band = io->band;
63 	unsigned long num_inflight __attribute__((unused));
64 
65 	if (!(io->flags & FTL_IO_CACHE) && io->type != FTL_IO_READ && io->type != FTL_IO_ERASE) {
66 		ftl_band_release_lba_map(band);
67 	}
68 
69 	num_inflight = __atomic_fetch_sub(&io->dev->num_inflight, 1, __ATOMIC_SEQ_CST);
70 
71 	assert(num_inflight > 0);
72 	assert(io->req_cnt > 0);
73 
74 	--io->req_cnt;
75 }
76 
77 struct iovec *
78 ftl_io_iovec(struct ftl_io *io)
79 {
80 	return &io->iov[0];
81 }
82 
83 uint64_t
84 ftl_io_get_lba(const struct ftl_io *io, size_t offset)
85 {
86 	assert(offset < io->lbk_cnt);
87 
88 	if (io->flags & FTL_IO_VECTOR_LBA) {
89 		return io->lba.vector[offset];
90 	} else {
91 		return io->lba.single + offset;
92 	}
93 }
94 
95 uint64_t
96 ftl_io_current_lba(const struct ftl_io *io)
97 {
98 	return ftl_io_get_lba(io, io->pos);
99 }
100 
101 void
102 ftl_io_advance(struct ftl_io *io, size_t lbk_cnt)
103 {
104 	struct iovec *iov = ftl_io_iovec(io);
105 	size_t iov_lbks, lbk_left = lbk_cnt;
106 
107 	io->pos += lbk_cnt;
108 
109 	if (io->iov_cnt != 0) {
110 		while (lbk_left > 0) {
111 			assert(io->iov_pos < io->iov_cnt);
112 			iov_lbks = iov[io->iov_pos].iov_len / FTL_BLOCK_SIZE;
113 
114 			if (io->iov_off + lbk_left < iov_lbks) {
115 				io->iov_off += lbk_left;
116 				break;
117 			}
118 
119 			assert(iov_lbks > io->iov_off);
120 			lbk_left -= (iov_lbks - io->iov_off);
121 			io->iov_off = 0;
122 			io->iov_pos++;
123 		}
124 	}
125 
126 	if (io->parent) {
127 		ftl_io_advance(io->parent, lbk_cnt);
128 	}
129 }
130 
131 size_t
132 ftl_iovec_num_lbks(struct iovec *iov, size_t iov_cnt)
133 {
134 	size_t lbks = 0, i = 0;
135 
136 	for (; i < iov_cnt; ++i) {
137 		lbks += iov[i].iov_len / FTL_BLOCK_SIZE;
138 	}
139 
140 	return lbks;
141 }
142 
143 void *
144 ftl_io_iovec_addr(struct ftl_io *io)
145 {
146 	assert(io->iov_pos < io->iov_cnt);
147 	assert(io->iov_off * FTL_BLOCK_SIZE < ftl_io_iovec(io)[io->iov_pos].iov_len);
148 
149 	return (char *)ftl_io_iovec(io)[io->iov_pos].iov_base +
150 	       io->iov_off * FTL_BLOCK_SIZE;
151 }
152 
153 size_t
154 ftl_io_iovec_len_left(struct ftl_io *io)
155 {
156 	struct iovec *iov = ftl_io_iovec(io);
157 	return iov[io->iov_pos].iov_len / FTL_BLOCK_SIZE - io->iov_off;
158 }
159 
160 static void
161 _ftl_io_init_iovec(struct ftl_io *io, const struct iovec *iov, size_t iov_cnt, size_t lbk_cnt)
162 {
163 	size_t iov_off;
164 
165 	io->iov_pos = 0;
166 	io->iov_cnt = iov_cnt;
167 	io->lbk_cnt = lbk_cnt;
168 
169 	memcpy(io->iov, iov, iov_cnt * sizeof(*iov));
170 
171 	if (lbk_cnt == 0) {
172 		for (iov_off = 0; iov_off < iov_cnt; ++iov_off) {
173 			io->lbk_cnt += iov[iov_off].iov_len / FTL_BLOCK_SIZE;
174 		}
175 	}
176 }
177 
178 static void _ftl_io_free(struct ftl_io *io);
179 
180 static int
181 ftl_io_add_child(struct ftl_io *io, const struct iovec *iov, size_t iov_cnt)
182 {
183 	struct ftl_io *child;
184 
185 	child = ftl_io_alloc_child(io);
186 	if (spdk_unlikely(!child)) {
187 		return -ENOMEM;
188 	}
189 
190 	_ftl_io_init_iovec(child, iov, iov_cnt, 0);
191 
192 	if (io->flags & FTL_IO_VECTOR_LBA) {
193 		child->lba.vector = io->lba.vector + io->lbk_cnt;
194 	} else {
195 		child->lba.single = io->lba.single + io->lbk_cnt;
196 	}
197 
198 	io->lbk_cnt += child->lbk_cnt;
199 	return 0;
200 }
201 
202 static int
203 ftl_io_init_iovec(struct ftl_io *io, const struct iovec *iov, size_t iov_cnt, size_t lbk_cnt)
204 {
205 	struct ftl_io *child;
206 	size_t iov_off = 0, iov_left;
207 	int rc;
208 
209 	if (spdk_likely(iov_cnt <= FTL_IO_MAX_IOVEC)) {
210 		_ftl_io_init_iovec(io, iov, iov_cnt, lbk_cnt);
211 		return 0;
212 	}
213 
214 	while (iov_off < iov_cnt) {
215 		iov_left = spdk_min(iov_cnt - iov_off, FTL_IO_MAX_IOVEC);
216 
217 		rc = ftl_io_add_child(io, &iov[iov_off], iov_left);
218 		if (spdk_unlikely(rc != 0)) {
219 			while ((child = LIST_FIRST(&io->children))) {
220 				assert(LIST_EMPTY(&child->children));
221 				LIST_REMOVE(child, child_entry);
222 				_ftl_io_free(child);
223 			}
224 
225 			return -ENOMEM;
226 		}
227 
228 		iov_off += iov_left;
229 	}
230 
231 	assert(io->lbk_cnt == lbk_cnt);
232 	return 0;
233 }
234 
235 void
236 ftl_io_shrink_iovec(struct ftl_io *io, size_t lbk_cnt)
237 {
238 	size_t iov_off = 0, lbk_off = 0;
239 
240 	assert(io->lbk_cnt >= lbk_cnt);
241 	assert(io->pos == 0 && io->iov_pos == 0 && io->iov_off == 0);
242 
243 	for (; iov_off < io->iov_cnt; ++iov_off) {
244 		size_t num_iov = io->iov[iov_off].iov_len / FTL_BLOCK_SIZE;
245 		size_t num_left = lbk_cnt - lbk_off;
246 
247 		if (num_iov >= num_left) {
248 			io->iov[iov_off].iov_len = num_left * FTL_BLOCK_SIZE;
249 			io->iov_cnt = iov_off + 1;
250 			io->lbk_cnt = lbk_cnt;
251 			break;
252 		}
253 
254 		lbk_off += num_iov;
255 	}
256 }
257 
258 static void
259 ftl_io_init(struct ftl_io *io, struct spdk_ftl_dev *dev,
260 	    ftl_io_fn fn, void *ctx, int flags, int type)
261 {
262 	io->flags |= flags | FTL_IO_INITIALIZED;
263 	io->type = type;
264 	io->dev = dev;
265 	io->lba.single = FTL_LBA_INVALID;
266 	io->ppa.ppa = FTL_PPA_INVALID;
267 	io->cb_fn = fn;
268 	io->cb_ctx = ctx;
269 	io->trace = ftl_trace_alloc_id(dev);
270 }
271 
272 struct ftl_io *
273 ftl_io_init_internal(const struct ftl_io_init_opts *opts)
274 {
275 	struct ftl_io *io = opts->io;
276 	struct ftl_io *parent = opts->parent;
277 	struct spdk_ftl_dev *dev = opts->dev;
278 	struct iovec iov = {
279 		.iov_base = opts->data,
280 		.iov_len  = opts->lbk_cnt * FTL_BLOCK_SIZE
281 	};
282 
283 	if (!io) {
284 		if (parent) {
285 			io = ftl_io_alloc_child(parent);
286 		} else {
287 			io = ftl_io_alloc(ftl_get_io_channel(dev));
288 		}
289 
290 		if (!io) {
291 			return NULL;
292 		}
293 	}
294 
295 	ftl_io_clear(io);
296 	ftl_io_init(io, dev, opts->cb_fn, opts->cb_ctx, opts->flags | FTL_IO_INTERNAL, opts->type);
297 
298 	io->rwb_batch = opts->rwb_batch;
299 	io->band = opts->band;
300 	io->md = opts->md;
301 
302 	if (parent) {
303 		if (parent->flags & FTL_IO_VECTOR_LBA) {
304 			io->lba.vector = parent->lba.vector + parent->pos;
305 		} else {
306 			io->lba.single = parent->lba.single + parent->pos;
307 		}
308 	}
309 
310 	if (ftl_io_init_iovec(io, &iov, 1, opts->lbk_cnt)) {
311 		if (!opts->io) {
312 			ftl_io_free(io);
313 		}
314 		return NULL;
315 	}
316 
317 	if (opts->flags & FTL_IO_VECTOR_LBA) {
318 		io->lba.vector = calloc(io->lbk_cnt, sizeof(uint64_t));
319 		if (!io->lba.vector) {
320 			ftl_io_free(io);
321 			return NULL;
322 		}
323 	}
324 
325 	return io;
326 }
327 
328 struct ftl_io *
329 ftl_io_rwb_init(struct spdk_ftl_dev *dev, struct ftl_band *band,
330 		struct ftl_rwb_batch *batch, ftl_io_fn cb)
331 {
332 	struct ftl_io_init_opts opts = {
333 		.dev		= dev,
334 		.io		= NULL,
335 		.rwb_batch	= batch,
336 		.band		= band,
337 		.size		= sizeof(struct ftl_io),
338 		.flags		= 0,
339 		.type		= FTL_IO_WRITE,
340 		.lbk_cnt	= dev->xfer_size,
341 		.cb_fn		= cb,
342 		.data		= ftl_rwb_batch_get_data(batch),
343 		.md		= ftl_rwb_batch_get_md(batch),
344 	};
345 
346 	return ftl_io_init_internal(&opts);
347 }
348 
349 struct ftl_io *
350 ftl_io_erase_init(struct ftl_band *band, size_t lbk_cnt, ftl_io_fn cb)
351 {
352 	struct ftl_io *io;
353 	struct ftl_io_init_opts opts = {
354 		.dev		= band->dev,
355 		.io		= NULL,
356 		.rwb_batch	= NULL,
357 		.band		= band,
358 		.size		= sizeof(struct ftl_io),
359 		.flags		= FTL_IO_PPA_MODE,
360 		.type		= FTL_IO_ERASE,
361 		.lbk_cnt	= 1,
362 		.cb_fn		= cb,
363 		.data		= NULL,
364 		.md		= NULL,
365 	};
366 
367 	io = ftl_io_init_internal(&opts);
368 	if (!io) {
369 		return NULL;
370 	}
371 
372 	io->lbk_cnt = lbk_cnt;
373 
374 	return io;
375 }
376 
377 static void
378 _ftl_user_cb(struct ftl_io *io, void *arg, int status)
379 {
380 	io->user_fn(arg, status);
381 }
382 
383 struct ftl_io *
384 ftl_io_user_init(struct spdk_io_channel *_ioch, uint64_t lba, size_t lbk_cnt, struct iovec *iov,
385 		 size_t iov_cnt, spdk_ftl_fn cb_fn, void *cb_ctx, int type)
386 {
387 	struct ftl_io_channel *ioch = spdk_io_channel_get_ctx(_ioch);
388 	struct spdk_ftl_dev *dev = ioch->dev;
389 	struct ftl_io *io;
390 
391 	io = ftl_io_alloc(_ioch);
392 	if (spdk_unlikely(!io)) {
393 		return NULL;
394 	}
395 
396 	ftl_io_init(io, dev, _ftl_user_cb, cb_ctx, 0, type);
397 	io->lba.single = lba;
398 	io->user_fn = cb_fn;
399 
400 	if (ftl_io_init_iovec(io, iov, iov_cnt, lbk_cnt)) {
401 		ftl_io_free(io);
402 		return NULL;
403 	}
404 
405 	ftl_trace_lba_io_init(io->dev, io);
406 	return io;
407 }
408 
409 static void
410 _ftl_io_free(struct ftl_io *io)
411 {
412 	struct ftl_io_channel *ioch;
413 
414 	assert(LIST_EMPTY(&io->children));
415 
416 	if (io->flags & FTL_IO_VECTOR_LBA) {
417 		free(io->lba.vector);
418 	}
419 
420 	if (pthread_spin_destroy(&io->lock)) {
421 		SPDK_ERRLOG("pthread_spin_destroy failed\n");
422 	}
423 
424 	ioch = spdk_io_channel_get_ctx(io->ioch);
425 	spdk_mempool_put(ioch->io_pool, io);
426 }
427 
428 static bool
429 ftl_io_remove_child(struct ftl_io *io)
430 {
431 	struct ftl_io *parent = io->parent;
432 	bool parent_done;
433 
434 	pthread_spin_lock(&parent->lock);
435 	LIST_REMOVE(io, child_entry);
436 	parent_done = parent->done && LIST_EMPTY(&parent->children);
437 	parent->status = parent->status ? : io->status;
438 	pthread_spin_unlock(&parent->lock);
439 
440 	return parent_done;
441 }
442 
443 void
444 ftl_io_complete(struct ftl_io *io)
445 {
446 	struct ftl_io *parent = io->parent;
447 	bool complete;
448 
449 	io->flags &= ~FTL_IO_INITIALIZED;
450 
451 	pthread_spin_lock(&io->lock);
452 	complete = LIST_EMPTY(&io->children);
453 	io->done = true;
454 	pthread_spin_unlock(&io->lock);
455 
456 	if (complete) {
457 		if (io->cb_fn) {
458 			io->cb_fn(io, io->cb_ctx, io->status);
459 		}
460 
461 		if (parent && ftl_io_remove_child(io)) {
462 			ftl_io_complete(parent);
463 		}
464 
465 		_ftl_io_free(io);
466 	}
467 }
468 
469 struct ftl_io *
470 ftl_io_alloc_child(struct ftl_io *parent)
471 {
472 	struct ftl_io *io;
473 
474 	io = ftl_io_alloc(parent->ioch);
475 	if (spdk_unlikely(!io)) {
476 		return NULL;
477 	}
478 
479 	ftl_io_init(io, parent->dev, NULL, NULL, parent->flags, parent->type);
480 	io->parent = parent;
481 
482 	pthread_spin_lock(&parent->lock);
483 	LIST_INSERT_HEAD(&parent->children, io, child_entry);
484 	pthread_spin_unlock(&parent->lock);
485 
486 	return io;
487 }
488 
489 void
490 ftl_io_process_error(struct ftl_io *io, const struct spdk_nvme_cpl *status)
491 {
492 	char ppa_buf[128];
493 
494 	/* TODO: add error handling for specifc cases */
495 	if (status->status.sct == SPDK_NVME_SCT_MEDIA_ERROR &&
496 	    status->status.sc == SPDK_OCSSD_SC_READ_HIGH_ECC) {
497 		return;
498 	}
499 
500 	SPDK_ERRLOG("Status code type 0x%x, status code 0x%x for IO type %u @ppa: %s, lba 0x%lx, cnt %lu\n",
501 		    status->status.sct, status->status.sc, io->type, ftl_ppa2str(io->ppa, ppa_buf, sizeof(ppa_buf)),
502 		    ftl_io_get_lba(io, 0), io->lbk_cnt);
503 
504 	io->status = -EIO;
505 }
506 
507 void ftl_io_fail(struct ftl_io *io, int status)
508 {
509 	io->status = status;
510 	ftl_io_advance(io, io->lbk_cnt - io->pos);
511 }
512 
513 void *
514 ftl_io_get_md(const struct ftl_io *io)
515 {
516 	if (!io->md) {
517 		return NULL;
518 	}
519 
520 	return (char *)io->md + io->pos * io->dev->md_size;
521 }
522 
523 struct ftl_io *
524 ftl_io_alloc(struct spdk_io_channel *ch)
525 {
526 	struct ftl_io *io;
527 	struct ftl_io_channel *ioch = spdk_io_channel_get_ctx(ch);
528 
529 	io = spdk_mempool_get(ioch->io_pool);
530 	if (!io) {
531 		return NULL;
532 	}
533 
534 	memset(io, 0, ioch->elem_size);
535 	io->ioch = ch;
536 
537 	if (pthread_spin_init(&io->lock, PTHREAD_PROCESS_PRIVATE)) {
538 		SPDK_ERRLOG("pthread_spin_init failed\n");
539 		spdk_mempool_put(ioch->io_pool, io);
540 		return NULL;
541 	}
542 
543 	return io;
544 }
545 
546 void
547 ftl_io_reinit(struct ftl_io *io, ftl_io_fn cb, void *ctx, int flags, int type)
548 {
549 	ftl_io_clear(io);
550 	ftl_io_init(io, io->dev, cb, ctx, flags, type);
551 }
552 
553 void
554 ftl_io_clear(struct ftl_io *io)
555 {
556 	ftl_io_reset(io);
557 
558 	io->flags = 0;
559 	io->rwb_batch = NULL;
560 	io->band = NULL;
561 }
562 
563 void
564 ftl_io_reset(struct ftl_io *io)
565 {
566 	io->req_cnt = io->pos = io->iov_pos = io->iov_off = 0;
567 	io->done = false;
568 }
569 
570 void
571 ftl_io_free(struct ftl_io *io)
572 {
573 	struct ftl_io *parent;
574 
575 	if (!io) {
576 		return;
577 	}
578 
579 	parent = io->parent;
580 	if (parent && ftl_io_remove_child(io)) {
581 		ftl_io_complete(parent);
582 	}
583 
584 	_ftl_io_free(io);
585 }
586 
587 void
588 ftl_io_call_foreach_child(struct ftl_io *io, int (*callback)(struct ftl_io *))
589 {
590 	struct ftl_io *child, *tmp;
591 
592 	assert(!io->done);
593 
594 	/*
595 	 * If the IO doesn't have any children, it means that it directly describes a request (i.e.
596 	 * all of the buffers, LBAs, etc. are filled). Otherwise the IO only groups together several
597 	 * requests and may be partially filled, so the callback needs to be called on all of its
598 	 * children instead.
599 	 */
600 	if (LIST_EMPTY(&io->children)) {
601 		callback(io);
602 		return;
603 	}
604 
605 	LIST_FOREACH_SAFE(child, &io->children, child_entry, tmp) {
606 		int rc = callback(child);
607 		if (rc) {
608 			assert(rc != -EAGAIN);
609 			ftl_io_fail(io, rc);
610 			break;
611 		}
612 	}
613 
614 	/*
615 	 * If all the callbacks were processed or an error occurred, treat this IO as completed.
616 	 * Multiple calls to ftl_io_call_foreach_child are not supported, resubmissions are supposed
617 	 * to be handled in the callback.
618 	 */
619 	ftl_io_complete(io);
620 }
621