xref: /spdk/lib/ftl/ftl_reloc.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/likely.h"
35 #include "spdk_internal/log.h"
36 #include "spdk/ftl.h"
37 
38 #include "ftl_reloc.h"
39 #include "ftl_core.h"
40 #include "ftl_io.h"
41 #include "ftl_rwb.h"
42 #include "ftl_band.h"
43 #include "ftl_debug.h"
44 
45 /* Maximum active reloc moves */
46 #define FTL_RELOC_MAX_MOVES 256
47 
48 struct ftl_reloc;
49 struct ftl_band_reloc;
50 
51 enum ftl_reloc_move_state {
52 	FTL_RELOC_STATE_READ_LBA_MAP,
53 	FTL_RELOC_STATE_READ,
54 	FTL_RELOC_STATE_WRITE,
55 };
56 
57 struct ftl_reloc_move {
58 	struct ftl_band_reloc			*breloc;
59 
60 	/* Start ppa */
61 	struct ftl_ppa				ppa;
62 
63 	/* Number of logical blocks */
64 	size_t					lbk_cnt;
65 
66 	/* Data buffer */
67 	void					*data;
68 
69 	/* Move state (read lba_map, read, write) */
70 	enum ftl_reloc_move_state		state;
71 
72 	/* IO associated with move */
73 	struct ftl_io				*io;
74 };
75 
76 struct ftl_band_reloc {
77 	struct ftl_reloc			*parent;
78 
79 	/* Band being relocated */
80 	struct ftl_band				*band;
81 
82 	/* Number of logical blocks to be relocated */
83 	size_t					num_lbks;
84 
85 	/* Bitmap of logical blocks to be relocated */
86 	struct spdk_bit_array			*reloc_map;
87 
88 	/* Indicates band being acitvely processed */
89 	int					active;
90 	/* The band is being defragged */
91 	bool					defrag;
92 
93 	/* Reloc map iterator */
94 	struct {
95 		/* Array of chunk offsets */
96 		size_t				*chk_offset;
97 
98 		/* Currently chunk */
99 		size_t				chk_current;
100 	} iter;
101 
102 	/* Number of outstanding moves */
103 	size_t					num_outstanding;
104 
105 	/* Pool of move objects */
106 	struct ftl_reloc_move			*moves;
107 
108 	/* Move queue */
109 	struct spdk_ring			*move_queue;
110 
111 	TAILQ_ENTRY(ftl_band_reloc)		entry;
112 };
113 
114 struct ftl_reloc {
115 	/* Device associated with relocate */
116 	struct spdk_ftl_dev			*dev;
117 
118 	/* Indicates relocate is about to halt */
119 	bool					halt;
120 
121 	/* Maximum number of IOs per band */
122 	size_t					max_qdepth;
123 
124 	/* Maximum number of active band relocates */
125 	size_t					max_active;
126 
127 	/* Maximum transfer size (in logical blocks) per single IO */
128 	size_t					xfer_size;
129 	/* Number of bands being defragged */
130 	size_t					num_defrag_bands;
131 
132 	/* Array of band relocates */
133 	struct ftl_band_reloc			*brelocs;
134 
135 	/* Number of active/priority band relocates */
136 	size_t					num_active;
137 
138 	/* Priority band relocates queue */
139 	TAILQ_HEAD(, ftl_band_reloc)		prio_queue;
140 
141 	/* Active band relocates queue */
142 	TAILQ_HEAD(, ftl_band_reloc)		active_queue;
143 
144 	/* Pending band relocates queue */
145 	TAILQ_HEAD(, ftl_band_reloc)		pending_queue;
146 };
147 
148 bool
149 ftl_reloc_is_defrag_active(const struct ftl_reloc *reloc)
150 {
151 	return reloc->num_defrag_bands > 0;
152 }
153 
154 static size_t
155 ftl_reloc_iter_chk_offset(struct ftl_band_reloc *breloc)
156 {
157 	size_t chunk = breloc->iter.chk_current;
158 
159 	return breloc->iter.chk_offset[chunk];
160 }
161 
162 static size_t
163 ftl_reloc_iter_chk_done(struct ftl_band_reloc *breloc)
164 {
165 	size_t num_lbks = ftl_dev_lbks_in_chunk(breloc->parent->dev);
166 
167 	return ftl_reloc_iter_chk_offset(breloc) == num_lbks;
168 }
169 
170 static void
171 ftl_reloc_clr_lbk(struct ftl_band_reloc *breloc, size_t lbkoff)
172 {
173 	if (!spdk_bit_array_get(breloc->reloc_map, lbkoff)) {
174 		return;
175 	}
176 
177 	spdk_bit_array_clear(breloc->reloc_map, lbkoff);
178 	assert(breloc->num_lbks);
179 	breloc->num_lbks--;
180 }
181 
182 static void
183 ftl_reloc_read_lba_map_cb(struct ftl_io *io, void *arg, int status)
184 {
185 	struct ftl_reloc_move *move = arg;
186 	struct ftl_band_reloc *breloc = move->breloc;
187 
188 	breloc->num_outstanding--;
189 	assert(status == 0);
190 	move->state = FTL_RELOC_STATE_WRITE;
191 	spdk_ring_enqueue(breloc->move_queue, (void **)&move, 1, NULL);
192 }
193 
194 static int
195 ftl_reloc_read_lba_map(struct ftl_band_reloc *breloc, struct ftl_reloc_move *move)
196 {
197 	struct ftl_band *band = breloc->band;
198 
199 	breloc->num_outstanding++;
200 	return ftl_band_read_lba_map(band, ftl_band_lbkoff_from_ppa(band, move->ppa),
201 				     move->lbk_cnt, ftl_reloc_read_lba_map_cb, move);
202 }
203 
204 static void
205 ftl_reloc_prep(struct ftl_band_reloc *breloc)
206 {
207 	struct ftl_band *band = breloc->band;
208 	struct ftl_reloc *reloc = breloc->parent;
209 	struct ftl_reloc_move *move;
210 	size_t i;
211 
212 	breloc->active = 1;
213 	reloc->num_active++;
214 
215 	if (!band->high_prio) {
216 		if (band->lba_map.ref_cnt == 0) {
217 			if (ftl_band_alloc_lba_map(band)) {
218 				assert(false);
219 			}
220 		} else {
221 			ftl_band_acquire_lba_map(band);
222 		}
223 	}
224 
225 	for (i = 0; i < reloc->max_qdepth; ++i) {
226 		move = &breloc->moves[i];
227 		move->state = FTL_RELOC_STATE_READ;
228 		spdk_ring_enqueue(breloc->move_queue, (void **)&move, 1, NULL);
229 	}
230 }
231 
232 static void
233 ftl_reloc_free_move(struct ftl_band_reloc *breloc, struct ftl_reloc_move *move)
234 {
235 	assert(move);
236 	spdk_dma_free(move->data);
237 	memset(move, 0, sizeof(*move));
238 	move->state = FTL_RELOC_STATE_READ;
239 	spdk_ring_enqueue(breloc->move_queue, (void **)&move, 1, NULL);
240 }
241 
242 static void
243 ftl_reloc_write_cb(struct ftl_io *io, void *arg, int status)
244 {
245 	struct ftl_reloc_move *move = arg;
246 	struct ftl_ppa ppa = move->ppa;
247 	struct ftl_band_reloc *breloc = move->breloc;
248 	size_t i;
249 
250 	breloc->num_outstanding--;
251 
252 	if (status) {
253 		SPDK_ERRLOG("Reloc write failed with status: %d\n", status);
254 		assert(false);
255 		return;
256 	}
257 
258 	for (i = 0; i < move->lbk_cnt; ++i) {
259 		ppa.lbk = move->ppa.lbk + i;
260 		size_t lbkoff = ftl_band_lbkoff_from_ppa(breloc->band, ppa);
261 		ftl_reloc_clr_lbk(breloc, lbkoff);
262 	}
263 
264 	ftl_reloc_free_move(breloc, move);
265 }
266 
267 static void
268 ftl_reloc_read_cb(struct ftl_io *io, void *arg, int status)
269 {
270 	struct ftl_reloc_move *move = arg;
271 	struct ftl_band_reloc *breloc = move->breloc;
272 
273 	breloc->num_outstanding--;
274 
275 	/* TODO: We should handle fail on relocation read. We need to inform */
276 	/* user that this group of blocks is bad (update l2p with bad block address and */
277 	/* put it to lba_map/sector_lba). Maybe we could also retry read with smaller granularity? */
278 	if (status) {
279 		SPDK_ERRLOG("Reloc read failed with status: %d\n", status);
280 		assert(false);
281 		return;
282 	}
283 
284 	move->state = FTL_RELOC_STATE_READ_LBA_MAP;
285 	move->io = NULL;
286 	spdk_ring_enqueue(breloc->move_queue, (void **)&move, 1, NULL);
287 }
288 
289 static void
290 ftl_reloc_iter_reset(struct ftl_band_reloc *breloc)
291 {
292 	memset(breloc->iter.chk_offset, 0, ftl_dev_num_punits(breloc->band->dev) *
293 	       sizeof(*breloc->iter.chk_offset));
294 	breloc->iter.chk_current = 0;
295 }
296 
297 static size_t
298 ftl_reloc_iter_lbkoff(struct ftl_band_reloc *breloc)
299 {
300 	size_t chk_offset = breloc->iter.chk_current * ftl_dev_lbks_in_chunk(breloc->parent->dev);
301 
302 	return breloc->iter.chk_offset[breloc->iter.chk_current] + chk_offset;
303 }
304 
305 static void
306 ftl_reloc_iter_next_chk(struct ftl_band_reloc *breloc)
307 {
308 	size_t num_chk = ftl_dev_num_punits(breloc->band->dev);
309 
310 	breloc->iter.chk_current = (breloc->iter.chk_current + 1) % num_chk;
311 }
312 
313 static int
314 ftl_reloc_lbk_valid(struct ftl_band_reloc *breloc, size_t lbkoff)
315 {
316 	struct ftl_ppa ppa = ftl_band_ppa_from_lbkoff(breloc->band, lbkoff);
317 
318 	return ftl_ppa_is_written(breloc->band, ppa) &&
319 	       spdk_bit_array_get(breloc->reloc_map, lbkoff) &&
320 	       ftl_band_lbkoff_valid(breloc->band, lbkoff);
321 }
322 
323 static int
324 ftl_reloc_iter_next(struct ftl_band_reloc *breloc, size_t *lbkoff)
325 {
326 	size_t chunk = breloc->iter.chk_current;
327 
328 	*lbkoff = ftl_reloc_iter_lbkoff(breloc);
329 
330 	if (ftl_reloc_iter_chk_done(breloc)) {
331 		return 0;
332 	}
333 
334 	breloc->iter.chk_offset[chunk]++;
335 
336 	if (!ftl_reloc_lbk_valid(breloc, *lbkoff)) {
337 		ftl_reloc_clr_lbk(breloc, *lbkoff);
338 		return 0;
339 	}
340 
341 	return 1;
342 }
343 
344 static int
345 ftl_reloc_first_valid_lbk(struct ftl_band_reloc *breloc, size_t *lbkoff)
346 {
347 	size_t i, num_lbks = ftl_dev_lbks_in_chunk(breloc->parent->dev);
348 
349 	for (i = ftl_reloc_iter_chk_offset(breloc); i < num_lbks; ++i) {
350 		if (ftl_reloc_iter_next(breloc, lbkoff)) {
351 			return 1;
352 		}
353 	}
354 
355 	return 0;
356 }
357 
358 static int
359 ftl_reloc_iter_done(struct ftl_band_reloc *breloc)
360 {
361 	size_t i;
362 	size_t num_chks = ftl_dev_num_punits(breloc->band->dev);
363 	size_t num_lbks = ftl_dev_lbks_in_chunk(breloc->parent->dev);
364 
365 	for (i = 0; i < num_chks; ++i) {
366 		if (breloc->iter.chk_offset[i] != num_lbks) {
367 			return 0;
368 		}
369 	}
370 
371 	return 1;
372 }
373 
374 static size_t
375 ftl_reloc_find_valid_lbks(struct ftl_band_reloc *breloc,
376 			  size_t num_lbk, struct ftl_ppa *ppa)
377 {
378 	size_t lbkoff, lbk_cnt = 0;
379 
380 	if (!ftl_reloc_first_valid_lbk(breloc, &lbkoff)) {
381 		return 0;
382 	}
383 
384 	*ppa = ftl_band_ppa_from_lbkoff(breloc->band, lbkoff);
385 
386 	for (lbk_cnt = 1; lbk_cnt < num_lbk; lbk_cnt++) {
387 		if (!ftl_reloc_iter_next(breloc, &lbkoff)) {
388 			break;
389 		}
390 	}
391 
392 	return lbk_cnt;
393 }
394 
395 static size_t
396 ftl_reloc_next_lbks(struct ftl_band_reloc *breloc, struct ftl_ppa *ppa)
397 {
398 	size_t i, lbk_cnt = 0;
399 	struct spdk_ftl_dev *dev = breloc->parent->dev;
400 
401 	for (i = 0; i < ftl_dev_num_punits(dev); ++i) {
402 		lbk_cnt = ftl_reloc_find_valid_lbks(breloc, breloc->parent->xfer_size, ppa);
403 		ftl_reloc_iter_next_chk(breloc);
404 
405 		if (lbk_cnt || ftl_reloc_iter_done(breloc)) {
406 			break;
407 		}
408 	}
409 
410 	return lbk_cnt;
411 }
412 
413 static struct ftl_io *
414 ftl_reloc_io_init(struct ftl_band_reloc *breloc, struct ftl_reloc_move *move,
415 		  ftl_io_fn fn, enum ftl_io_type io_type, int flags)
416 {
417 	size_t lbkoff, i;
418 	struct ftl_ppa ppa = move->ppa;
419 	struct ftl_io *io = NULL;
420 	struct ftl_io_init_opts opts = {
421 		.dev		= breloc->parent->dev,
422 		.band		= breloc->band,
423 		.size		= sizeof(*io),
424 		.flags		= flags | FTL_IO_INTERNAL | FTL_IO_PPA_MODE,
425 		.type		= io_type,
426 		.lbk_cnt	= move->lbk_cnt,
427 		.data		= move->data,
428 		.cb_fn		= fn,
429 	};
430 
431 	io = ftl_io_init_internal(&opts);
432 	if (!io) {
433 		return NULL;
434 	}
435 
436 	io->cb_ctx = move;
437 	io->ppa = move->ppa;
438 
439 	if (flags & FTL_IO_VECTOR_LBA) {
440 		for (i = 0; i < io->lbk_cnt; ++i, ++ppa.lbk) {
441 			lbkoff = ftl_band_lbkoff_from_ppa(breloc->band, ppa);
442 
443 			if (!ftl_band_lbkoff_valid(breloc->band, lbkoff)) {
444 				io->lba.vector[i] = FTL_LBA_INVALID;
445 				continue;
446 			}
447 
448 			io->lba.vector[i] = breloc->band->lba_map.map[lbkoff];
449 		}
450 	}
451 
452 	ftl_trace_lba_io_init(io->dev, io);
453 
454 	return io;
455 }
456 
457 static int
458 ftl_reloc_write(struct ftl_band_reloc *breloc, struct ftl_reloc_move *move)
459 {
460 	int io_flags =  FTL_IO_WEAK | FTL_IO_VECTOR_LBA | FTL_IO_BYPASS_CACHE;
461 
462 	if (spdk_likely(!move->io)) {
463 		move->io = ftl_reloc_io_init(breloc, move, ftl_reloc_write_cb,
464 					     FTL_IO_WRITE, io_flags);
465 		if (!move->io) {
466 			ftl_reloc_free_move(breloc, move);
467 			return -ENOMEM;
468 		}
469 	}
470 
471 	breloc->num_outstanding++;
472 	ftl_io_write(move->io);
473 	return 0;
474 }
475 
476 static int
477 ftl_reloc_read(struct ftl_band_reloc *breloc, struct ftl_reloc_move *move)
478 {
479 	struct ftl_ppa ppa = {};
480 
481 	move->lbk_cnt = ftl_reloc_next_lbks(breloc, &ppa);
482 	move->breloc = breloc;
483 	move->ppa = ppa;
484 
485 	if (!move->lbk_cnt) {
486 		return 0;
487 	}
488 
489 	move->data = spdk_dma_malloc(FTL_BLOCK_SIZE * move->lbk_cnt, 4096, NULL);
490 	if (!move->data) {
491 		return -1;
492 	}
493 
494 	move->io = ftl_reloc_io_init(breloc, move, ftl_reloc_read_cb, FTL_IO_READ, 0);
495 	if (!move->io) {
496 		ftl_reloc_free_move(breloc, move);
497 		SPDK_ERRLOG("Failed to initialize io for relocation.");
498 		return -1;
499 	}
500 
501 	breloc->num_outstanding++;
502 	ftl_io_read(move->io);
503 	return 0;
504 }
505 
506 static void
507 ftl_reloc_process_moves(struct ftl_band_reloc *breloc)
508 {
509 	int rc = 0;
510 	size_t i, num_moves;
511 	struct ftl_reloc_move *moves[FTL_RELOC_MAX_MOVES] = {0};
512 	struct ftl_reloc *reloc = breloc->parent;
513 	struct ftl_reloc_move *move;
514 
515 	num_moves = spdk_ring_dequeue(breloc->move_queue, (void **)moves, reloc->max_qdepth);
516 
517 	for (i = 0; i < num_moves; ++i) {
518 		move = moves[i];
519 		assert(move != NULL);
520 		switch (move->state) {
521 		case FTL_RELOC_STATE_READ_LBA_MAP:
522 			rc = ftl_reloc_read_lba_map(breloc, move);
523 			break;
524 		case FTL_RELOC_STATE_READ:
525 			rc = ftl_reloc_read(breloc, move);
526 			break;
527 		case FTL_RELOC_STATE_WRITE:
528 			rc = ftl_reloc_write(breloc, move);
529 			break;
530 		default:
531 			assert(false);
532 			break;
533 		}
534 
535 		if (rc) {
536 			SPDK_ERRLOG("Move queue processing failed\n");
537 			assert(false);
538 		}
539 	}
540 }
541 
542 static bool
543 ftl_reloc_done(struct ftl_band_reloc *breloc)
544 {
545 	return !breloc->num_outstanding && !spdk_ring_count(breloc->move_queue);
546 }
547 
548 static void
549 ftl_reloc_release(struct ftl_band_reloc *breloc)
550 {
551 	struct ftl_reloc *reloc = breloc->parent;
552 	struct ftl_band *band = breloc->band;
553 
554 	if (band->high_prio && breloc->num_lbks == 0) {
555 		band->high_prio = 0;
556 		TAILQ_REMOVE(&reloc->prio_queue, breloc, entry);
557 	} else if (!band->high_prio) {
558 		TAILQ_REMOVE(&reloc->active_queue, breloc, entry);
559 	}
560 
561 	ftl_reloc_iter_reset(breloc);
562 
563 	ftl_band_release_lba_map(band);
564 
565 	breloc->active = 0;
566 	reloc->num_active--;
567 
568 	if (!band->high_prio && breloc->num_lbks) {
569 		TAILQ_INSERT_TAIL(&reloc->pending_queue, breloc, entry);
570 		return;
571 	}
572 
573 	if (ftl_band_empty(band) && band->state == FTL_BAND_STATE_CLOSED) {
574 		ftl_band_set_state(breloc->band, FTL_BAND_STATE_FREE);
575 
576 		if (breloc->defrag) {
577 			breloc->defrag = false;
578 			assert(reloc->num_defrag_bands > 0);
579 			reloc->num_defrag_bands--;
580 		}
581 	}
582 }
583 
584 static void
585 ftl_process_reloc(struct ftl_band_reloc *breloc)
586 {
587 	ftl_reloc_process_moves(breloc);
588 
589 	if (ftl_reloc_done(breloc)) {
590 		ftl_reloc_release(breloc);
591 	}
592 }
593 
594 static int
595 ftl_band_reloc_init(struct ftl_reloc *reloc, struct ftl_band_reloc *breloc,
596 		    struct ftl_band *band)
597 {
598 	breloc->band = band;
599 	breloc->parent = reloc;
600 
601 	breloc->reloc_map = spdk_bit_array_create(ftl_num_band_lbks(reloc->dev));
602 	if (!breloc->reloc_map) {
603 		SPDK_ERRLOG("Failed to initialize reloc map");
604 		return -1;
605 	}
606 
607 	breloc->iter.chk_offset = calloc(ftl_dev_num_punits(band->dev),
608 					 sizeof(*breloc->iter.chk_offset));
609 	if (!breloc->iter.chk_offset) {
610 		SPDK_ERRLOG("Failed to initialize reloc iterator");
611 		return -1;
612 	}
613 
614 	breloc->move_queue = spdk_ring_create(SPDK_RING_TYPE_MP_SC,
615 					      reloc->max_qdepth * 2,
616 					      SPDK_ENV_SOCKET_ID_ANY);
617 	if (!breloc->move_queue) {
618 		SPDK_ERRLOG("Failed to initialize reloc write queue");
619 		return -1;
620 	}
621 
622 	breloc->moves = calloc(reloc->max_qdepth, sizeof(*breloc->moves));
623 	if (!breloc->moves) {
624 		return -1;
625 	}
626 
627 	return 0;
628 }
629 
630 static void
631 ftl_band_reloc_free(struct ftl_band_reloc *breloc)
632 {
633 	struct ftl_reloc *reloc;
634 	struct ftl_reloc_move *moves[FTL_RELOC_MAX_MOVES] = {};
635 	size_t i, num_moves;
636 
637 	if (!breloc) {
638 		return;
639 	}
640 
641 	assert(breloc->num_outstanding == 0);
642 	reloc = breloc->parent;
643 
644 	/* Drain write queue if there is active band relocation during shutdown */
645 	if (breloc->active) {
646 		assert(reloc->halt);
647 		num_moves = spdk_ring_dequeue(breloc->move_queue, (void **)&moves, reloc->max_qdepth);
648 		for (i = 0; i < num_moves; ++i) {
649 			ftl_reloc_free_move(breloc, moves[i]);
650 		}
651 	}
652 
653 	spdk_ring_free(breloc->move_queue);
654 	spdk_bit_array_free(&breloc->reloc_map);
655 	free(breloc->iter.chk_offset);
656 	free(breloc->moves);
657 }
658 
659 static void
660 ftl_reloc_add_active_queue(struct ftl_band_reloc *breloc)
661 {
662 	struct ftl_reloc *reloc = breloc->parent;
663 
664 	TAILQ_REMOVE(&reloc->pending_queue, breloc, entry);
665 	TAILQ_INSERT_HEAD(&reloc->active_queue, breloc, entry);
666 	ftl_reloc_prep(breloc);
667 }
668 
669 struct ftl_reloc *
670 ftl_reloc_init(struct spdk_ftl_dev *dev)
671 {
672 #define POOL_NAME_LEN 128
673 	struct ftl_reloc *reloc;
674 	char pool_name[POOL_NAME_LEN];
675 	int rc;
676 	size_t i;
677 
678 	reloc = calloc(1, sizeof(*reloc));
679 	if (!reloc) {
680 		return NULL;
681 	}
682 
683 	reloc->dev = dev;
684 	reloc->halt = true;
685 	reloc->max_qdepth = dev->conf.max_reloc_qdepth;
686 	reloc->max_active = dev->conf.max_active_relocs;
687 	reloc->xfer_size = dev->xfer_size;
688 	reloc->num_defrag_bands = 0;
689 
690 	if (reloc->max_qdepth > FTL_RELOC_MAX_MOVES) {
691 		goto error;
692 	}
693 
694 	reloc->brelocs = calloc(ftl_dev_num_bands(dev), sizeof(*reloc->brelocs));
695 	if (!reloc->brelocs) {
696 		goto error;
697 	}
698 
699 	for (i = 0; i < ftl_dev_num_bands(reloc->dev); ++i) {
700 		if (ftl_band_reloc_init(reloc, &reloc->brelocs[i], &dev->bands[i])) {
701 			goto error;
702 		}
703 	}
704 
705 	rc = snprintf(pool_name, sizeof(pool_name), "%s-%s", dev->name, "reloc-io-pool");
706 	if (rc < 0 || rc >= POOL_NAME_LEN) {
707 		goto error;
708 	}
709 
710 	TAILQ_INIT(&reloc->pending_queue);
711 	TAILQ_INIT(&reloc->active_queue);
712 	TAILQ_INIT(&reloc->prio_queue);
713 
714 	return reloc;
715 error:
716 	ftl_reloc_free(reloc);
717 	return NULL;
718 }
719 
720 void
721 ftl_reloc_free(struct ftl_reloc *reloc)
722 {
723 	size_t i;
724 
725 	if (!reloc) {
726 		return;
727 	}
728 
729 	for (i = 0; i < ftl_dev_num_bands(reloc->dev); ++i) {
730 		ftl_band_reloc_free(&reloc->brelocs[i]);
731 	}
732 
733 	free(reloc->brelocs);
734 	free(reloc);
735 }
736 
737 bool
738 ftl_reloc_is_halted(const struct ftl_reloc *reloc)
739 {
740 	return reloc->halt;
741 }
742 
743 void
744 ftl_reloc_halt(struct ftl_reloc *reloc)
745 {
746 	reloc->halt = true;
747 }
748 
749 void
750 ftl_reloc_resume(struct ftl_reloc *reloc)
751 {
752 	reloc->halt = false;
753 }
754 
755 void
756 ftl_reloc(struct ftl_reloc *reloc)
757 {
758 	struct ftl_band_reloc *breloc, *tbreloc;
759 
760 	if (ftl_reloc_is_halted(reloc)) {
761 		return;
762 	}
763 
764 	/* Process first band from priority queue and return */
765 	breloc = TAILQ_FIRST(&reloc->prio_queue);
766 	if (breloc) {
767 		if (!breloc->active) {
768 			ftl_reloc_prep(breloc);
769 		}
770 		ftl_process_reloc(breloc);
771 		return;
772 	}
773 
774 	TAILQ_FOREACH_SAFE(breloc, &reloc->pending_queue, entry, tbreloc) {
775 		if (reloc->num_active == reloc->max_active) {
776 			break;
777 		}
778 
779 		/* TODO: Add handling relocation on open bands */
780 		if (breloc->band->state != FTL_BAND_STATE_CLOSED) {
781 			continue;
782 		}
783 
784 		ftl_reloc_add_active_queue(breloc);
785 	}
786 
787 	TAILQ_FOREACH_SAFE(breloc, &reloc->active_queue, entry, tbreloc) {
788 		ftl_process_reloc(breloc);
789 	}
790 }
791 
792 void
793 ftl_reloc_add(struct ftl_reloc *reloc, struct ftl_band *band, size_t offset,
794 	      size_t num_lbks, int prio, bool is_defrag)
795 {
796 	struct ftl_band_reloc *breloc = &reloc->brelocs[band->id];
797 	size_t i, prev_lbks = breloc->num_lbks;
798 
799 	/* No need to add anything if already at high prio - whole band should be relocated */
800 	if (!prio && band->high_prio) {
801 		return;
802 	}
803 
804 	pthread_spin_lock(&band->lba_map.lock);
805 	if (band->lba_map.num_vld == 0) {
806 		pthread_spin_unlock(&band->lba_map.lock);
807 
808 		/* If the band is closed and has no valid blocks, free it */
809 		if (band->state == FTL_BAND_STATE_CLOSED) {
810 			ftl_band_set_state(band, FTL_BAND_STATE_FREE);
811 		}
812 
813 		return;
814 	}
815 	pthread_spin_unlock(&band->lba_map.lock);
816 
817 	for (i = offset; i < offset + num_lbks; ++i) {
818 		if (spdk_bit_array_get(breloc->reloc_map, i)) {
819 			continue;
820 		}
821 		spdk_bit_array_set(breloc->reloc_map, i);
822 		breloc->num_lbks++;
823 	}
824 
825 	if (!prio && prev_lbks == breloc->num_lbks) {
826 		return;
827 	}
828 
829 	/* If the band is coming from the defrag process, mark it appropriately */
830 	if (is_defrag) {
831 		assert(offset == 0 && num_lbks == ftl_num_band_lbks(band->dev));
832 		reloc->num_defrag_bands++;
833 		breloc->defrag = true;
834 	}
835 
836 	if (!prev_lbks && !prio && !breloc->active) {
837 		TAILQ_INSERT_HEAD(&reloc->pending_queue, breloc, entry);
838 	}
839 
840 	if (prio) {
841 		struct ftl_band_reloc *iter_breloc;
842 
843 		/* If priority band is already on pending or active queue, remove it from it */
844 		TAILQ_FOREACH(iter_breloc, &reloc->pending_queue, entry) {
845 			if (breloc == iter_breloc) {
846 				TAILQ_REMOVE(&reloc->pending_queue, breloc, entry);
847 				break;
848 			}
849 		}
850 
851 		TAILQ_FOREACH(iter_breloc, &reloc->active_queue, entry) {
852 			if (breloc == iter_breloc) {
853 				TAILQ_REMOVE(&reloc->active_queue, breloc, entry);
854 				break;
855 			}
856 		}
857 
858 		TAILQ_INSERT_TAIL(&reloc->prio_queue, breloc, entry);
859 		ftl_band_acquire_lba_map(breloc->band);
860 	}
861 }
862