1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) 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 ftl_band_init_md(struct ftl_band *band) 13 { 14 struct spdk_ftl_dev *dev = band->dev; 15 struct ftl_md *band_info_md = dev->layout.md[FTL_LAYOUT_REGION_TYPE_BAND_MD]; 16 struct ftl_band_md *band_md = ftl_md_get_buffer(band_info_md); 17 18 band->md = &band_md[band->id]; 19 20 return 0; 21 } 22 23 static int 24 ftl_dev_init_bands(struct spdk_ftl_dev *dev) 25 { 26 struct ftl_band *band; 27 uint64_t i; 28 29 TAILQ_INIT(&dev->free_bands); 30 TAILQ_INIT(&dev->shut_bands); 31 32 dev->num_free = 0; 33 dev->bands = calloc(ftl_get_num_bands(dev), sizeof(*dev->bands)); 34 if (!dev->bands) { 35 return -ENOMEM; 36 } 37 38 for (i = 0; i < ftl_get_num_bands(dev); ++i) { 39 band = &dev->bands[i]; 40 band->id = i; 41 band->dev = dev; 42 43 /* Adding to shut_bands is necessary - see ftl_restore_band_close_cb() */ 44 TAILQ_INSERT_TAIL(&dev->shut_bands, band, queue_entry); 45 } 46 47 return 0; 48 } 49 50 static int 51 ftl_dev_init_bands_md(struct spdk_ftl_dev *dev) 52 { 53 uint64_t i; 54 int rc = 0; 55 56 for (i = 0; i < ftl_get_num_bands(dev); ++i) { 57 rc = ftl_band_init_md(&dev->bands[i]); 58 if (rc) { 59 FTL_ERRLOG(dev, "Failed to initialize metadata structures for band [%lu]\n", i); 60 break; 61 } 62 } 63 64 return rc; 65 } 66 67 static void 68 ftl_dev_deinit_bands(struct spdk_ftl_dev *dev) 69 { 70 free(dev->bands); 71 } 72 73 void 74 ftl_mngt_init_bands(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt) 75 { 76 if (ftl_dev_init_bands(dev)) { 77 ftl_mngt_fail_step(mngt); 78 } else { 79 ftl_mngt_next_step(mngt); 80 } 81 } 82 83 void 84 ftl_mngt_init_bands_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt) 85 { 86 if (ftl_dev_init_bands_md(dev)) { 87 ftl_mngt_fail_step(mngt); 88 } else { 89 ftl_mngt_next_step(mngt); 90 } 91 } 92 93 void 94 ftl_mngt_deinit_bands(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt) 95 { 96 ftl_dev_deinit_bands(dev); 97 ftl_mngt_next_step(mngt); 98 } 99 100 /* 101 * For grouping multiple logical bands (1GiB) to make any IOs more sequential from the drive's 102 * perspective. Improves WAF. 103 */ 104 #define BASE_BDEV_RECLAIM_UNIT_SIZE (72 * GiB) 105 106 static void 107 decorate_bands(struct spdk_ftl_dev *dev) 108 { 109 struct ftl_band *band; 110 uint64_t i, num_to_drop, phys_id = 0; 111 uint64_t num_blocks, num_bands; 112 uint64_t num_blocks_in_band = ftl_get_num_blocks_in_band(dev); 113 uint64_t reclaim_unit_num_blocks = BASE_BDEV_RECLAIM_UNIT_SIZE / FTL_BLOCK_SIZE; 114 uint32_t num_logical_in_phys = 2; 115 116 assert(reclaim_unit_num_blocks % num_blocks_in_band == 0); 117 118 num_blocks = spdk_bdev_get_num_blocks(spdk_bdev_desc_get_bdev(dev->base_bdev_desc)); 119 120 /* For base bdev bigger than 1TB take reclaim uint size for grouping GC bands */ 121 if (num_blocks > (TiB / FTL_BLOCK_SIZE)) { 122 assert(reclaim_unit_num_blocks < num_blocks); 123 num_logical_in_phys = reclaim_unit_num_blocks / num_blocks_in_band; 124 } 125 126 num_to_drop = ftl_get_num_bands(dev) % num_logical_in_phys; 127 128 i = 0; 129 while (i < ftl_get_num_bands(dev) - num_to_drop) { 130 band = &dev->bands[i]; 131 band->start_addr = i * dev->num_blocks_in_band; 132 band->tail_md_addr = ftl_band_tail_md_addr(band); 133 134 band->phys_id = phys_id; 135 i++; 136 if (i % num_logical_in_phys == 0) { 137 phys_id++; 138 } 139 } 140 141 /* Mark not aligned logical bands as broken */ 142 num_bands = ftl_get_num_bands(dev); 143 while (i < num_bands) { 144 band = &dev->bands[i]; 145 dev->num_bands--; 146 TAILQ_REMOVE(&dev->shut_bands, band, queue_entry); 147 i++; 148 } 149 150 dev->num_logical_bands_in_physical = num_logical_in_phys; 151 } 152 153 void 154 ftl_mngt_decorate_bands(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt) 155 { 156 decorate_bands(dev); 157 ftl_mngt_next_step(mngt); 158 } 159 160 static struct ftl_band * 161 next_high_prio_band(struct spdk_ftl_dev *dev) 162 { 163 struct ftl_band *result = NULL, *band; 164 uint64_t validity = UINT64_MAX; 165 166 TAILQ_FOREACH(band, &dev->shut_bands, queue_entry) { 167 if (band->p2l_map.num_valid < validity) { 168 result = band; 169 validity = result->p2l_map.num_valid; 170 } 171 } 172 173 return result; 174 } 175 176 static int 177 finalize_init_gc(struct spdk_ftl_dev *dev) 178 { 179 struct ftl_band *band; 180 uint64_t free_blocks, blocks_to_move; 181 182 ftl_band_init_gc_iter(dev); 183 dev->sb_shm->gc_info.band_id_high_prio = FTL_BAND_ID_INVALID; 184 185 if (0 == dev->num_free) { 186 /* Get number of available blocks in writer */ 187 free_blocks = ftl_writer_get_free_blocks(&dev->writer_gc); 188 189 /* 190 * First, check a band candidate to GC 191 */ 192 band = ftl_band_search_next_to_reloc(dev); 193 ftl_bug(NULL == band); 194 blocks_to_move = band->p2l_map.num_valid; 195 if (blocks_to_move <= free_blocks) { 196 /* This GC band can be moved */ 197 return 0; 198 } 199 200 /* 201 * The GC candidate cannot be moved because no enough space. We need to find 202 * another band. 203 */ 204 band = next_high_prio_band(dev); 205 ftl_bug(NULL == band); 206 207 if (band->p2l_map.num_valid > free_blocks) { 208 FTL_ERRLOG(dev, "CRITICAL ERROR, no more free bands and cannot start\n"); 209 return -1; 210 } else { 211 /* GC needs to start using this band */ 212 dev->sb_shm->gc_info.band_id_high_prio = band->id; 213 } 214 } 215 216 return 0; 217 } 218 219 void 220 ftl_mngt_finalize_init_bands(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt) 221 { 222 struct ftl_band *band, *temp_band, *open_bands[FTL_MAX_OPEN_BANDS]; 223 struct ftl_writer *writer; 224 uint64_t i, num_open = 0, num_shut = 0; 225 uint64_t offset; 226 227 TAILQ_FOREACH_SAFE(band, &dev->shut_bands, queue_entry, temp_band) { 228 if (band->md->state == FTL_BAND_STATE_OPEN || 229 band->md->state == FTL_BAND_STATE_FULL) { 230 TAILQ_REMOVE(&dev->shut_bands, band, queue_entry); 231 open_bands[num_open++] = band; 232 assert(num_open <= FTL_MAX_OPEN_BANDS); 233 continue; 234 } 235 236 if (dev->conf.mode & SPDK_FTL_MODE_CREATE) { 237 TAILQ_REMOVE(&dev->shut_bands, band, queue_entry); 238 assert(band->md->state == FTL_BAND_STATE_FREE); 239 band->md->state = FTL_BAND_STATE_CLOSED; 240 ftl_band_set_state(band, FTL_BAND_STATE_FREE); 241 } else { 242 num_shut++; 243 } 244 } 245 246 /* Assign open bands to writers and alloc necessary resources */ 247 for (i = 0; i < num_open; ++i) { 248 band = open_bands[i]; 249 250 if (band->md->type == FTL_BAND_TYPE_COMPACTION) { 251 writer = &dev->writer_user; 252 } else if (band->md->type == FTL_BAND_TYPE_GC) { 253 writer = &dev->writer_gc; 254 } else { 255 assert(false); 256 } 257 258 if (band->md->state == FTL_BAND_STATE_FULL) { 259 TAILQ_INSERT_TAIL(&writer->full_bands, band, queue_entry); 260 } else { 261 if (writer->band == NULL) { 262 writer->band = band; 263 } else { 264 writer->next_band = band; 265 } 266 } 267 268 writer->num_bands++; 269 ftl_band_set_owner(band, ftl_writer_band_state_change, writer); 270 271 if (dev->sb->clean) { 272 if (ftl_band_alloc_p2l_map(band)) { 273 ftl_mngt_fail_step(mngt); 274 return; 275 } 276 277 offset = band->md->iter.offset; 278 ftl_band_iter_init(band); 279 ftl_band_iter_set(band, offset); 280 } 281 } 282 283 /* Recalculate number of free bands */ 284 dev->num_free = 0; 285 TAILQ_FOREACH(band, &dev->free_bands, queue_entry) { 286 assert(band->md->state == FTL_BAND_STATE_FREE); 287 dev->num_free++; 288 } 289 ftl_apply_limits(dev); 290 291 if ((num_shut + num_open + dev->num_free) != ftl_get_num_bands(dev)) { 292 FTL_ERRLOG(dev, "ERROR, band list inconsistent state\n"); 293 ftl_mngt_fail_step(mngt); 294 return; 295 } 296 297 if (finalize_init_gc(dev)) { 298 ftl_mngt_fail_step(mngt); 299 } else { 300 ftl_mngt_next_step(mngt); 301 } 302 } 303