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 "ftl_mngt.h"
7 : : #include "ftl_mngt_steps.h"
8 : : #include "ftl_internal.h"
9 : : #include "ftl_core.h"
10 : : #include "ftl_band.h"
11 : :
12 : : struct ftl_validate_ctx {
13 : : struct {
14 : : struct ftl_bitmap *bitmap;
15 : : void *buffer;
16 : : uint64_t buffer_size;
17 : : uint64_t bit_count;
18 : : uint64_t base_valid_count;
19 : : uint64_t cache_valid_count;
20 : : } valid_map;
21 : :
22 : : int status;
23 : : };
24 : :
25 : : static void
26 : 0 : ftl_mngt_test_prepare(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
27 : : {
28 : 0 : struct ftl_validate_ctx *cntx = ftl_mngt_get_process_ctx(mngt);
29 : :
30 : 0 : cntx->valid_map.bit_count = dev->layout.base.total_blocks +
31 : 0 : dev->layout.nvc.total_blocks;
32 : 0 : cntx->valid_map.buffer_size = spdk_divide_round_up(cntx->valid_map.bit_count, 8);
33 : 0 : cntx->valid_map.buffer_size = SPDK_ALIGN_CEIL(cntx->valid_map.buffer_size,
34 : : ftl_bitmap_buffer_alignment);
35 : :
36 : 0 : cntx->valid_map.buffer = calloc(cntx->valid_map.buffer_size, 1);
37 [ # # ]: 0 : if (!cntx->valid_map.buffer) {
38 : 0 : ftl_mngt_fail_step(mngt);
39 : 0 : return;
40 : : }
41 : :
42 : 0 : cntx->valid_map.bitmap = ftl_bitmap_create(cntx->valid_map.buffer,
43 : : cntx->valid_map.buffer_size);
44 [ # # ]: 0 : if (!cntx->valid_map.bitmap) {
45 : 0 : ftl_mngt_fail_step(mngt);
46 : 0 : return;
47 : : }
48 : :
49 : 0 : ftl_mngt_next_step(mngt);
50 : : }
51 : :
52 : : static void
53 : 0 : ftl_mngt_test_cleanup(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
54 : : {
55 : 0 : struct ftl_validate_ctx *cntx = ftl_mngt_get_process_ctx(mngt);
56 : :
57 : 0 : ftl_bitmap_destroy(cntx->valid_map.bitmap);
58 : 0 : cntx->valid_map.bitmap = NULL;
59 : :
60 : 0 : free(cntx->valid_map.buffer);
61 : 0 : cntx->valid_map.buffer = NULL;
62 : :
63 : 0 : ftl_mngt_next_step(mngt);
64 : 0 : }
65 : :
66 : : static void
67 : 0 : test_valid_map_pin_cb(struct spdk_ftl_dev *dev, int status,
68 : : struct ftl_l2p_pin_ctx *pin_ctx)
69 : : {
70 : 0 : struct ftl_mngt_process *mngt = pin_ctx->cb_ctx;
71 : 0 : struct ftl_validate_ctx *ctx = ftl_mngt_get_process_ctx(mngt);
72 : : uint64_t lba, end;
73 : :
74 [ # # ]: 0 : if (status) {
75 [ # # ]: 0 : FTL_ERRLOG(dev, "L2P pin ERROR when testing valid map\n");
76 : 0 : ftl_mngt_fail_step(mngt);
77 : 0 : return;
78 : : }
79 : :
80 : 0 : lba = pin_ctx->lba;
81 : 0 : end = pin_ctx->lba + pin_ctx->count;
82 : :
83 [ # # ]: 0 : for (; lba < end; ++lba) {
84 : 0 : ftl_addr addr = ftl_l2p_get(dev, lba);
85 : : bool valid;
86 : :
87 [ # # ]: 0 : if (FTL_ADDR_INVALID == addr) {
88 : 0 : continue;
89 : : }
90 : :
91 [ # # ]: 0 : if (ftl_bitmap_get(ctx->valid_map.bitmap, addr)) {
92 : 0 : status = -EINVAL;
93 [ # # ]: 0 : FTL_ERRLOG(dev, "L2P mapping ERROR, double reference, "
94 : : "address 0x%.16"PRIX64"\n", addr);
95 : 0 : break;
96 : : } else {
97 : 0 : ftl_bitmap_set(ctx->valid_map.bitmap, addr);
98 : : }
99 : :
100 [ # # ]: 0 : if (ftl_addr_in_nvc(dev, addr)) {
101 : 0 : ctx->valid_map.cache_valid_count++;
102 : : } else {
103 : 0 : ctx->valid_map.base_valid_count++;
104 : : }
105 : :
106 : 0 : valid = ftl_bitmap_get(dev->valid_map, addr);
107 [ # # ]: 0 : if (!valid) {
108 : 0 : status = -EINVAL;
109 [ # # ]: 0 : FTL_ERRLOG(dev, "L2P and valid map mismatch"
110 : : ", LBA 0x%.16"PRIX64
111 : : ", address 0x%.16"PRIX64" unset\n",
112 : : lba, addr);
113 : 0 : break;
114 : : }
115 : : }
116 : :
117 : 0 : ftl_l2p_unpin(dev, pin_ctx->lba, pin_ctx->count);
118 : 0 : pin_ctx->lba += pin_ctx->count;
119 : :
120 [ # # ]: 0 : if (!status) {
121 : 0 : ftl_mngt_continue_step(mngt);
122 : : } else {
123 : 0 : ftl_mngt_fail_step(mngt);
124 : : }
125 : : }
126 : :
127 : : static void
128 : 0 : ftl_mngt_test_valid_map(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
129 : : {
130 : : struct ftl_l2p_pin_ctx *pin_ctx;
131 : 0 : struct ftl_validate_ctx *ctx = ftl_mngt_get_process_ctx(mngt);
132 : : uint64_t left;
133 : :
134 : 0 : pin_ctx = ftl_mngt_get_step_ctx(mngt);
135 [ # # ]: 0 : if (!pin_ctx) {
136 [ # # ]: 0 : if (ftl_mngt_alloc_step_ctx(mngt, sizeof(*pin_ctx))) {
137 : 0 : ftl_mngt_fail_step(mngt);
138 : 0 : return;
139 : : }
140 : 0 : pin_ctx = ftl_mngt_get_step_ctx(mngt);
141 [ # # ]: 0 : assert(pin_ctx);
142 : :
143 : 0 : pin_ctx->lba = 0;
144 : 0 : memset(ctx->valid_map.buffer, 0, ctx->valid_map.buffer_size);
145 : : }
146 : :
147 : 0 : left = dev->num_lbas - pin_ctx->lba;
148 : 0 : pin_ctx->count = spdk_min(left, 4096);
149 : :
150 [ # # ]: 0 : if (pin_ctx->count) {
151 : 0 : ftl_l2p_pin(dev, pin_ctx->lba, pin_ctx->count,
152 : : test_valid_map_pin_cb, mngt, pin_ctx);
153 : : } else {
154 [ # # ]: 0 : if (!ctx->status) {
155 : 0 : uint64_t valid = ctx->valid_map.base_valid_count +
156 : 0 : ctx->valid_map.cache_valid_count;
157 : :
158 [ # # ]: 0 : if (ftl_bitmap_count_set(dev->valid_map) != valid) {
159 : 0 : ctx->status = -EINVAL;
160 : : }
161 : : }
162 : :
163 : : /* All done */
164 [ # # ]: 0 : if (ctx->status) {
165 : 0 : ftl_mngt_fail_step(mngt);
166 : : } else {
167 : 0 : ftl_mngt_next_step(mngt);
168 : : }
169 : : }
170 : : }
171 : :
172 : : /*
173 : : * Verifies the contents of L2P versus valid map. Makes sure any physical addresses in the L2P
174 : : * have their corresponding valid bits set and that two different logical addresses don't point
175 : : * to the same physical address.
176 : : *
177 : : * For debugging purposes only, directed via environment variable - whole L2P needs to be loaded in
178 : : * and checked.
179 : : */
180 : : static const struct ftl_mngt_process_desc desc_self_test = {
181 : : .name = "[Test] Startup Test",
182 : : .ctx_size = sizeof(struct ftl_validate_ctx),
183 : : .steps = {
184 : : {
185 : : .name = "[TEST] Initialize selftest",
186 : :
187 : : .action = ftl_mngt_test_prepare,
188 : : .cleanup = ftl_mngt_test_cleanup
189 : : },
190 : : {
191 : : .name = "[TEST] Validate map and L2P consistency",
192 : : .action = ftl_mngt_test_valid_map
193 : : },
194 : : {
195 : : .name = "[TEST] Deinitialize cleanup",
196 : : .action = ftl_mngt_test_cleanup
197 : : },
198 : : {}
199 : : }
200 : : };
201 : :
202 : : void
203 : 0 : ftl_mngt_self_test(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
204 : : {
205 [ # # ]: 0 : if (getenv("FTL_SELF_TEST")) {
206 : 0 : ftl_mngt_call_process(mngt, &desc_self_test, NULL);
207 : : } else {
208 [ # # ]: 0 : FTL_NOTICELOG(dev, "Self test skipped\n");
209 : 0 : ftl_mngt_next_step(mngt);
210 : : }
211 : 0 : }
|