Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2018 Intel Corporation.
3 : : * Copyright 2023 Solidigm All Rights Reserved
4 : : * All rights reserved.
5 : : */
6 : :
7 : : #include "spdk/stdinc.h"
8 : : #include "spdk/crc32.h"
9 : : #include "spdk/likely.h"
10 : : #include "spdk/util.h"
11 : : #include "spdk/ftl.h"
12 : :
13 : : #include "ftl_band.h"
14 : : #include "ftl_io.h"
15 : : #include "ftl_core.h"
16 : : #include "ftl_debug.h"
17 : : #include "ftl_internal.h"
18 : : #include "utils/ftl_md.h"
19 : : #include "utils/ftl_defs.h"
20 : :
21 : : static uint64_t
22 : 8694 : ftl_band_tail_md_offset(const struct ftl_band *band)
23 : : {
24 : 17388 : return ftl_get_num_blocks_in_band(band->dev) -
25 : 8694 : ftl_tail_md_num_blocks(band->dev);
26 : : }
27 : :
28 : : int
29 : 4622 : ftl_band_filled(struct ftl_band *band, size_t offset)
30 : : {
31 : 4622 : return offset == ftl_band_tail_md_offset(band);
32 : : }
33 : :
34 : : static void
35 : 34 : ftl_band_free_p2l_map(struct ftl_band *band)
36 : : {
37 : 34 : struct spdk_ftl_dev *dev = band->dev;
38 : 34 : struct ftl_p2l_map *p2l_map = &band->p2l_map;
39 : :
40 [ - + - - ]: 34 : assert(band->md->state == FTL_BAND_STATE_CLOSED ||
41 : : band->md->state == FTL_BAND_STATE_FREE);
42 [ - + ]: 34 : assert(p2l_map->ref_cnt == 0);
43 [ - + ]: 34 : assert(p2l_map->band_map != NULL);
44 : :
45 : 34 : band->md->df_p2l_map = FTL_DF_OBJ_ID_INVALID;
46 : 34 : ftl_mempool_put(dev->p2l_pool, p2l_map->band_map);
47 : 34 : p2l_map->band_map = NULL;
48 : 34 : }
49 : :
50 : :
51 : : static void
52 : 34 : ftl_band_free_md_entry(struct ftl_band *band)
53 : : {
54 : 34 : struct spdk_ftl_dev *dev = band->dev;
55 : 34 : struct ftl_p2l_map *p2l_map = &band->p2l_map;
56 : :
57 [ - + - - ]: 34 : assert(band->md->state == FTL_BAND_STATE_CLOSED ||
58 : : band->md->state == FTL_BAND_STATE_FREE);
59 [ - + ]: 34 : assert(p2l_map->band_dma_md != NULL);
60 : :
61 : 34 : ftl_mempool_put(dev->band_md_pool, p2l_map->band_dma_md);
62 : 34 : p2l_map->band_dma_md = NULL;
63 : 34 : }
64 : :
65 : : static void
66 : 2029 : _ftl_band_set_free(struct ftl_band *band)
67 : : {
68 : 2029 : struct spdk_ftl_dev *dev = band->dev;
69 : :
70 : : /* Add the band to the free band list */
71 : 2029 : TAILQ_INSERT_TAIL(&dev->free_bands, band, queue_entry);
72 : 2029 : band->md->close_seq_id = 0;
73 : 2029 : band->reloc = false;
74 : :
75 : 2029 : dev->num_free++;
76 : 2029 : ftl_apply_limits(dev);
77 : :
78 : 2029 : band->md->p2l_map_checksum = 0;
79 : 2029 : }
80 : :
81 : : static void
82 : 6 : _ftl_band_set_preparing(struct ftl_band *band)
83 : : {
84 : 6 : struct spdk_ftl_dev *dev = band->dev;
85 : :
86 : : /* Remove band from free list */
87 [ + - ]: 6 : TAILQ_REMOVE(&dev->free_bands, band, queue_entry);
88 : :
89 : 6 : band->md->wr_cnt++;
90 : :
91 [ - + ]: 6 : assert(dev->num_free > 0);
92 : 6 : dev->num_free--;
93 : :
94 : 6 : ftl_apply_limits(dev);
95 : 6 : }
96 : :
97 : : static void
98 : 4 : _ftl_band_set_closed_cb(struct ftl_band *band, bool valid)
99 : : {
100 : 4 : struct spdk_ftl_dev *dev = band->dev;
101 : :
102 [ - + ]: 4 : assert(valid == true);
103 : :
104 : : /* Set the state as free_md() checks for that */
105 : 4 : band->md->state = FTL_BAND_STATE_CLOSED;
106 [ + - ]: 4 : if (band->owner.state_change_fn) {
107 : 4 : band->owner.state_change_fn(band);
108 : : }
109 : :
110 : 4 : ftl_p2l_validate_ckpt(band);
111 : :
112 : : /* Free the P2L map if there are no outstanding IOs */
113 : 4 : ftl_band_release_p2l_map(band);
114 [ - + ]: 4 : assert(band->p2l_map.ref_cnt == 0);
115 : :
116 : 4 : TAILQ_INSERT_TAIL(&dev->shut_bands, band, queue_entry);
117 : 4 : }
118 : :
119 : : static void
120 : 4 : _ftl_band_set_closed(struct ftl_band *band)
121 : : {
122 : : /* Verify that band's metadata is consistent with l2p */
123 : 4 : ftl_band_validate_md(band, _ftl_band_set_closed_cb);
124 : 4 : }
125 : :
126 : : ftl_addr
127 : 2036 : ftl_band_tail_md_addr(struct ftl_band *band)
128 : : {
129 : : ftl_addr addr;
130 : :
131 : : /* Metadata should be aligned to xfer size */
132 [ - + - + ]: 2036 : assert(ftl_band_tail_md_offset(band) % band->dev->xfer_size == 0);
133 : :
134 : 2036 : addr = ftl_band_tail_md_offset(band) + band->start_addr;
135 : :
136 : 2036 : return addr;
137 : : }
138 : :
139 : : const char *
140 : 54 : ftl_band_get_state_name(struct ftl_band *band)
141 : : {
142 : : static const char *names[] = {
143 : : "FREE", "PREPARING", "OPENING", "OPEN", "FULL", "CLOSING",
144 : : "CLOSED",
145 : : };
146 : :
147 [ - + ]: 54 : assert(band->md->state < SPDK_COUNTOF(names));
148 [ + - ]: 54 : if (band->md->state < SPDK_COUNTOF(names)) {
149 : 54 : return names[band->md->state];
150 : : } else {
151 : 0 : assert(false);
152 : : return "?";
153 : : }
154 : : }
155 : :
156 : : void
157 : 448 : ftl_band_set_state(struct ftl_band *band, enum ftl_band_state state)
158 : : {
159 [ + + + + : 448 : switch (state) {
+ - ]
160 : 418 : case FTL_BAND_STATE_FREE:
161 [ - + ]: 418 : assert(band->md->state == FTL_BAND_STATE_CLOSED);
162 : 418 : _ftl_band_set_free(band);
163 : 418 : break;
164 : :
165 : 6 : case FTL_BAND_STATE_PREP:
166 [ - + ]: 6 : assert(band->md->state == FTL_BAND_STATE_FREE);
167 : 6 : _ftl_band_set_preparing(band);
168 : 6 : break;
169 : :
170 : 4 : case FTL_BAND_STATE_CLOSED:
171 [ + - ]: 4 : if (band->md->state != FTL_BAND_STATE_CLOSED) {
172 [ - + ]: 4 : assert(band->md->state == FTL_BAND_STATE_CLOSING);
173 : 4 : _ftl_band_set_closed(band);
174 : 4 : return; /* state can be changed asynchronously */
175 : : }
176 : 0 : break;
177 : :
178 : 6 : case FTL_BAND_STATE_OPEN:
179 : 6 : band->md->p2l_map_checksum = 0;
180 : 6 : break;
181 : 14 : case FTL_BAND_STATE_OPENING:
182 : : case FTL_BAND_STATE_FULL:
183 : : case FTL_BAND_STATE_CLOSING:
184 : 14 : break;
185 : 0 : default:
186 [ # # ]: 0 : FTL_ERRLOG(band->dev, "Unknown band state, %u", state);
187 : 0 : assert(false);
188 : : break;
189 : : }
190 : :
191 : 444 : band->md->state = state;
192 : : }
193 : :
194 : : void
195 : 6 : ftl_band_set_type(struct ftl_band *band, enum ftl_band_type type)
196 : : {
197 [ + - ]: 6 : switch (type) {
198 : 6 : case FTL_BAND_TYPE_COMPACTION:
199 : : case FTL_BAND_TYPE_GC:
200 : 6 : band->md->type = type;
201 : 6 : break;
202 : 0 : default:
203 : 0 : assert(false);
204 : : break;
205 : : }
206 : 6 : }
207 : :
208 : : void
209 : 923161 : ftl_band_set_p2l(struct ftl_band *band, uint64_t lba, ftl_addr addr, uint64_t seq_id)
210 : : {
211 : 923161 : struct ftl_p2l_map *p2l_map = &band->p2l_map;
212 : : uint64_t offset;
213 : :
214 : 923161 : offset = ftl_band_block_offset_from_addr(band, addr);
215 : :
216 : 923161 : p2l_map->band_map[offset].lba = lba;
217 : 923161 : p2l_map->band_map[offset].seq_id = seq_id;
218 : 923161 : }
219 : :
220 : : void
221 : 923161 : ftl_band_set_addr(struct ftl_band *band, uint64_t lba, ftl_addr addr)
222 : : {
223 : 923161 : band->p2l_map.num_valid++;
224 : 923161 : ftl_bitmap_set(band->dev->valid_map, addr);
225 : 923161 : }
226 : :
227 : : size_t
228 : 0 : ftl_band_user_blocks_left(const struct ftl_band *band, size_t offset)
229 : : {
230 : 0 : size_t tail_md_offset = ftl_band_tail_md_offset(band);
231 : :
232 [ # # ]: 0 : if (spdk_unlikely(offset > tail_md_offset)) {
233 : 0 : return 0;
234 : : }
235 : :
236 : 0 : return tail_md_offset - offset;
237 : : }
238 : :
239 : : size_t
240 : 2112 : ftl_band_user_blocks(const struct ftl_band *band)
241 : : {
242 : 4224 : return ftl_get_num_blocks_in_band(band->dev) -
243 : 2112 : ftl_tail_md_num_blocks(band->dev);
244 : : }
245 : :
246 : : static inline uint64_t
247 : 4110994 : ftl_addr_get_band(const struct spdk_ftl_dev *dev, ftl_addr addr)
248 : : {
249 [ - + ]: 4110994 : return (addr - dev->bands->start_addr) / ftl_get_num_blocks_in_band(dev);
250 : : }
251 : :
252 : : struct ftl_band *
253 : 923146 : ftl_band_from_addr(struct spdk_ftl_dev *dev, ftl_addr addr)
254 : : {
255 : 923146 : uint64_t band_id = ftl_addr_get_band(dev, addr);
256 : :
257 [ - + ]: 923146 : assert(band_id < ftl_get_num_bands(dev));
258 : 923146 : return &dev->bands[band_id];
259 : : }
260 : :
261 : : uint64_t
262 : 3133133 : ftl_band_block_offset_from_addr(struct ftl_band *band, ftl_addr addr)
263 : : {
264 [ - + ]: 3133133 : assert(ftl_addr_get_band(band->dev, addr) == band->id);
265 : 3133133 : return addr - band->start_addr;
266 : : }
267 : :
268 : : ftl_addr
269 : 4640 : ftl_band_next_xfer_addr(struct ftl_band *band, ftl_addr addr, size_t num_blocks)
270 : : {
271 : 4640 : struct spdk_ftl_dev *dev = band->dev;
272 : : size_t num_xfers;
273 : : uint64_t offset;
274 : :
275 [ - + ]: 4640 : assert(ftl_addr_get_band(dev, addr) == band->id);
276 : :
277 : 4640 : offset = addr - band->start_addr;
278 : :
279 : : /* In case starting address wasn't aligned to xfer_size, we'll align for consistent calculation
280 : : * purposes - the unaligned value will be preserved at the end however.
281 : : */
282 [ - + ]: 4640 : num_blocks += (offset % dev->xfer_size);
283 [ - + ]: 4640 : offset -= (offset % dev->xfer_size);
284 : :
285 : : /* Calculate offset based on xfer_size aligned writes */
286 [ - + ]: 4640 : num_xfers = (num_blocks / dev->xfer_size);
287 : 4640 : offset += num_xfers * dev->xfer_size;
288 : 4640 : num_blocks -= num_xfers * dev->xfer_size;
289 : :
290 [ - + ]: 4640 : if (offset > ftl_get_num_blocks_in_band(dev)) {
291 : 0 : return FTL_ADDR_INVALID;
292 : : }
293 : :
294 : : /* If there's any unalignment (either starting addr value or num_blocks), reintroduce it to the final address
295 : : */
296 [ + + ]: 4640 : if (num_blocks) {
297 : 10 : offset += num_blocks;
298 [ - + ]: 10 : if (offset > ftl_get_num_blocks_in_band(dev)) {
299 : 0 : return FTL_ADDR_INVALID;
300 : : }
301 : : }
302 : :
303 : 4640 : addr = band->start_addr + offset;
304 : 4640 : return addr;
305 : : }
306 : :
307 : : ftl_addr
308 : 2940752 : ftl_band_addr_from_block_offset(struct ftl_band *band, uint64_t block_off)
309 : : {
310 : : ftl_addr addr;
311 : :
312 : 2940752 : addr = block_off + band->start_addr;
313 : 2940752 : return addr;
314 : : }
315 : :
316 : : ftl_addr
317 : 2105344 : ftl_band_next_addr(struct ftl_band *band, ftl_addr addr, size_t offset)
318 : : {
319 : 2105344 : uint64_t block_off = ftl_band_block_offset_from_addr(band, addr);
320 : :
321 : 2105344 : return ftl_band_addr_from_block_offset(band, block_off + offset);
322 : : }
323 : :
324 : : void
325 : 39 : ftl_band_acquire_p2l_map(struct ftl_band *band)
326 : : {
327 [ - + ]: 39 : assert(band->p2l_map.band_map != NULL);
328 : 39 : band->p2l_map.ref_cnt++;
329 : 39 : }
330 : :
331 : : static int
332 : 39 : ftl_band_alloc_md_entry(struct ftl_band *band)
333 : : {
334 : 39 : struct spdk_ftl_dev *dev = band->dev;
335 : 39 : struct ftl_p2l_map *p2l_map = &band->p2l_map;
336 : 39 : struct ftl_layout_region *region = ftl_layout_region_get(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD);
337 : :
338 : 39 : p2l_map->band_dma_md = ftl_mempool_get(dev->band_md_pool);
339 : :
340 [ - + ]: 39 : if (!p2l_map->band_dma_md) {
341 : 0 : return -1;
342 : : }
343 : :
344 [ - + ]: 39 : memset(p2l_map->band_dma_md, 0, region->entry_size * FTL_BLOCK_SIZE);
345 : 39 : return 0;
346 : : }
347 : :
348 : : int
349 : 39 : ftl_band_alloc_p2l_map(struct ftl_band *band)
350 : : {
351 : 39 : struct spdk_ftl_dev *dev = band->dev;
352 : 39 : struct ftl_p2l_map *p2l_map = &band->p2l_map;
353 : :
354 [ - + ]: 39 : assert(p2l_map->ref_cnt == 0);
355 [ - + ]: 39 : assert(p2l_map->band_map == NULL);
356 : :
357 [ - + ]: 39 : assert(band->md->df_p2l_map == FTL_DF_OBJ_ID_INVALID);
358 : 39 : p2l_map->band_map = ftl_mempool_get(dev->p2l_pool);
359 [ - + ]: 39 : if (!p2l_map->band_map) {
360 : 0 : return -1;
361 : : }
362 : :
363 [ - + ]: 39 : if (ftl_band_alloc_md_entry(band)) {
364 : 0 : ftl_band_free_p2l_map(band);
365 : 0 : return -1;
366 : : }
367 : :
368 : 39 : band->md->df_p2l_map = ftl_mempool_get_df_obj_id(dev->p2l_pool, p2l_map->band_map);
369 : :
370 : : /* Set the P2L to FTL_LBA_INVALID */
371 [ - + ]: 39 : memset(p2l_map->band_map, -1, FTL_BLOCK_SIZE * ftl_p2l_map_num_blocks(band->dev));
372 : :
373 : 39 : ftl_band_acquire_p2l_map(band);
374 : 39 : return 0;
375 : : }
376 : :
377 : : int
378 : 0 : ftl_band_open_p2l_map(struct ftl_band *band)
379 : : {
380 : 0 : struct spdk_ftl_dev *dev = band->dev;
381 : 0 : struct ftl_p2l_map *p2l_map = &band->p2l_map;
382 : :
383 [ # # ]: 0 : assert(p2l_map->ref_cnt == 0);
384 [ # # ]: 0 : assert(p2l_map->band_map == NULL);
385 : :
386 [ # # ]: 0 : assert(band->md->df_p2l_map != FTL_DF_OBJ_ID_INVALID);
387 : :
388 [ # # ]: 0 : if (ftl_band_alloc_md_entry(band)) {
389 : 0 : p2l_map->band_map = NULL;
390 : 0 : return -1;
391 : : }
392 : :
393 : 0 : p2l_map->band_map = ftl_mempool_claim_df(dev->p2l_pool, band->md->df_p2l_map);
394 : :
395 : 0 : ftl_band_acquire_p2l_map(band);
396 : 0 : return 0;
397 : : }
398 : :
399 : : void
400 : 34 : ftl_band_release_p2l_map(struct ftl_band *band)
401 : : {
402 : 34 : struct ftl_p2l_map *p2l_map = &band->p2l_map;
403 : :
404 [ - + ]: 34 : assert(p2l_map->band_map != NULL);
405 [ - + ]: 34 : assert(p2l_map->ref_cnt > 0);
406 : 34 : p2l_map->ref_cnt--;
407 : :
408 [ + - ]: 34 : if (p2l_map->ref_cnt == 0) {
409 [ + + ]: 34 : if (p2l_map->p2l_ckpt) {
410 : 4 : ftl_p2l_ckpt_release(band->dev, p2l_map->p2l_ckpt);
411 : 4 : p2l_map->p2l_ckpt = NULL;
412 : : }
413 : 34 : ftl_band_free_p2l_map(band);
414 : 34 : ftl_band_free_md_entry(band);
415 : : }
416 : 34 : }
417 : :
418 : : ftl_addr
419 : 0 : ftl_band_p2l_map_addr(struct ftl_band *band)
420 : : {
421 : 0 : return band->tail_md_addr;
422 : : }
423 : :
424 : : int
425 : 6 : ftl_band_write_prep(struct ftl_band *band)
426 : : {
427 : 6 : struct spdk_ftl_dev *dev = band->dev;
428 : :
429 [ - + ]: 6 : if (ftl_band_alloc_p2l_map(band)) {
430 : 0 : return -1;
431 : : }
432 : :
433 : 6 : band->p2l_map.p2l_ckpt = ftl_p2l_ckpt_acquire(dev);
434 : 6 : band->md->p2l_md_region = ftl_p2l_ckpt_region_type(band->p2l_map.p2l_ckpt);
435 : 6 : ftl_band_iter_init(band);
436 : :
437 : 6 : band->md->seq = ftl_get_next_seq_id(dev);
438 : :
439 [ + - ]: 6 : FTL_DEBUGLOG(dev, "Band to write, id %u seq %"PRIu64"\n", band->id, band->md->seq);
440 : 6 : return 0;
441 : : }
442 : :
443 : : size_t
444 : 22 : ftl_p2l_map_pool_elem_size(struct spdk_ftl_dev *dev)
445 : : {
446 : : /* Map pool element holds the whole tail md */
447 : 22 : return ftl_tail_md_num_blocks(dev) * FTL_BLOCK_SIZE;
448 : : }
449 : :
450 : : double
451 : 54 : ftl_band_invalidity(struct ftl_band *band)
452 : : {
453 : 54 : double valid = band->p2l_map.num_valid;
454 : 54 : double count = ftl_band_user_blocks(band);
455 : :
456 : 54 : return 1.0 - (valid / count);
457 : : }
458 : :
459 : : static void
460 : 0 : dump_bands_under_relocation(struct spdk_ftl_dev *dev)
461 : : {
462 : 0 : uint64_t i = dev->sb_shm->gc_info.current_band_id;
463 : 0 : uint64_t end = dev->sb_shm->gc_info.current_band_id + dev->num_logical_bands_in_physical;
464 : :
465 [ # # ]: 0 : for (; i < end; i++) {
466 : 0 : struct ftl_band *band = &dev->bands[i];
467 : :
468 [ # # ]: 0 : FTL_DEBUGLOG(dev, "Band, id %u, phys_is %u, wr cnt = %u, invalidity = %u%%\n",
469 : : band->id, band->phys_id, (uint32_t)band->md->wr_cnt,
470 : : (uint32_t)(ftl_band_invalidity(band) * 100));
471 : : }
472 : 0 : }
473 : :
474 : : static bool
475 : 0 : is_band_relocateable(struct ftl_band *band)
476 : : {
477 : : /* Can only move data from closed bands */
478 [ # # ]: 0 : if (FTL_BAND_STATE_CLOSED != band->md->state) {
479 : 0 : return false;
480 : : }
481 : :
482 : : /* Band is already under relocation, skip it */
483 [ # # # # ]: 0 : if (band->reloc) {
484 : 0 : return false;
485 : : }
486 : :
487 : 0 : return true;
488 : : }
489 : :
490 : : static void
491 : 0 : get_band_phys_info(struct spdk_ftl_dev *dev, uint64_t phys_id,
492 : : double *invalidity, double *wr_cnt)
493 : : {
494 : : struct ftl_band *band;
495 : 0 : uint64_t band_id = phys_id * dev->num_logical_bands_in_physical;
496 : :
497 : 0 : *wr_cnt = *invalidity = 0.0L;
498 [ # # ]: 0 : for (; band_id < ftl_get_num_bands(dev); band_id++) {
499 : 0 : band = &dev->bands[band_id];
500 : :
501 [ # # ]: 0 : if (phys_id != band->phys_id) {
502 : 0 : break;
503 : : }
504 : :
505 : 0 : *wr_cnt += band->md->wr_cnt;
506 : :
507 [ # # ]: 0 : if (!is_band_relocateable(band)) {
508 : 0 : continue;
509 : : }
510 : :
511 : 0 : *invalidity += ftl_band_invalidity(band);
512 : : }
513 : :
514 : 0 : *invalidity /= dev->num_logical_bands_in_physical;
515 : 0 : *wr_cnt /= dev->num_logical_bands_in_physical;
516 : 0 : }
517 : :
518 : : static bool
519 : 0 : band_cmp(double a_invalidity, double a_wr_cnt,
520 : : double b_invalidity, double b_wr_cnt,
521 : : uint64_t a_id, uint64_t b_id)
522 : : {
523 [ # # ]: 0 : assert(a_id != FTL_BAND_PHYS_ID_INVALID);
524 [ # # ]: 0 : assert(b_id != FTL_BAND_PHYS_ID_INVALID);
525 : 0 : double diff = a_invalidity - b_invalidity;
526 [ # # ]: 0 : if (diff < 0.0L) {
527 : 0 : diff *= -1.0L;
528 : : }
529 : :
530 : : /* Use the following metrics for picking bands for GC (in order):
531 : : * - relative invalidity
532 : : * - if invalidity is similar (within 10% points), then their write counts (how many times band was written to)
533 : : * - if write count is equal, then pick based on their placement on base device (lower LBAs win)
534 : : */
535 [ # # ]: 0 : if (diff > 0.1L) {
536 : 0 : return a_invalidity > b_invalidity;
537 : : }
538 : :
539 [ # # ]: 0 : if (a_wr_cnt != b_wr_cnt) {
540 : 0 : return a_wr_cnt < b_wr_cnt;
541 : : }
542 : :
543 : 0 : return a_id < b_id;
544 : : }
545 : :
546 : : static void
547 : 0 : band_start_gc(struct spdk_ftl_dev *dev, struct ftl_band *band)
548 : : {
549 [ # # ]: 0 : ftl_bug(false == is_band_relocateable(band));
550 : :
551 [ # # ]: 0 : TAILQ_REMOVE(&dev->shut_bands, band, queue_entry);
552 : 0 : band->reloc = true;
553 : :
554 [ # # ]: 0 : FTL_DEBUGLOG(dev, "Band to GC, id %u\n", band->id);
555 : 0 : }
556 : :
557 : : static struct ftl_band *
558 : 0 : gc_high_priority_band(struct spdk_ftl_dev *dev)
559 : : {
560 : : struct ftl_band *band;
561 : 0 : uint64_t high_prio_id = dev->sb_shm->gc_info.band_id_high_prio;
562 : :
563 [ # # ]: 0 : if (FTL_BAND_ID_INVALID != high_prio_id) {
564 [ # # ]: 0 : ftl_bug(high_prio_id >= dev->num_bands);
565 : :
566 : 0 : band = &dev->bands[high_prio_id];
567 : 0 : dev->sb_shm->gc_info.band_id_high_prio = FTL_BAND_ID_INVALID;
568 : :
569 : 0 : band_start_gc(dev, band);
570 [ # # ]: 0 : FTL_NOTICELOG(dev, "GC takes high priority band, id %u\n", band->id);
571 : 0 : return band;
572 : : }
573 : :
574 : 0 : return 0;
575 : : }
576 : :
577 : : static void
578 : 10 : ftl_band_reset_gc_iter(struct spdk_ftl_dev *dev)
579 : : {
580 : 10 : dev->sb->gc_info.is_valid = 0;
581 : 10 : dev->sb->gc_info.current_band_id = FTL_BAND_ID_INVALID;
582 : 10 : dev->sb->gc_info.band_id_high_prio = FTL_BAND_ID_INVALID;
583 : 10 : dev->sb->gc_info.band_phys_id = FTL_BAND_PHYS_ID_INVALID;
584 : :
585 : 10 : dev->sb_shm->gc_info = dev->sb->gc_info;
586 : 10 : }
587 : :
588 : : struct ftl_band *
589 : 0 : ftl_band_search_next_to_reloc(struct spdk_ftl_dev *dev)
590 : : {
591 : 0 : double invalidity, max_invalidity = 0.0L;
592 : 0 : double wr_cnt, max_wr_cnt = 0.0L;
593 : 0 : uint64_t phys_id = FTL_BAND_PHYS_ID_INVALID;
594 : : struct ftl_band *band;
595 : : uint64_t i, band_count;
596 : : uint64_t phys_count;
597 : :
598 : 0 : band = gc_high_priority_band(dev);
599 [ # # ]: 0 : if (spdk_unlikely(NULL != band)) {
600 : 0 : return band;
601 : : }
602 : :
603 : 0 : phys_count = dev->num_logical_bands_in_physical;
604 : 0 : band_count = ftl_get_num_bands(dev);
605 : :
606 [ # # ]: 0 : for (; dev->sb_shm->gc_info.current_band_id < band_count;) {
607 : 0 : band = &dev->bands[dev->sb_shm->gc_info.current_band_id];
608 [ # # ]: 0 : if (band->phys_id != dev->sb_shm->gc_info.band_phys_id) {
609 : 0 : break;
610 : : }
611 : :
612 [ # # ]: 0 : if (false == is_band_relocateable(band)) {
613 : 0 : dev->sb_shm->gc_info.current_band_id++;
614 : 0 : continue;
615 : : }
616 : :
617 : 0 : band_start_gc(dev, band);
618 : 0 : return band;
619 : : }
620 : :
621 [ # # ]: 0 : for (i = 0; i < band_count; i += phys_count) {
622 : 0 : band = &dev->bands[i];
623 : :
624 : : /* Calculate entire band physical group invalidity */
625 : 0 : get_band_phys_info(dev, band->phys_id, &invalidity, &wr_cnt);
626 : :
627 [ # # ]: 0 : if (invalidity != 0.0L) {
628 [ # # # # ]: 0 : if (phys_id == FTL_BAND_PHYS_ID_INVALID ||
629 : 0 : band_cmp(invalidity, wr_cnt, max_invalidity, max_wr_cnt,
630 : 0 : band->phys_id, phys_id)) {
631 : 0 : max_wr_cnt = wr_cnt;
632 : 0 : phys_id = band->phys_id;
633 : :
634 [ # # ]: 0 : if (invalidity > max_invalidity) {
635 : 0 : max_invalidity = invalidity;
636 : : }
637 : : }
638 : : }
639 : : }
640 : :
641 [ # # ]: 0 : if (FTL_BAND_PHYS_ID_INVALID != phys_id) {
642 [ # # ]: 0 : FTL_DEBUGLOG(dev, "Band physical id %"PRIu64" to GC\n", phys_id);
643 : 0 : dev->sb_shm->gc_info.is_valid = 0;
644 : 0 : dev->sb_shm->gc_info.current_band_id = phys_id * phys_count;
645 : 0 : dev->sb_shm->gc_info.band_phys_id = phys_id;
646 : 0 : dev->sb_shm->gc_info.is_valid = 1;
647 : 0 : dump_bands_under_relocation(dev);
648 : 0 : return ftl_band_search_next_to_reloc(dev);
649 : : } else {
650 : 0 : ftl_band_reset_gc_iter(dev);
651 : : }
652 : :
653 : 0 : return NULL;
654 : : }
655 : :
656 : : void
657 : 27 : ftl_band_init_gc_iter(struct spdk_ftl_dev *dev)
658 : : {
659 [ + + ]: 27 : if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
660 : 10 : ftl_band_reset_gc_iter(dev);
661 : 10 : return;
662 : : }
663 : :
664 [ + + ]: 17 : if (dev->sb->clean) {
665 : 16 : dev->sb_shm->gc_info = dev->sb->gc_info;
666 : 16 : return;
667 : : }
668 : :
669 [ + - + - ]: 1 : if (ftl_fast_startup(dev) || ftl_fast_recovery(dev)) {
670 : 1 : return;
671 : : }
672 : :
673 : : /* We lost GC state due to dirty shutdown, reset GC state to start over */
674 : 0 : ftl_band_reset_gc_iter(dev);
675 : : }
676 : :
677 : : void
678 : 17 : ftl_valid_map_load_state(struct spdk_ftl_dev *dev)
679 : : {
680 : : uint64_t i;
681 : : struct ftl_band *band;
682 : :
683 [ + + ]: 1635 : for (i = 0; i < dev->num_bands; i++) {
684 : 1618 : band = &dev->bands[i];
685 : 1618 : band->p2l_map.num_valid = ftl_bitmap_count_set(band->p2l_map.valid);
686 : : }
687 : 17 : }
688 : :
689 : : void
690 : 1611 : ftl_band_initialize_free_state(struct ftl_band *band)
691 : : {
692 : : /* All bands start on the shut list during startup, removing it manually here */
693 [ + + ]: 1611 : TAILQ_REMOVE(&band->dev->shut_bands, band, queue_entry);
694 : 1611 : _ftl_band_set_free(band);
695 : 1611 : }
696 : :
697 : : int
698 : 16 : ftl_bands_load_state(struct spdk_ftl_dev *dev)
699 : : {
700 : : uint64_t i;
701 : : struct ftl_band *band;
702 : :
703 [ + + ]: 1616 : for (i = 0; i < dev->num_bands; i++) {
704 : 1600 : band = &dev->bands[i];
705 : :
706 [ - + ]: 1600 : if (band->md->version != FTL_BAND_VERSION_CURRENT) {
707 [ # # ]: 0 : FTL_ERRLOG(dev, "Invalid band version detected, %"PRIu64" (expected %d)\n",
708 : : band->md->version, FTL_BAND_VERSION_CURRENT);
709 : 0 : return -1;
710 : : }
711 : :
712 [ + + ]: 1600 : if (band->md->state == FTL_BAND_STATE_FREE) {
713 : 1596 : ftl_band_initialize_free_state(band);
714 : : }
715 : : }
716 : :
717 : 16 : return 0;
718 : : }
|