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