xref: /spdk/lib/ftl/mngt/ftl_mngt_md.c (revision ffa823557a7c4c580cec5fb46c6c424c11b45458)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (c) Intel Corporation.
3  *   All rights reserved.
4  */
5 
6 #include "spdk/thread.h"
7 #include "spdk/crc32.h"
8 
9 #include "ftl_core.h"
10 #include "ftl_mngt.h"
11 #include "ftl_mngt_steps.h"
12 #include "ftl_utils.h"
13 #include "ftl_band.h"
14 #include "ftl_internal.h"
15 #include "ftl_sb.h"
16 
17 void
18 ftl_mngt_init_layout(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
19 {
20 	if (ftl_layout_setup(dev)) {
21 		ftl_mngt_fail_step(mngt);
22 	} else {
23 		ftl_mngt_next_step(mngt);
24 	}
25 }
26 
27 static bool
28 is_buffer_needed(enum ftl_layout_region_type type)
29 {
30 	switch (type) {
31 #ifdef SPDK_FTL_VSS_EMU
32 	case FTL_LAYOUT_REGION_TYPE_VSS:
33 #endif
34 	case FTL_LAYOUT_REGION_TYPE_SB:
35 	case FTL_LAYOUT_REGION_TYPE_SB_BASE:
36 	case FTL_LAYOUT_REGION_TYPE_DATA_NVC:
37 	case FTL_LAYOUT_REGION_TYPE_DATA_BASE:
38 	case FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR:
39 	case FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR:
40 		return false;
41 
42 	default:
43 		return true;
44 	}
45 }
46 
47 void
48 ftl_mngt_init_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
49 {
50 	struct ftl_layout *layout = &dev->layout;
51 	struct ftl_layout_region *region = layout->region;
52 	uint64_t i;
53 	int md_flags;
54 
55 	for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; i++, region++) {
56 		if (layout->md[i]) {
57 			/*
58 			 * Some metadata objects are initialized by other FTL
59 			 * components. At the moment it's only used by superblock (and its mirror) -
60 			 * during load time we need to read it earlier in order to get the layout for the
61 			 * other regions.
62 			 */
63 			continue;
64 		}
65 		md_flags = is_buffer_needed(i) ?
66 			   FTL_MD_CREATE_SHM | FTL_MD_CREATE_SHM_NEW :
67 			   FTL_MD_CREATE_NO_MEM;
68 		layout->md[i] = ftl_md_create(dev, region->current.blocks, region->vss_blksz, region->name,
69 					      md_flags, region);
70 		if (NULL == layout->md[i]) {
71 			ftl_mngt_fail_step(mngt);
72 			return;
73 		}
74 	}
75 
76 	ftl_mngt_next_step(mngt);
77 }
78 
79 void
80 ftl_mngt_deinit_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
81 {
82 	struct ftl_layout *layout = &dev->layout;
83 	struct ftl_layout_region *region = layout->region;
84 	uint64_t i;
85 
86 	for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; i++, region++) {
87 		if (layout->md[i]) {
88 			ftl_md_destroy(layout->md[i]);
89 			layout->md[i] = NULL;
90 		}
91 	}
92 
93 	ftl_mngt_next_step(mngt);
94 }
95 
96 static void
97 persist_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
98 {
99 	struct ftl_mngt_process *mngt = md->owner.cb_ctx;
100 
101 	if (status) {
102 		ftl_mngt_fail_step(mngt);
103 	} else {
104 		ftl_mngt_next_step(mngt);
105 	}
106 }
107 
108 static void
109 persist(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt,
110 	enum ftl_layout_region_type type)
111 {
112 	struct ftl_layout *layout = &dev->layout;
113 	struct ftl_md *md;
114 
115 	assert(type < FTL_LAYOUT_REGION_TYPE_MAX);
116 
117 	md = layout->md[type];
118 	if (!md) {
119 		ftl_mngt_fail_step(mngt);
120 		return;
121 	}
122 
123 	md->owner.cb_ctx = mngt;
124 	md->cb = persist_cb;
125 	ftl_md_persist(md);
126 }
127 
128 void
129 ftl_mngt_persist_nv_cache_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
130 {
131 	if (ftl_nv_cache_save_state(&dev->nv_cache)) {
132 		ftl_mngt_fail_step(mngt);
133 		return;
134 	}
135 
136 	persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_NVC_MD);
137 }
138 
139 void
140 ftl_mngt_persist_band_info_metadata(
141 	struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
142 {
143 	persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_BAND_MD);
144 }
145 
146 static uint32_t
147 get_sb_crc(struct ftl_superblock *sb)
148 {
149 	uint32_t crc = 0;
150 
151 	/* Calculate CRC excluding CRC field in superblock */
152 	void *buffer = sb;
153 	size_t offset = offsetof(struct ftl_superblock, header.crc);
154 	size_t size = offset;
155 	crc = spdk_crc32c_update(buffer, size, crc);
156 
157 	buffer += offset + sizeof(sb->header.crc);
158 	size = FTL_SUPERBLOCK_SIZE - offset - sizeof(sb->header.crc);
159 	crc = spdk_crc32c_update(buffer, size, crc);
160 
161 	return crc;
162 }
163 
164 void
165 ftl_mngt_init_default_sb(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
166 {
167 	struct ftl_superblock *sb = dev->sb;
168 
169 	sb->header.magic = FTL_SUPERBLOCK_MAGIC;
170 	sb->header.version = FTL_METADATA_VERSION_CURRENT;
171 	sb->uuid = dev->conf.uuid;
172 	sb->clean = 0;
173 	dev->sb_shm->shm_clean = false;
174 
175 	/* Max 16 IO depth per band relocate */
176 	sb->max_reloc_qdepth = 16;
177 
178 	sb->overprovisioning = dev->conf.overprovisioning;
179 
180 	ftl_band_init_gc_iter(dev);
181 
182 	/* md layout isn't initialized yet.
183 	 * empty region list => all regions in the default location */
184 	sb->md_layout_head.type = FTL_LAYOUT_REGION_TYPE_INVALID;
185 
186 	sb->header.crc = get_sb_crc(sb);
187 
188 	ftl_mngt_next_step(mngt);
189 }
190 
191 void
192 ftl_mngt_set_dirty(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
193 {
194 	struct ftl_superblock *sb = dev->sb;
195 
196 	sb->clean = 0;
197 	dev->sb_shm->shm_clean = false;
198 	sb->header.crc = get_sb_crc(sb);
199 	persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB);
200 }
201 
202 /*
203  * Initializes the superblock fields during first startup of FTL
204  */
205 static const struct ftl_mngt_process_desc desc_init_sb = {
206 	.name = "SB initialize",
207 	.steps = {
208 		{
209 			.name = "Default-initialize superblock",
210 			.action = ftl_mngt_init_default_sb,
211 		},
212 		{}
213 	}
214 };
215 
216 #ifdef SPDK_FTL_VSS_EMU
217 void
218 ftl_mngt_md_init_vss_emu(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
219 {
220 	struct ftl_layout *layout = &dev->layout;
221 	struct ftl_layout_region *region = &layout->region[FTL_LAYOUT_REGION_TYPE_VSS];
222 
223 	/* Initialize VSS layout */
224 	ftl_layout_setup_vss_emu(dev);
225 
226 	/* Allocate md buf */
227 	layout->md[FTL_LAYOUT_REGION_TYPE_VSS] = ftl_md_create(dev, region->current.blocks,
228 			region->vss_blksz, NULL, 0, region);
229 	if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_VSS]) {
230 		ftl_mngt_fail_step(mngt);
231 		return;
232 	}
233 	ftl_mngt_next_step(mngt);
234 }
235 
236 void
237 ftl_mngt_md_deinit_vss_emu(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
238 {
239 	struct ftl_layout *layout = &dev->layout;
240 
241 	if (layout->md[FTL_LAYOUT_REGION_TYPE_VSS]) {
242 		ftl_md_destroy(layout->md[FTL_LAYOUT_REGION_TYPE_VSS]);
243 		layout->md[FTL_LAYOUT_REGION_TYPE_VSS] = NULL;
244 	}
245 
246 	ftl_mngt_next_step(mngt);
247 }
248 #endif
249 
250 void
251 ftl_mngt_superblock_init(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
252 {
253 	struct ftl_layout *layout = &dev->layout;
254 	struct ftl_layout_region *region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB];
255 	char uuid[SPDK_UUID_STRING_LEN];
256 	int md_create_flags = FTL_MD_CREATE_SHM | FTL_MD_CREATE_SHM_NEW;
257 
258 	/* Must generate UUID before MD create on SHM for the SB */
259 	if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
260 		spdk_uuid_generate(&dev->conf.uuid);
261 		spdk_uuid_fmt_lower(uuid, sizeof(uuid), &dev->conf.uuid);
262 		FTL_NOTICELOG(dev, "Create new FTL, UUID %s\n", uuid);
263 	}
264 
265 	/* Allocate md buf */
266 	dev->sb_shm = NULL;
267 	dev->sb_shm_md = ftl_md_create(dev, spdk_divide_round_up(sizeof(*dev->sb_shm), FTL_BLOCK_SIZE),
268 				       0, "sb_shm",
269 				       md_create_flags, NULL);
270 	if (dev->sb_shm_md == NULL) {
271 		ftl_mngt_fail_step(mngt);
272 		return;
273 	}
274 
275 	dev->sb_shm = ftl_md_get_buffer(dev->sb_shm_md);
276 
277 	/* Setup the layout of a superblock */
278 	if (ftl_layout_setup_superblock(dev)) {
279 		ftl_mngt_fail_step(mngt);
280 		return;
281 	}
282 
283 	/* Allocate md buf */
284 	layout->md[FTL_LAYOUT_REGION_TYPE_SB] = ftl_md_create(dev, region->current.blocks,
285 						region->vss_blksz, region->name,
286 						md_create_flags, region);
287 	if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_SB]) {
288 		ftl_mngt_fail_step(mngt);
289 		return;
290 	}
291 
292 	/* Link the md buf to the device */
293 	dev->sb = ftl_md_get_buffer(layout->md[FTL_LAYOUT_REGION_TYPE_SB]);
294 
295 	/* Setup superblock mirror to QLC */
296 	region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB_BASE];
297 	layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE] = ftl_md_create(dev, region->current.blocks,
298 			region->vss_blksz, NULL, FTL_MD_CREATE_HEAP, region);
299 	if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE]) {
300 		ftl_mngt_fail_step(mngt);
301 		return;
302 	}
303 
304 	/* Initialize the superblock */
305 	if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
306 		ftl_mngt_call_process(mngt, &desc_init_sb);
307 	} else {
308 		ftl_mngt_fail_step(mngt);
309 	}
310 }
311 
312 void
313 ftl_mngt_superblock_deinit(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
314 {
315 	struct ftl_layout *layout = &dev->layout;
316 
317 	if (layout->md[FTL_LAYOUT_REGION_TYPE_SB]) {
318 		ftl_md_destroy(layout->md[FTL_LAYOUT_REGION_TYPE_SB]);
319 		layout->md[FTL_LAYOUT_REGION_TYPE_SB] = NULL;
320 	}
321 
322 	if (layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE]) {
323 		ftl_md_destroy(layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE]);
324 		layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE] = NULL;
325 	}
326 
327 	ftl_md_destroy(dev->sb_shm_md);
328 	dev->sb_shm_md = NULL;
329 	dev->sb_shm = NULL;
330 
331 	ftl_mngt_next_step(mngt);
332 }
333