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