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 "spdk/stdinc.h"
7 : : #include "spdk_internal/cunit.h"
8 : : #include "spdk/env.h"
9 : : #include "spdk_internal/mock.h"
10 : :
11 : : #include "common/lib/test_env.c"
12 : : #include "bdev/raid/bdev_raid_sb.c"
13 : :
14 : : #define TEST_BUF_ALIGN 64
15 : : #define TEST_BLOCK_SIZE 512
16 : :
17 : 105 : DEFINE_STUB(spdk_bdev_desc_get_bdev, struct spdk_bdev *, (struct spdk_bdev_desc *desc), NULL);
18 : 40 : DEFINE_STUB(spdk_bdev_get_block_size, uint32_t, (const struct spdk_bdev *bdev), TEST_BLOCK_SIZE);
19 : 0 : DEFINE_STUB(spdk_bdev_queue_io_wait, int, (struct spdk_bdev *bdev, struct spdk_io_channel *ch,
20 : : struct spdk_bdev_io_wait_entry *entry), 0);
21 : 20 : DEFINE_STUB(spdk_bdev_get_name, const char *, (const struct spdk_bdev *bdev), "test_bdev");
22 : 35 : DEFINE_STUB(spdk_bdev_get_buf_align, size_t, (const struct spdk_bdev *bdev), TEST_BUF_ALIGN);
23 : :
24 : : void *g_buf;
25 : : TAILQ_HEAD(, spdk_bdev_io) g_bdev_io_queue = TAILQ_HEAD_INITIALIZER(g_bdev_io_queue);
26 : : int g_read_counter;
27 : :
28 : : static int
29 : 5 : test_setup(void)
30 : : {
31 : 5 : g_buf = spdk_dma_zmalloc(RAID_BDEV_SB_MAX_LENGTH, TEST_BUF_ALIGN, NULL);
32 [ - + ]: 5 : if (!g_buf) {
33 : 0 : return -ENOMEM;
34 : : }
35 : :
36 : 5 : return 0;
37 : : }
38 : :
39 : : static int
40 : 5 : test_cleanup(void)
41 : : {
42 : 5 : spdk_dma_free(g_buf);
43 : :
44 : 5 : return 0;
45 : : }
46 : :
47 : : const struct spdk_uuid *
48 : 0 : spdk_bdev_get_uuid(const struct spdk_bdev *bdev)
49 : : {
50 : 0 : return &bdev->uuid;
51 : : }
52 : :
53 : : void
54 : 45 : spdk_bdev_free_io(struct spdk_bdev_io *bdev_io)
55 : : {
56 : 45 : free(bdev_io);
57 : 45 : }
58 : :
59 : : int
60 : 35 : spdk_bdev_read(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
61 : : void *buf, uint64_t offset, uint64_t nbytes,
62 : : spdk_bdev_io_completion_cb cb, void *cb_arg)
63 : : {
64 : 35 : g_read_counter++;
65 [ - + - + ]: 35 : memcpy(buf, g_buf + offset, nbytes);
66 : 35 : cb(NULL, true, cb_arg);
67 : 35 : return 0;
68 : : }
69 : :
70 : : int
71 : 10 : spdk_bdev_write(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
72 : : void *buf, uint64_t offset, uint64_t nbytes,
73 : : spdk_bdev_io_completion_cb cb, void *cb_arg)
74 : : {
75 : 10 : struct raid_bdev_superblock *sb = buf;
76 : : struct spdk_bdev_io *bdev_io;
77 : :
78 : 10 : CU_ASSERT(offset == 0);
79 : 10 : CU_ASSERT(nbytes / TEST_BLOCK_SIZE == spdk_divide_round_up(sb->length, TEST_BLOCK_SIZE));
80 : :
81 : 10 : bdev_io = calloc(1, sizeof(*bdev_io));
82 [ - + ]: 10 : SPDK_CU_ASSERT_FATAL(bdev_io != NULL);
83 : 10 : bdev_io->internal.cb = cb;
84 : 10 : bdev_io->internal.caller_ctx = cb_arg;
85 : :
86 : 10 : TAILQ_INSERT_TAIL(&g_bdev_io_queue, bdev_io, internal.link);
87 : :
88 : 10 : return 0;
89 : : }
90 : :
91 : : static void
92 : 5 : process_io_completions(void)
93 : : {
94 : : struct spdk_bdev_io *bdev_io;
95 : :
96 [ + + ]: 15 : while ((bdev_io = TAILQ_FIRST(&g_bdev_io_queue))) {
97 [ + + ]: 10 : TAILQ_REMOVE(&g_bdev_io_queue, bdev_io, internal.link);
98 : :
99 : 10 : bdev_io->internal.cb(bdev_io, true, bdev_io->internal.caller_ctx);
100 : : }
101 : 5 : }
102 : :
103 : : static void
104 : 60 : prepare_sb(struct raid_bdev_superblock *sb)
105 : : {
106 : : /* prepare a simplest valid sb */
107 [ - + ]: 60 : memset(sb, 0, RAID_BDEV_SB_MAX_LENGTH);
108 [ - + - + ]: 60 : memcpy(sb->signature, RAID_BDEV_SB_SIG, sizeof(sb->signature));
109 : 60 : sb->version.major = RAID_BDEV_SB_VERSION_MAJOR;
110 : 60 : sb->version.minor = RAID_BDEV_SB_VERSION_MINOR;
111 : 60 : sb->length = sizeof(*sb);
112 : 60 : sb->crc = spdk_crc32c_update(sb, sb->length, 0);
113 : 60 : }
114 : :
115 : : static void
116 : 5 : write_sb_cb(int status, struct raid_bdev *raid_bdev, void *ctx)
117 : : {
118 : 5 : int *status_out = ctx;
119 : :
120 : 5 : *status_out = status;
121 : 5 : }
122 : :
123 : : static void
124 : 5 : test_raid_bdev_write_superblock(void)
125 : : {
126 : 5 : struct raid_base_bdev_info base_info[3] = {{0}};
127 : 5 : struct raid_bdev raid_bdev = {
128 : : .sb = g_buf,
129 : : .num_base_bdevs = SPDK_COUNTOF(base_info),
130 : : .base_bdev_info = base_info,
131 : : };
132 : 4 : int status;
133 : : uint8_t i;
134 : :
135 [ + + ]: 15 : for (i = 1; i < SPDK_COUNTOF(base_info); i++) {
136 : 10 : base_info[i].desc = (void *)0x1;
137 : : }
138 : :
139 : 5 : prepare_sb(raid_bdev.sb);
140 : :
141 : 5 : status = INT_MAX;
142 : 5 : raid_bdev_write_superblock(&raid_bdev, write_sb_cb, &status);
143 : 5 : CU_ASSERT(TAILQ_EMPTY(&g_bdev_io_queue) == false);
144 : 5 : process_io_completions();
145 : 5 : CU_ASSERT(status == 0);
146 : 5 : }
147 : :
148 : : static void
149 : 25 : load_sb_cb(const struct raid_bdev_superblock *sb, int status, void *ctx)
150 : : {
151 : 25 : int *status_out = ctx;
152 : :
153 [ + + ]: 25 : if (status == 0) {
154 [ - + - + ]: 10 : CU_ASSERT(memcmp(sb, g_buf, sb->length) == 0);
155 : : }
156 : :
157 : 25 : *status_out = status;
158 : 25 : }
159 : :
160 : : static void
161 : 5 : test_raid_bdev_load_base_bdev_superblock(void)
162 : : {
163 : 5 : struct raid_bdev_superblock *sb = g_buf;
164 : : int rc;
165 : 4 : int status;
166 : :
167 : : /* valid superblock */
168 : 5 : prepare_sb(sb);
169 : :
170 : 5 : g_read_counter = 0;
171 : 5 : status = INT_MAX;
172 : 5 : rc = raid_bdev_load_base_bdev_superblock(NULL, NULL, load_sb_cb, &status);
173 : 5 : CU_ASSERT(rc == 0);
174 : 5 : CU_ASSERT(status == 0);
175 : 5 : CU_ASSERT(g_read_counter == 1);
176 : :
177 : : /* invalid signature */
178 : 5 : prepare_sb(sb);
179 : 5 : sb->signature[3] = 'Z';
180 : 5 : raid_bdev_sb_update_crc(sb);
181 : :
182 : 5 : g_read_counter = 0;
183 : 5 : status = INT_MAX;
184 : 5 : rc = raid_bdev_load_base_bdev_superblock(NULL, NULL, load_sb_cb, &status);
185 : 5 : CU_ASSERT(rc == 0);
186 : 5 : CU_ASSERT(status == -EINVAL);
187 : 5 : CU_ASSERT(g_read_counter == 1);
188 : :
189 : : /* make the sb longer than 1 bdev block - expect 2 reads */
190 : 5 : prepare_sb(sb);
191 : 5 : sb->length = TEST_BLOCK_SIZE * 3;
192 : 5 : raid_bdev_sb_update_crc(sb);
193 : :
194 : 5 : g_read_counter = 0;
195 : 5 : status = INT_MAX;
196 : 5 : rc = raid_bdev_load_base_bdev_superblock(NULL, NULL, load_sb_cb, &status);
197 : 5 : CU_ASSERT(rc == 0);
198 : 5 : CU_ASSERT(status == 0);
199 : 5 : CU_ASSERT(g_read_counter == 2);
200 : :
201 : : /* corrupted sb contents, length > 1 bdev block - expect 2 reads */
202 : 5 : prepare_sb(sb);
203 : 5 : sb->length = TEST_BLOCK_SIZE * 3;
204 : 5 : raid_bdev_sb_update_crc(sb);
205 : 5 : sb->reserved[0] = 0xff;
206 : :
207 : 5 : g_read_counter = 0;
208 : 5 : status = INT_MAX;
209 : 5 : rc = raid_bdev_load_base_bdev_superblock(NULL, NULL, load_sb_cb, &status);
210 : 5 : CU_ASSERT(rc == 0);
211 : 5 : CU_ASSERT(status == -EINVAL);
212 : 5 : CU_ASSERT(g_read_counter == 2);
213 : :
214 : : /* invalid signature, length > 1 bdev block - expect 1 read */
215 : 5 : prepare_sb(sb);
216 : 5 : sb->signature[3] = 'Z';
217 : 5 : sb->length = TEST_BLOCK_SIZE * 3;
218 : 5 : raid_bdev_sb_update_crc(sb);
219 : :
220 : 5 : g_read_counter = 0;
221 : 5 : status = INT_MAX;
222 : 5 : rc = raid_bdev_load_base_bdev_superblock(NULL, NULL, load_sb_cb, &status);
223 : 5 : CU_ASSERT(rc == 0);
224 : 5 : CU_ASSERT(status == -EINVAL);
225 : 5 : CU_ASSERT(g_read_counter == 1);
226 : 5 : }
227 : :
228 : : static void
229 : 5 : test_raid_bdev_parse_superblock(void)
230 : : {
231 : 5 : struct raid_bdev_superblock *sb = g_buf;
232 : 5 : struct raid_bdev_read_sb_ctx ctx = {
233 : : .buf = g_buf,
234 : : .buf_size = TEST_BLOCK_SIZE,
235 : : };
236 : :
237 : : /* valid superblock */
238 : 5 : prepare_sb(sb);
239 : 5 : CU_ASSERT(raid_bdev_parse_superblock(&ctx) == 0);
240 : :
241 : : /* invalid signature */
242 : 5 : prepare_sb(sb);
243 : 5 : sb->signature[3] = 'Z';
244 : 5 : raid_bdev_sb_update_crc(sb);
245 : 5 : CU_ASSERT(raid_bdev_parse_superblock(&ctx) == -EINVAL);
246 : :
247 : : /* invalid crc */
248 : 5 : prepare_sb(sb);
249 : 5 : sb->crc = 0xdeadbeef;
250 : 5 : CU_ASSERT(raid_bdev_parse_superblock(&ctx) == -EINVAL);
251 : :
252 : : /* corrupted sb contents */
253 : 5 : prepare_sb(sb);
254 : 5 : sb->reserved[0] = 0xff;
255 : 5 : CU_ASSERT(raid_bdev_parse_superblock(&ctx) == -EINVAL);
256 : :
257 : : /* invalid major version */
258 : 5 : prepare_sb(sb);
259 : 5 : sb->version.major = 9999;
260 : 5 : raid_bdev_sb_update_crc(sb);
261 : 5 : CU_ASSERT(raid_bdev_parse_superblock(&ctx) == -EINVAL);
262 : :
263 : : /* sb longer than 1 bdev block */
264 : 5 : prepare_sb(sb);
265 : 5 : sb->length = TEST_BLOCK_SIZE * 3;
266 : 5 : raid_bdev_sb_update_crc(sb);
267 : 5 : CU_ASSERT(raid_bdev_parse_superblock(&ctx) == -EAGAIN);
268 : 5 : ctx.buf_size = sb->length;
269 : 5 : CU_ASSERT(raid_bdev_parse_superblock(&ctx) == 0);
270 : 5 : }
271 : :
272 : : int
273 : 5 : main(int argc, char **argv)
274 : : {
275 : 5 : CU_pSuite suite = NULL;
276 : : unsigned int num_failures;
277 : :
278 : 5 : CU_initialize_registry();
279 : :
280 : 5 : suite = CU_add_suite("raid_sb", test_setup, test_cleanup);
281 : 5 : CU_ADD_TEST(suite, test_raid_bdev_write_superblock);
282 : 5 : CU_ADD_TEST(suite, test_raid_bdev_load_base_bdev_superblock);
283 : 5 : CU_ADD_TEST(suite, test_raid_bdev_parse_superblock);
284 : :
285 : 5 : num_failures = spdk_ut_run_tests(argc, argv, NULL);
286 : 5 : CU_cleanup_registry();
287 : 5 : return num_failures;
288 : : }
|