xref: /spdk/lib/ftl/mngt/ftl_mngt_md.c (revision 510f4c134a21b45ff3a5add9ebc6c6cf7e49aeab)
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) ? ftl_md_create_region_flags(dev,
66 				region->type) : FTL_MD_CREATE_NO_MEM;
67 		layout->md[i] = ftl_md_create(dev, region->current.blocks, region->vss_blksz, region->name,
68 					      md_flags, region);
69 		if (NULL == layout->md[i]) {
70 			ftl_mngt_fail_step(mngt);
71 			return;
72 		}
73 	}
74 
75 	ftl_mngt_next_step(mngt);
76 }
77 
78 void
79 ftl_mngt_deinit_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
80 {
81 	struct ftl_layout *layout = &dev->layout;
82 	struct ftl_layout_region *region = layout->region;
83 	uint64_t i;
84 
85 	for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; i++, region++) {
86 		if (layout->md[i]) {
87 			ftl_md_destroy(layout->md[i], ftl_md_destroy_region_flags(dev, layout->region[i].type));
88 			layout->md[i] = NULL;
89 		}
90 	}
91 
92 	ftl_mngt_next_step(mngt);
93 }
94 
95 static void
96 persist_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
97 {
98 	struct ftl_mngt_process *mngt = md->owner.cb_ctx;
99 
100 	if (status) {
101 		ftl_mngt_fail_step(mngt);
102 	} else {
103 		ftl_mngt_next_step(mngt);
104 	}
105 }
106 
107 static void
108 persist(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt,
109 	enum ftl_layout_region_type type)
110 {
111 	struct ftl_layout *layout = &dev->layout;
112 	struct ftl_md *md;
113 
114 	assert(type < FTL_LAYOUT_REGION_TYPE_MAX);
115 
116 	md = layout->md[type];
117 	if (!md) {
118 		ftl_mngt_fail_step(mngt);
119 		return;
120 	}
121 
122 	md->owner.cb_ctx = mngt;
123 	md->cb = persist_cb;
124 	ftl_md_persist(md);
125 }
126 
127 void
128 ftl_mngt_persist_nv_cache_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
129 {
130 	if (ftl_nv_cache_save_state(&dev->nv_cache)) {
131 		ftl_mngt_fail_step(mngt);
132 		return;
133 	}
134 
135 	persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_NVC_MD);
136 }
137 
138 void
139 ftl_mngt_persist_band_info_metadata(
140 	struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
141 {
142 	persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_BAND_MD);
143 }
144 
145 static uint32_t
146 get_sb_crc(struct ftl_superblock *sb)
147 {
148 	uint32_t crc = 0;
149 
150 	/* Calculate CRC excluding CRC field in superblock */
151 	void *buffer = sb;
152 	size_t offset = offsetof(struct ftl_superblock, header.crc);
153 	size_t size = offset;
154 	crc = spdk_crc32c_update(buffer, size, crc);
155 
156 	buffer += offset + sizeof(sb->header.crc);
157 	size = FTL_SUPERBLOCK_SIZE - offset - sizeof(sb->header.crc);
158 	crc = spdk_crc32c_update(buffer, size, crc);
159 
160 	return crc;
161 }
162 
163 void
164 ftl_mngt_init_default_sb(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
165 {
166 	struct ftl_superblock *sb = dev->sb;
167 
168 	sb->header.magic = FTL_SUPERBLOCK_MAGIC;
169 	sb->header.version = FTL_METADATA_VERSION_CURRENT;
170 	sb->uuid = dev->conf.uuid;
171 	sb->clean = 0;
172 	dev->sb_shm->shm_clean = false;
173 
174 	/* Max 16 IO depth per band relocate */
175 	sb->max_reloc_qdepth = 16;
176 
177 	sb->overprovisioning = dev->conf.overprovisioning;
178 
179 	ftl_band_init_gc_iter(dev);
180 
181 	/* md layout isn't initialized yet.
182 	 * empty region list => all regions in the default location */
183 	sb->md_layout_head.type = FTL_LAYOUT_REGION_TYPE_INVALID;
184 
185 	sb->header.crc = get_sb_crc(sb);
186 
187 	ftl_mngt_next_step(mngt);
188 }
189 
190 void
191 ftl_mngt_set_dirty(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
192 {
193 	struct ftl_superblock *sb = dev->sb;
194 
195 	sb->clean = 0;
196 	dev->sb_shm->shm_clean = false;
197 	sb->header.crc = get_sb_crc(sb);
198 	persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB);
199 }
200 
201 /*
202  * Initializes the superblock fields during first startup of FTL
203  */
204 static const struct ftl_mngt_process_desc desc_init_sb = {
205 	.name = "SB initialize",
206 	.steps = {
207 		{
208 			.name = "Default-initialize superblock",
209 			.action = ftl_mngt_init_default_sb,
210 		},
211 		{}
212 	}
213 };
214 
215 #ifdef SPDK_FTL_VSS_EMU
216 void
217 ftl_mngt_md_init_vss_emu(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
218 {
219 	struct ftl_layout *layout = &dev->layout;
220 	struct ftl_layout_region *region = &layout->region[FTL_LAYOUT_REGION_TYPE_VSS];
221 
222 	/* Initialize VSS layout */
223 	ftl_layout_setup_vss_emu(dev);
224 
225 	/* Allocate md buf */
226 	layout->md[FTL_LAYOUT_REGION_TYPE_VSS] = ftl_md_create(dev, region->current.blocks,
227 			region->vss_blksz, NULL, 0, region);
228 	if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_VSS]) {
229 		ftl_mngt_fail_step(mngt);
230 		return;
231 	}
232 	ftl_mngt_next_step(mngt);
233 }
234 
235 void
236 ftl_mngt_md_deinit_vss_emu(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
237 {
238 	struct ftl_layout *layout = &dev->layout;
239 
240 	if (layout->md[FTL_LAYOUT_REGION_TYPE_VSS]) {
241 		ftl_md_destroy(layout->md[FTL_LAYOUT_REGION_TYPE_VSS], 0);
242 		layout->md[FTL_LAYOUT_REGION_TYPE_VSS] = NULL;
243 	}
244 
245 	ftl_mngt_next_step(mngt);
246 }
247 #endif
248 
249 void
250 ftl_mngt_superblock_init(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
251 {
252 	struct ftl_layout *layout = &dev->layout;
253 	struct ftl_layout_region *region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB];
254 	char uuid[SPDK_UUID_STRING_LEN];
255 	int md_create_flags = ftl_md_create_region_flags(dev, FTL_LAYOUT_REGION_TYPE_SB);
256 
257 	/* Must generate UUID before MD create on SHM for the SB */
258 	if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
259 		spdk_uuid_generate(&dev->conf.uuid);
260 		spdk_uuid_fmt_lower(uuid, sizeof(uuid), &dev->conf.uuid);
261 		FTL_NOTICELOG(dev, "Create new FTL, UUID %s\n", uuid);
262 	}
263 
264 shm_retry:
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 		/* The first attempt may fail when trying to open SHM - try to create new */
272 		if ((md_create_flags & FTL_MD_CREATE_SHM_NEW) == 0) {
273 			md_create_flags |= FTL_MD_CREATE_SHM_NEW;
274 			goto shm_retry;
275 		}
276 		if (dev->sb_shm_md == NULL) {
277 			ftl_mngt_fail_step(mngt);
278 			return;
279 		}
280 	}
281 
282 	dev->sb_shm = ftl_md_get_buffer(dev->sb_shm_md);
283 
284 	/* Setup the layout of a superblock */
285 	if (ftl_layout_setup_superblock(dev)) {
286 		ftl_mngt_fail_step(mngt);
287 		return;
288 	}
289 
290 	/* Allocate md buf */
291 	layout->md[FTL_LAYOUT_REGION_TYPE_SB] = ftl_md_create(dev, region->current.blocks,
292 						region->vss_blksz, region->name,
293 						md_create_flags, region);
294 	if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_SB]) {
295 		/* The first attempt may fail when trying to open SHM - try to create new */
296 		if ((md_create_flags & FTL_MD_CREATE_SHM_NEW) == 0) {
297 			md_create_flags |= FTL_MD_CREATE_SHM_NEW;
298 			ftl_md_destroy(dev->sb_shm_md, 0);
299 			goto shm_retry;
300 		}
301 		ftl_mngt_fail_step(mngt);
302 		return;
303 	}
304 
305 	/* Link the md buf to the device */
306 	dev->sb = ftl_md_get_buffer(layout->md[FTL_LAYOUT_REGION_TYPE_SB]);
307 
308 	/* Setup superblock mirror to QLC */
309 	region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB_BASE];
310 	layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE] = ftl_md_create(dev, region->current.blocks,
311 			region->vss_blksz, NULL, FTL_MD_CREATE_HEAP, region);
312 	if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE]) {
313 		ftl_mngt_fail_step(mngt);
314 		return;
315 	}
316 
317 	/* Initialize the superblock */
318 	if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
319 		ftl_mngt_call_process(mngt, &desc_init_sb);
320 	} else {
321 		ftl_mngt_fail_step(mngt);
322 	}
323 }
324 
325 void
326 ftl_mngt_superblock_deinit(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
327 {
328 	struct ftl_layout *layout = &dev->layout;
329 
330 	if (layout->md[FTL_LAYOUT_REGION_TYPE_SB]) {
331 		ftl_md_destroy(layout->md[FTL_LAYOUT_REGION_TYPE_SB],
332 			       ftl_md_destroy_region_flags(dev, FTL_LAYOUT_REGION_TYPE_SB));
333 		layout->md[FTL_LAYOUT_REGION_TYPE_SB] = NULL;
334 	}
335 
336 	if (layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE]) {
337 		ftl_md_destroy(layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE], 0);
338 		layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE] = NULL;
339 	}
340 
341 	ftl_md_destroy(dev->sb_shm_md, ftl_md_destroy_shm_flags(dev));
342 	dev->sb_shm_md = NULL;
343 	dev->sb_shm = NULL;
344 
345 	ftl_mngt_next_step(mngt);
346 }
347