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