xref: /spdk/lib/ftl/mngt/ftl_mngt_band.c (revision ffa823557a7c4c580cec5fb46c6c424c11b45458)
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