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
16 DEFINE_STUB(spdk_bdev_queue_io_wait, int, (struct spdk_bdev *bdev, struct spdk_io_channel *ch,
17 struct spdk_bdev_io_wait_entry *entry), 0);
18 DEFINE_STUB(spdk_bdev_get_name, const char *, (const struct spdk_bdev *bdev), "test_bdev");
19 DEFINE_STUB(spdk_bdev_get_buf_align, size_t, (const struct spdk_bdev *bdev), TEST_BUF_ALIGN);
20
21 void *g_buf;
22 TAILQ_HEAD(, spdk_bdev_io) g_bdev_io_queue = TAILQ_HEAD_INITIALIZER(g_bdev_io_queue);
23 int g_read_counter;
24 int g_write_counter;
25 struct spdk_bdev g_bdev;
26 struct spdk_bdev_io g_bdev_io = {
27 .bdev = &g_bdev,
28 };
29
30 static int
_test_setup(uint32_t blocklen,uint32_t md_len)31 _test_setup(uint32_t blocklen, uint32_t md_len)
32 {
33 g_bdev.blocklen = blocklen;
34 g_bdev.md_len = md_len;
35
36 g_buf = spdk_dma_zmalloc(SPDK_ALIGN_CEIL(RAID_BDEV_SB_MAX_LENGTH,
37 spdk_bdev_get_data_block_size(&g_bdev)), TEST_BUF_ALIGN, NULL);
38 if (!g_buf) {
39 return -ENOMEM;
40 }
41
42 return 0;
43 }
44
45 static int
test_setup(void)46 test_setup(void)
47 {
48 return _test_setup(512, 0);
49 }
50
51 static int
test_setup_md(void)52 test_setup_md(void)
53 {
54 return _test_setup(512, 8);
55 }
56
57 static int
test_setup_md_interleaved(void)58 test_setup_md_interleaved(void)
59 {
60 return _test_setup(512 + 8, 8);
61 }
62
63 static int
test_cleanup(void)64 test_cleanup(void)
65 {
66 spdk_dma_free(g_buf);
67
68 return 0;
69 }
70
71 bool
spdk_bdev_is_md_interleaved(const struct spdk_bdev * bdev)72 spdk_bdev_is_md_interleaved(const struct spdk_bdev *bdev)
73 {
74 return spdk_u32_is_pow2(bdev->blocklen) == false;
75 }
76
77 uint32_t
spdk_bdev_get_data_block_size(const struct spdk_bdev * bdev)78 spdk_bdev_get_data_block_size(const struct spdk_bdev *bdev)
79 {
80 return spdk_bdev_is_md_interleaved(bdev) ? bdev->blocklen - bdev->md_len : bdev->blocklen;
81 }
82
83 struct spdk_bdev *
spdk_bdev_desc_get_bdev(struct spdk_bdev_desc * desc)84 spdk_bdev_desc_get_bdev(struct spdk_bdev_desc *desc)
85 {
86 return &g_bdev;
87 }
88
89 const struct spdk_uuid *
spdk_bdev_get_uuid(const struct spdk_bdev * bdev)90 spdk_bdev_get_uuid(const struct spdk_bdev *bdev)
91 {
92 return &bdev->uuid;
93 }
94
95 void
spdk_bdev_free_io(struct spdk_bdev_io * bdev_io)96 spdk_bdev_free_io(struct spdk_bdev_io *bdev_io)
97 {
98 if (bdev_io != &g_bdev_io) {
99 free(bdev_io);
100 }
101 }
102
103 int
spdk_bdev_read(struct spdk_bdev_desc * desc,struct spdk_io_channel * ch,void * buf,uint64_t offset,uint64_t nbytes,spdk_bdev_io_completion_cb cb,void * cb_arg)104 spdk_bdev_read(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
105 void *buf, uint64_t offset, uint64_t nbytes,
106 spdk_bdev_io_completion_cb cb, void *cb_arg)
107 {
108 struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(desc);
109 struct spdk_bdev_io *bdev_io = &g_bdev_io;
110 uint64_t offset_blocks = offset / bdev->blocklen;
111 uint32_t data_block_size = spdk_bdev_get_data_block_size(bdev);
112 void *src = g_buf + offset_blocks * data_block_size;
113
114 g_read_counter++;
115
116 memset(buf, 0xab, nbytes);
117
118 while (nbytes > 0) {
119 memcpy(buf, src, data_block_size);
120 src += data_block_size;
121 buf += bdev->blocklen;
122 nbytes -= bdev->blocklen;
123 }
124
125 cb(bdev_io, true, cb_arg);
126 return 0;
127 }
128
129 int
spdk_bdev_write(struct spdk_bdev_desc * desc,struct spdk_io_channel * ch,void * buf,uint64_t offset,uint64_t nbytes,spdk_bdev_io_completion_cb cb,void * cb_arg)130 spdk_bdev_write(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
131 void *buf, uint64_t offset, uint64_t nbytes,
132 spdk_bdev_io_completion_cb cb, void *cb_arg)
133 {
134 struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(desc);
135 struct raid_bdev_superblock *sb = buf;
136 struct spdk_bdev_io *bdev_io;
137 void *dest = g_buf;
138 uint32_t data_block_size = spdk_bdev_get_data_block_size(bdev);
139
140 g_write_counter++;
141 CU_ASSERT(offset == 0);
142 CU_ASSERT(nbytes == spdk_divide_round_up(sb->length, data_block_size) * bdev->blocklen);
143
144 while (nbytes > 0) {
145 memcpy(dest, buf, data_block_size);
146 dest += data_block_size;
147 buf += bdev->blocklen;
148 nbytes -= bdev->blocklen;
149 }
150
151 bdev_io = calloc(1, sizeof(*bdev_io));
152 SPDK_CU_ASSERT_FATAL(bdev_io != NULL);
153 bdev_io->internal.cb = cb;
154 bdev_io->internal.caller_ctx = cb_arg;
155 bdev_io->bdev = bdev;
156
157 TAILQ_INSERT_TAIL(&g_bdev_io_queue, bdev_io, internal.link);
158
159 return 0;
160 }
161
162 static void
process_io_completions(void)163 process_io_completions(void)
164 {
165 struct spdk_bdev_io *bdev_io;
166
167 while ((bdev_io = TAILQ_FIRST(&g_bdev_io_queue))) {
168 TAILQ_REMOVE(&g_bdev_io_queue, bdev_io, internal.link);
169
170 bdev_io->internal.cb(bdev_io, true, bdev_io->internal.caller_ctx);
171 }
172 }
173
174 static void
prepare_sb(struct raid_bdev_superblock * sb)175 prepare_sb(struct raid_bdev_superblock *sb)
176 {
177 /* prepare a simplest valid sb */
178 memset(sb, 0, RAID_BDEV_SB_MAX_LENGTH);
179 memcpy(sb->signature, RAID_BDEV_SB_SIG, sizeof(sb->signature));
180 sb->version.major = RAID_BDEV_SB_VERSION_MAJOR;
181 sb->version.minor = RAID_BDEV_SB_VERSION_MINOR;
182 sb->length = sizeof(*sb);
183 sb->crc = spdk_crc32c_update(sb, sb->length, 0);
184 }
185
186 static void
write_sb_cb(int status,struct raid_bdev * raid_bdev,void * ctx)187 write_sb_cb(int status, struct raid_bdev *raid_bdev, void *ctx)
188 {
189 int *status_out = ctx;
190
191 *status_out = status;
192 }
193
194 static void
test_raid_bdev_write_superblock(void)195 test_raid_bdev_write_superblock(void)
196 {
197 struct raid_base_bdev_info base_info[3] = {{0}};
198 struct raid_bdev raid_bdev = {
199 .num_base_bdevs = SPDK_COUNTOF(base_info),
200 .base_bdev_info = base_info,
201 .bdev = g_bdev,
202 };
203 int status;
204 uint8_t i;
205
206 for (i = 0; i < SPDK_COUNTOF(base_info); i++) {
207 base_info[i].raid_bdev = &raid_bdev;
208 if (i > 0) {
209 base_info[i].is_configured = true;
210 }
211 }
212
213 status = raid_bdev_alloc_superblock(&raid_bdev, spdk_bdev_get_data_block_size(&raid_bdev.bdev));
214 CU_ASSERT(status == 0);
215
216 /* test initial sb write */
217 raid_bdev_init_superblock(&raid_bdev);
218
219 status = INT_MAX;
220 g_write_counter = 0;
221 raid_bdev_write_superblock(&raid_bdev, write_sb_cb, &status);
222 CU_ASSERT(g_write_counter == raid_bdev.num_base_bdevs - 1);
223 CU_ASSERT(TAILQ_EMPTY(&g_bdev_io_queue) == false);
224 process_io_completions();
225 CU_ASSERT(status == 0);
226 CU_ASSERT(memcmp(raid_bdev.sb, g_buf, raid_bdev.sb->length) == 0);
227
228 /* test max size sb write */
229 raid_bdev.sb->length = RAID_BDEV_SB_MAX_LENGTH;
230 if (spdk_bdev_is_md_interleaved(&raid_bdev.bdev)) {
231 SPDK_CU_ASSERT_FATAL(raid_bdev.sb_io_buf != raid_bdev.sb);
232 spdk_dma_free(raid_bdev.sb_io_buf);
233 }
234 raid_bdev.sb_io_buf = NULL;
235
236 status = INT_MAX;
237 g_write_counter = 0;
238 raid_bdev_write_superblock(&raid_bdev, write_sb_cb, &status);
239 CU_ASSERT(g_write_counter == raid_bdev.num_base_bdevs - 1);
240 CU_ASSERT(TAILQ_EMPTY(&g_bdev_io_queue) == false);
241 process_io_completions();
242 CU_ASSERT(status == 0);
243 CU_ASSERT(memcmp(raid_bdev.sb, g_buf, raid_bdev.sb->length) == 0);
244
245 raid_bdev_free_superblock(&raid_bdev);
246 }
247
248 static void
load_sb_cb(const struct raid_bdev_superblock * sb,int status,void * ctx)249 load_sb_cb(const struct raid_bdev_superblock *sb, int status, void *ctx)
250 {
251 int *status_out = ctx;
252
253 if (status == 0) {
254 CU_ASSERT(memcmp(sb, g_buf, sb->length) == 0);
255 }
256
257 *status_out = status;
258 }
259
260 static void
test_raid_bdev_load_base_bdev_superblock(void)261 test_raid_bdev_load_base_bdev_superblock(void)
262 {
263 const uint32_t data_block_size = spdk_bdev_get_data_block_size(&g_bdev);
264 struct raid_bdev_superblock *sb = g_buf;
265 int rc;
266 int status;
267
268 /* valid superblock */
269 prepare_sb(sb);
270
271 g_read_counter = 0;
272 status = INT_MAX;
273 rc = raid_bdev_load_base_bdev_superblock(NULL, NULL, load_sb_cb, &status);
274 CU_ASSERT(rc == 0);
275 CU_ASSERT(status == 0);
276 CU_ASSERT(g_read_counter == 1);
277
278 /* invalid signature */
279 prepare_sb(sb);
280 sb->signature[3] = 'Z';
281 raid_bdev_sb_update_crc(sb);
282
283 g_read_counter = 0;
284 status = INT_MAX;
285 rc = raid_bdev_load_base_bdev_superblock(NULL, NULL, load_sb_cb, &status);
286 CU_ASSERT(rc == 0);
287 CU_ASSERT(status == -EINVAL);
288 CU_ASSERT(g_read_counter == 1);
289
290 /* make the sb longer than 1 bdev block - expect 2 reads */
291 prepare_sb(sb);
292 sb->length = data_block_size * 3;
293 memset(sb->base_bdevs, 0xef, sb->length - offsetof(struct raid_bdev_superblock, base_bdevs));
294 raid_bdev_sb_update_crc(sb);
295
296 g_read_counter = 0;
297 status = INT_MAX;
298 rc = raid_bdev_load_base_bdev_superblock(NULL, NULL, load_sb_cb, &status);
299 CU_ASSERT(rc == 0);
300 CU_ASSERT(status == 0);
301 CU_ASSERT(g_read_counter == 2);
302
303 /* corrupted sb contents, length > 1 bdev block - expect 2 reads */
304 prepare_sb(sb);
305 sb->length = data_block_size * 3;
306 raid_bdev_sb_update_crc(sb);
307 sb->reserved[0] = 0xff;
308
309 g_read_counter = 0;
310 status = INT_MAX;
311 rc = raid_bdev_load_base_bdev_superblock(NULL, NULL, load_sb_cb, &status);
312 CU_ASSERT(rc == 0);
313 CU_ASSERT(status == -EINVAL);
314 CU_ASSERT(g_read_counter == 2);
315
316 /* invalid signature, length > 1 bdev block - expect 1 read */
317 prepare_sb(sb);
318 sb->signature[3] = 'Z';
319 sb->length = data_block_size * 3;
320 raid_bdev_sb_update_crc(sb);
321
322 g_read_counter = 0;
323 status = INT_MAX;
324 rc = raid_bdev_load_base_bdev_superblock(NULL, NULL, load_sb_cb, &status);
325 CU_ASSERT(rc == 0);
326 CU_ASSERT(status == -EINVAL);
327 CU_ASSERT(g_read_counter == 1);
328 }
329
330 static void
test_raid_bdev_parse_superblock(void)331 test_raid_bdev_parse_superblock(void)
332 {
333 struct raid_bdev_superblock *sb = g_buf;
334 struct raid_bdev_read_sb_ctx ctx = {
335 .buf = g_buf,
336 .buf_size = g_bdev.blocklen,
337 };
338
339 /* valid superblock */
340 prepare_sb(sb);
341 CU_ASSERT(raid_bdev_parse_superblock(&ctx) == 0);
342
343 /* invalid signature */
344 prepare_sb(sb);
345 sb->signature[3] = 'Z';
346 raid_bdev_sb_update_crc(sb);
347 CU_ASSERT(raid_bdev_parse_superblock(&ctx) == -EINVAL);
348
349 /* invalid crc */
350 prepare_sb(sb);
351 sb->crc = 0xdeadbeef;
352 CU_ASSERT(raid_bdev_parse_superblock(&ctx) == -EINVAL);
353
354 /* corrupted sb contents */
355 prepare_sb(sb);
356 sb->reserved[0] = 0xff;
357 CU_ASSERT(raid_bdev_parse_superblock(&ctx) == -EINVAL);
358
359 /* invalid major version */
360 prepare_sb(sb);
361 sb->version.major = 9999;
362 raid_bdev_sb_update_crc(sb);
363 CU_ASSERT(raid_bdev_parse_superblock(&ctx) == -EINVAL);
364
365 /* sb longer than 1 bdev block */
366 prepare_sb(sb);
367 sb->length = spdk_bdev_get_data_block_size(&g_bdev) * 3;
368 raid_bdev_sb_update_crc(sb);
369 CU_ASSERT(raid_bdev_parse_superblock(&ctx) == -EAGAIN);
370 ctx.buf_size = g_bdev.blocklen * 3;
371 CU_ASSERT(raid_bdev_parse_superblock(&ctx) == 0);
372
373 /* invalid base bdev slot number */
374 prepare_sb(sb);
375 sb->base_bdevs[0].slot = sb->num_base_bdevs = sb->base_bdevs_size = 2;
376 raid_bdev_sb_update_crc(sb);
377 CU_ASSERT(raid_bdev_parse_superblock(&ctx) == -EINVAL);
378 }
379
380 int
main(int argc,char ** argv)381 main(int argc, char **argv)
382 {
383 unsigned int num_failures;
384 CU_TestInfo tests[] = {
385 { "test_raid_bdev_write_superblock", test_raid_bdev_write_superblock },
386 { "test_raid_bdev_load_base_bdev_superblock", test_raid_bdev_load_base_bdev_superblock },
387 { "test_raid_bdev_parse_superblock", test_raid_bdev_parse_superblock },
388 CU_TEST_INFO_NULL,
389 };
390 CU_SuiteInfo suites[] = {
391 { "raid_sb", test_setup, test_cleanup, NULL, NULL, tests },
392 { "raid_sb_md", test_setup_md, test_cleanup, NULL, NULL, tests },
393 { "raid_sb_md_interleaved", test_setup_md_interleaved, test_cleanup, NULL, NULL, tests },
394 CU_SUITE_INFO_NULL,
395 };
396
397 CU_initialize_registry();
398 CU_register_suites(suites);
399 num_failures = spdk_ut_run_tests(argc, argv, NULL);
400 CU_cleanup_registry();
401 return num_failures;
402 }
403