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