Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2022 Intel Corporation.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "ftl_core.h"
7 : : #include "ftl_mngt_steps.h"
8 : : #include "ftl_band.h"
9 : : #include "ftl_internal.h"
10 : :
11 : : static int
12 : 2536 : ftl_band_init_md(struct ftl_band *band)
13 : : {
14 : 2536 : struct spdk_ftl_dev *dev = band->dev;
15 : 2536 : struct ftl_p2l_map *p2l_map = &band->p2l_map;
16 : 2536 : struct ftl_md *band_info_md = dev->layout.md[FTL_LAYOUT_REGION_TYPE_BAND_MD];
17 : 2536 : struct ftl_md *valid_map_md = dev->layout.md[FTL_LAYOUT_REGION_TYPE_VALID_MAP];
18 : 2536 : uint64_t band_num_blocks = ftl_get_num_blocks_in_band(band->dev);
19 : : size_t band_valid_map_bytes;
20 : 2536 : struct ftl_band_md *band_md = ftl_md_get_buffer(band_info_md);
21 : :
22 [ - + - + ]: 2536 : if (band_num_blocks % (ftl_bitmap_buffer_alignment * 8)) {
23 [ # # ]: 0 : FTL_ERRLOG(dev, "The number of blocks in band is not divisible by bitmap word bits\n");
24 : 0 : return -EINVAL;
25 : : }
26 : 2536 : band_valid_map_bytes = band_num_blocks / 8;
27 : :
28 : 5072 : p2l_map->valid = ftl_bitmap_create(ftl_md_get_buffer(valid_map_md) +
29 : 2536 : band->start_addr / 8, band_valid_map_bytes);
30 [ - + ]: 2536 : if (!p2l_map->valid) {
31 : 0 : return -ENOMEM;
32 : : }
33 : :
34 : 2536 : band->md = &band_md[band->id];
35 : 2536 : band->md->version = FTL_BAND_VERSION_CURRENT;
36 [ + + ]: 2536 : if (!ftl_fast_startup(dev)) {
37 : 2236 : band->md->df_p2l_map = FTL_DF_OBJ_ID_INVALID;
38 : : }
39 : :
40 : 2536 : return 0;
41 : : }
42 : :
43 : : static int
44 : 27 : ftl_dev_init_bands(struct spdk_ftl_dev *dev)
45 : : {
46 : : struct ftl_band *band;
47 : : uint64_t i, blocks, md_blocks, md_bands;
48 : :
49 : : /* Calculate initial number of bands */
50 : 27 : blocks = spdk_bdev_get_num_blocks(spdk_bdev_desc_get_bdev(dev->base_bdev_desc));
51 [ - + ]: 27 : dev->num_bands = blocks / ftl_get_num_blocks_in_band(dev);
52 : :
53 : : /* Calculate number of bands considering base device metadata size requirement */
54 : 27 : md_blocks = ftl_layout_base_md_blocks(dev);
55 : 27 : md_bands = spdk_divide_round_up(md_blocks, dev->num_blocks_in_band);
56 : :
57 [ + - ]: 27 : if (dev->num_bands > md_bands) {
58 : : /* Save a band worth of space for metadata */
59 : 27 : dev->num_bands -= md_bands;
60 : : } else {
61 [ # # ]: 0 : FTL_ERRLOG(dev, "Base device too small to store metadata\n");
62 : 0 : return -1;
63 : : }
64 : :
65 : 27 : TAILQ_INIT(&dev->free_bands);
66 : 27 : TAILQ_INIT(&dev->shut_bands);
67 : :
68 : 27 : dev->num_free = 0;
69 : 27 : dev->bands = calloc(ftl_get_num_bands(dev), sizeof(*dev->bands));
70 [ - + ]: 27 : if (!dev->bands) {
71 : 0 : return -ENOMEM;
72 : : }
73 : :
74 [ + + ]: 2565 : for (i = 0; i < ftl_get_num_bands(dev); ++i) {
75 : 2538 : band = &dev->bands[i];
76 : 2538 : band->id = i;
77 : 2538 : band->dev = dev;
78 : :
79 : : /* Adding to shut_bands is necessary - see ftl_restore_band_close_cb() */
80 : 2538 : TAILQ_INSERT_TAIL(&dev->shut_bands, band, queue_entry);
81 : : }
82 : :
83 : 27 : return 0;
84 : : }
85 : :
86 : : static int
87 : 27 : ftl_dev_init_bands_md(struct spdk_ftl_dev *dev)
88 : : {
89 : : uint64_t i;
90 : 27 : int rc = 0;
91 : :
92 [ + + ]: 2563 : for (i = 0; i < ftl_get_num_bands(dev); ++i) {
93 : 2536 : rc = ftl_band_init_md(&dev->bands[i]);
94 [ - + ]: 2536 : if (rc) {
95 [ # # ]: 0 : FTL_ERRLOG(dev, "Failed to initialize metadata structures for band [%lu]\n", i);
96 : 0 : break;
97 : : }
98 : : }
99 : :
100 : 27 : return rc;
101 : : }
102 : :
103 : : static void
104 : 27 : ftl_dev_deinit_bands(struct spdk_ftl_dev *dev)
105 : : {
106 : 27 : free(dev->bands);
107 : 27 : }
108 : :
109 : : static void
110 : 27 : ftl_dev_deinit_bands_md(struct spdk_ftl_dev *dev)
111 : : {
112 [ + - ]: 27 : if (dev->bands) {
113 : : uint64_t i;
114 [ + + ]: 2563 : for (i = 0; i < dev->num_bands; ++i) {
115 : 2536 : struct ftl_band *band = &dev->bands[i];
116 : :
117 : 2536 : ftl_bitmap_destroy(band->p2l_map.valid);
118 : 2536 : band->p2l_map.valid = NULL;
119 : :
120 : 2536 : band->md = NULL;
121 : : }
122 : : }
123 : 27 : }
124 : :
125 : : void
126 : 27 : ftl_mngt_init_bands(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
127 : : {
128 [ - + ]: 27 : if (ftl_dev_init_bands(dev)) {
129 : 0 : ftl_mngt_fail_step(mngt);
130 : : } else {
131 : 27 : ftl_mngt_next_step(mngt);
132 : : }
133 : 27 : }
134 : :
135 : : void
136 : 27 : ftl_mngt_init_bands_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
137 : : {
138 [ - + ]: 27 : if (ftl_dev_init_bands_md(dev)) {
139 : 0 : ftl_mngt_fail_step(mngt);
140 : : } else {
141 : 27 : ftl_mngt_next_step(mngt);
142 : : }
143 : 27 : }
144 : :
145 : : void
146 : 27 : ftl_mngt_deinit_bands(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
147 : : {
148 : 27 : ftl_dev_deinit_bands(dev);
149 : 27 : ftl_mngt_next_step(mngt);
150 : 27 : }
151 : :
152 : : void
153 : 27 : ftl_mngt_deinit_bands_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
154 : : {
155 : 27 : ftl_dev_deinit_bands_md(dev);
156 : 27 : ftl_mngt_next_step(mngt);
157 : 27 : }
158 : :
159 : : /*
160 : : * For grouping multiple logical bands (1GiB) to make any IOs more sequential from the drive's
161 : : * perspective. Improves WAF.
162 : : */
163 : : #define BASE_BDEV_RECLAIM_UNIT_SIZE (72 * GiB)
164 : :
165 : : static void
166 : 27 : decorate_bands(struct spdk_ftl_dev *dev)
167 : : {
168 : : struct ftl_band *band;
169 : 27 : uint64_t i, num_to_drop, phys_id = 0;
170 : : uint64_t num_blocks, num_bands;
171 : 27 : uint64_t num_blocks_in_band = ftl_get_num_blocks_in_band(dev);
172 : 27 : uint64_t reclaim_unit_num_blocks = BASE_BDEV_RECLAIM_UNIT_SIZE / FTL_BLOCK_SIZE;
173 : 27 : uint32_t num_logical_in_phys = 2;
174 : :
175 [ - + - + ]: 27 : assert(reclaim_unit_num_blocks % num_blocks_in_band == 0);
176 : :
177 : 27 : num_blocks = spdk_bdev_get_num_blocks(spdk_bdev_desc_get_bdev(dev->base_bdev_desc));
178 : :
179 : : /* For base bdev bigger than 1TB take reclaim uint size for grouping GC bands */
180 [ - + ]: 27 : if (num_blocks > (TiB / FTL_BLOCK_SIZE)) {
181 [ # # ]: 0 : assert(reclaim_unit_num_blocks < num_blocks);
182 [ # # ]: 0 : num_logical_in_phys = reclaim_unit_num_blocks / num_blocks_in_band;
183 : : }
184 : :
185 [ - + ]: 27 : num_to_drop = ftl_get_num_bands(dev) % num_logical_in_phys;
186 : :
187 : 27 : i = 0;
188 [ + + ]: 2563 : while (i < ftl_get_num_bands(dev) - num_to_drop) {
189 : 2536 : band = &dev->bands[i];
190 : :
191 : 2536 : band->phys_id = phys_id;
192 : 2536 : i++;
193 [ - + + + ]: 2536 : if (i % num_logical_in_phys == 0) {
194 : 1268 : phys_id++;
195 : : }
196 : : }
197 : :
198 : : /* Mark not aligned logical bands as broken */
199 : 27 : num_bands = ftl_get_num_bands(dev);
200 [ + + ]: 29 : while (i < num_bands) {
201 : 2 : band = &dev->bands[i];
202 : 2 : dev->num_bands--;
203 [ - + ]: 2 : TAILQ_REMOVE(&dev->shut_bands, band, queue_entry);
204 : 2 : i++;
205 : : }
206 : :
207 : 27 : dev->num_logical_bands_in_physical = num_logical_in_phys;
208 : 27 : }
209 : :
210 : : void
211 : 27 : ftl_mngt_decorate_bands(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
212 : : {
213 : 27 : decorate_bands(dev);
214 : 27 : ftl_mngt_next_step(mngt);
215 : 27 : }
216 : :
217 : : void
218 : 27 : ftl_mngt_initialize_band_address(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
219 : : {
220 : : struct ftl_band *band;
221 : 27 : struct ftl_md *data_md = dev->layout.md[FTL_LAYOUT_REGION_TYPE_DATA_BASE];
222 : : uint64_t i;
223 : :
224 [ + + ]: 2563 : for (i = 0; i < ftl_get_num_bands(dev); i++) {
225 : 2536 : band = &dev->bands[i];
226 : 2536 : band->start_addr = data_md->region->current.offset + i * dev->num_blocks_in_band;
227 : 2536 : band->tail_md_addr = ftl_band_tail_md_addr(band);
228 : : }
229 : :
230 : 27 : ftl_mngt_next_step(mngt);
231 : 27 : }
232 : :
233 : : void
234 : 28 : ftl_recover_max_seq(struct spdk_ftl_dev *dev)
235 : : {
236 : : struct ftl_band *band;
237 : 28 : uint64_t band_close_seq_id = 0, band_open_seq_id = 0;
238 : 28 : uint64_t chunk_close_seq_id = 0, chunk_open_seq_id = 0;
239 : 28 : uint64_t max = 0;
240 : :
241 [ + + ]: 557 : TAILQ_FOREACH(band, &dev->shut_bands, queue_entry) {
242 : 529 : band_open_seq_id = spdk_max(band_open_seq_id, band->md->seq);
243 : 529 : band_close_seq_id = spdk_max(band_close_seq_id, band->md->close_seq_id);
244 : : }
245 : 28 : ftl_nv_cache_get_max_seq_id(&dev->nv_cache, &chunk_open_seq_id, &chunk_close_seq_id);
246 : :
247 : :
248 : 28 : dev->nv_cache.last_seq_id = chunk_close_seq_id;
249 : 28 : dev->writer_gc.last_seq_id = band_close_seq_id;
250 : 28 : dev->writer_user.last_seq_id = band_close_seq_id;
251 : :
252 : 28 : max = spdk_max(max, band_open_seq_id);
253 : 28 : max = spdk_max(max, band_close_seq_id);
254 : 28 : max = spdk_max(max, chunk_open_seq_id);
255 : 28 : max = spdk_max(max, chunk_close_seq_id);
256 : :
257 : 28 : dev->sb->seq_id = max;
258 : 28 : }
259 : :
260 : : static int
261 : 0 : _band_cmp(const void *_a, const void *_b)
262 : : {
263 : : struct ftl_band *a, *b;
264 : :
265 : 0 : a = *((struct ftl_band **)_a);
266 : 0 : b = *((struct ftl_band **)_b);
267 : :
268 : 0 : return a->md->seq - b->md->seq;
269 : : }
270 : :
271 : : static struct ftl_band *
272 : 0 : next_high_prio_band(struct spdk_ftl_dev *dev)
273 : : {
274 : 0 : struct ftl_band *result = NULL, *band;
275 : 0 : uint64_t validity = UINT64_MAX;
276 : :
277 [ # # ]: 0 : TAILQ_FOREACH(band, &dev->shut_bands, queue_entry) {
278 [ # # ]: 0 : if (band->p2l_map.num_valid < validity) {
279 : 0 : result = band;
280 : 0 : validity = result->p2l_map.num_valid;
281 : : }
282 : : }
283 : :
284 : 0 : return result;
285 : : }
286 : :
287 : : static int
288 : 27 : finalize_init_gc(struct spdk_ftl_dev *dev)
289 : : {
290 : : struct ftl_band *band;
291 : : uint64_t free_blocks, blocks_to_move;
292 : :
293 : 27 : ftl_band_init_gc_iter(dev);
294 : 27 : dev->sb_shm->gc_info.band_id_high_prio = FTL_BAND_ID_INVALID;
295 : :
296 [ - + ]: 27 : if (0 == dev->num_free) {
297 : : /* Get number of available blocks in writer */
298 : 0 : free_blocks = ftl_writer_get_free_blocks(&dev->writer_gc);
299 : :
300 : : /*
301 : : * First, check a band candidate to GC
302 : : */
303 : 0 : band = ftl_band_search_next_to_reloc(dev);
304 [ # # ]: 0 : ftl_bug(NULL == band);
305 : 0 : blocks_to_move = band->p2l_map.num_valid;
306 [ # # ]: 0 : if (blocks_to_move <= free_blocks) {
307 : : /* This GC band can be moved */
308 : 0 : return 0;
309 : : }
310 : :
311 : : /*
312 : : * The GC candidate cannot be moved because no enough space. We need to find
313 : : * another band.
314 : : */
315 : 0 : band = next_high_prio_band(dev);
316 [ # # ]: 0 : ftl_bug(NULL == band);
317 : :
318 [ # # ]: 0 : if (band->p2l_map.num_valid > free_blocks) {
319 [ # # ]: 0 : FTL_ERRLOG(dev, "CRITICAL ERROR, no more free bands and cannot start\n");
320 : 0 : return -1;
321 : : } else {
322 : : /* GC needs to start using this band */
323 : 0 : dev->sb_shm->gc_info.band_id_high_prio = band->id;
324 : : }
325 : : }
326 : :
327 : 27 : return 0;
328 : : }
329 : :
330 : : static void
331 : 3 : ftl_property_dump_base_dev(struct spdk_ftl_dev *dev, const struct ftl_property *property,
332 : : struct spdk_json_write_ctx *w)
333 : : {
334 : : uint64_t i;
335 : : struct ftl_band *band;
336 : :
337 : 3 : spdk_json_write_named_array_begin(w, "bands");
338 [ + + ]: 57 : for (i = 0, band = dev->bands; i < ftl_get_num_bands(dev); i++, band++) {
339 : 54 : spdk_json_write_object_begin(w);
340 : 54 : spdk_json_write_named_uint64(w, "id", i);
341 : 54 : spdk_json_write_named_string(w, "state", ftl_band_get_state_name(band));
342 : 54 : spdk_json_write_named_double(w, "validity", 1.0 - ftl_band_invalidity(band));
343 : 54 : spdk_json_write_object_end(w);
344 : : }
345 : 3 : spdk_json_write_array_end(w);
346 : 3 : }
347 : :
348 : : void
349 : 27 : ftl_mngt_finalize_init_bands(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
350 : : {
351 : 27 : struct ftl_band *band, *temp_band, *open_bands[FTL_MAX_OPEN_BANDS];
352 : 27 : struct ftl_writer *writer = NULL;
353 : 27 : uint64_t i, num_open = 0, num_shut = 0;
354 : : uint64_t offset;
355 : 27 : bool fast_startup = ftl_fast_startup(dev);
356 : :
357 : 27 : ftl_recover_max_seq(dev);
358 : 27 : ftl_property_register(dev, "base_device", NULL, 0, NULL, NULL, ftl_property_dump_base_dev, NULL,
359 : : NULL, true);
360 : :
361 [ + + ]: 2037 : TAILQ_FOREACH_SAFE(band, &dev->free_bands, queue_entry, temp_band) {
362 : 2010 : band->md->df_p2l_map = FTL_DF_OBJ_ID_INVALID;
363 : : }
364 : :
365 [ + + ]: 553 : TAILQ_FOREACH_SAFE(band, &dev->shut_bands, queue_entry, temp_band) {
366 [ + + ]: 526 : if (band->md->state == FTL_BAND_STATE_OPEN ||
367 [ - + ]: 522 : band->md->state == FTL_BAND_STATE_FULL) {
368 [ - + ]: 4 : TAILQ_REMOVE(&dev->shut_bands, band, queue_entry);
369 : 4 : open_bands[num_open++] = band;
370 [ - + ]: 4 : assert(num_open <= FTL_MAX_OPEN_BANDS);
371 : 4 : continue;
372 : : }
373 : :
374 [ + + ]: 522 : if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
375 [ + + ]: 518 : TAILQ_REMOVE(&dev->shut_bands, band, queue_entry);
376 [ - + ]: 518 : assert(band->md->state == FTL_BAND_STATE_FREE);
377 : 518 : band->md->state = FTL_BAND_STATE_CLOSED;
378 : 518 : ftl_band_set_state(band, FTL_BAND_STATE_FREE);
379 : : } else {
380 : 4 : num_shut++;
381 : : }
382 : :
383 : 522 : band->md->df_p2l_map = FTL_DF_OBJ_ID_INVALID;
384 : : }
385 : :
386 : : /* Assign open bands to writers and alloc necessary resources */
387 [ - + - + ]: 27 : qsort(open_bands, num_open, sizeof(open_bands[0]), _band_cmp);
388 : :
389 [ + + ]: 31 : for (i = 0; i < num_open; ++i) {
390 : 4 : band = open_bands[i];
391 : :
392 [ + - ]: 4 : if (band->md->type == FTL_BAND_TYPE_COMPACTION) {
393 : 4 : writer = &dev->writer_user;
394 [ # # ]: 0 : } else if (band->md->type == FTL_BAND_TYPE_GC) {
395 : 0 : writer = &dev->writer_gc;
396 : : } else {
397 : 0 : assert(false);
398 : : }
399 : :
400 [ - + ]: 4 : if (band->md->state == FTL_BAND_STATE_FULL) {
401 : 0 : TAILQ_INSERT_TAIL(&writer->full_bands, band, queue_entry);
402 : : } else {
403 [ + - ]: 4 : if (writer->band == NULL) {
404 : 4 : writer->band = band;
405 : : } else {
406 : 0 : writer->next_band = band;
407 : : }
408 : : }
409 : :
410 : 4 : writer->num_bands++;
411 : 4 : ftl_band_set_owner(band, ftl_writer_band_state_change, writer);
412 : :
413 [ + + ]: 4 : if (fast_startup) {
414 [ + - ]: 1 : FTL_NOTICELOG(dev, "SHM: band open P2L map df_id 0x%"PRIx64"\n", band->md->df_p2l_map);
415 [ - + ]: 1 : if (ftl_band_open_p2l_map(band)) {
416 : 0 : ftl_mngt_fail_step(mngt);
417 : 0 : return;
418 : : }
419 : :
420 : 1 : offset = band->md->iter.offset;
421 : 1 : ftl_band_iter_init(band);
422 : 1 : ftl_band_iter_set(band, offset);
423 : 1 : ftl_mngt_p2l_ckpt_restore_shm_clean(band);
424 [ + - ]: 3 : } else if (dev->sb->clean) {
425 : 3 : band->md->df_p2l_map = FTL_DF_OBJ_ID_INVALID;
426 [ - + ]: 3 : if (ftl_band_alloc_p2l_map(band)) {
427 : 0 : ftl_mngt_fail_step(mngt);
428 : 0 : return;
429 : : }
430 : :
431 : 3 : offset = band->md->iter.offset;
432 : 3 : ftl_band_iter_init(band);
433 : 3 : ftl_band_iter_set(band, offset);
434 : :
435 [ - + ]: 3 : if (ftl_mngt_p2l_ckpt_restore_clean(band)) {
436 : 0 : ftl_mngt_fail_step(mngt);
437 : 0 : return;
438 : : }
439 : : }
440 : : }
441 : :
442 [ + + ]: 27 : if (fast_startup) {
443 : 3 : ftl_mempool_initialize_ext(dev->p2l_pool);
444 : : }
445 : :
446 : :
447 : : /* Recalculate number of free bands */
448 : 27 : dev->num_free = 0;
449 [ + + ]: 2555 : TAILQ_FOREACH(band, &dev->free_bands, queue_entry) {
450 [ - + ]: 2528 : assert(band->md->state == FTL_BAND_STATE_FREE);
451 : 2528 : dev->num_free++;
452 : : }
453 : 27 : ftl_apply_limits(dev);
454 : :
455 [ - + ]: 27 : if ((num_shut + num_open + dev->num_free) != ftl_get_num_bands(dev)) {
456 [ # # ]: 0 : FTL_ERRLOG(dev, "ERROR, band list inconsistent state\n");
457 : 0 : ftl_mngt_fail_step(mngt);
458 : 0 : return;
459 : : }
460 : :
461 [ - + ]: 27 : if (finalize_init_gc(dev)) {
462 : 0 : ftl_mngt_fail_step(mngt);
463 : : } else {
464 : 27 : ftl_mngt_next_step(mngt);
465 : : }
466 : : }
|