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/xor.h"
10 : :
11 : : #include "common/lib/ut_multithread.c"
12 : :
13 : : #include "bdev/raid/raid5f.c"
14 : : #include "../common.c"
15 : :
16 : : static void *g_accel_p = (void *)0xdeadbeaf;
17 : : static bool g_test_degraded;
18 : :
19 : 1 : DEFINE_STUB_V(raid_bdev_module_list_add, (struct raid_bdev_module *raid_module));
20 : 4224 : DEFINE_STUB(spdk_bdev_get_buf_align, size_t, (const struct spdk_bdev *bdev), 0);
21 : 528 : DEFINE_STUB_V(raid_bdev_module_stop_done, (struct raid_bdev *raid_bdev));
22 : 462 : DEFINE_STUB(accel_channel_create, int, (void *io_device, void *ctx_buf), 0);
23 : 462 : DEFINE_STUB_V(accel_channel_destroy, (void *io_device, void *ctx_buf));
24 : 0 : DEFINE_STUB_V(raid_bdev_process_request_complete, (struct raid_bdev_process_request *process_req,
25 : : int status));
26 : 0 : DEFINE_STUB_V(raid_bdev_io_init, (struct raid_bdev_io *raid_io,
27 : : struct raid_bdev_io_channel *raid_ch,
28 : : enum spdk_bdev_io_type type, uint64_t offset_blocks,
29 : : uint64_t num_blocks, struct iovec *iovs, int iovcnt, void *md_buf,
30 : : struct spdk_memory_domain *memory_domain, void *memory_domain_ctx));
31 : :
32 : : struct spdk_io_channel *
33 : 462 : spdk_accel_get_io_channel(void)
34 : : {
35 : 462 : return spdk_get_io_channel(g_accel_p);
36 : : }
37 : :
38 : : uint32_t
39 : 37609 : spdk_bdev_get_md_size(const struct spdk_bdev *bdev)
40 : : {
41 : 37609 : return bdev->md_len;
42 : : }
43 : :
44 : : struct xor_ctx {
45 : : spdk_accel_completion_cb cb_fn;
46 : : void *cb_arg;
47 : : };
48 : :
49 : : static void
50 : 42585 : finish_xor(void *_ctx)
51 : : {
52 : 42585 : struct xor_ctx *ctx = _ctx;
53 : :
54 : 42585 : ctx->cb_fn(ctx->cb_arg, 0);
55 : :
56 : 42585 : free(ctx);
57 : 42585 : }
58 : :
59 : : int
60 : 42585 : spdk_accel_submit_xor(struct spdk_io_channel *ch, void *dst, void **sources, uint32_t nsrcs,
61 : : uint64_t nbytes, spdk_accel_completion_cb cb_fn, void *cb_arg)
62 : : {
63 : : struct xor_ctx *ctx;
64 : :
65 : 42585 : ctx = malloc(sizeof(*ctx));
66 [ - + ]: 42585 : SPDK_CU_ASSERT_FATAL(ctx != NULL);
67 : 42585 : ctx->cb_fn = cb_fn;
68 : 42585 : ctx->cb_arg = cb_arg;
69 [ - + ]: 42585 : SPDK_CU_ASSERT_FATAL(spdk_xor_gen(dst, sources, nsrcs, nbytes) == 0);
70 : :
71 : 42585 : spdk_thread_send_msg(spdk_get_thread(), finish_xor, ctx);
72 : :
73 : 42585 : return 0;
74 : : }
75 : :
76 : : static void
77 : 1 : init_accel(void)
78 : : {
79 : 1 : spdk_io_device_register(g_accel_p, accel_channel_create, accel_channel_destroy,
80 : : sizeof(int), "accel_p");
81 : 1 : }
82 : :
83 : : static void
84 : 1 : fini_accel(void)
85 : : {
86 : 1 : spdk_io_device_unregister(g_accel_p, NULL);
87 : 1 : }
88 : :
89 : : static int
90 : 1 : test_suite_init(void)
91 : : {
92 : 1 : uint8_t num_base_bdevs_values[] = { 3, 4, 5 };
93 : 1 : uint64_t base_bdev_blockcnt_values[] = { 1, 1024, 1024 * 1024 };
94 : 1 : uint32_t base_bdev_blocklen_values[] = { 512, 4096 };
95 : 1 : uint32_t strip_size_kb_values[] = { 1, 4, 128 };
96 : 1 : uint32_t md_len_values[] = { 0, 64 };
97 : : uint8_t *num_base_bdevs;
98 : : uint64_t *base_bdev_blockcnt;
99 : : uint32_t *base_bdev_blocklen;
100 : : uint32_t *strip_size_kb;
101 : : uint32_t *md_len;
102 : 1 : struct raid_params params;
103 : : uint64_t params_count;
104 : : int rc;
105 : :
106 : 1 : params_count = SPDK_COUNTOF(num_base_bdevs_values) *
107 : : SPDK_COUNTOF(base_bdev_blockcnt_values) *
108 : : SPDK_COUNTOF(base_bdev_blocklen_values) *
109 : : SPDK_COUNTOF(strip_size_kb_values) *
110 : : SPDK_COUNTOF(md_len_values);
111 : 1 : rc = raid_test_params_alloc(params_count);
112 [ - + ]: 1 : if (rc) {
113 : 0 : return rc;
114 : : }
115 : :
116 [ + + ]: 4 : ARRAY_FOR_EACH(num_base_bdevs_values, num_base_bdevs) {
117 [ + + ]: 12 : ARRAY_FOR_EACH(base_bdev_blockcnt_values, base_bdev_blockcnt) {
118 [ + + ]: 27 : ARRAY_FOR_EACH(base_bdev_blocklen_values, base_bdev_blocklen) {
119 [ + + ]: 72 : ARRAY_FOR_EACH(strip_size_kb_values, strip_size_kb) {
120 [ + + ]: 162 : ARRAY_FOR_EACH(md_len_values, md_len) {
121 : 108 : params.num_base_bdevs = *num_base_bdevs;
122 : 108 : params.base_bdev_blockcnt = *base_bdev_blockcnt;
123 : 108 : params.base_bdev_blocklen = *base_bdev_blocklen;
124 [ - + ]: 108 : params.strip_size = *strip_size_kb * 1024 / *base_bdev_blocklen;
125 : 108 : params.md_len = *md_len;
126 [ + + ]: 108 : if (params.strip_size == 0 ||
127 [ + + ]: 90 : params.strip_size > *base_bdev_blockcnt) {
128 : 42 : continue;
129 : : }
130 : 66 : raid_test_params_add(¶ms);
131 : : }
132 : : }
133 : : }
134 : : }
135 : : }
136 : :
137 : 1 : init_accel();
138 : :
139 : 1 : return 0;
140 : : }
141 : :
142 : : static int
143 : 1 : test_suite_cleanup(void)
144 : : {
145 : 1 : fini_accel();
146 : 1 : raid_test_params_free();
147 : 1 : return 0;
148 : : }
149 : :
150 : : static void
151 : 8 : test_setup(void)
152 : : {
153 : 8 : g_test_degraded = false;
154 : 8 : }
155 : :
156 : : static struct raid5f_info *
157 : 528 : create_raid5f(struct raid_params *params)
158 : : {
159 : 528 : struct raid_bdev *raid_bdev = raid_test_create_raid_bdev(params, &g_raid5f_module);
160 : :
161 [ - + ]: 528 : SPDK_CU_ASSERT_FATAL(raid5f_start(raid_bdev) == 0);
162 : :
163 : 528 : return raid_bdev->module_private;
164 : : }
165 : :
166 : : static void
167 : 528 : delete_raid5f(struct raid5f_info *r5f_info)
168 : : {
169 : 528 : struct raid_bdev *raid_bdev = r5f_info->raid_bdev;
170 : :
171 : 528 : raid5f_stop(raid_bdev);
172 : :
173 : 528 : raid_test_delete_raid_bdev(raid_bdev);
174 : 528 : }
175 : :
176 : : static void
177 : 1 : test_raid5f_start(void)
178 : : {
179 : : struct raid_params *params;
180 : :
181 [ + + ]: 67 : RAID_PARAMS_FOR_EACH(params) {
182 : : struct raid5f_info *r5f_info;
183 : :
184 : 66 : r5f_info = create_raid5f(params);
185 : :
186 [ - + ]: 66 : SPDK_CU_ASSERT_FATAL(r5f_info != NULL);
187 : :
188 : 66 : CU_ASSERT_EQUAL(r5f_info->stripe_blocks, params->strip_size * (params->num_base_bdevs - 1));
189 [ - + ]: 66 : CU_ASSERT_EQUAL(r5f_info->total_stripes, params->base_bdev_blockcnt / params->strip_size);
190 [ - + ]: 66 : CU_ASSERT_EQUAL(r5f_info->raid_bdev->bdev.blockcnt,
191 : : (params->base_bdev_blockcnt - params->base_bdev_blockcnt % params->strip_size) *
192 : : (params->num_base_bdevs - 1));
193 : 66 : CU_ASSERT_EQUAL(r5f_info->raid_bdev->bdev.optimal_io_boundary, params->strip_size);
194 [ - + ]: 66 : CU_ASSERT_TRUE(r5f_info->raid_bdev->bdev.split_on_optimal_io_boundary);
195 : 66 : CU_ASSERT_EQUAL(r5f_info->raid_bdev->bdev.write_unit_size, r5f_info->stripe_blocks);
196 : :
197 : 66 : delete_raid5f(r5f_info);
198 : : }
199 : 1 : }
200 : :
201 : : enum test_bdev_error_type {
202 : : TEST_BDEV_ERROR_NONE,
203 : : TEST_BDEV_ERROR_SUBMIT,
204 : : TEST_BDEV_ERROR_COMPLETE,
205 : : TEST_BDEV_ERROR_NOMEM,
206 : : };
207 : :
208 : : struct raid_io_info {
209 : : struct raid5f_info *r5f_info;
210 : : struct raid_bdev_io_channel *raid_ch;
211 : : enum spdk_bdev_io_type io_type;
212 : : uint64_t stripe_index;
213 : : uint64_t offset_blocks;
214 : : uint64_t stripe_offset_blocks;
215 : : uint64_t num_blocks;
216 : : void *src_buf;
217 : : void *dest_buf;
218 : : void *src_md_buf;
219 : : void *dest_md_buf;
220 : : size_t buf_size;
221 : : size_t buf_md_size;
222 : : void *parity_buf;
223 : : void *reference_parity;
224 : : size_t parity_buf_size;
225 : : void *parity_md_buf;
226 : : void *reference_md_parity;
227 : : size_t parity_md_buf_size;
228 : : void *degraded_buf;
229 : : void *degraded_md_buf;
230 : : enum spdk_bdev_io_status status;
231 : : TAILQ_HEAD(, spdk_bdev_io) bdev_io_queue;
232 : : TAILQ_HEAD(, spdk_bdev_io_wait_entry) bdev_io_wait_queue;
233 : : struct {
234 : : enum test_bdev_error_type type;
235 : : struct spdk_bdev *bdev;
236 : : void (*on_enomem_cb)(struct raid_io_info *io_info, void *ctx);
237 : : void *on_enomem_cb_ctx;
238 : : } error;
239 : : };
240 : :
241 : : struct test_raid_bdev_io {
242 : : struct raid_bdev_io raid_io;
243 : : struct raid_io_info *io_info;
244 : : void *buf;
245 : : void *buf_md;
246 : : };
247 : :
248 : : void
249 : 2554 : raid_bdev_queue_io_wait(struct raid_bdev_io *raid_io, struct spdk_bdev *bdev,
250 : : struct spdk_io_channel *ch, spdk_bdev_io_wait_cb cb_fn)
251 : : {
252 : 2554 : struct test_raid_bdev_io *test_raid_bdev_io = SPDK_CONTAINEROF(raid_io, struct test_raid_bdev_io,
253 : : raid_io);
254 : 2554 : struct raid_io_info *io_info = test_raid_bdev_io->io_info;
255 : :
256 : 2554 : raid_io->waitq_entry.bdev = bdev;
257 : 2554 : raid_io->waitq_entry.cb_fn = cb_fn;
258 : 2554 : raid_io->waitq_entry.cb_arg = raid_io;
259 : 2554 : TAILQ_INSERT_TAIL(&io_info->bdev_io_wait_queue, &raid_io->waitq_entry, link);
260 : 2554 : }
261 : :
262 : : static void
263 : 10586 : raid_test_bdev_io_complete(struct raid_bdev_io *raid_io, enum spdk_bdev_io_status status)
264 : : {
265 : 10586 : struct test_raid_bdev_io *test_raid_bdev_io = SPDK_CONTAINEROF(raid_io, struct test_raid_bdev_io,
266 : : raid_io);
267 : :
268 : 10586 : test_raid_bdev_io->io_info->status = status;
269 : :
270 : 10586 : free(raid_io->iovs);
271 : 10586 : free(test_raid_bdev_io);
272 : 10586 : }
273 : :
274 : : static struct raid_bdev_io *
275 : 10586 : get_raid_io(struct raid_io_info *io_info)
276 : : {
277 : : struct raid_bdev_io *raid_io;
278 : 10586 : struct raid_bdev *raid_bdev = io_info->r5f_info->raid_bdev;
279 : 10586 : uint32_t blocklen = raid_bdev->bdev.blocklen;
280 : : struct test_raid_bdev_io *test_raid_bdev_io;
281 : : struct iovec *iovs;
282 : : int iovcnt;
283 : : void *md_buf;
284 : : size_t iov_len, remaining;
285 : : struct iovec *iov;
286 : : void *buf;
287 : : int i;
288 : :
289 : 10586 : test_raid_bdev_io = calloc(1, sizeof(*test_raid_bdev_io));
290 [ - + ]: 10586 : SPDK_CU_ASSERT_FATAL(test_raid_bdev_io != NULL);
291 : :
292 : 10586 : test_raid_bdev_io->io_info = io_info;
293 : :
294 [ + + ]: 10586 : if (io_info->io_type == SPDK_BDEV_IO_TYPE_READ) {
295 : 5516 : test_raid_bdev_io->buf = io_info->src_buf;
296 : 5516 : test_raid_bdev_io->buf_md = io_info->src_md_buf;
297 : 5516 : buf = io_info->dest_buf;
298 : 5516 : md_buf = io_info->dest_md_buf;
299 : : } else {
300 : 5070 : test_raid_bdev_io->buf = io_info->dest_buf;
301 : 5070 : test_raid_bdev_io->buf_md = io_info->dest_md_buf;
302 : 5070 : buf = io_info->src_buf;
303 : 5070 : md_buf = io_info->src_md_buf;
304 : : }
305 : :
306 : 10586 : iovcnt = 7;
307 : 10586 : iovs = calloc(iovcnt, sizeof(*iovs));
308 [ - + ]: 10586 : SPDK_CU_ASSERT_FATAL(iovs != NULL);
309 : :
310 : 10586 : remaining = io_info->num_blocks * blocklen;
311 [ - + ]: 10586 : iov_len = remaining / iovcnt;
312 : :
313 [ + + ]: 84688 : for (i = 0; i < iovcnt; i++) {
314 : 74102 : iov = &iovs[i];
315 : 74102 : iov->iov_base = buf;
316 : 74102 : iov->iov_len = iov_len;
317 : 74102 : buf += iov_len;
318 : 74102 : remaining -= iov_len;
319 : : }
320 : 10586 : iov->iov_len += remaining;
321 : :
322 : 10586 : raid_io = &test_raid_bdev_io->raid_io;
323 : :
324 : 10586 : raid_test_bdev_io_init(raid_io, raid_bdev, io_info->raid_ch, io_info->io_type,
325 : : io_info->offset_blocks, io_info->num_blocks, iovs, iovcnt, md_buf);
326 : :
327 : 10586 : return raid_io;
328 : : }
329 : :
330 : : void
331 : 25136 : spdk_bdev_free_io(struct spdk_bdev_io *bdev_io)
332 : : {
333 : 25136 : free(bdev_io);
334 : 25136 : }
335 : :
336 : : static int
337 : 29474 : submit_io(struct raid_io_info *io_info, struct spdk_bdev_desc *desc,
338 : : spdk_bdev_io_completion_cb cb, void *cb_arg)
339 : : {
340 : 29474 : struct spdk_bdev *bdev = desc->bdev;
341 : : struct spdk_bdev_io *bdev_io;
342 : :
343 [ + + ]: 29474 : if (bdev == io_info->error.bdev) {
344 [ + + ]: 7136 : if (io_info->error.type == TEST_BDEV_ERROR_SUBMIT) {
345 : 1784 : return -EINVAL;
346 [ + + ]: 5352 : } else if (io_info->error.type == TEST_BDEV_ERROR_NOMEM) {
347 : 2554 : return -ENOMEM;
348 : : }
349 : : }
350 : :
351 : 25136 : bdev_io = calloc(1, sizeof(*bdev_io));
352 [ - + ]: 25136 : SPDK_CU_ASSERT_FATAL(bdev_io != NULL);
353 : 25136 : bdev_io->bdev = bdev;
354 : 25136 : bdev_io->internal.cb = cb;
355 : 25136 : bdev_io->internal.caller_ctx = cb_arg;
356 : :
357 : 25136 : TAILQ_INSERT_TAIL(&io_info->bdev_io_queue, bdev_io, internal.link);
358 : :
359 : 25136 : return 0;
360 : : }
361 : :
362 : : static void
363 : 13140 : process_io_completions(struct raid_io_info *io_info)
364 : : {
365 : : struct spdk_bdev_io *bdev_io;
366 : : bool success;
367 : :
368 [ + + ]: 38276 : while ((bdev_io = TAILQ_FIRST(&io_info->bdev_io_queue))) {
369 [ + + ]: 25136 : TAILQ_REMOVE(&io_info->bdev_io_queue, bdev_io, internal.link);
370 : :
371 [ + + ]: 25136 : if (io_info->error.type == TEST_BDEV_ERROR_COMPLETE &&
372 [ + + ]: 6818 : io_info->error.bdev == bdev_io->bdev) {
373 : 1784 : success = false;
374 : : } else {
375 : 23352 : success = true;
376 : : }
377 : :
378 : 25136 : bdev_io->internal.cb(bdev_io, success, bdev_io->internal.caller_ctx);
379 : : }
380 : :
381 [ + + ]: 13140 : if (io_info->error.type == TEST_BDEV_ERROR_NOMEM) {
382 : : struct spdk_bdev_io_wait_entry *waitq_entry, *tmp;
383 : 2554 : struct spdk_bdev *enomem_bdev = io_info->error.bdev;
384 : :
385 : 2554 : io_info->error.type = TEST_BDEV_ERROR_NONE;
386 : :
387 [ + + ]: 2554 : if (io_info->error.on_enomem_cb != NULL) {
388 : 1540 : io_info->error.on_enomem_cb(io_info, io_info->error.on_enomem_cb_ctx);
389 : : }
390 : :
391 [ + + ]: 5108 : TAILQ_FOREACH_SAFE(waitq_entry, &io_info->bdev_io_wait_queue, link, tmp) {
392 [ - + ]: 2554 : TAILQ_REMOVE(&io_info->bdev_io_wait_queue, waitq_entry, link);
393 : 2554 : CU_ASSERT(waitq_entry->bdev == enomem_bdev);
394 : 2554 : waitq_entry->cb_fn(waitq_entry->cb_arg);
395 : : }
396 : :
397 : 2554 : process_io_completions(io_info);
398 : : } else {
399 : 10586 : CU_ASSERT(TAILQ_EMPTY(&io_info->bdev_io_wait_queue));
400 : : }
401 : 13140 : }
402 : :
403 : : #define DATA_OFFSET_TO_MD_OFFSET(raid_bdev, data_offset) ((data_offset >> raid_bdev->blocklen_shift) * raid_bdev->bdev.md_len)
404 : :
405 : : int
406 : 22482 : spdk_bdev_writev_blocks_with_md(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
407 : : struct iovec *iov, int iovcnt, void *md_buf,
408 : : uint64_t offset_blocks, uint64_t num_blocks,
409 : : spdk_bdev_io_completion_cb cb, void *cb_arg)
410 : : {
411 : 22482 : struct chunk *chunk = cb_arg;
412 : : struct stripe_request *stripe_req;
413 : : struct test_raid_bdev_io *test_raid_bdev_io;
414 : : struct raid_io_info *io_info;
415 : : struct raid_bdev *raid_bdev;
416 : : uint8_t data_chunk_idx;
417 : : uint64_t data_offset;
418 : 22482 : struct iovec dest;
419 : : void *dest_md_buf;
420 : :
421 [ - + ]: 22482 : SPDK_CU_ASSERT_FATAL(cb == raid5f_chunk_complete_bdev_io);
422 : :
423 : 22482 : stripe_req = raid5f_chunk_stripe_req(chunk);
424 : 22482 : test_raid_bdev_io = SPDK_CONTAINEROF(stripe_req->raid_io, struct test_raid_bdev_io, raid_io);
425 : 22482 : io_info = test_raid_bdev_io->io_info;
426 : 22482 : raid_bdev = io_info->r5f_info->raid_bdev;
427 : :
428 [ + + ]: 22482 : if (chunk == stripe_req->parity_chunk) {
429 [ + + ]: 5214 : if (io_info->parity_buf == NULL) {
430 : 4784 : goto submit;
431 : : }
432 : 430 : dest.iov_base = io_info->parity_buf;
433 [ + + ]: 430 : if (md_buf != NULL) {
434 : 215 : dest_md_buf = io_info->parity_md_buf;
435 : : }
436 : : } else {
437 [ + + ]: 17268 : data_chunk_idx = chunk < stripe_req->parity_chunk ? chunk->index : chunk->index - 1;
438 : 17268 : data_offset = data_chunk_idx * raid_bdev->strip_size * raid_bdev->bdev.blocklen;
439 : 17268 : dest.iov_base = test_raid_bdev_io->buf + data_offset;
440 [ + + ]: 17268 : if (md_buf != NULL) {
441 [ - + ]: 8634 : data_offset = DATA_OFFSET_TO_MD_OFFSET(raid_bdev, data_offset);
442 : 8634 : dest_md_buf = test_raid_bdev_io->buf_md + data_offset;
443 : : }
444 : : }
445 : 17698 : dest.iov_len = num_blocks * raid_bdev->bdev.blocklen;
446 : :
447 : 17698 : spdk_iovcpy(iov, iovcnt, &dest, 1);
448 [ + + ]: 17698 : if (md_buf != NULL) {
449 [ - + - + ]: 8849 : memcpy(dest_md_buf, md_buf, num_blocks * raid_bdev->bdev.md_len);
450 : : }
451 : :
452 : 22482 : submit:
453 : 22482 : return submit_io(io_info, desc, cb, cb_arg);
454 : : }
455 : :
456 : : static int
457 : 2142 : spdk_bdev_readv_blocks_degraded(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
458 : : struct iovec *iov, int iovcnt, void *md_buf,
459 : : uint64_t offset_blocks, uint64_t num_blocks,
460 : : spdk_bdev_io_completion_cb cb, void *cb_arg)
461 : : {
462 : 2142 : struct chunk *chunk = cb_arg;
463 : : struct stripe_request *stripe_req;
464 : : struct test_raid_bdev_io *test_raid_bdev_io;
465 : : struct raid_io_info *io_info;
466 : : struct raid_bdev *raid_bdev;
467 : : uint8_t data_chunk_idx;
468 : : void *buf, *buf_md;
469 : 2142 : struct iovec src;
470 : :
471 [ - + ]: 2142 : SPDK_CU_ASSERT_FATAL(cb == raid5f_chunk_complete_bdev_io);
472 : :
473 : 2142 : stripe_req = raid5f_chunk_stripe_req(chunk);
474 : 2142 : test_raid_bdev_io = SPDK_CONTAINEROF(stripe_req->raid_io, struct test_raid_bdev_io, raid_io);
475 : 2142 : io_info = test_raid_bdev_io->io_info;
476 : 2142 : raid_bdev = io_info->r5f_info->raid_bdev;
477 : :
478 [ + + ]: 2142 : if (chunk == stripe_req->parity_chunk) {
479 : 666 : buf = io_info->reference_parity;
480 : 666 : buf_md = io_info->reference_md_parity;
481 : : } else {
482 [ + + ]: 1476 : data_chunk_idx = chunk < stripe_req->parity_chunk ? chunk->index : chunk->index - 1;
483 : 1476 : buf = io_info->degraded_buf +
484 : 1476 : data_chunk_idx * raid_bdev->strip_size * raid_bdev->bdev.blocklen;
485 : 2952 : buf_md = io_info->degraded_md_buf +
486 : 1476 : data_chunk_idx * raid_bdev->strip_size * raid_bdev->bdev.md_len;
487 : : }
488 : :
489 [ - + ]: 2142 : buf += (offset_blocks % raid_bdev->strip_size) * raid_bdev->bdev.blocklen;
490 [ - + ]: 2142 : buf_md += (offset_blocks % raid_bdev->strip_size) * raid_bdev->bdev.md_len;
491 : :
492 : 2142 : src.iov_base = buf;
493 : 2142 : src.iov_len = num_blocks * raid_bdev->bdev.blocklen;
494 : :
495 : 2142 : spdk_iovcpy(&src, 1, iov, iovcnt);
496 [ + + ]: 2142 : if (md_buf != NULL) {
497 [ - + - + ]: 1071 : memcpy(md_buf, buf_md, num_blocks * raid_bdev->bdev.md_len);
498 : : }
499 : :
500 : 2142 : return submit_io(io_info, desc, cb, cb_arg);
501 : : }
502 : :
503 : : int
504 : 0 : spdk_bdev_writev_blocks(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
505 : : struct iovec *iov, int iovcnt,
506 : : uint64_t offset_blocks, uint64_t num_blocks,
507 : : spdk_bdev_io_completion_cb cb, void *cb_arg)
508 : : {
509 : 0 : return spdk_bdev_writev_blocks_with_md(desc, ch, iov, iovcnt, NULL, offset_blocks, num_blocks, cb,
510 : : cb_arg);
511 : : }
512 : :
513 : : int
514 : 22482 : spdk_bdev_writev_blocks_ext(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
515 : : struct iovec *iov, int iovcnt, uint64_t offset_blocks,
516 : : uint64_t num_blocks, spdk_bdev_io_completion_cb cb, void *cb_arg,
517 : : struct spdk_bdev_ext_io_opts *opts)
518 : : {
519 : 22482 : CU_ASSERT_PTR_NULL(opts->memory_domain);
520 : 22482 : CU_ASSERT_PTR_NULL(opts->memory_domain_ctx);
521 : :
522 : 22482 : return spdk_bdev_writev_blocks_with_md(desc, ch, iov, iovcnt, opts->metadata, offset_blocks,
523 : : num_blocks, cb, cb_arg);
524 : : }
525 : :
526 : : int
527 : 6992 : spdk_bdev_readv_blocks_with_md(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
528 : : struct iovec *iov, int iovcnt, void *md_buf,
529 : : uint64_t offset_blocks, uint64_t num_blocks,
530 : : spdk_bdev_io_completion_cb cb, void *cb_arg)
531 : : {
532 : 6992 : struct raid_bdev_io *raid_io = cb_arg;
533 : 6992 : struct raid_bdev *raid_bdev = raid_io->raid_bdev;
534 : 6992 : struct test_raid_bdev_io *test_raid_bdev_io = SPDK_CONTAINEROF(raid_io, struct test_raid_bdev_io,
535 : : raid_io);
536 : 6992 : struct iovec src;
537 : :
538 [ + + ]: 6992 : if (cb == raid5f_chunk_complete_bdev_io) {
539 : 2142 : return spdk_bdev_readv_blocks_degraded(desc, ch, iov, iovcnt, md_buf, offset_blocks,
540 : : num_blocks, cb, cb_arg);
541 : : }
542 : :
543 [ - + ]: 4850 : SPDK_CU_ASSERT_FATAL(cb == raid5f_chunk_read_complete);
544 : :
545 : 4850 : src.iov_base = test_raid_bdev_io->buf;
546 : 4850 : src.iov_len = num_blocks * raid_bdev->bdev.blocklen;
547 : :
548 : 4850 : spdk_iovcpy(&src, 1, iov, iovcnt);
549 [ + + ]: 4850 : if (md_buf != NULL) {
550 [ - + - + ]: 2425 : memcpy(md_buf, test_raid_bdev_io->buf_md, num_blocks * raid_bdev->bdev.md_len);
551 : : }
552 : :
553 : 4850 : return submit_io(test_raid_bdev_io->io_info, desc, cb, cb_arg);
554 : : }
555 : :
556 : : int
557 : 0 : spdk_bdev_readv_blocks(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
558 : : struct iovec *iov, int iovcnt,
559 : : uint64_t offset_blocks, uint64_t num_blocks,
560 : : spdk_bdev_io_completion_cb cb, void *cb_arg)
561 : : {
562 : 0 : return spdk_bdev_readv_blocks_with_md(desc, ch, iov, iovcnt, NULL, offset_blocks, num_blocks, cb,
563 : : cb_arg);
564 : : }
565 : :
566 : : int
567 : 6992 : spdk_bdev_readv_blocks_ext(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
568 : : struct iovec *iov, int iovcnt, uint64_t offset_blocks,
569 : : uint64_t num_blocks, spdk_bdev_io_completion_cb cb, void *cb_arg,
570 : : struct spdk_bdev_ext_io_opts *opts)
571 : : {
572 : 6992 : CU_ASSERT_PTR_NULL(opts->memory_domain);
573 : 6992 : CU_ASSERT_PTR_NULL(opts->memory_domain_ctx);
574 : :
575 : 6992 : return spdk_bdev_readv_blocks_with_md(desc, ch, iov, iovcnt, opts->metadata, offset_blocks,
576 : : num_blocks, cb, cb_arg);
577 : : }
578 : :
579 : : static void
580 : 16203 : xor_block(uint8_t *a, uint8_t *b, size_t size)
581 : : {
582 [ + + ]: 638901000 : while (size-- > 0) {
583 : 638885000 : a[size] ^= b[size];
584 : : }
585 : 16203 : }
586 : :
587 : : static void
588 : 5070 : test_raid5f_write_request(struct raid_io_info *io_info)
589 : : {
590 : : struct raid_bdev_io *raid_io;
591 : :
592 [ - + - + ]: 5070 : SPDK_CU_ASSERT_FATAL(io_info->num_blocks / io_info->r5f_info->stripe_blocks == 1);
593 : :
594 : 5070 : raid_io = get_raid_io(io_info);
595 : :
596 : 5070 : raid5f_submit_rw_request(raid_io);
597 : :
598 : 5070 : poll_threads();
599 : :
600 : 5070 : process_io_completions(io_info);
601 : :
602 [ - + + + ]: 5070 : if (g_test_degraded) {
603 : 244 : struct raid_bdev *raid_bdev = io_info->r5f_info->raid_bdev;
604 : : uint8_t p_idx;
605 : : uint8_t i;
606 : : off_t offset;
607 : : uint32_t strip_len;
608 : :
609 [ + - ]: 244 : for (i = 0; i < raid_bdev->num_base_bdevs; i++) {
610 [ + - ]: 244 : if (!raid_bdev_channel_get_base_channel(io_info->raid_ch, i)) {
611 : 244 : break;
612 : : }
613 : : }
614 : :
615 [ - + ]: 244 : SPDK_CU_ASSERT_FATAL(i != raid_bdev->num_base_bdevs);
616 : :
617 : 244 : p_idx = raid5f_stripe_parity_chunk_index(raid_bdev, io_info->stripe_index);
618 : :
619 [ + + ]: 244 : if (i == p_idx) {
620 : 58 : return;
621 : : }
622 : :
623 [ - + ]: 186 : if (i >= p_idx) {
624 : 0 : i--;
625 : : }
626 : :
627 : 186 : strip_len = raid_bdev->strip_size_kb * 1024;
628 : 186 : offset = i * strip_len;
629 : :
630 [ - + - + ]: 186 : memcpy(io_info->dest_buf + offset, io_info->src_buf + offset, strip_len);
631 [ + + ]: 186 : if (io_info->dest_md_buf) {
632 : 93 : strip_len = raid_bdev->strip_size * raid_bdev->bdev.md_len;
633 : 93 : offset = i * strip_len;
634 [ - + - + ]: 93 : memcpy(io_info->dest_md_buf + offset, io_info->src_md_buf + offset, strip_len);
635 : : }
636 : : }
637 : :
638 [ + + ]: 5012 : if (io_info->status == SPDK_BDEV_IO_STATUS_SUCCESS) {
639 [ + + ]: 1444 : if (io_info->parity_buf) {
640 [ - + - + ]: 430 : CU_ASSERT(memcmp(io_info->parity_buf, io_info->reference_parity,
641 : : io_info->parity_buf_size) == 0);
642 : : }
643 [ + + ]: 1444 : if (io_info->parity_md_buf) {
644 [ - + - + ]: 215 : CU_ASSERT(memcmp(io_info->parity_md_buf, io_info->reference_md_parity,
645 : : io_info->parity_md_buf_size) == 0);
646 : : }
647 : : }
648 : : }
649 : :
650 : : static void
651 : 5516 : test_raid5f_read_request(struct raid_io_info *io_info)
652 : : {
653 : : struct raid_bdev_io *raid_io;
654 : :
655 [ - + ]: 5516 : SPDK_CU_ASSERT_FATAL(io_info->num_blocks <= io_info->r5f_info->raid_bdev->strip_size);
656 : :
657 : 5516 : raid_io = get_raid_io(io_info);
658 : :
659 : 5516 : raid5f_submit_rw_request(raid_io);
660 : :
661 : 5516 : process_io_completions(io_info);
662 : :
663 [ - + + + ]: 5516 : if (g_test_degraded) {
664 : : /* for the reconstruct read xor callback */
665 : 2758 : poll_threads();
666 : : }
667 : 5516 : }
668 : :
669 : : static void
670 : 10586 : deinit_io_info(struct raid_io_info *io_info)
671 : : {
672 : 10586 : free(io_info->src_buf);
673 : 10586 : free(io_info->dest_buf);
674 : 10586 : free(io_info->src_md_buf);
675 : 10586 : free(io_info->dest_md_buf);
676 : 10586 : free(io_info->parity_buf);
677 : 10586 : free(io_info->reference_parity);
678 : 10586 : free(io_info->parity_md_buf);
679 : 10586 : free(io_info->reference_md_parity);
680 : 10586 : free(io_info->degraded_buf);
681 : 10586 : free(io_info->degraded_md_buf);
682 : 10586 : }
683 : :
684 : : static void
685 : 10586 : init_io_info(struct raid_io_info *io_info, struct raid5f_info *r5f_info,
686 : : struct raid_bdev_io_channel *raid_ch, enum spdk_bdev_io_type io_type,
687 : : uint64_t stripe_index, uint64_t stripe_offset_blocks, uint64_t num_blocks)
688 : : {
689 : 10586 : struct raid_bdev *raid_bdev = r5f_info->raid_bdev;
690 : 10586 : uint32_t blocklen = raid_bdev->bdev.blocklen;
691 : : void *src_buf, *dest_buf;
692 : : void *src_md_buf, *dest_md_buf;
693 : 10586 : size_t buf_size = num_blocks * blocklen;
694 : 10586 : size_t buf_md_size = num_blocks * raid_bdev->bdev.md_len;
695 : : uint64_t block;
696 : : uint64_t i;
697 : :
698 [ - + ]: 10586 : SPDK_CU_ASSERT_FATAL(stripe_offset_blocks < r5f_info->stripe_blocks);
699 : :
700 [ - + ]: 10586 : memset(io_info, 0, sizeof(*io_info));
701 : :
702 [ + - ]: 10586 : if (buf_size) {
703 : 10586 : src_buf = spdk_dma_malloc(buf_size, 4096, NULL);
704 [ - + ]: 10586 : SPDK_CU_ASSERT_FATAL(src_buf != NULL);
705 : :
706 : 10586 : dest_buf = spdk_dma_malloc(buf_size, 4096, NULL);
707 [ - + ]: 10586 : SPDK_CU_ASSERT_FATAL(dest_buf != NULL);
708 : :
709 [ - + ]: 10586 : memset(src_buf, 0xff, buf_size);
710 [ + + ]: 1126460 : for (block = 0; block < num_blocks; block++) {
711 : 1115870 : *((uint64_t *)(src_buf + block * blocklen)) = block;
712 : : }
713 : : } else {
714 : 0 : src_buf = NULL;
715 : 0 : dest_buf = NULL;
716 : : }
717 : :
718 [ + + ]: 10586 : if (buf_md_size) {
719 : 5293 : src_md_buf = spdk_dma_malloc(buf_md_size, 4096, NULL);
720 [ - + ]: 5293 : SPDK_CU_ASSERT_FATAL(src_md_buf != NULL);
721 : :
722 : 5293 : dest_md_buf = spdk_dma_malloc(buf_md_size, 4096, NULL);
723 [ - + ]: 5293 : SPDK_CU_ASSERT_FATAL(dest_md_buf != NULL);
724 : :
725 [ - + ]: 5293 : memset(src_md_buf, 0xff, buf_md_size);
726 [ + + ]: 35713200 : for (i = 0; i < buf_md_size; i++) {
727 : 35707900 : *((uint8_t *)(src_md_buf + i)) = (uint8_t)i;
728 : : }
729 : : } else {
730 : 5293 : src_md_buf = NULL;
731 : 5293 : dest_md_buf = NULL;
732 : : }
733 : :
734 : 10586 : io_info->r5f_info = r5f_info;
735 : 10586 : io_info->raid_ch = raid_ch;
736 : 10586 : io_info->io_type = io_type;
737 : 10586 : io_info->stripe_index = stripe_index;
738 : 10586 : io_info->offset_blocks = stripe_index * r5f_info->stripe_blocks + stripe_offset_blocks;
739 : 10586 : io_info->stripe_offset_blocks = stripe_offset_blocks;
740 : 10586 : io_info->num_blocks = num_blocks;
741 : 10586 : io_info->src_buf = src_buf;
742 : 10586 : io_info->dest_buf = dest_buf;
743 : 10586 : io_info->src_md_buf = src_md_buf;
744 : 10586 : io_info->dest_md_buf = dest_md_buf;
745 : 10586 : io_info->buf_size = buf_size;
746 : 10586 : io_info->buf_md_size = buf_md_size;
747 : 10586 : io_info->status = SPDK_BDEV_IO_STATUS_PENDING;
748 : :
749 : 10586 : TAILQ_INIT(&io_info->bdev_io_queue);
750 : 10586 : TAILQ_INIT(&io_info->bdev_io_wait_queue);
751 : 10586 : }
752 : :
753 : : static void
754 : 3246 : io_info_setup_parity(struct raid_io_info *io_info, void *src, void *src_md)
755 : : {
756 : 3246 : struct raid5f_info *r5f_info = io_info->r5f_info;
757 : 3246 : struct raid_bdev *raid_bdev = r5f_info->raid_bdev;
758 : 3246 : uint32_t blocklen = raid_bdev->bdev.blocklen;
759 : 3246 : size_t strip_len = raid_bdev->strip_size * blocklen;
760 : : unsigned i;
761 : :
762 : 3246 : io_info->parity_buf_size = strip_len;
763 : 3246 : io_info->parity_buf = calloc(1, io_info->parity_buf_size);
764 [ - + ]: 3246 : SPDK_CU_ASSERT_FATAL(io_info->parity_buf != NULL);
765 : :
766 : 3246 : io_info->reference_parity = calloc(1, io_info->parity_buf_size);
767 [ - + ]: 3246 : SPDK_CU_ASSERT_FATAL(io_info->reference_parity != NULL);
768 : :
769 [ + + ]: 14048 : for (i = 0; i < raid5f_stripe_data_chunks_num(raid_bdev); i++) {
770 : 10802 : xor_block(io_info->reference_parity, src, strip_len);
771 : 10802 : src += strip_len;
772 : : }
773 : :
774 [ + + ]: 3246 : if (src_md) {
775 : 1623 : size_t strip_md_len = raid_bdev->strip_size * raid_bdev->bdev.md_len;
776 : :
777 : 1623 : io_info->parity_md_buf_size = strip_md_len;
778 : 1623 : io_info->parity_md_buf = calloc(1, io_info->parity_md_buf_size);
779 [ - + ]: 1623 : SPDK_CU_ASSERT_FATAL(io_info->parity_md_buf != NULL);
780 : :
781 : 1623 : io_info->reference_md_parity = calloc(1, io_info->parity_md_buf_size);
782 [ - + ]: 1623 : SPDK_CU_ASSERT_FATAL(io_info->reference_md_parity != NULL);
783 : :
784 [ + + ]: 7024 : for (i = 0; i < raid5f_stripe_data_chunks_num(raid_bdev); i++) {
785 : 5401 : xor_block(io_info->reference_md_parity, src_md, strip_md_len);
786 : 5401 : src_md += strip_md_len;
787 : : }
788 : : }
789 : 3246 : }
790 : :
791 : : static void
792 : 2758 : io_info_setup_degraded(struct raid_io_info *io_info)
793 : : {
794 : 2758 : struct raid5f_info *r5f_info = io_info->r5f_info;
795 : 2758 : struct raid_bdev *raid_bdev = r5f_info->raid_bdev;
796 : 2758 : uint32_t blocklen = raid_bdev->bdev.blocklen;
797 : 2758 : uint32_t md_len = raid_bdev->bdev.md_len;
798 : 2758 : size_t stripe_len = r5f_info->stripe_blocks * blocklen;
799 : 2758 : size_t stripe_md_len = r5f_info->stripe_blocks * md_len;
800 : :
801 : 2758 : io_info->degraded_buf = malloc(stripe_len);
802 [ - + ]: 2758 : SPDK_CU_ASSERT_FATAL(io_info->degraded_buf != NULL);
803 : :
804 [ - + ]: 2758 : memset(io_info->degraded_buf, 0xab, stripe_len);
805 : :
806 [ - + - + ]: 2758 : memcpy(io_info->degraded_buf + io_info->stripe_offset_blocks * blocklen,
807 : 2758 : io_info->src_buf, io_info->num_blocks * blocklen);
808 : :
809 [ + + ]: 2758 : if (stripe_md_len != 0) {
810 : 1379 : io_info->degraded_md_buf = malloc(stripe_md_len);
811 [ - + ]: 1379 : SPDK_CU_ASSERT_FATAL(io_info->degraded_md_buf != NULL);
812 : :
813 [ - + ]: 1379 : memset(io_info->degraded_md_buf, 0xab, stripe_md_len);
814 : :
815 [ - + - + ]: 1379 : memcpy(io_info->degraded_md_buf + io_info->stripe_offset_blocks * md_len,
816 : 1379 : io_info->src_md_buf, io_info->num_blocks * md_len);
817 : : }
818 : :
819 : 2758 : io_info_setup_parity(io_info, io_info->degraded_buf, io_info->degraded_md_buf);
820 : :
821 [ - + ]: 2758 : memset(io_info->degraded_buf + io_info->stripe_offset_blocks * blocklen,
822 : 2758 : 0xcd, io_info->num_blocks * blocklen);
823 : :
824 [ + + ]: 2758 : if (stripe_md_len != 0) {
825 [ - + ]: 1379 : memset(io_info->degraded_md_buf + io_info->stripe_offset_blocks * md_len,
826 : 1379 : 0xcd, io_info->num_blocks * md_len);
827 : : }
828 : 2758 : }
829 : :
830 : : static void
831 : 6004 : test_raid5f_submit_rw_request(struct raid5f_info *r5f_info, struct raid_bdev_io_channel *raid_ch,
832 : : enum spdk_bdev_io_type io_type, uint64_t stripe_index, uint64_t stripe_offset_blocks,
833 : : uint64_t num_blocks)
834 : : {
835 : 6004 : struct raid_io_info io_info;
836 : :
837 : 6004 : init_io_info(&io_info, r5f_info, raid_ch, io_type, stripe_index, stripe_offset_blocks, num_blocks);
838 : :
839 [ + + - ]: 6004 : switch (io_type) {
840 : 5516 : case SPDK_BDEV_IO_TYPE_READ:
841 [ - + + + ]: 5516 : if (g_test_degraded) {
842 : 2758 : io_info_setup_degraded(&io_info);
843 : : }
844 : 5516 : test_raid5f_read_request(&io_info);
845 : 5516 : break;
846 : 488 : case SPDK_BDEV_IO_TYPE_WRITE:
847 : 488 : io_info_setup_parity(&io_info, io_info.src_buf, io_info.src_md_buf);
848 : 488 : test_raid5f_write_request(&io_info);
849 : 488 : break;
850 : 0 : default:
851 : 0 : CU_FAIL_FATAL("unsupported io_type");
852 : : }
853 : :
854 : 6004 : CU_ASSERT(io_info.status == SPDK_BDEV_IO_STATUS_SUCCESS);
855 [ - + - + ]: 6004 : CU_ASSERT(memcmp(io_info.src_buf, io_info.dest_buf, io_info.buf_size) == 0);
856 [ + + ]: 6004 : if (io_info.buf_md_size) {
857 [ - + - + ]: 3002 : CU_ASSERT(memcmp(io_info.src_md_buf, io_info.dest_md_buf, io_info.buf_md_size) == 0);
858 : : }
859 : :
860 : 6004 : deinit_io_info(&io_info);
861 : 6004 : }
862 : :
863 : : static void
864 : 7 : run_for_each_raid5f_config(void (*test_fn)(struct raid_bdev *raid_bdev,
865 : : struct raid_bdev_io_channel *raid_ch))
866 : : {
867 : : struct raid_params *params;
868 : :
869 [ + + ]: 469 : RAID_PARAMS_FOR_EACH(params) {
870 : : struct raid5f_info *r5f_info;
871 : : struct raid_bdev_io_channel *raid_ch;
872 : :
873 : 462 : r5f_info = create_raid5f(params);
874 : 462 : raid_ch = raid_test_create_io_channel(r5f_info->raid_bdev);
875 : :
876 [ - + + + ]: 462 : if (g_test_degraded) {
877 : 132 : raid_ch->_base_channels[0] = NULL;
878 : : }
879 : :
880 : 462 : test_fn(r5f_info->raid_bdev, raid_ch);
881 : :
882 : 462 : raid_test_destroy_io_channel(raid_ch);
883 : 462 : delete_raid5f(r5f_info);
884 : : }
885 : 7 : }
886 : :
887 : : #define RAID5F_TEST_FOR_EACH_STRIPE(raid_bdev, i) \
888 : : for (i = 0; i < spdk_min(raid_bdev->num_base_bdevs, ((struct raid5f_info *)raid_bdev->module_private)->total_stripes); i++)
889 : :
890 : : static void
891 : 132 : __test_raid5f_submit_read_request(struct raid_bdev *raid_bdev, struct raid_bdev_io_channel *raid_ch)
892 : : {
893 : 132 : struct raid5f_info *r5f_info = raid_bdev->module_private;
894 : 132 : uint32_t strip_size = raid_bdev->strip_size;
895 : : uint64_t stripe_index;
896 : : unsigned int i;
897 : :
898 [ + + ]: 528 : for (i = 0; i < raid5f_stripe_data_chunks_num(raid_bdev); i++) {
899 : 396 : uint64_t stripe_offset = i * strip_size;
900 : :
901 [ + + ]: 1936 : RAID5F_TEST_FOR_EACH_STRIPE(raid_bdev, stripe_index) {
902 : 1540 : test_raid5f_submit_rw_request(r5f_info, raid_ch, SPDK_BDEV_IO_TYPE_READ,
903 : : stripe_index, stripe_offset, 1);
904 : :
905 : 1540 : test_raid5f_submit_rw_request(r5f_info, raid_ch, SPDK_BDEV_IO_TYPE_READ,
906 : : stripe_index, stripe_offset, strip_size);
907 : :
908 : 1540 : test_raid5f_submit_rw_request(r5f_info, raid_ch, SPDK_BDEV_IO_TYPE_READ,
909 : 1540 : stripe_index, stripe_offset + strip_size - 1, 1);
910 [ + + ]: 1540 : if (strip_size <= 2) {
911 : 644 : continue;
912 : : }
913 : 896 : test_raid5f_submit_rw_request(r5f_info, raid_ch, SPDK_BDEV_IO_TYPE_READ,
914 : 896 : stripe_index, stripe_offset + 1, strip_size - 2);
915 : : }
916 : : }
917 : 132 : }
918 : : static void
919 : 1 : test_raid5f_submit_read_request(void)
920 : : {
921 : 1 : run_for_each_raid5f_config(__test_raid5f_submit_read_request);
922 : 1 : }
923 : :
924 : : static void
925 : 66 : __test_raid5f_stripe_request_map_iovecs(struct raid_bdev *raid_bdev,
926 : : struct raid_bdev_io_channel *raid_ch)
927 : : {
928 : 66 : struct raid5f_io_channel *r5ch = raid_bdev_channel_get_module_ctx(raid_ch);
929 : 66 : size_t strip_bytes = raid_bdev->strip_size * raid_bdev->bdev.blocklen;
930 : 66 : struct raid_bdev_io raid_io = {};
931 : : struct stripe_request *stripe_req;
932 : : struct chunk *chunk;
933 : 66 : struct iovec iovs[] = {
934 : : { .iov_base = (void *)0x0ff0000, .iov_len = strip_bytes },
935 : 66 : { .iov_base = (void *)0x1ff0000, .iov_len = strip_bytes / 2 },
936 : 66 : { .iov_base = (void *)0x2ff0000, .iov_len = strip_bytes * 2 },
937 : 66 : { .iov_base = (void *)0x3ff0000, .iov_len = strip_bytes * raid_bdev->num_base_bdevs },
938 : : };
939 : 66 : size_t iovcnt = SPDK_COUNTOF(iovs);
940 : : int ret;
941 : :
942 : 66 : raid_io.raid_bdev = raid_bdev;
943 : 66 : raid_io.iovs = iovs;
944 : 66 : raid_io.iovcnt = iovcnt;
945 : :
946 : 66 : stripe_req = raid5f_stripe_request_alloc(r5ch, STRIPE_REQ_WRITE);
947 [ - + ]: 66 : SPDK_CU_ASSERT_FATAL(stripe_req != NULL);
948 : :
949 : 66 : stripe_req->parity_chunk = &stripe_req->chunks[raid5f_stripe_data_chunks_num(raid_bdev)];
950 : 66 : stripe_req->raid_io = &raid_io;
951 : :
952 : 66 : ret = raid5f_stripe_request_map_iovecs(stripe_req);
953 : 66 : CU_ASSERT(ret == 0);
954 : :
955 : 66 : chunk = &stripe_req->chunks[0];
956 : 66 : CU_ASSERT_EQUAL(chunk->iovcnt, 1);
957 : 66 : CU_ASSERT_EQUAL(chunk->iovs[0].iov_base, iovs[0].iov_base);
958 : 66 : CU_ASSERT_EQUAL(chunk->iovs[0].iov_len, iovs[0].iov_len);
959 : :
960 : 66 : chunk = &stripe_req->chunks[1];
961 : 66 : CU_ASSERT_EQUAL(chunk->iovcnt, 2);
962 : 66 : CU_ASSERT_EQUAL(chunk->iovs[0].iov_base, iovs[1].iov_base);
963 : 66 : CU_ASSERT_EQUAL(chunk->iovs[0].iov_len, iovs[1].iov_len);
964 : 66 : CU_ASSERT_EQUAL(chunk->iovs[1].iov_base, iovs[2].iov_base);
965 : 66 : CU_ASSERT_EQUAL(chunk->iovs[1].iov_len, iovs[2].iov_len / 4);
966 : :
967 [ + + ]: 66 : if (raid_bdev->num_base_bdevs > 3) {
968 : 44 : chunk = &stripe_req->chunks[2];
969 : 44 : CU_ASSERT_EQUAL(chunk->iovcnt, 1);
970 : 44 : CU_ASSERT_EQUAL(chunk->iovs[0].iov_base, iovs[2].iov_base + strip_bytes / 2);
971 : 44 : CU_ASSERT_EQUAL(chunk->iovs[0].iov_len, iovs[2].iov_len / 2);
972 : : }
973 [ + + ]: 66 : if (raid_bdev->num_base_bdevs > 4) {
974 : 22 : chunk = &stripe_req->chunks[3];
975 : 22 : CU_ASSERT_EQUAL(chunk->iovcnt, 2);
976 : 22 : CU_ASSERT_EQUAL(chunk->iovs[0].iov_base, iovs[2].iov_base + (strip_bytes / 2) * 3);
977 : 22 : CU_ASSERT_EQUAL(chunk->iovs[0].iov_len, iovs[2].iov_len / 4);
978 : 22 : CU_ASSERT_EQUAL(chunk->iovs[1].iov_base, iovs[3].iov_base);
979 : 22 : CU_ASSERT_EQUAL(chunk->iovs[1].iov_len, strip_bytes / 2);
980 : : }
981 : :
982 : 66 : raid5f_stripe_request_free(stripe_req);
983 : 66 : }
984 : : static void
985 : 1 : test_raid5f_stripe_request_map_iovecs(void)
986 : : {
987 : 1 : run_for_each_raid5f_config(__test_raid5f_stripe_request_map_iovecs);
988 : 1 : }
989 : :
990 : : static void
991 : 132 : __test_raid5f_submit_full_stripe_write_request(struct raid_bdev *raid_bdev,
992 : : struct raid_bdev_io_channel *raid_ch)
993 : : {
994 : 132 : struct raid5f_info *r5f_info = raid_bdev->module_private;
995 : : uint64_t stripe_index;
996 : :
997 [ + + ]: 620 : RAID5F_TEST_FOR_EACH_STRIPE(raid_bdev, stripe_index) {
998 : 488 : test_raid5f_submit_rw_request(r5f_info, raid_ch, SPDK_BDEV_IO_TYPE_WRITE,
999 : : stripe_index, 0, r5f_info->stripe_blocks);
1000 : : }
1001 : 132 : }
1002 : : static void
1003 : 1 : test_raid5f_submit_full_stripe_write_request(void)
1004 : : {
1005 : 1 : run_for_each_raid5f_config(__test_raid5f_submit_full_stripe_write_request);
1006 : 1 : }
1007 : :
1008 : : static void
1009 : 66 : __test_raid5f_chunk_write_error(struct raid_bdev *raid_bdev, struct raid_bdev_io_channel *raid_ch)
1010 : : {
1011 : 66 : struct raid5f_info *r5f_info = raid_bdev->module_private;
1012 : : struct raid_base_bdev_info *base_bdev_info;
1013 : : uint64_t stripe_index;
1014 : 66 : struct raid_io_info io_info;
1015 : : enum test_bdev_error_type error_type;
1016 : :
1017 [ + + ]: 264 : for (error_type = TEST_BDEV_ERROR_SUBMIT; error_type <= TEST_BDEV_ERROR_NOMEM; error_type++) {
1018 [ + + ]: 930 : RAID5F_TEST_FOR_EACH_STRIPE(raid_bdev, stripe_index) {
1019 [ + + ]: 3774 : RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_bdev_info) {
1020 : 3042 : init_io_info(&io_info, r5f_info, raid_ch, SPDK_BDEV_IO_TYPE_WRITE,
1021 : : stripe_index, 0, r5f_info->stripe_blocks);
1022 : :
1023 : 3042 : io_info.error.type = error_type;
1024 : 3042 : io_info.error.bdev = base_bdev_info->desc->bdev;
1025 : :
1026 : 3042 : test_raid5f_write_request(&io_info);
1027 : :
1028 [ + + ]: 3042 : if (error_type == TEST_BDEV_ERROR_NOMEM) {
1029 : 1014 : CU_ASSERT(io_info.status == SPDK_BDEV_IO_STATUS_SUCCESS);
1030 : : } else {
1031 : 2028 : CU_ASSERT(io_info.status == SPDK_BDEV_IO_STATUS_FAILED);
1032 : : }
1033 : :
1034 : 3042 : deinit_io_info(&io_info);
1035 : : }
1036 : : }
1037 : : }
1038 : 66 : }
1039 : : static void
1040 : 1 : test_raid5f_chunk_write_error(void)
1041 : : {
1042 : 1 : run_for_each_raid5f_config(__test_raid5f_chunk_write_error);
1043 : 1 : }
1044 : :
1045 : : struct chunk_write_error_with_enomem_ctx {
1046 : : enum test_bdev_error_type error_type;
1047 : : struct spdk_bdev *bdev;
1048 : : };
1049 : :
1050 : : static void
1051 : 1540 : chunk_write_error_with_enomem_cb(struct raid_io_info *io_info, void *_ctx)
1052 : : {
1053 : 1540 : struct chunk_write_error_with_enomem_ctx *ctx = _ctx;
1054 : :
1055 : 1540 : io_info->error.type = ctx->error_type;
1056 : 1540 : io_info->error.bdev = ctx->bdev;
1057 : 1540 : }
1058 : :
1059 : : static void
1060 : 66 : __test_raid5f_chunk_write_error_with_enomem(struct raid_bdev *raid_bdev,
1061 : : struct raid_bdev_io_channel *raid_ch)
1062 : : {
1063 : 66 : struct raid5f_info *r5f_info = raid_bdev->module_private;
1064 : : struct raid_base_bdev_info *base_bdev_info;
1065 : : uint64_t stripe_index;
1066 : 66 : struct raid_io_info io_info;
1067 : : enum test_bdev_error_type error_type;
1068 : 66 : struct chunk_write_error_with_enomem_ctx on_enomem_cb_ctx;
1069 : :
1070 [ + + ]: 198 : for (error_type = TEST_BDEV_ERROR_SUBMIT; error_type <= TEST_BDEV_ERROR_COMPLETE; error_type++) {
1071 [ + + ]: 620 : RAID5F_TEST_FOR_EACH_STRIPE(raid_bdev, stripe_index) {
1072 : 976 : struct raid_base_bdev_info *base_bdev_info_last =
1073 : 488 : &raid_bdev->base_bdev_info[raid_bdev->num_base_bdevs - 1];
1074 : :
1075 [ + + ]: 2516 : RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_bdev_info) {
1076 [ + + ]: 2028 : if (base_bdev_info == base_bdev_info_last) {
1077 : 488 : continue;
1078 : : }
1079 : :
1080 : 1540 : init_io_info(&io_info, r5f_info, raid_ch, SPDK_BDEV_IO_TYPE_WRITE,
1081 : : stripe_index, 0, r5f_info->stripe_blocks);
1082 : :
1083 : 1540 : io_info.error.type = TEST_BDEV_ERROR_NOMEM;
1084 : 1540 : io_info.error.bdev = base_bdev_info->desc->bdev;
1085 : 1540 : io_info.error.on_enomem_cb = chunk_write_error_with_enomem_cb;
1086 : 1540 : io_info.error.on_enomem_cb_ctx = &on_enomem_cb_ctx;
1087 : 1540 : on_enomem_cb_ctx.error_type = error_type;
1088 : 1540 : on_enomem_cb_ctx.bdev = base_bdev_info_last->desc->bdev;
1089 : :
1090 : 1540 : test_raid5f_write_request(&io_info);
1091 : :
1092 : 1540 : CU_ASSERT(io_info.status == SPDK_BDEV_IO_STATUS_FAILED);
1093 : :
1094 : 1540 : deinit_io_info(&io_info);
1095 : : }
1096 : : }
1097 : : }
1098 : 66 : }
1099 : : static void
1100 : 1 : test_raid5f_chunk_write_error_with_enomem(void)
1101 : : {
1102 : 1 : run_for_each_raid5f_config(__test_raid5f_chunk_write_error_with_enomem);
1103 : 1 : }
1104 : :
1105 : : static void
1106 : 1 : test_raid5f_submit_full_stripe_write_request_degraded(void)
1107 : : {
1108 : 1 : g_test_degraded = true;
1109 : 1 : run_for_each_raid5f_config(__test_raid5f_submit_full_stripe_write_request);
1110 : 1 : }
1111 : :
1112 : : static void
1113 : 1 : test_raid5f_submit_read_request_degraded(void)
1114 : : {
1115 : 1 : g_test_degraded = true;
1116 : 1 : run_for_each_raid5f_config(__test_raid5f_submit_read_request);
1117 : 1 : }
1118 : :
1119 : : int
1120 : 1 : main(int argc, char **argv)
1121 : : {
1122 : 1 : CU_pSuite suite = NULL;
1123 : : unsigned int num_failures;
1124 : :
1125 : 1 : CU_initialize_registry();
1126 : :
1127 : 1 : suite = CU_add_suite_with_setup_and_teardown("raid5f", test_suite_init, test_suite_cleanup,
1128 : : test_setup, NULL);
1129 : 1 : CU_ADD_TEST(suite, test_raid5f_start);
1130 : 1 : CU_ADD_TEST(suite, test_raid5f_submit_read_request);
1131 : 1 : CU_ADD_TEST(suite, test_raid5f_stripe_request_map_iovecs);
1132 : 1 : CU_ADD_TEST(suite, test_raid5f_submit_full_stripe_write_request);
1133 : 1 : CU_ADD_TEST(suite, test_raid5f_chunk_write_error);
1134 : 1 : CU_ADD_TEST(suite, test_raid5f_chunk_write_error_with_enomem);
1135 : 1 : CU_ADD_TEST(suite, test_raid5f_submit_full_stripe_write_request_degraded);
1136 : 1 : CU_ADD_TEST(suite, test_raid5f_submit_read_request_degraded);
1137 : :
1138 : 1 : allocate_threads(1);
1139 : 1 : set_thread(0);
1140 : :
1141 : 1 : num_failures = spdk_ut_run_tests(argc, argv, NULL);
1142 : 1 : CU_cleanup_registry();
1143 : :
1144 : 1 : free_threads();
1145 : :
1146 : 1 : return num_failures;
1147 : : }
|