Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2024 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 : :
10 : : #include "common/lib/ut_multithread.c"
11 : :
12 : : #include "bdev/raid/raid0.c"
13 : : #include "../common.c"
14 : :
15 : : #define MAX_BASE_DRIVES 32
16 : : #define MAX_TEST_IO_RANGE (3 * 3 * 3 * (MAX_BASE_DRIVES + 5))
17 : : #define BLOCK_CNT (1024ul * 1024ul * 1024ul * 1024ul)
18 : :
19 : : /* Data structure to capture the output of IO for verification */
20 : : struct io_output {
21 : : struct spdk_bdev_desc *desc;
22 : : struct spdk_io_channel *ch;
23 : : uint64_t offset_blocks;
24 : : uint64_t num_blocks;
25 : : spdk_bdev_io_completion_cb cb;
26 : : void *cb_arg;
27 : : enum spdk_bdev_io_type iotype;
28 : : struct iovec *iovs;
29 : : int iovcnt;
30 : : void *md_buf;
31 : : };
32 : :
33 : : struct raid_io_ranges {
34 : : uint64_t lba;
35 : : uint64_t nblocks;
36 : : };
37 : :
38 : : /* Globals */
39 : : struct io_output *g_io_output = NULL;
40 : : uint32_t g_io_output_index;
41 : : uint32_t g_io_comp_status;
42 : : bool g_child_io_status_flag;
43 : : TAILQ_HEAD(bdev, spdk_bdev);
44 : : uint32_t g_block_len;
45 : : uint32_t g_strip_size;
46 : : uint32_t g_max_io_size;
47 : : uint8_t g_max_base_drives;
48 : : struct raid_io_ranges g_io_ranges[MAX_TEST_IO_RANGE];
49 : : uint32_t g_io_range_idx;
50 : : bool g_enable_dif;
51 : :
52 : 5 : DEFINE_STUB_V(raid_bdev_module_list_add, (struct raid_bdev_module *raid_module));
53 : 0 : DEFINE_STUB_V(raid_bdev_queue_io_wait, (struct raid_bdev_io *raid_io, struct spdk_bdev *bdev,
54 : : struct spdk_io_channel *ch, spdk_bdev_io_wait_cb cb_fn));
55 [ # # ]: 0 : DEFINE_STUB(spdk_bdev_flush_blocks, int, (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
56 : : uint64_t offset_blocks, uint64_t num_blocks, spdk_bdev_io_completion_cb cb,
57 : : void *cb_arg), 0);
58 [ - + - + ]: 90 : DEFINE_STUB(spdk_bdev_is_dif_head_of_md, bool, (const struct spdk_bdev *bdev), false);
59 [ # # ]: 0 : DEFINE_STUB(spdk_bdev_notify_blockcnt_change, int, (struct spdk_bdev *bdev, uint64_t size), 0);
60 : :
61 : : bool
62 : 140 : spdk_bdev_is_md_interleaved(const struct spdk_bdev *bdev)
63 : : {
64 [ + + - + : 140 : return (bdev->md_len != 0) && bdev->md_interleave;
- + ]
65 : : }
66 : :
67 : : bool
68 : 50 : spdk_bdev_is_md_separate(const struct spdk_bdev *bdev)
69 : : {
70 [ + + + + : 50 : return (bdev->md_len != 0) && !bdev->md_interleave;
+ - ]
71 : : }
72 : :
73 : : uint32_t
74 : 205 : spdk_bdev_get_md_size(const struct spdk_bdev *bdev)
75 : : {
76 : 205 : return bdev->md_len;
77 : : }
78 : :
79 : : uint32_t
80 : 90 : spdk_bdev_get_block_size(const struct spdk_bdev *bdev)
81 : : {
82 : 90 : return bdev->blocklen;
83 : : }
84 : :
85 : : static int
86 : 10 : set_test_opts(void)
87 : : {
88 : 10 : g_max_base_drives = MAX_BASE_DRIVES;
89 : 10 : g_block_len = 4096;
90 : 10 : g_strip_size = 64;
91 : 10 : g_max_io_size = 1024;
92 : 10 : g_enable_dif = false;
93 : :
94 : 10 : return 0;
95 : : }
96 : :
97 : : static int
98 : 5 : set_test_opts_dif(void)
99 : : {
100 : 5 : set_test_opts();
101 : 5 : g_enable_dif = true;
102 : :
103 : 5 : return 0;
104 : : }
105 : :
106 : : /* Set globals before every test run */
107 : : static void
108 : 40 : set_globals(void)
109 : : {
110 : : uint32_t max_splits;
111 : :
112 [ - + ]: 40 : if (g_max_io_size < g_strip_size) {
113 : 0 : max_splits = 2;
114 : : } else {
115 [ - + ]: 40 : max_splits = (g_max_io_size / g_strip_size) + 1;
116 : : }
117 [ + - ]: 40 : if (max_splits < g_max_base_drives) {
118 : 40 : max_splits = g_max_base_drives;
119 : : }
120 : :
121 : 40 : g_io_output = calloc(max_splits, sizeof(struct io_output));
122 [ - + ]: 40 : SPDK_CU_ASSERT_FATAL(g_io_output != NULL);
123 : 40 : g_io_output_index = 0;
124 : 40 : g_io_comp_status = 0;
125 : 40 : g_child_io_status_flag = true;
126 : 40 : }
127 : :
128 : : /* Reset globals */
129 : : static void
130 : 40 : reset_globals(void)
131 : : {
132 [ + - ]: 40 : if (g_io_output) {
133 : 40 : free(g_io_output);
134 : 40 : g_io_output = NULL;
135 : : }
136 : 40 : }
137 : :
138 : : static void
139 : 50 : generate_dif(struct iovec *iovs, int iovcnt, void *md_buf,
140 : : uint64_t offset_blocks, uint32_t num_blocks, struct spdk_bdev *bdev)
141 : : {
142 : 40 : struct spdk_dif_ctx dif_ctx;
143 : : int rc;
144 : 40 : struct spdk_dif_ctx_init_ext_opts dif_opts;
145 : : spdk_dif_type_t dif_type;
146 : : bool md_interleaved;
147 : 40 : struct iovec md_iov;
148 : :
149 : 50 : dif_type = spdk_bdev_get_dif_type(bdev);
150 : 50 : md_interleaved = spdk_bdev_is_md_interleaved(bdev);
151 : :
152 [ + + ]: 50 : if (dif_type == SPDK_DIF_DISABLE) {
153 : 25 : return;
154 : : }
155 : :
156 : 25 : dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format);
157 : 25 : dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
158 : 45 : rc = spdk_dif_ctx_init(&dif_ctx,
159 : : spdk_bdev_get_block_size(bdev),
160 : : spdk_bdev_get_md_size(bdev),
161 : : md_interleaved,
162 : 25 : spdk_bdev_is_dif_head_of_md(bdev),
163 : : dif_type,
164 : : bdev->dif_check_flags,
165 : : offset_blocks,
166 : : 0xFFFF, 0x123, 0, 0, &dif_opts);
167 [ - + ]: 25 : SPDK_CU_ASSERT_FATAL(rc == 0);
168 : :
169 [ + - ]: 25 : if (!md_interleaved) {
170 : 25 : md_iov.iov_base = md_buf;
171 : 25 : md_iov.iov_len = spdk_bdev_get_md_size(bdev) * num_blocks;
172 : :
173 : 25 : rc = spdk_dix_generate(iovs, iovcnt, &md_iov, num_blocks, &dif_ctx);
174 [ - + ]: 25 : SPDK_CU_ASSERT_FATAL(rc == 0);
175 : : }
176 : : }
177 : :
178 : : static void
179 : 75 : verify_dif(struct iovec *iovs, int iovcnt, void *md_buf,
180 : : uint64_t offset_blocks, uint32_t num_blocks, struct spdk_bdev *bdev)
181 : : {
182 : 60 : struct spdk_dif_ctx dif_ctx;
183 : : int rc;
184 : 60 : struct spdk_dif_ctx_init_ext_opts dif_opts;
185 : 60 : struct spdk_dif_error errblk;
186 : : spdk_dif_type_t dif_type;
187 : : bool md_interleaved;
188 : 60 : struct iovec md_iov;
189 : :
190 : 75 : dif_type = spdk_bdev_get_dif_type(bdev);
191 : 75 : md_interleaved = spdk_bdev_is_md_interleaved(bdev);
192 : :
193 [ + + ]: 75 : if (dif_type == SPDK_DIF_DISABLE) {
194 : 25 : return;
195 : : }
196 : :
197 : 50 : dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format);
198 : 50 : dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
199 : 90 : rc = spdk_dif_ctx_init(&dif_ctx,
200 : : spdk_bdev_get_block_size(bdev),
201 : : spdk_bdev_get_md_size(bdev),
202 : : md_interleaved,
203 : 50 : spdk_bdev_is_dif_head_of_md(bdev),
204 : : dif_type,
205 : : bdev->dif_check_flags,
206 : : offset_blocks,
207 : : 0xFFFF, 0x123, 0, 0, &dif_opts);
208 [ - + ]: 50 : SPDK_CU_ASSERT_FATAL(rc == 0);
209 : :
210 [ + - ]: 50 : if (!md_interleaved) {
211 : 50 : md_iov.iov_base = md_buf;
212 : 50 : md_iov.iov_len = spdk_bdev_get_md_size(bdev) * num_blocks;
213 : :
214 : 50 : rc = spdk_dix_verify(iovs, iovcnt,
215 : : &md_iov, num_blocks, &dif_ctx, &errblk);
216 [ - + ]: 50 : SPDK_CU_ASSERT_FATAL(rc == 0);
217 : : }
218 : : }
219 : :
220 : : static void
221 : 15 : remap_dif(void *md_buf, uint64_t num_blocks, struct spdk_bdev *bdev, uint32_t remapped_offset)
222 : : {
223 : 12 : struct spdk_dif_ctx dif_ctx;
224 : : int rc;
225 : 12 : struct spdk_dif_ctx_init_ext_opts dif_opts;
226 : 12 : struct spdk_dif_error errblk;
227 : : spdk_dif_type_t dif_type;
228 : : bool md_interleaved;
229 : 12 : struct iovec md_iov;
230 : :
231 : 15 : dif_type = spdk_bdev_get_dif_type(bdev);
232 : 15 : md_interleaved = spdk_bdev_is_md_interleaved(bdev);
233 : :
234 [ - + ]: 15 : if (dif_type == SPDK_DIF_DISABLE) {
235 : 0 : return;
236 : : }
237 : :
238 : 15 : dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format);
239 : 15 : dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
240 : 27 : rc = spdk_dif_ctx_init(&dif_ctx,
241 : : spdk_bdev_get_block_size(bdev),
242 : : spdk_bdev_get_md_size(bdev),
243 : : md_interleaved,
244 : 15 : spdk_bdev_is_dif_head_of_md(bdev),
245 : : dif_type,
246 : : bdev->dif_check_flags,
247 : : 0,
248 : : 0xFFFF, 0x123, 0, 0, &dif_opts);
249 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(rc == 0);
250 : :
251 [ + - ]: 15 : if (!md_interleaved) {
252 : 15 : md_iov.iov_base = md_buf;
253 : 15 : md_iov.iov_len = spdk_bdev_get_md_size(bdev) * num_blocks;
254 : :
255 : 15 : spdk_dif_ctx_set_remapped_init_ref_tag(&dif_ctx, remapped_offset);
256 : :
257 : 15 : rc = spdk_dix_remap_ref_tag(&md_iov, num_blocks, &dif_ctx, &errblk, false);
258 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(rc == 0);
259 : : }
260 : : }
261 : :
262 : : /* Store the IO completion status in global variable to verify by various tests */
263 : : void
264 : 9680 : raid_test_bdev_io_complete(struct raid_bdev_io *raid_io, enum spdk_bdev_io_status status)
265 : : {
266 : 9680 : g_io_comp_status = ((status == SPDK_BDEV_IO_STATUS_SUCCESS) ? true : false);
267 : 9680 : }
268 : :
269 : : int
270 : 15 : raid_bdev_remap_dix_reftag(void *md_buf, uint64_t num_blocks,
271 : : struct spdk_bdev *bdev, uint32_t remapped_offset)
272 : : {
273 : 15 : remap_dif(md_buf, num_blocks, bdev, remapped_offset);
274 : :
275 : 15 : return 0;
276 : : }
277 : :
278 : : int
279 : 25 : raid_bdev_verify_dix_reftag(struct iovec *iovs, int iovcnt, void *md_buf,
280 : : uint64_t num_blocks, struct spdk_bdev *bdev, uint32_t offset_blocks)
281 : : {
282 : 25 : verify_dif(iovs, iovcnt, md_buf, offset_blocks, num_blocks, bdev);
283 : :
284 : 25 : return 0;
285 : : }
286 : :
287 : : static void
288 : 177080 : set_io_output(struct io_output *output,
289 : : struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
290 : : uint64_t offset_blocks, uint64_t num_blocks,
291 : : spdk_bdev_io_completion_cb cb, void *cb_arg,
292 : : enum spdk_bdev_io_type iotype, struct iovec *iovs,
293 : : int iovcnt, void *md)
294 : : {
295 : 177080 : output->desc = desc;
296 : 177080 : output->ch = ch;
297 : 177080 : output->offset_blocks = offset_blocks;
298 : 177080 : output->num_blocks = num_blocks;
299 : 177080 : output->cb = cb;
300 : 177080 : output->cb_arg = cb_arg;
301 : 177080 : output->iotype = iotype;
302 : 177080 : output->iovs = iovs;
303 : 177080 : output->iovcnt = iovcnt;
304 : 177080 : output->md_buf = md;
305 : 177080 : }
306 : :
307 : : static struct spdk_bdev_io *
308 : 177080 : get_child_io(struct io_output *output)
309 : : {
310 : : struct spdk_bdev_io *bdev_io;
311 : :
312 : 177080 : bdev_io = calloc(1, sizeof(*bdev_io));
313 [ - + ]: 177080 : SPDK_CU_ASSERT_FATAL(bdev_io != NULL);
314 : :
315 : 177080 : bdev_io->bdev = spdk_bdev_desc_get_bdev(output->desc);
316 : 177080 : bdev_io->type = output->iotype;
317 : 177080 : bdev_io->u.bdev.offset_blocks = output->offset_blocks;
318 : 177080 : bdev_io->u.bdev.num_blocks = output->num_blocks;
319 : 177080 : bdev_io->u.bdev.iovs = output->iovs;
320 : 177080 : bdev_io->u.bdev.iovcnt = output->iovcnt;
321 : 177080 : bdev_io->u.bdev.md_buf = output->md_buf;
322 : :
323 : 177080 : return bdev_io;
324 : : }
325 : :
326 : : static void
327 : 177080 : child_io_complete(struct spdk_bdev_io *bdev_io, spdk_bdev_io_completion_cb cb, void *cb_arg)
328 : : {
329 [ + + + + : 177080 : if (g_child_io_status_flag && bdev_io->type == SPDK_BDEV_IO_TYPE_READ) {
+ + ]
330 : 36 : verify_dif(bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt, bdev_io->u.bdev.md_buf,
331 : 20 : bdev_io->u.bdev.offset_blocks, bdev_io->u.bdev.num_blocks, bdev_io->bdev);
332 : : }
333 : :
334 [ - + ]: 177080 : cb(bdev_io, g_child_io_status_flag, cb_arg);
335 : 177080 : }
336 : :
337 : : int
338 : 30 : spdk_bdev_writev_blocks_ext(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
339 : : struct iovec *iov, int iovcnt,
340 : : uint64_t offset_blocks, uint64_t num_blocks,
341 : : spdk_bdev_io_completion_cb cb, void *cb_arg,
342 : : struct spdk_bdev_ext_io_opts *opts)
343 : : {
344 : 30 : struct io_output *output = &g_io_output[g_io_output_index];
345 : : struct spdk_bdev_io *child_io;
346 : :
347 [ - + ]: 30 : if (g_max_io_size < g_strip_size) {
348 [ # # ]: 0 : SPDK_CU_ASSERT_FATAL(g_io_output_index < 2);
349 : : } else {
350 [ - + - + ]: 30 : SPDK_CU_ASSERT_FATAL(g_io_output_index < (g_max_io_size / g_strip_size) + 1);
351 : : }
352 : 30 : set_io_output(output, desc, ch, offset_blocks, num_blocks, cb, cb_arg,
353 : : SPDK_BDEV_IO_TYPE_WRITE, iov, iovcnt, opts->metadata);
354 : 30 : g_io_output_index++;
355 : :
356 : 30 : child_io = get_child_io(output);
357 : 30 : child_io_complete(child_io, cb, cb_arg);
358 : :
359 : 30 : return 0;
360 : : }
361 : :
362 : : int
363 : 177030 : spdk_bdev_unmap_blocks(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
364 : : uint64_t offset_blocks, uint64_t num_blocks,
365 : : spdk_bdev_io_completion_cb cb, void *cb_arg)
366 : : {
367 : 177030 : struct io_output *output = &g_io_output[g_io_output_index];
368 : : struct spdk_bdev_io *child_io;
369 : :
370 : 177030 : set_io_output(output, desc, ch, offset_blocks, num_blocks, cb, cb_arg,
371 : : SPDK_BDEV_IO_TYPE_UNMAP, NULL, 0, NULL);
372 : 177030 : g_io_output_index++;
373 : :
374 : 177030 : child_io = get_child_io(output);
375 : 177030 : child_io_complete(child_io, cb, cb_arg);
376 : :
377 : 177030 : return 0;
378 : : }
379 : :
380 : : void
381 : 177080 : spdk_bdev_free_io(struct spdk_bdev_io *bdev_io)
382 : : {
383 [ + - ]: 177080 : if (bdev_io) {
384 : 177080 : free(bdev_io);
385 : : }
386 : 177080 : }
387 : :
388 : : int
389 : 20 : spdk_bdev_readv_blocks_ext(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
390 : : struct iovec *iov, int iovcnt,
391 : : uint64_t offset_blocks, uint64_t num_blocks,
392 : : spdk_bdev_io_completion_cb cb, void *cb_arg,
393 : : struct spdk_bdev_ext_io_opts *opts)
394 : : {
395 : 20 : struct io_output *output = &g_io_output[g_io_output_index];
396 : : struct spdk_bdev_io *child_io;
397 : :
398 [ - + - + ]: 20 : SPDK_CU_ASSERT_FATAL(g_io_output_index <= (g_max_io_size / g_strip_size) + 1);
399 : 20 : set_io_output(output, desc, ch, offset_blocks, num_blocks, cb, cb_arg,
400 : : SPDK_BDEV_IO_TYPE_READ, iov, iovcnt, opts->metadata);
401 : 20 : generate_dif(iov, iovcnt, opts->metadata, offset_blocks, num_blocks,
402 : : spdk_bdev_desc_get_bdev(desc));
403 : 20 : g_io_output_index++;
404 : :
405 : 20 : child_io = get_child_io(output);
406 : 20 : child_io_complete(child_io, cb, cb_arg);
407 : :
408 : 20 : return 0;
409 : : }
410 : :
411 : : static void
412 : 9680 : raid_io_cleanup(struct raid_bdev_io *raid_io)
413 : : {
414 [ + + ]: 9680 : if (raid_io->iovs) {
415 : : int i;
416 : :
417 [ + + ]: 100 : for (i = 0; i < raid_io->iovcnt; i++) {
418 : 50 : free(raid_io->iovs[i].iov_base);
419 : : }
420 : 50 : free(raid_io->iovs);
421 : : }
422 : :
423 : 9680 : free(raid_io->md_buf);
424 : 9680 : free(raid_io);
425 : 9680 : }
426 : :
427 : : static void
428 : 9680 : raid_io_initialize(struct raid_bdev_io *raid_io, struct raid_bdev_io_channel *raid_ch,
429 : : struct raid_bdev *raid_bdev, uint64_t lba, uint64_t blocks, int16_t iotype)
430 : : {
431 : 9680 : struct iovec *iovs = NULL;
432 : 9680 : int iovcnt = 0;
433 : 9680 : void *md_buf = NULL;
434 : :
435 [ + + + - ]: 9680 : if (iotype != SPDK_BDEV_IO_TYPE_UNMAP && iotype != SPDK_BDEV_IO_TYPE_FLUSH) {
436 : 50 : iovcnt = 1;
437 : 50 : iovs = calloc(iovcnt, sizeof(struct iovec));
438 [ - + ]: 50 : SPDK_CU_ASSERT_FATAL(iovs != NULL);
439 : 50 : iovs->iov_len = blocks * g_block_len;
440 : 50 : iovs->iov_base = calloc(1, iovs->iov_len);
441 [ - + ]: 50 : SPDK_CU_ASSERT_FATAL(iovs->iov_base != NULL);
442 : :
443 [ + + ]: 50 : if (spdk_bdev_is_md_separate(&raid_bdev->bdev)) {
444 : 25 : md_buf = calloc(1, blocks * spdk_bdev_get_md_size(&raid_bdev->bdev));
445 [ - + ]: 25 : SPDK_CU_ASSERT_FATAL(md_buf != NULL);
446 : : }
447 : : }
448 : :
449 : 9680 : raid_test_bdev_io_init(raid_io, raid_bdev, raid_ch, iotype, lba, blocks, iovs, iovcnt, md_buf);
450 : 9680 : }
451 : :
452 : : static void
453 : 50 : verify_io(struct raid_bdev_io *raid_io, uint32_t io_status)
454 : : {
455 : 50 : struct raid_bdev *raid_bdev = raid_io->raid_bdev;
456 : 50 : uint8_t num_base_drives = raid_bdev->num_base_bdevs;
457 : 50 : uint32_t strip_shift = spdk_u32log2(g_strip_size);
458 [ - + ]: 50 : uint64_t start_strip = raid_io->offset_blocks >> strip_shift;
459 [ - + ]: 50 : uint64_t end_strip = (raid_io->offset_blocks + raid_io->num_blocks - 1) >>
460 : : strip_shift;
461 : 50 : uint32_t splits_reqd = (end_strip - start_strip + 1);
462 : : uint32_t strip;
463 : : uint64_t pd_strip;
464 : : uint8_t pd_idx;
465 : : uint32_t offset_in_strip;
466 : : uint64_t pd_lba;
467 : : uint64_t pd_blocks;
468 : 50 : uint32_t index = 0;
469 : : struct io_output *output;
470 : :
471 [ - + ]: 50 : SPDK_CU_ASSERT_FATAL(raid_bdev != NULL);
472 [ - + ]: 50 : SPDK_CU_ASSERT_FATAL(num_base_drives != 0);
473 : :
474 : 50 : CU_ASSERT(splits_reqd == g_io_output_index);
475 [ + + ]: 100 : for (strip = start_strip; strip <= end_strip; strip++, index++) {
476 [ - + ]: 50 : pd_strip = strip / num_base_drives;
477 [ - + ]: 50 : pd_idx = strip % num_base_drives;
478 [ + - ]: 50 : if (strip == start_strip) {
479 : 50 : offset_in_strip = raid_io->offset_blocks & (g_strip_size - 1);
480 [ - + ]: 50 : pd_lba = (pd_strip << strip_shift) + offset_in_strip;
481 [ + - ]: 50 : if (strip == end_strip) {
482 : 50 : pd_blocks = raid_io->num_blocks;
483 : : } else {
484 : 0 : pd_blocks = g_strip_size - offset_in_strip;
485 : : }
486 [ # # ]: 0 : } else if (strip == end_strip) {
487 [ # # ]: 0 : pd_lba = pd_strip << strip_shift;
488 : 0 : pd_blocks = ((raid_io->offset_blocks + raid_io->num_blocks - 1) &
489 : 0 : (g_strip_size - 1)) + 1;
490 : : } else {
491 [ # # ]: 0 : pd_lba = pd_strip << raid_bdev->strip_size_shift;
492 : 0 : pd_blocks = raid_bdev->strip_size;
493 : : }
494 : 50 : output = &g_io_output[index];
495 : 50 : CU_ASSERT(pd_lba == output->offset_blocks);
496 : 50 : CU_ASSERT(pd_blocks == output->num_blocks);
497 : 50 : CU_ASSERT(raid_bdev_channel_get_base_channel(raid_io->raid_ch, pd_idx) == output->ch);
498 : 50 : CU_ASSERT(raid_bdev->base_bdev_info[pd_idx].desc == output->desc);
499 : 50 : CU_ASSERT(raid_io->type == output->iotype);
500 [ + + ]: 50 : if (raid_io->type == SPDK_BDEV_IO_TYPE_WRITE) {
501 : 60 : verify_dif(output->iovs, output->iovcnt, output->md_buf,
502 : 30 : output->offset_blocks, output->num_blocks,
503 : 30 : spdk_bdev_desc_get_bdev(raid_bdev->base_bdev_info[pd_idx].desc));
504 : : }
505 : : }
506 : 50 : CU_ASSERT(g_io_comp_status == io_status);
507 : 50 : }
508 : :
509 : : static void
510 : 9630 : verify_io_without_payload(struct raid_bdev_io *raid_io, uint32_t io_status)
511 : : {
512 : 9630 : struct raid_bdev *raid_bdev = raid_io->raid_bdev;
513 : 9630 : uint8_t num_base_drives = raid_bdev->num_base_bdevs;
514 : 9630 : uint32_t strip_shift = spdk_u32log2(g_strip_size);
515 [ - + ]: 9630 : uint64_t start_offset_in_strip = raid_io->offset_blocks % g_strip_size;
516 [ - + ]: 9630 : uint64_t end_offset_in_strip = (raid_io->offset_blocks + raid_io->num_blocks - 1) %
517 : : g_strip_size;
518 [ - + ]: 9630 : uint64_t start_strip = raid_io->offset_blocks >> strip_shift;
519 [ - + ]: 9630 : uint64_t end_strip = (raid_io->offset_blocks + raid_io->num_blocks - 1) >>
520 : : strip_shift;
521 : : uint8_t n_disks_involved;
522 : : uint64_t start_strip_disk_idx;
523 : : uint64_t end_strip_disk_idx;
524 : : uint64_t nblocks_in_start_disk;
525 : : uint64_t offset_in_start_disk;
526 : : uint8_t disk_idx;
527 : : uint64_t base_io_idx;
528 : 9630 : uint64_t sum_nblocks = 0;
529 : : struct io_output *output;
530 : :
531 [ - + ]: 9630 : SPDK_CU_ASSERT_FATAL(raid_bdev != NULL);
532 [ - + ]: 9630 : SPDK_CU_ASSERT_FATAL(num_base_drives != 0);
533 [ - + ]: 9630 : SPDK_CU_ASSERT_FATAL(raid_io->type != SPDK_BDEV_IO_TYPE_READ);
534 [ - + ]: 9630 : SPDK_CU_ASSERT_FATAL(raid_io->type != SPDK_BDEV_IO_TYPE_WRITE);
535 : :
536 : 9630 : n_disks_involved = spdk_min(end_strip - start_strip + 1, num_base_drives);
537 : 9630 : CU_ASSERT(n_disks_involved == g_io_output_index);
538 : :
539 [ - + ]: 9630 : start_strip_disk_idx = start_strip % num_base_drives;
540 [ - + ]: 9630 : end_strip_disk_idx = end_strip % num_base_drives;
541 : :
542 : 9630 : offset_in_start_disk = g_io_output[0].offset_blocks;
543 : 9630 : nblocks_in_start_disk = g_io_output[0].num_blocks;
544 : :
545 [ + + ]: 186660 : for (base_io_idx = 0, disk_idx = start_strip_disk_idx; base_io_idx < n_disks_involved;
546 : 177030 : base_io_idx++, disk_idx++) {
547 : : uint64_t start_offset_in_disk;
548 : : uint64_t end_offset_in_disk;
549 : :
550 : 177030 : output = &g_io_output[base_io_idx];
551 : :
552 : : /* round disk_idx */
553 [ + + ]: 177030 : if (disk_idx >= num_base_drives) {
554 [ - + ]: 4950 : disk_idx %= num_base_drives;
555 : : }
556 : :
557 : : /* start_offset_in_disk aligned in strip check:
558 : : * The first base io has a same start_offset_in_strip with the whole raid io.
559 : : * Other base io should have aligned start_offset_in_strip which is 0.
560 : : */
561 : 177030 : start_offset_in_disk = output->offset_blocks;
562 [ + + ]: 177030 : if (base_io_idx == 0) {
563 [ - + ]: 9630 : CU_ASSERT(start_offset_in_disk % g_strip_size == start_offset_in_strip);
564 : : } else {
565 [ - + ]: 167400 : CU_ASSERT(start_offset_in_disk % g_strip_size == 0);
566 : : }
567 : :
568 : : /* end_offset_in_disk aligned in strip check:
569 : : * Base io on disk at which end_strip is located, has a same end_offset_in_strip
570 : : * with the whole raid io.
571 : : * Other base io should have aligned end_offset_in_strip.
572 : : */
573 : 177030 : end_offset_in_disk = output->offset_blocks + output->num_blocks - 1;
574 [ + + ]: 177030 : if (disk_idx == end_strip_disk_idx) {
575 [ - + ]: 9630 : CU_ASSERT(end_offset_in_disk % g_strip_size == end_offset_in_strip);
576 : : } else {
577 [ - + ]: 167400 : CU_ASSERT(end_offset_in_disk % g_strip_size == g_strip_size - 1);
578 : : }
579 : :
580 : : /* start_offset_in_disk compared with start_disk.
581 : : * 1. For disk_idx which is larger than start_strip_disk_idx: Its start_offset_in_disk
582 : : * mustn't be larger than the start offset of start_offset_in_disk; And the gap
583 : : * must be less than strip size.
584 : : * 2. For disk_idx which is less than start_strip_disk_idx, Its start_offset_in_disk
585 : : * must be larger than the start offset of start_offset_in_disk; And the gap mustn't
586 : : * be less than strip size.
587 : : */
588 [ + + ]: 177030 : if (disk_idx > start_strip_disk_idx) {
589 : 93600 : CU_ASSERT(start_offset_in_disk <= offset_in_start_disk);
590 : 93600 : CU_ASSERT(offset_in_start_disk - start_offset_in_disk < g_strip_size);
591 [ + + ]: 83430 : } else if (disk_idx < start_strip_disk_idx) {
592 : 73800 : CU_ASSERT(start_offset_in_disk > offset_in_start_disk);
593 : 73800 : CU_ASSERT(output->offset_blocks - offset_in_start_disk <= g_strip_size);
594 : : }
595 : :
596 : : /* nblocks compared with start_disk:
597 : : * The gap between them must be within a strip size.
598 : : */
599 [ + + ]: 177030 : if (output->num_blocks <= nblocks_in_start_disk) {
600 : 70440 : CU_ASSERT(nblocks_in_start_disk - output->num_blocks <= g_strip_size);
601 : : } else {
602 : 106590 : CU_ASSERT(output->num_blocks - nblocks_in_start_disk < g_strip_size);
603 : : }
604 : :
605 : 177030 : sum_nblocks += output->num_blocks;
606 : :
607 : 177030 : CU_ASSERT(raid_bdev_channel_get_base_channel(raid_io->raid_ch, disk_idx) == output->ch);
608 : 177030 : CU_ASSERT(raid_bdev->base_bdev_info[disk_idx].desc == output->desc);
609 : 177030 : CU_ASSERT(raid_io->type == output->iotype);
610 : : }
611 : :
612 : : /* Sum of each nblocks should be same with raid bdev_io */
613 : 9630 : CU_ASSERT(raid_io->num_blocks == sum_nblocks);
614 : :
615 : 9630 : CU_ASSERT(g_io_comp_status == io_status);
616 : 9630 : }
617 : :
618 : : static struct raid_bdev *
619 : 40 : create_raid0(void)
620 : : {
621 : : struct raid_bdev *raid_bdev;
622 : : struct raid_base_bdev_info *base_info;
623 : 48 : struct raid_params params = {
624 : : .num_base_bdevs = g_max_base_drives,
625 : : .base_bdev_blockcnt = BLOCK_CNT,
626 : : .base_bdev_blocklen = g_block_len,
627 : : .strip_size = g_strip_size,
628 [ - + ]: 40 : .md_type = g_enable_dif ? RAID_PARAMS_MD_SEPARATE : RAID_PARAMS_MD_NONE,
629 : : };
630 : :
631 : 40 : raid_bdev = raid_test_create_raid_bdev(¶ms, &g_raid0_module);
632 : :
633 [ - + ]: 40 : SPDK_CU_ASSERT_FATAL(raid0_start(raid_bdev) == 0);
634 : :
635 [ + + + + ]: 40 : if (g_enable_dif) {
636 : 20 : raid_bdev->bdev.dif_type = SPDK_DIF_TYPE1;
637 : 20 : raid_bdev->bdev.dif_check_flags =
638 : : SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_REFTAG_CHECK |
639 : : SPDK_DIF_FLAGS_APPTAG_CHECK;
640 : :
641 [ + + ]: 660 : RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
642 : 640 : struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(base_info->desc);
643 : :
644 : 640 : bdev->dif_type = raid_bdev->bdev.dif_type;
645 : 640 : bdev->dif_check_flags = raid_bdev->bdev.dif_check_flags;
646 : : }
647 : : }
648 : :
649 : 40 : return raid_bdev;
650 : : }
651 : :
652 : : static void
653 : 40 : delete_raid0(struct raid_bdev *raid_bdev)
654 : : {
655 : 40 : raid_test_delete_raid_bdev(raid_bdev);
656 : 40 : }
657 : :
658 : : static void
659 : 10 : test_write_io(void)
660 : : {
661 : : struct raid_bdev *raid_bdev;
662 : : uint8_t i;
663 : : uint64_t io_len;
664 : 10 : uint64_t lba = 0;
665 : : struct raid_bdev_io *raid_io;
666 : : struct raid_bdev_io_channel *raid_ch;
667 : :
668 : 10 : set_globals();
669 : :
670 : 10 : raid_bdev = create_raid0();
671 : 10 : raid_ch = raid_test_create_io_channel(raid_bdev);
672 : :
673 : : /* test 2 IO sizes based on global strip size set earlier */
674 [ + + ]: 30 : for (i = 0; i < 2; i++) {
675 : 20 : raid_io = calloc(1, sizeof(*raid_io));
676 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(raid_io != NULL);
677 [ - + ]: 20 : io_len = (g_strip_size / 2) << i;
678 : 20 : raid_io_initialize(raid_io, raid_ch, raid_bdev, lba, io_len, SPDK_BDEV_IO_TYPE_WRITE);
679 : 20 : lba += g_strip_size;
680 [ - + - + ]: 20 : memset(g_io_output, 0, ((g_max_io_size / g_strip_size) + 1) * sizeof(struct io_output));
681 : 20 : g_io_output_index = 0;
682 : 36 : generate_dif(raid_io->iovs, raid_io->iovcnt, raid_io->md_buf,
683 : 20 : raid_io->offset_blocks, raid_io->num_blocks, &raid_bdev->bdev);
684 : 20 : raid0_submit_rw_request(raid_io);
685 [ - + ]: 20 : verify_io(raid_io, g_child_io_status_flag);
686 : 20 : raid_io_cleanup(raid_io);
687 : : }
688 : :
689 : 10 : raid_test_destroy_io_channel(raid_ch);
690 : 10 : delete_raid0(raid_bdev);
691 : :
692 : 10 : reset_globals();
693 : 10 : }
694 : :
695 : : static void
696 : 10 : test_read_io(void)
697 : : {
698 : : struct raid_bdev *raid_bdev;
699 : : uint8_t i;
700 : : uint64_t io_len;
701 : 10 : uint64_t lba = 0;
702 : : struct raid_bdev_io *raid_io;
703 : : struct raid_bdev_io_channel *raid_ch;
704 : :
705 : 10 : set_globals();
706 : :
707 : 10 : raid_bdev = create_raid0();
708 : 10 : raid_ch = raid_test_create_io_channel(raid_bdev);
709 : :
710 : : /* test 2 IO sizes based on global strip size set earlier */
711 : 10 : lba = 0;
712 [ + + ]: 30 : for (i = 0; i < 2; i++) {
713 : 20 : raid_io = calloc(1, sizeof(*raid_io));
714 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(raid_io != NULL);
715 [ - + ]: 20 : io_len = (g_strip_size / 2) << i;
716 : 20 : raid_io_initialize(raid_io, raid_ch, raid_bdev, lba, io_len, SPDK_BDEV_IO_TYPE_READ);
717 : 20 : lba += g_strip_size;
718 [ - + - + ]: 20 : memset(g_io_output, 0, ((g_max_io_size / g_strip_size) + 1) * sizeof(struct io_output));
719 : 20 : g_io_output_index = 0;
720 : 20 : raid0_submit_rw_request(raid_io);
721 [ - + ]: 20 : verify_io(raid_io, g_child_io_status_flag);
722 : 20 : raid_io_cleanup(raid_io);
723 : : }
724 : :
725 : 10 : raid_test_destroy_io_channel(raid_ch);
726 : 10 : delete_raid0(raid_bdev);
727 : :
728 : 10 : reset_globals();
729 : 10 : }
730 : :
731 : : static void
732 : 360 : raid_bdev_io_generate_by_strips(uint64_t n_strips)
733 : : {
734 : : uint64_t lba;
735 : : uint64_t nblocks;
736 : : uint64_t start_offset;
737 : : uint64_t end_offset;
738 : 288 : uint64_t offsets_in_strip[3];
739 : : uint64_t start_bdev_idx;
740 : : uint64_t start_bdev_offset;
741 : 288 : uint64_t start_bdev_idxs[3];
742 : : int i, j, l;
743 : :
744 : : /* 3 different situations of offset in strip */
745 : 360 : offsets_in_strip[0] = 0;
746 : 360 : offsets_in_strip[1] = g_strip_size >> 1;
747 : 360 : offsets_in_strip[2] = g_strip_size - 1;
748 : :
749 : : /* 3 different situations of start_bdev_idx */
750 : 360 : start_bdev_idxs[0] = 0;
751 : 360 : start_bdev_idxs[1] = g_max_base_drives >> 1;
752 : 360 : start_bdev_idxs[2] = g_max_base_drives - 1;
753 : :
754 : : /* consider different offset in strip */
755 [ + + ]: 1440 : for (i = 0; i < 3; i++) {
756 : 1080 : start_offset = offsets_in_strip[i];
757 [ + + ]: 4320 : for (j = 0; j < 3; j++) {
758 : 3240 : end_offset = offsets_in_strip[j];
759 [ + + + + ]: 3240 : if (n_strips == 1 && start_offset > end_offset) {
760 : 30 : continue;
761 : : }
762 : :
763 : : /* consider at which base_bdev lba is started. */
764 [ + + ]: 12840 : for (l = 0; l < 3; l++) {
765 : 9630 : start_bdev_idx = start_bdev_idxs[l];
766 : 9630 : start_bdev_offset = start_bdev_idx * g_strip_size;
767 : 9630 : lba = start_bdev_offset + start_offset;
768 : 9630 : nblocks = (n_strips - 1) * g_strip_size + end_offset - start_offset + 1;
769 : :
770 : 9630 : g_io_ranges[g_io_range_idx].lba = lba;
771 : 9630 : g_io_ranges[g_io_range_idx].nblocks = nblocks;
772 : :
773 [ - + ]: 9630 : SPDK_CU_ASSERT_FATAL(g_io_range_idx < MAX_TEST_IO_RANGE);
774 : 9630 : g_io_range_idx++;
775 : : }
776 : : }
777 : : }
778 : 360 : }
779 : :
780 : : static void
781 : 10 : raid_bdev_io_generate(void)
782 : : {
783 : : uint64_t n_strips;
784 : 10 : uint64_t n_strips_span = g_max_base_drives;
785 : 10 : uint64_t n_strips_times[5] = {g_max_base_drives + 1, g_max_base_drives * 2 - 1,
786 : 10 : g_max_base_drives * 2, g_max_base_drives * 3,
787 : 10 : g_max_base_drives * 4
788 : : };
789 : : uint32_t i;
790 : :
791 : 10 : g_io_range_idx = 0;
792 : :
793 : : /* consider different number of strips from 1 to strips spanned base bdevs,
794 : : * and even to times of strips spanned base bdevs
795 : : */
796 [ + + ]: 320 : for (n_strips = 1; n_strips < n_strips_span; n_strips++) {
797 : 310 : raid_bdev_io_generate_by_strips(n_strips);
798 : : }
799 : :
800 [ + + ]: 60 : for (i = 0; i < SPDK_COUNTOF(n_strips_times); i++) {
801 : 50 : n_strips = n_strips_times[i];
802 : 50 : raid_bdev_io_generate_by_strips(n_strips);
803 : : }
804 : 10 : }
805 : :
806 : : static void
807 : 10 : test_unmap_io(void)
808 : : {
809 : : struct raid_bdev *raid_bdev;
810 : : uint32_t count;
811 : : uint64_t io_len;
812 : : uint64_t lba;
813 : : struct raid_bdev_io *raid_io;
814 : : struct raid_bdev_io_channel *raid_ch;
815 : :
816 : 10 : set_globals();
817 : :
818 : 10 : raid_bdev = create_raid0();
819 : 10 : raid_ch = raid_test_create_io_channel(raid_bdev);
820 : :
821 : 10 : raid_bdev_io_generate();
822 [ + + ]: 9640 : for (count = 0; count < g_io_range_idx; count++) {
823 : 9630 : raid_io = calloc(1, sizeof(*raid_io));
824 [ - + ]: 9630 : SPDK_CU_ASSERT_FATAL(raid_io != NULL);
825 : 9630 : io_len = g_io_ranges[count].nblocks;
826 : 9630 : lba = g_io_ranges[count].lba;
827 : 9630 : raid_io_initialize(raid_io, raid_ch, raid_bdev, lba, io_len, SPDK_BDEV_IO_TYPE_UNMAP);
828 [ - + ]: 9630 : memset(g_io_output, 0, g_max_base_drives * sizeof(struct io_output));
829 : 9630 : g_io_output_index = 0;
830 : 9630 : raid0_submit_null_payload_request(raid_io);
831 [ - + ]: 9630 : verify_io_without_payload(raid_io, g_child_io_status_flag);
832 : 9630 : raid_io_cleanup(raid_io);
833 : : }
834 : :
835 : 10 : raid_test_destroy_io_channel(raid_ch);
836 : 10 : delete_raid0(raid_bdev);
837 : :
838 : 10 : reset_globals();
839 : 10 : }
840 : :
841 : : /* Test IO failures */
842 : : static void
843 : 10 : test_io_failure(void)
844 : : {
845 : : struct raid_bdev *raid_bdev;
846 : : uint32_t count;
847 : : uint64_t io_len;
848 : : uint64_t lba;
849 : : struct raid_bdev_io *raid_io;
850 : : struct raid_bdev_io_channel *raid_ch;
851 : :
852 : 10 : set_globals();
853 : :
854 : 10 : raid_bdev = create_raid0();
855 : 10 : raid_ch = raid_test_create_io_channel(raid_bdev);
856 : :
857 : 10 : lba = 0;
858 : 10 : g_child_io_status_flag = false;
859 [ + + ]: 20 : for (count = 0; count < 1; count++) {
860 : 10 : raid_io = calloc(1, sizeof(*raid_io));
861 [ - + ]: 10 : SPDK_CU_ASSERT_FATAL(raid_io != NULL);
862 [ - + ]: 10 : io_len = (g_strip_size / 2) << count;
863 : 10 : raid_io_initialize(raid_io, raid_ch, raid_bdev, lba, io_len, SPDK_BDEV_IO_TYPE_WRITE);
864 : 10 : lba += g_strip_size;
865 [ - + - + ]: 10 : memset(g_io_output, 0, ((g_max_io_size / g_strip_size) + 1) * sizeof(struct io_output));
866 : 10 : g_io_output_index = 0;
867 : 18 : generate_dif(raid_io->iovs, raid_io->iovcnt, raid_io->md_buf,
868 : 10 : raid_io->offset_blocks, raid_io->num_blocks, &raid_bdev->bdev);
869 : 10 : raid0_submit_rw_request(raid_io);
870 [ - + ]: 10 : verify_io(raid_io, g_child_io_status_flag);
871 : 10 : raid_io_cleanup(raid_io);
872 : : }
873 : :
874 : 10 : raid_test_destroy_io_channel(raid_ch);
875 : 10 : delete_raid0(raid_bdev);
876 : :
877 : 10 : reset_globals();
878 : 10 : }
879 : :
880 : : int
881 : 5 : main(int argc, char **argv)
882 : : {
883 : : unsigned int num_failures;
884 : :
885 : 5 : CU_TestInfo tests[] = {
886 : : { "test_write_io", test_write_io },
887 : : { "test_read_io", test_read_io },
888 : : { "test_unmap_io", test_unmap_io },
889 : : { "test_io_failure", test_io_failure },
890 : : CU_TEST_INFO_NULL,
891 : : };
892 : 5 : CU_SuiteInfo suites[] = {
893 : : { "raid0", set_test_opts, NULL, NULL, NULL, tests },
894 : : { "raid0_dif", set_test_opts_dif, NULL, NULL, NULL, tests },
895 : : CU_SUITE_INFO_NULL,
896 : : };
897 : :
898 : 5 : CU_initialize_registry();
899 : 5 : CU_register_suites(suites);
900 : :
901 : 5 : allocate_threads(1);
902 : 5 : set_thread(0);
903 : :
904 : 5 : num_failures = spdk_ut_run_tests(argc, argv, NULL);
905 : 5 : CU_cleanup_registry();
906 : :
907 : 5 : free_threads();
908 : :
909 : 5 : return num_failures;
910 : : }
|