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_nv_cache.h"
8 : : #include "ftl_layout_upgrade.h"
9 : : #include "ftl_utils.h"
10 : :
11 : : struct upgrade_ctx {
12 : : struct ftl_md *md;
13 : : struct ftl_layout_region reg;
14 : : };
15 : :
16 : : static void
17 : 0 : v0_to_v1_upgrade_cleanup(struct ftl_layout_upgrade_ctx *lctx)
18 : : {
19 : 0 : struct upgrade_ctx *ctx = lctx->ctx;
20 : :
21 [ # # ]: 0 : if (ctx->md) {
22 : 0 : ftl_md_destroy(ctx->md, 0);
23 : 0 : ctx->md = NULL;
24 : : }
25 : 0 : }
26 : :
27 : : static void
28 : 0 : v0_to_v1_upgrade_finish(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *lctx, int status)
29 : : {
30 : 0 : struct upgrade_ctx *ctx = lctx->ctx;
31 : :
32 : 0 : v0_to_v1_upgrade_cleanup(lctx);
33 : 0 : ftl_region_upgrade_completed(dev, lctx, ctx->reg.entry_size, ctx->reg.num_entries, status);
34 : 0 : }
35 : :
36 : : static void
37 : 0 : v0_to_v1_upgrade_md_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
38 : : {
39 : 0 : struct ftl_layout_upgrade_ctx *lctx = md->owner.cb_ctx;
40 : :
41 : 0 : v0_to_v1_upgrade_finish(dev, lctx, status);
42 : 0 : }
43 : :
44 : : static int
45 : 0 : v0_to_v1_upgrade_setup_ctx(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *lctx,
46 : : uint32_t type)
47 : : {
48 : 0 : struct upgrade_ctx *ctx = lctx->ctx;
49 : 0 : const struct ftl_md_layout_ops *md_ops = &dev->nv_cache.nvc_type->ops.md_layout_ops;
50 : :
51 : : /* Create the new NV cache metadata region - v2 */
52 [ # # ]: 0 : if (md_ops->region_open(dev, type, FTL_TRIM_LOG_VERSION_1, sizeof(struct ftl_trim_log), 1,
53 : : &ctx->reg)) {
54 : 0 : return -1;
55 : : }
56 : 0 : ctx->md = ftl_md_create(dev, ctx->reg.current.blocks, 0, ctx->reg.name, FTL_MD_CREATE_HEAP,
57 : 0 : &ctx->reg);
58 [ # # ]: 0 : if (!ctx->md) {
59 : 0 : return -1;
60 : : }
61 : :
62 : 0 : ctx->md->owner.cb_ctx = lctx;
63 : 0 : ctx->md->cb = v0_to_v1_upgrade_md_cb;
64 : :
65 : 0 : return 0;
66 : : }
67 : :
68 : : static int
69 : 0 : v0_to_v1_upgrade(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *lctx)
70 : : {
71 : 0 : struct upgrade_ctx *ctx = lctx->ctx;
72 : :
73 [ # # ]: 0 : if (v0_to_v1_upgrade_setup_ctx(dev, lctx, lctx->reg->type)) {
74 : 0 : goto error;
75 : : }
76 : 0 : ftl_md_clear(ctx->md, 0, NULL);
77 : 0 : return 0;
78 : :
79 : 0 : error:
80 : 0 : v0_to_v1_upgrade_cleanup(lctx);
81 : 0 : return -1;
82 : : }
83 : :
84 : : static int
85 : 0 : v0_to_v1_upgrade_enabled(struct spdk_ftl_dev *dev, struct ftl_layout_region *region)
86 : : {
87 : 0 : const struct ftl_md_layout_ops *md_ops = &dev->nv_cache.nvc_type->ops.md_layout_ops;
88 : :
89 : : assert(sizeof(struct ftl_nv_cache_chunk_md) == FTL_BLOCK_SIZE);
90 : :
91 [ # # ]: 0 : if (ftl_region_major_upgrade_enabled(dev, region)) {
92 : 0 : return -1;
93 : : }
94 : :
95 : : /* Create the new trim metadata region (v1) up front - this allocates a separate entry in the superblock and
96 : : * area on the cache for us. This is to reserve space for other region upgrades allocating new regions and it
97 : : * allows us to do an atomic upgrade of the whole region.
98 : : *
99 : : * If the upgrade is stopped by power failure/crash after the V1 region has been added, then the upgrade process
100 : : * will start again (since V0 still exists), but region_create will fail (since the v1 region has already been
101 : : * created). In such a case only verification of the region length by region_open is needed.
102 : : *
103 : : * Once the upgrade is fully done, the old v0 region entry will be removed from the SB and its area on the cache
104 : : * freed.
105 : : */
106 : :
107 : :
108 [ # # # # ]: 0 : if (md_ops->region_create(dev, region->type, FTL_TRIM_LOG_VERSION_1, 1) &&
109 : 0 : md_ops->region_open(dev, region->type, FTL_TRIM_LOG_VERSION_1, sizeof(struct ftl_trim_log),
110 : : 1, NULL)) {
111 : 0 : return -1;
112 : : }
113 : :
114 : 0 : return 0;
115 : : }
116 : :
117 : : struct ftl_region_upgrade_desc trim_log_upgrade_desc[] = {
118 : : [FTL_TRIM_LOG_VERSION_0] = {
119 : : .verify = v0_to_v1_upgrade_enabled,
120 : : .ctx_size = sizeof(struct upgrade_ctx),
121 : : .new_version = FTL_TRIM_LOG_VERSION_1,
122 : : .upgrade = v0_to_v1_upgrade,
123 : : },
124 : : };
125 : :
126 : : SPDK_STATIC_ASSERT(SPDK_COUNTOF(trim_log_upgrade_desc) == FTL_TRIM_LOG_VERSION_CURRENT,
127 : : "Missing NVC region upgrade descriptors");
|