xref: /spdk/lib/ftl/upgrade/ftl_band_upgrade.c (revision cb00e90aee3bcd300f2672ca2baab5257e5e389e)
18c41c403SKozlowski Mateusz /*   SPDX-License-Identifier: BSD-3-Clause
2*cb00e90aSMateusz Kozlowski  *   Copyright 2023 Solidigm All Rights Reserved
3a6dbe372Spaul luse  *   Copyright (C) 2022 Intel Corporation.
48c41c403SKozlowski Mateusz  *   All rights reserved.
58c41c403SKozlowski Mateusz  */
68c41c403SKozlowski Mateusz 
78c41c403SKozlowski Mateusz #include "ftl_band.h"
88c41c403SKozlowski Mateusz #include "ftl_layout_upgrade.h"
98c41c403SKozlowski Mateusz 
10*cb00e90aSMateusz Kozlowski struct upgrade_ctx {
11*cb00e90aSMateusz Kozlowski 	struct ftl_md			*md;
12*cb00e90aSMateusz Kozlowski 	struct ftl_layout_region	reg;
13*cb00e90aSMateusz Kozlowski };
14*cb00e90aSMateusz Kozlowski 
15*cb00e90aSMateusz Kozlowski static void
v2_upgrade_cleanup(struct ftl_layout_upgrade_ctx * lctx)16*cb00e90aSMateusz Kozlowski v2_upgrade_cleanup(struct ftl_layout_upgrade_ctx *lctx)
17*cb00e90aSMateusz Kozlowski {
18*cb00e90aSMateusz Kozlowski 	struct upgrade_ctx *ctx = lctx->ctx;
19*cb00e90aSMateusz Kozlowski 
20*cb00e90aSMateusz Kozlowski 	if (ctx->md) {
21*cb00e90aSMateusz Kozlowski 		ftl_md_destroy(ctx->md, 0);
22*cb00e90aSMateusz Kozlowski 		ctx->md = NULL;
23*cb00e90aSMateusz Kozlowski 	}
24*cb00e90aSMateusz Kozlowski }
25*cb00e90aSMateusz Kozlowski 
26*cb00e90aSMateusz Kozlowski static void
v2_upgrade_finish(struct spdk_ftl_dev * dev,struct ftl_layout_upgrade_ctx * lctx,int status)27*cb00e90aSMateusz Kozlowski v2_upgrade_finish(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *lctx, int status)
28*cb00e90aSMateusz Kozlowski {
29*cb00e90aSMateusz Kozlowski 	struct upgrade_ctx *ctx = lctx->ctx;
30*cb00e90aSMateusz Kozlowski 
31*cb00e90aSMateusz Kozlowski 	v2_upgrade_cleanup(lctx);
32*cb00e90aSMateusz Kozlowski 	ftl_region_upgrade_completed(dev, lctx, ctx->reg.entry_size, ctx->reg.num_entries, status);
33*cb00e90aSMateusz Kozlowski }
34*cb00e90aSMateusz Kozlowski 
35*cb00e90aSMateusz Kozlowski static void
v2_upgrade_md_persist_cb(struct spdk_ftl_dev * dev,struct ftl_md * md,int status)36*cb00e90aSMateusz Kozlowski v2_upgrade_md_persist_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
37*cb00e90aSMateusz Kozlowski {
38*cb00e90aSMateusz Kozlowski 	struct ftl_layout_upgrade_ctx *lctx = md->owner.cb_ctx;
39*cb00e90aSMateusz Kozlowski 
40*cb00e90aSMateusz Kozlowski 	v2_upgrade_finish(dev, lctx, status);
41*cb00e90aSMateusz Kozlowski }
42*cb00e90aSMateusz Kozlowski 
43*cb00e90aSMateusz Kozlowski static void
v2_upgrade_md_restore_cb(struct spdk_ftl_dev * dev,struct ftl_md * md,int status)44*cb00e90aSMateusz Kozlowski v2_upgrade_md_restore_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
45*cb00e90aSMateusz Kozlowski {
46*cb00e90aSMateusz Kozlowski 	struct ftl_layout_upgrade_ctx *lctx = md->owner.cb_ctx;
47*cb00e90aSMateusz Kozlowski 	struct upgrade_ctx *ctx = lctx->ctx;
48*cb00e90aSMateusz Kozlowski 	struct ftl_band_md *band = ftl_md_get_buffer(md);
49*cb00e90aSMateusz Kozlowski 	uint64_t move = sizeof(band->version);
50*cb00e90aSMateusz Kozlowski 
51*cb00e90aSMateusz Kozlowski 	if (status) {
52*cb00e90aSMateusz Kozlowski 		v2_upgrade_finish(dev, lctx, status);
53*cb00e90aSMateusz Kozlowski 		return;
54*cb00e90aSMateusz Kozlowski 	}
55*cb00e90aSMateusz Kozlowski 
56*cb00e90aSMateusz Kozlowski 	/* If the upgrade process is interrupted while only part of the update persisted,
57*cb00e90aSMateusz Kozlowski 	 * then the V1 version will be read from again and this section will rewrite the whole band md.
58*cb00e90aSMateusz Kozlowski 	 */
59*cb00e90aSMateusz Kozlowski 	for (uint64_t i = 0; i < dev->num_bands; i++, band++) {
60*cb00e90aSMateusz Kozlowski 		char *buffer = (char *)band;
61*cb00e90aSMateusz Kozlowski 
62*cb00e90aSMateusz Kozlowski 		memmove(buffer + move, buffer, sizeof(*band) - move);
63*cb00e90aSMateusz Kozlowski 		band->version = FTL_BAND_VERSION_2;
64*cb00e90aSMateusz Kozlowski 
65*cb00e90aSMateusz Kozlowski 		if (band->state != FTL_BAND_STATE_CLOSED && band->state != FTL_BAND_STATE_FREE) {
66*cb00e90aSMateusz Kozlowski 			v2_upgrade_finish(dev, lctx, -EINVAL);
67*cb00e90aSMateusz Kozlowski 			return;
68*cb00e90aSMateusz Kozlowski 		}
69*cb00e90aSMateusz Kozlowski 	}
70*cb00e90aSMateusz Kozlowski 
71*cb00e90aSMateusz Kozlowski 	ctx->md->cb = v2_upgrade_md_persist_cb;
72*cb00e90aSMateusz Kozlowski 	ftl_md_set_region(ctx->md, &ctx->reg);
73*cb00e90aSMateusz Kozlowski 	ftl_md_persist(ctx->md);
74*cb00e90aSMateusz Kozlowski }
75*cb00e90aSMateusz Kozlowski 
76*cb00e90aSMateusz Kozlowski static int
v2_upgrade_setup_ctx(struct spdk_ftl_dev * dev,struct ftl_layout_upgrade_ctx * lctx)77*cb00e90aSMateusz Kozlowski v2_upgrade_setup_ctx(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *lctx)
78*cb00e90aSMateusz Kozlowski {
79*cb00e90aSMateusz Kozlowski 	struct upgrade_ctx *ctx = lctx->ctx;
80*cb00e90aSMateusz Kozlowski 	const struct ftl_md_layout_ops *md_ops = &dev->nv_cache.nvc_type->ops.md_layout_ops;
81*cb00e90aSMateusz Kozlowski 
82*cb00e90aSMateusz Kozlowski 	assert(sizeof(struct ftl_band_md) == FTL_BLOCK_SIZE);
83*cb00e90aSMateusz Kozlowski 
84*cb00e90aSMateusz Kozlowski 	if (lctx->reg->num_entries != dev->num_bands) {
85*cb00e90aSMateusz Kozlowski 		return -1;
86*cb00e90aSMateusz Kozlowski 	}
87*cb00e90aSMateusz Kozlowski 
88*cb00e90aSMateusz Kozlowski 	/* Open metadata region */
89*cb00e90aSMateusz Kozlowski 	if (md_ops->region_open(dev, lctx->reg->type, FTL_BAND_VERSION_2, sizeof(struct ftl_band_md),
90*cb00e90aSMateusz Kozlowski 				dev->num_bands, &ctx->reg)) {
91*cb00e90aSMateusz Kozlowski 		return -1;
92*cb00e90aSMateusz Kozlowski 	}
93*cb00e90aSMateusz Kozlowski 
94*cb00e90aSMateusz Kozlowski 	if (lctx->reg->current.blocks != ctx->reg.current.blocks) {
95*cb00e90aSMateusz Kozlowski 		return -1;
96*cb00e90aSMateusz Kozlowski 	}
97*cb00e90aSMateusz Kozlowski 
98*cb00e90aSMateusz Kozlowski 	ctx->md = ftl_md_create(dev, lctx->reg->current.blocks, 0, ctx->reg.name, FTL_MD_CREATE_HEAP,
99*cb00e90aSMateusz Kozlowski 				lctx->reg);
100*cb00e90aSMateusz Kozlowski 	if (!ctx->md) {
101*cb00e90aSMateusz Kozlowski 		return -1;
102*cb00e90aSMateusz Kozlowski 	}
103*cb00e90aSMateusz Kozlowski 
104*cb00e90aSMateusz Kozlowski 	ctx->md->owner.cb_ctx = lctx;
105*cb00e90aSMateusz Kozlowski 	ctx->md->cb = v2_upgrade_md_restore_cb;
106*cb00e90aSMateusz Kozlowski 
107*cb00e90aSMateusz Kozlowski 	return 0;
108*cb00e90aSMateusz Kozlowski }
109*cb00e90aSMateusz Kozlowski 
110*cb00e90aSMateusz Kozlowski static int
v2_upgrade(struct spdk_ftl_dev * dev,struct ftl_layout_upgrade_ctx * lctx)111*cb00e90aSMateusz Kozlowski v2_upgrade(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *lctx)
112*cb00e90aSMateusz Kozlowski {
113*cb00e90aSMateusz Kozlowski 	struct upgrade_ctx *ctx = lctx->ctx;
114*cb00e90aSMateusz Kozlowski 
115*cb00e90aSMateusz Kozlowski 	if (v2_upgrade_setup_ctx(dev, lctx)) {
116*cb00e90aSMateusz Kozlowski 		goto error;
117*cb00e90aSMateusz Kozlowski 	}
118*cb00e90aSMateusz Kozlowski 	/* At this point we're reading the contents of the v1 md */
119*cb00e90aSMateusz Kozlowski 	ftl_md_restore(ctx->md);
120*cb00e90aSMateusz Kozlowski 	return 0;
121*cb00e90aSMateusz Kozlowski error:
122*cb00e90aSMateusz Kozlowski 	v2_upgrade_cleanup(lctx);
123*cb00e90aSMateusz Kozlowski 	return -1;
124*cb00e90aSMateusz Kozlowski }
125*cb00e90aSMateusz Kozlowski 
126*cb00e90aSMateusz Kozlowski static int
v1_to_v2_upgrade_enabled(struct spdk_ftl_dev * dev,struct ftl_layout_region * region)127*cb00e90aSMateusz Kozlowski v1_to_v2_upgrade_enabled(struct spdk_ftl_dev *dev, struct ftl_layout_region *region)
128*cb00e90aSMateusz Kozlowski {
129*cb00e90aSMateusz Kozlowski 	const struct ftl_md_layout_ops *md_ops = &dev->nv_cache.nvc_type->ops.md_layout_ops;
130*cb00e90aSMateusz Kozlowski 
131*cb00e90aSMateusz Kozlowski 	if (ftl_region_major_upgrade_enabled(dev, region)) {
132*cb00e90aSMateusz Kozlowski 		return -1;
133*cb00e90aSMateusz Kozlowski 	}
134*cb00e90aSMateusz Kozlowski 
135*cb00e90aSMateusz Kozlowski 	/* Create the new band metadata region (v2) up front - this allocates a separate entry in the superblock and
136*cb00e90aSMateusz Kozlowski 	 * area on the cache for us. This is to reserve space for other region upgrades allocating new regions and it
137*cb00e90aSMateusz Kozlowski 	 * allows us to do an atomic upgrade of the whole region.
138*cb00e90aSMateusz Kozlowski 	 *
139*cb00e90aSMateusz Kozlowski 	 * If the upgrade is stopped by power failure/crash after the V2 region has been added, then the upgrade process
140*cb00e90aSMateusz Kozlowski 	 * will start again (since V1 still exists), but region_create will fail (since the v2 region has already been
141*cb00e90aSMateusz Kozlowski 	 * created). In such a case only verification of the region length by region_open is needed.
142*cb00e90aSMateusz Kozlowski 	 *
143*cb00e90aSMateusz Kozlowski 	 * Once the upgrade is fully done, the old v1 region entry will be removed from the SB and its area on the cache
144*cb00e90aSMateusz Kozlowski 	 * freed.
145*cb00e90aSMateusz Kozlowski 	 */
146*cb00e90aSMateusz Kozlowski 	if (md_ops->region_create(dev, region->type, FTL_BAND_VERSION_2, dev->num_bands) &&
147*cb00e90aSMateusz Kozlowski 	    md_ops->region_open(dev, region->type, FTL_BAND_VERSION_2, sizeof(struct ftl_band_md),
148*cb00e90aSMateusz Kozlowski 				dev->num_bands, NULL)) {
149*cb00e90aSMateusz Kozlowski 		return -1;
150*cb00e90aSMateusz Kozlowski 	}
151*cb00e90aSMateusz Kozlowski 
152*cb00e90aSMateusz Kozlowski 	return 0;
153*cb00e90aSMateusz Kozlowski }
154*cb00e90aSMateusz Kozlowski 
1558c41c403SKozlowski Mateusz struct ftl_region_upgrade_desc band_upgrade_desc[] = {
1568c41c403SKozlowski Mateusz 	[FTL_BAND_VERSION_0] = {
1578c41c403SKozlowski Mateusz 		.verify = ftl_region_upgrade_disabled,
1588c41c403SKozlowski Mateusz 	},
159*cb00e90aSMateusz Kozlowski 	[FTL_BAND_VERSION_1] = {
160*cb00e90aSMateusz Kozlowski 		.verify = v1_to_v2_upgrade_enabled,
161*cb00e90aSMateusz Kozlowski 		.ctx_size = sizeof(struct upgrade_ctx),
162*cb00e90aSMateusz Kozlowski 		.new_version = FTL_BAND_VERSION_2,
163*cb00e90aSMateusz Kozlowski 		.upgrade = v2_upgrade,
164*cb00e90aSMateusz Kozlowski 	},
1658c41c403SKozlowski Mateusz };
1668c41c403SKozlowski Mateusz 
1678c41c403SKozlowski Mateusz SPDK_STATIC_ASSERT(SPDK_COUNTOF(band_upgrade_desc) == FTL_BAND_VERSION_CURRENT,
1688c41c403SKozlowski Mateusz 		   "Missing band region upgrade descriptors");
169