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");
|