LCOV - code coverage report
Current view: top level - lib/ftl/mngt - ftl_mngt_band.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 0 244 0.0 %
Date: 2024-07-15 08:19:11 Functions: 0 18 0.0 %

          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           0 : ftl_band_init_md(struct ftl_band *band)
      13             : {
      14           0 :         struct spdk_ftl_dev *dev = band->dev;
      15           0 :         struct ftl_p2l_map *p2l_map = &band->p2l_map;
      16           0 :         struct ftl_md *band_info_md = dev->layout.md[FTL_LAYOUT_REGION_TYPE_BAND_MD];
      17           0 :         struct ftl_md *valid_map_md = dev->layout.md[FTL_LAYOUT_REGION_TYPE_VALID_MAP];
      18           0 :         uint64_t band_num_blocks = ftl_get_num_blocks_in_band(band->dev);
      19             :         size_t band_valid_map_bytes;
      20           0 :         struct ftl_band_md *band_md = ftl_md_get_buffer(band_info_md);
      21             : 
      22           0 :         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           0 :         band_valid_map_bytes = band_num_blocks / 8;
      27             : 
      28           0 :         p2l_map->valid = ftl_bitmap_create(ftl_md_get_buffer(valid_map_md) +
      29           0 :                                            band->start_addr / 8, band_valid_map_bytes);
      30           0 :         if (!p2l_map->valid) {
      31           0 :                 return -ENOMEM;
      32             :         }
      33             : 
      34           0 :         band->md = &band_md[band->id];
      35           0 :         band->md->version = FTL_BAND_VERSION_CURRENT;
      36           0 :         if (!ftl_fast_startup(dev)) {
      37           0 :                 band->md->df_p2l_map = FTL_DF_OBJ_ID_INVALID;
      38             :         }
      39             : 
      40           0 :         return 0;
      41             : }
      42             : 
      43             : static int
      44           0 : 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           0 :         blocks = spdk_bdev_get_num_blocks(spdk_bdev_desc_get_bdev(dev->base_bdev_desc));
      51           0 :         dev->num_bands = blocks / ftl_get_num_blocks_in_band(dev);
      52             : 
      53             :         /* Calculate number of bands considering base device metadata size requirement */
      54           0 :         md_blocks = ftl_layout_base_md_blocks(dev);
      55           0 :         md_bands = spdk_divide_round_up(md_blocks, dev->num_blocks_in_band);
      56             : 
      57           0 :         if (dev->num_bands > md_bands) {
      58             :                 /* Save a band worth of space for metadata */
      59           0 :                 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           0 :         TAILQ_INIT(&dev->free_bands);
      66           0 :         TAILQ_INIT(&dev->shut_bands);
      67             : 
      68           0 :         dev->num_free = 0;
      69           0 :         dev->bands = calloc(ftl_get_num_bands(dev), sizeof(*dev->bands));
      70           0 :         if (!dev->bands) {
      71           0 :                 return -ENOMEM;
      72             :         }
      73             : 
      74           0 :         for (i = 0; i < ftl_get_num_bands(dev); ++i) {
      75           0 :                 band = &dev->bands[i];
      76           0 :                 band->id = i;
      77           0 :                 band->dev = dev;
      78             : 
      79             :                 /* Adding to shut_bands is necessary - see ftl_restore_band_close_cb() */
      80           0 :                 TAILQ_INSERT_TAIL(&dev->shut_bands, band, queue_entry);
      81             :         }
      82             : 
      83           0 :         return 0;
      84             : }
      85             : 
      86             : static int
      87           0 : ftl_dev_init_bands_md(struct spdk_ftl_dev *dev)
      88             : {
      89             :         uint64_t i;
      90           0 :         int rc = 0;
      91             : 
      92           0 :         for (i = 0; i < ftl_get_num_bands(dev); ++i) {
      93           0 :                 rc = ftl_band_init_md(&dev->bands[i]);
      94           0 :                 if (rc) {
      95           0 :                         FTL_ERRLOG(dev, "Failed to initialize metadata structures for band [%lu]\n", i);
      96           0 :                         break;
      97             :                 }
      98             :         }
      99             : 
     100           0 :         return rc;
     101             : }
     102             : 
     103             : static void
     104           0 : ftl_dev_deinit_bands(struct spdk_ftl_dev *dev)
     105             : {
     106           0 :         free(dev->bands);
     107           0 : }
     108             : 
     109             : static void
     110           0 : ftl_dev_deinit_bands_md(struct spdk_ftl_dev *dev)
     111             : {
     112           0 :         if (dev->bands) {
     113             :                 uint64_t i;
     114           0 :                 for (i = 0; i < dev->num_bands; ++i) {
     115           0 :                         struct ftl_band *band = &dev->bands[i];
     116             : 
     117           0 :                         ftl_bitmap_destroy(band->p2l_map.valid);
     118           0 :                         band->p2l_map.valid = NULL;
     119             : 
     120           0 :                         band->md = NULL;
     121             :                 }
     122             :         }
     123           0 : }
     124             : 
     125             : void
     126           0 : ftl_mngt_init_bands(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
     127             : {
     128           0 :         if (ftl_dev_init_bands(dev)) {
     129           0 :                 ftl_mngt_fail_step(mngt);
     130             :         } else {
     131           0 :                 ftl_mngt_next_step(mngt);
     132             :         }
     133           0 : }
     134             : 
     135             : void
     136           0 : ftl_mngt_init_bands_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
     137             : {
     138           0 :         if (ftl_dev_init_bands_md(dev)) {
     139           0 :                 ftl_mngt_fail_step(mngt);
     140             :         } else {
     141           0 :                 ftl_mngt_next_step(mngt);
     142             :         }
     143           0 : }
     144             : 
     145             : void
     146           0 : ftl_mngt_deinit_bands(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
     147             : {
     148           0 :         ftl_dev_deinit_bands(dev);
     149           0 :         ftl_mngt_next_step(mngt);
     150           0 : }
     151             : 
     152             : void
     153           0 : ftl_mngt_deinit_bands_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
     154             : {
     155           0 :         ftl_dev_deinit_bands_md(dev);
     156           0 :         ftl_mngt_next_step(mngt);
     157           0 : }
     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           0 : decorate_bands(struct spdk_ftl_dev *dev)
     167             : {
     168             :         struct ftl_band *band;
     169           0 :         uint64_t i, num_to_drop, phys_id = 0;
     170             :         uint64_t num_blocks, num_bands;
     171           0 :         uint64_t num_blocks_in_band = ftl_get_num_blocks_in_band(dev);
     172           0 :         uint64_t reclaim_unit_num_blocks = BASE_BDEV_RECLAIM_UNIT_SIZE / FTL_BLOCK_SIZE;
     173           0 :         uint32_t num_logical_in_phys = 2;
     174             : 
     175           0 :         assert(reclaim_unit_num_blocks % num_blocks_in_band == 0);
     176             : 
     177           0 :         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           0 :         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           0 :         num_to_drop = ftl_get_num_bands(dev) % num_logical_in_phys;
     186             : 
     187           0 :         i = 0;
     188           0 :         while (i < ftl_get_num_bands(dev) - num_to_drop) {
     189           0 :                 band = &dev->bands[i];
     190             : 
     191           0 :                 band->phys_id = phys_id;
     192           0 :                 i++;
     193           0 :                 if (i % num_logical_in_phys == 0) {
     194           0 :                         phys_id++;
     195             :                 }
     196             :         }
     197             : 
     198             :         /* Mark not aligned logical bands as broken */
     199           0 :         num_bands = ftl_get_num_bands(dev);
     200           0 :         while (i < num_bands) {
     201           0 :                 band = &dev->bands[i];
     202           0 :                 dev->num_bands--;
     203           0 :                 TAILQ_REMOVE(&dev->shut_bands, band, queue_entry);
     204           0 :                 i++;
     205             :         }
     206             : 
     207           0 :         dev->num_logical_bands_in_physical = num_logical_in_phys;
     208           0 : }
     209             : 
     210             : void
     211           0 : ftl_mngt_decorate_bands(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
     212             : {
     213           0 :         decorate_bands(dev);
     214           0 :         ftl_mngt_next_step(mngt);
     215           0 : }
     216             : 
     217             : void
     218           0 : ftl_mngt_initialize_band_address(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
     219             : {
     220             :         struct ftl_band *band;
     221           0 :         struct ftl_md *data_md = dev->layout.md[FTL_LAYOUT_REGION_TYPE_DATA_BASE];
     222             :         uint64_t i;
     223             : 
     224           0 :         for (i = 0; i < ftl_get_num_bands(dev); i++) {
     225           0 :                 band = &dev->bands[i];
     226           0 :                 band->start_addr = data_md->region->current.offset + i * dev->num_blocks_in_band;
     227           0 :                 band->tail_md_addr = ftl_band_tail_md_addr(band);
     228             :         }
     229             : 
     230           0 :         ftl_mngt_next_step(mngt);
     231           0 : }
     232             : 
     233             : void
     234           0 : ftl_recover_max_seq(struct spdk_ftl_dev *dev)
     235             : {
     236             :         struct ftl_band *band;
     237           0 :         uint64_t band_close_seq_id = 0, band_open_seq_id = 0;
     238           0 :         uint64_t chunk_close_seq_id = 0, chunk_open_seq_id = 0;
     239           0 :         uint64_t max = 0;
     240             : 
     241           0 :         TAILQ_FOREACH(band, &dev->shut_bands, queue_entry) {
     242           0 :                 band_open_seq_id = spdk_max(band_open_seq_id, band->md->seq);
     243           0 :                 band_close_seq_id = spdk_max(band_close_seq_id, band->md->close_seq_id);
     244             :         }
     245           0 :         ftl_nv_cache_get_max_seq_id(&dev->nv_cache, &chunk_open_seq_id, &chunk_close_seq_id);
     246             : 
     247             : 
     248           0 :         dev->nv_cache.last_seq_id = chunk_close_seq_id;
     249           0 :         dev->writer_gc.last_seq_id = band_close_seq_id;
     250           0 :         dev->writer_user.last_seq_id = band_close_seq_id;
     251             : 
     252           0 :         max = spdk_max(max, band_open_seq_id);
     253           0 :         max = spdk_max(max, band_close_seq_id);
     254           0 :         max = spdk_max(max, chunk_open_seq_id);
     255           0 :         max = spdk_max(max, chunk_close_seq_id);
     256             : 
     257           0 :         dev->sb->seq_id = max;
     258           0 : }
     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           0 : finalize_init_gc(struct spdk_ftl_dev *dev)
     289             : {
     290             :         struct ftl_band *band;
     291             :         uint64_t free_blocks, blocks_to_move;
     292             : 
     293           0 :         ftl_band_init_gc_iter(dev);
     294           0 :         dev->sb_shm->gc_info.band_id_high_prio = FTL_BAND_ID_INVALID;
     295             : 
     296           0 :         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           0 :         return 0;
     328             : }
     329             : 
     330             : static void
     331           0 : 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           0 :         spdk_json_write_named_array_begin(w, "bands");
     338           0 :         for (i = 0, band = dev->bands; i < ftl_get_num_bands(dev); i++, band++) {
     339           0 :                 spdk_json_write_object_begin(w);
     340           0 :                 spdk_json_write_named_uint64(w, "id", i);
     341           0 :                 spdk_json_write_named_string(w, "state", ftl_band_get_state_name(band));
     342           0 :                 spdk_json_write_named_double(w, "validity", 1.0 - ftl_band_invalidity(band));
     343           0 :                 spdk_json_write_object_end(w);
     344             :         }
     345           0 :         spdk_json_write_array_end(w);
     346           0 : }
     347             : 
     348             : void
     349           0 : ftl_mngt_finalize_init_bands(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
     350             : {
     351           0 :         struct ftl_band *band, *temp_band, *open_bands[FTL_MAX_OPEN_BANDS];
     352           0 :         struct ftl_writer *writer = NULL;
     353           0 :         uint64_t i, num_open = 0, num_shut = 0;
     354             :         uint64_t offset;
     355           0 :         bool fast_startup = ftl_fast_startup(dev);
     356             : 
     357           0 :         ftl_recover_max_seq(dev);
     358           0 :         ftl_property_register(dev, "base_device", NULL, 0, NULL, NULL, ftl_property_dump_base_dev, NULL,
     359             :                               NULL, true);
     360             : 
     361           0 :         TAILQ_FOREACH_SAFE(band, &dev->free_bands, queue_entry, temp_band) {
     362           0 :                 band->md->df_p2l_map = FTL_DF_OBJ_ID_INVALID;
     363             :         }
     364             : 
     365           0 :         TAILQ_FOREACH_SAFE(band, &dev->shut_bands, queue_entry, temp_band) {
     366           0 :                 if (band->md->state == FTL_BAND_STATE_OPEN ||
     367           0 :                     band->md->state == FTL_BAND_STATE_FULL) {
     368           0 :                         TAILQ_REMOVE(&dev->shut_bands, band, queue_entry);
     369           0 :                         open_bands[num_open++] = band;
     370           0 :                         assert(num_open <= FTL_MAX_OPEN_BANDS);
     371           0 :                         continue;
     372             :                 }
     373             : 
     374           0 :                 if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
     375           0 :                         TAILQ_REMOVE(&dev->shut_bands, band, queue_entry);
     376           0 :                         assert(band->md->state == FTL_BAND_STATE_FREE);
     377           0 :                         band->md->state = FTL_BAND_STATE_CLOSED;
     378           0 :                         ftl_band_set_state(band, FTL_BAND_STATE_FREE);
     379             :                 } else {
     380           0 :                         num_shut++;
     381             :                 }
     382             : 
     383           0 :                 band->md->df_p2l_map = FTL_DF_OBJ_ID_INVALID;
     384             :         }
     385             : 
     386             :         /* Assign open bands to writers and alloc necessary resources */
     387           0 :         qsort(open_bands, num_open, sizeof(open_bands[0]), _band_cmp);
     388             : 
     389           0 :         for (i = 0; i < num_open; ++i) {
     390           0 :                 band = open_bands[i];
     391             : 
     392           0 :                 if (band->md->type == FTL_BAND_TYPE_COMPACTION) {
     393           0 :                         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           0 :                 if (band->md->state == FTL_BAND_STATE_FULL) {
     401           0 :                         TAILQ_INSERT_TAIL(&writer->full_bands, band, queue_entry);
     402             :                 } else {
     403           0 :                         if (writer->band == NULL) {
     404           0 :                                 writer->band = band;
     405             :                         } else {
     406           0 :                                 writer->next_band = band;
     407             :                         }
     408             :                 }
     409             : 
     410           0 :                 writer->num_bands++;
     411           0 :                 ftl_band_set_owner(band, ftl_writer_band_state_change, writer);
     412             : 
     413           0 :                 if (fast_startup) {
     414           0 :                         FTL_NOTICELOG(dev, "SHM: band open P2L map df_id 0x%"PRIx64"\n", band->md->df_p2l_map);
     415           0 :                         if (ftl_band_open_p2l_map(band)) {
     416           0 :                                 ftl_mngt_fail_step(mngt);
     417           0 :                                 return;
     418             :                         }
     419             : 
     420           0 :                         offset = band->md->iter.offset;
     421           0 :                         ftl_band_iter_init(band);
     422           0 :                         ftl_band_iter_set(band, offset);
     423           0 :                         ftl_mngt_p2l_ckpt_restore_shm_clean(band);
     424           0 :                 } else if (dev->sb->clean) {
     425           0 :                         band->md->df_p2l_map = FTL_DF_OBJ_ID_INVALID;
     426           0 :                         if (ftl_band_alloc_p2l_map(band)) {
     427           0 :                                 ftl_mngt_fail_step(mngt);
     428           0 :                                 return;
     429             :                         }
     430             : 
     431           0 :                         offset = band->md->iter.offset;
     432           0 :                         ftl_band_iter_init(band);
     433           0 :                         ftl_band_iter_set(band, offset);
     434             : 
     435           0 :                         if (ftl_mngt_p2l_ckpt_restore_clean(band)) {
     436           0 :                                 ftl_mngt_fail_step(mngt);
     437           0 :                                 return;
     438             :                         }
     439             :                 }
     440             :         }
     441             : 
     442           0 :         if (fast_startup) {
     443           0 :                 ftl_mempool_initialize_ext(dev->p2l_pool);
     444             :         }
     445             : 
     446             : 
     447             :         /* Recalculate number of free bands */
     448           0 :         dev->num_free = 0;
     449           0 :         TAILQ_FOREACH(band, &dev->free_bands, queue_entry) {
     450           0 :                 assert(band->md->state == FTL_BAND_STATE_FREE);
     451           0 :                 dev->num_free++;
     452             :         }
     453           0 :         ftl_apply_limits(dev);
     454             : 
     455           0 :         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           0 :         if (finalize_init_gc(dev)) {
     462           0 :                 ftl_mngt_fail_step(mngt);
     463             :         } else {
     464           0 :                 ftl_mngt_next_step(mngt);
     465             :         }
     466             : }

Generated by: LCOV version 1.15