Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2022 Intel Corporation.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "mngt/ftl_mngt.h"
7 : : #include "mngt/ftl_mngt_steps.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_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 int
44 : 0 : v2_upgrade_setup_ctx(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *lctx, uint32_t type)
45 : : {
46 : 0 : struct upgrade_ctx *ctx = lctx->ctx;
47 : 0 : const struct ftl_md_layout_ops *md_ops = &dev->nv_cache.nvc_type->ops.md_layout_ops;
48 : :
49 : : /* TODO Add validation if no open bands */
50 : :
51 : : /* Open metadata region */
52 [ # # ]: 0 : if (md_ops->region_open(dev, lctx->reg->type, FTL_P2L_VERSION_2,
53 : : sizeof(struct ftl_p2l_ckpt_page_no_vss),
54 : : dev->layout.p2l.ckpt_pages, &ctx->reg)) {
55 : 0 : return -1;
56 : : }
57 : :
58 : 0 : ctx->md = ftl_md_create(dev, ctx->reg.current.blocks, 0, ctx->reg.name, FTL_MD_CREATE_HEAP,
59 : 0 : &ctx->reg);
60 [ # # ]: 0 : if (!ctx->md) {
61 : 0 : return -1;
62 : : }
63 : :
64 : 0 : ctx->md->owner.cb_ctx = lctx;
65 : 0 : ctx->md->cb = v2_upgrade_md_cb;
66 : :
67 : 0 : return 0;
68 : : }
69 : :
70 : : static int
71 : 0 : v2_upgrade(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *lctx)
72 : : {
73 : 0 : struct upgrade_ctx *ctx = lctx->ctx;
74 : :
75 [ # # ]: 0 : if (v2_upgrade_setup_ctx(dev, lctx, lctx->reg->type)) {
76 : 0 : goto error;
77 : : }
78 : 0 : ftl_md_clear(ctx->md, 0, NULL);
79 : 0 : return 0;
80 : 0 : error:
81 : 0 : v2_upgrade_cleanup(lctx);
82 : 0 : return -1;
83 : : }
84 : :
85 : : static int
86 : 0 : v1_to_v2_upgrade_enabled(struct spdk_ftl_dev *dev, struct ftl_layout_region *region)
87 : : {
88 : 0 : const struct ftl_md_layout_ops *md_ops = &dev->nv_cache.nvc_type->ops.md_layout_ops;
89 : :
90 [ # # ]: 0 : if (ftl_region_major_upgrade_enabled(dev, region)) {
91 : 0 : return -1;
92 : : }
93 : :
94 : : /* Create the new P2L metadata region (v2) up front - this allocates a separate entry in the superblock and
95 : : * area on the cache for us. This is to reserve space for other region upgrades allocating new regions and it
96 : : * allows us to do an atomic upgrade of the whole region.
97 : : *
98 : : * If the upgrade is stopped by power failure/crash after the V2 region has been added, then the upgrade process
99 : : * will start again (since V1 still exists), but region_create will fail (since the v2 region has already been
100 : : * created). In such a case only verification of the region length by region_open is needed.
101 : : *
102 : : * Once the upgrade is fully done, the old v1 region entry will be removed from the SB and its area on the cache
103 : : * freed.
104 : : */
105 [ # # # # ]: 0 : if (md_ops->region_create(dev, region->type, FTL_P2L_VERSION_2, dev->layout.p2l.ckpt_pages) &&
106 : 0 : md_ops->region_open(dev, region->type, FTL_P2L_VERSION_2, sizeof(struct ftl_p2l_ckpt_page_no_vss),
107 : : dev->layout.p2l.ckpt_pages, NULL)) {
108 : 0 : return -1;
109 : : }
110 : :
111 : 0 : return 0;
112 : : }
113 : :
114 : : struct ftl_region_upgrade_desc p2l_upgrade_desc[] = {
115 : : [FTL_P2L_VERSION_0] = {
116 : : .verify = ftl_region_upgrade_disabled
117 : : },
118 : : [FTL_P2L_VERSION_1] = {
119 : : .verify = v1_to_v2_upgrade_enabled,
120 : : .ctx_size = sizeof(struct upgrade_ctx),
121 : : .new_version = FTL_P2L_VERSION_2,
122 : : .upgrade = v2_upgrade,
123 : : },
124 : : };
125 : :
126 : : SPDK_STATIC_ASSERT(SPDK_COUNTOF(p2l_upgrade_desc) == FTL_P2L_VERSION_CURRENT,
127 : : "Missing P2L region upgrade descriptors");
|