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