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 "bdev_raid.h"
7 : :
8 : : #include "spdk/env.h"
9 : : #include "spdk/thread.h"
10 : : #include "spdk/string.h"
11 : : #include "spdk/util.h"
12 : : #include "spdk/likely.h"
13 : : #include "spdk/log.h"
14 : : #include "spdk/accel.h"
15 : :
16 : : /* Maximum concurrent full stripe writes per io channel */
17 : : #define RAID5F_MAX_STRIPES 32
18 : :
19 : : struct chunk {
20 : : /* Corresponds to base_bdev index */
21 : : uint8_t index;
22 : :
23 : : /* Array of iovecs */
24 : : struct iovec *iovs;
25 : :
26 : : /* Number of used iovecs */
27 : : int iovcnt;
28 : :
29 : : /* Total number of available iovecs in the array */
30 : : int iovcnt_max;
31 : :
32 : : /* Pointer to buffer with I/O metadata */
33 : : void *md_buf;
34 : : };
35 : :
36 : : struct stripe_request;
37 : : typedef void (*stripe_req_xor_cb)(struct stripe_request *stripe_req, int status);
38 : :
39 : : struct stripe_request {
40 : : enum stripe_request_type {
41 : : STRIPE_REQ_WRITE,
42 : : STRIPE_REQ_RECONSTRUCT,
43 : : } type;
44 : :
45 : : struct raid5f_io_channel *r5ch;
46 : :
47 : : /* The associated raid_bdev_io */
48 : : struct raid_bdev_io *raid_io;
49 : :
50 : : /* The stripe's index in the raid array. */
51 : : uint64_t stripe_index;
52 : :
53 : : /* The stripe's parity chunk */
54 : : struct chunk *parity_chunk;
55 : :
56 : : union {
57 : : struct {
58 : : /* Buffer for stripe parity */
59 : : void *parity_buf;
60 : :
61 : : /* Buffer for stripe io metadata parity */
62 : : void *parity_md_buf;
63 : : } write;
64 : :
65 : : struct {
66 : : /* Array of buffers for reading chunk data */
67 : : void **chunk_buffers;
68 : :
69 : : /* Array of buffers for reading chunk metadata */
70 : : void **chunk_md_buffers;
71 : :
72 : : /* Chunk to reconstruct from parity */
73 : : struct chunk *chunk;
74 : :
75 : : /* Offset from chunk start */
76 : : uint64_t chunk_offset;
77 : : } reconstruct;
78 : : };
79 : :
80 : : /* Array of iovec iterators for each chunk */
81 : : struct spdk_ioviter *chunk_iov_iters;
82 : :
83 : : /* Array of source buffer pointers for parity calculation */
84 : : void **chunk_xor_buffers;
85 : :
86 : : /* Array of source buffer pointers for parity calculation of io metadata */
87 : : void **chunk_xor_md_buffers;
88 : :
89 : : struct {
90 : : size_t len;
91 : : size_t remaining;
92 : : size_t remaining_md;
93 : : int status;
94 : : stripe_req_xor_cb cb;
95 : : } xor;
96 : :
97 : : TAILQ_ENTRY(stripe_request) link;
98 : :
99 : : /* Array of chunks corresponding to base_bdevs */
100 : : struct chunk chunks[0];
101 : : };
102 : :
103 : : struct raid5f_info {
104 : : /* The parent raid bdev */
105 : : struct raid_bdev *raid_bdev;
106 : :
107 : : /* Number of data blocks in a stripe (without parity) */
108 : : uint64_t stripe_blocks;
109 : :
110 : : /* Number of stripes on this array */
111 : : uint64_t total_stripes;
112 : :
113 : : /* Alignment for buffer allocation */
114 : : size_t buf_alignment;
115 : : };
116 : :
117 : : struct raid5f_io_channel {
118 : : /* All available stripe requests on this channel */
119 : : struct {
120 : : TAILQ_HEAD(, stripe_request) write;
121 : : TAILQ_HEAD(, stripe_request) reconstruct;
122 : : } free_stripe_requests;
123 : :
124 : : /* accel_fw channel */
125 : : struct spdk_io_channel *accel_ch;
126 : :
127 : : /* For retrying xor if accel_ch runs out of resources */
128 : : TAILQ_HEAD(, stripe_request) xor_retry_queue;
129 : :
130 : : /* For iterating over chunk iovecs during xor calculation */
131 : : void **chunk_xor_buffers;
132 : : struct iovec **chunk_xor_iovs;
133 : : size_t *chunk_xor_iovcnt;
134 : : };
135 : :
136 : : #define __CHUNK_IN_RANGE(req, c) \
137 : : c < req->chunks + raid5f_ch_to_r5f_info(req->r5ch)->raid_bdev->num_base_bdevs
138 : :
139 : : #define FOR_EACH_CHUNK_FROM(req, c, from) \
140 : : for (c = from; __CHUNK_IN_RANGE(req, c); c++)
141 : :
142 : : #define FOR_EACH_CHUNK(req, c) \
143 : : FOR_EACH_CHUNK_FROM(req, c, req->chunks)
144 : :
145 : : #define __NEXT_DATA_CHUNK(req, c) \
146 : : c == req->parity_chunk ? c+1 : c
147 : :
148 : : #define FOR_EACH_DATA_CHUNK(req, c) \
149 : : for (c = __NEXT_DATA_CHUNK(req, req->chunks); __CHUNK_IN_RANGE(req, c); \
150 : : c = __NEXT_DATA_CHUNK(req, c+1))
151 : :
152 : : static inline struct raid5f_info *
153 : 7455477 : raid5f_ch_to_r5f_info(struct raid5f_io_channel *r5ch)
154 : : {
155 : 7455477 : return spdk_io_channel_get_io_device(spdk_io_channel_from_ctx(r5ch));
156 : : }
157 : :
158 : : static inline struct stripe_request *
159 : 3346314 : raid5f_chunk_stripe_req(struct chunk *chunk)
160 : : {
161 : 3346314 : return SPDK_CONTAINEROF((chunk - chunk->index), struct stripe_request, chunks);
162 : : }
163 : :
164 : : static inline uint8_t
165 : 3374217 : raid5f_stripe_data_chunks_num(const struct raid_bdev *raid_bdev)
166 : : {
167 : 3374217 : return raid_bdev->min_base_bdevs_operational;
168 : : }
169 : :
170 : : static inline uint8_t
171 : 1928334 : raid5f_stripe_parity_chunk_index(const struct raid_bdev *raid_bdev, uint64_t stripe_index)
172 : : {
173 [ - + ]: 1928334 : return raid5f_stripe_data_chunks_num(raid_bdev) - stripe_index % raid_bdev->num_base_bdevs;
174 : : }
175 : :
176 : : static inline void
177 : 533063 : raid5f_stripe_request_release(struct stripe_request *stripe_req)
178 : : {
179 [ + + ]: 533063 : if (spdk_likely(stripe_req->type == STRIPE_REQ_WRITE)) {
180 [ + + ]: 525495 : TAILQ_INSERT_HEAD(&stripe_req->r5ch->free_stripe_requests.write, stripe_req, link);
181 [ + - ]: 7568 : } else if (stripe_req->type == STRIPE_REQ_RECONSTRUCT) {
182 [ + - ]: 7568 : TAILQ_INSERT_HEAD(&stripe_req->r5ch->free_stripe_requests.reconstruct, stripe_req, link);
183 : : } else {
184 : 0 : assert(false);
185 : : }
186 : 533063 : }
187 : :
188 : : static void raid5f_xor_stripe_retry(struct stripe_request *stripe_req);
189 : :
190 : : static void
191 : 532831 : raid5f_xor_stripe_done(struct stripe_request *stripe_req)
192 : : {
193 : 532831 : struct raid5f_io_channel *r5ch = stripe_req->r5ch;
194 : :
195 [ - + ]: 532831 : if (stripe_req->xor.status != 0) {
196 : 0 : SPDK_ERRLOG("stripe xor failed: %s\n", spdk_strerror(-stripe_req->xor.status));
197 : : }
198 : :
199 : 532831 : stripe_req->xor.cb(stripe_req, stripe_req->xor.status);
200 : :
201 [ - + ]: 532831 : if (!TAILQ_EMPTY(&r5ch->xor_retry_queue)) {
202 : 0 : stripe_req = TAILQ_FIRST(&r5ch->xor_retry_queue);
203 [ # # ]: 0 : TAILQ_REMOVE(&r5ch->xor_retry_queue, stripe_req, link);
204 : 0 : raid5f_xor_stripe_retry(stripe_req);
205 : : }
206 : 532831 : }
207 : :
208 : : static void raid5f_xor_stripe_continue(struct stripe_request *stripe_req);
209 : :
210 : : static void
211 : 680491 : _raid5f_xor_stripe_cb(struct stripe_request *stripe_req, int status)
212 : : {
213 [ - + ]: 680491 : if (status != 0) {
214 : 0 : stripe_req->xor.status = status;
215 : : }
216 : :
217 [ + + ]: 680491 : if (stripe_req->xor.remaining + stripe_req->xor.remaining_md == 0) {
218 : 532831 : raid5f_xor_stripe_done(stripe_req);
219 : : }
220 : 680491 : }
221 : :
222 : : static void
223 : 669135 : raid5f_xor_stripe_cb(void *_stripe_req, int status)
224 : : {
225 : 669135 : struct stripe_request *stripe_req = _stripe_req;
226 : :
227 : 669135 : stripe_req->xor.remaining -= stripe_req->xor.len;
228 : :
229 [ + + ]: 669135 : if (stripe_req->xor.remaining > 0) {
230 : 136304 : stripe_req->xor.len = spdk_ioviter_nextv(stripe_req->chunk_iov_iters,
231 : 136304 : stripe_req->r5ch->chunk_xor_buffers);
232 : 136304 : raid5f_xor_stripe_continue(stripe_req);
233 : : }
234 : :
235 : 669135 : _raid5f_xor_stripe_cb(stripe_req, status);
236 : 669135 : }
237 : :
238 : : static void
239 : 11356 : raid5f_xor_stripe_md_cb(void *_stripe_req, int status)
240 : : {
241 : 11356 : struct stripe_request *stripe_req = _stripe_req;
242 : :
243 : 11356 : stripe_req->xor.remaining_md = 0;
244 : :
245 : 11356 : _raid5f_xor_stripe_cb(stripe_req, status);
246 : 11356 : }
247 : :
248 : : static void
249 : 669135 : raid5f_xor_stripe_continue(struct stripe_request *stripe_req)
250 : : {
251 : 669135 : struct raid5f_io_channel *r5ch = stripe_req->r5ch;
252 : 669135 : struct raid_bdev_io *raid_io = stripe_req->raid_io;
253 : 669135 : struct raid_bdev *raid_bdev = raid_io->raid_bdev;
254 : 669135 : uint8_t n_src = raid5f_stripe_data_chunks_num(raid_bdev);
255 : : uint8_t i;
256 : : int ret;
257 : :
258 [ - + ]: 669135 : assert(stripe_req->xor.len > 0);
259 : :
260 [ + + ]: 2218801 : for (i = 0; i < n_src; i++) {
261 : 1549666 : stripe_req->chunk_xor_buffers[i] = r5ch->chunk_xor_buffers[i];
262 : : }
263 : :
264 : 669135 : ret = spdk_accel_submit_xor(r5ch->accel_ch, r5ch->chunk_xor_buffers[n_src],
265 : : stripe_req->chunk_xor_buffers, n_src, stripe_req->xor.len,
266 : : raid5f_xor_stripe_cb, stripe_req);
267 [ - + ]: 669135 : if (spdk_unlikely(ret)) {
268 [ # # ]: 0 : if (ret == -ENOMEM) {
269 [ # # ]: 0 : TAILQ_INSERT_HEAD(&r5ch->xor_retry_queue, stripe_req, link);
270 : : } else {
271 : 0 : stripe_req->xor.status = ret;
272 : 0 : raid5f_xor_stripe_done(stripe_req);
273 : : }
274 : : }
275 : 669135 : }
276 : :
277 : : static void
278 : 532831 : raid5f_xor_stripe(struct stripe_request *stripe_req, stripe_req_xor_cb cb)
279 : : {
280 : 532831 : struct raid5f_io_channel *r5ch = stripe_req->r5ch;
281 : 532831 : struct raid_bdev_io *raid_io = stripe_req->raid_io;
282 : 532831 : struct raid_bdev *raid_bdev = raid_io->raid_bdev;
283 : : struct chunk *chunk;
284 : 532831 : struct chunk *dest_chunk = NULL;
285 : 532831 : uint64_t num_blocks = 0;
286 : : uint8_t c;
287 : :
288 [ - + ]: 532831 : assert(cb != NULL);
289 : :
290 [ + + ]: 532831 : if (spdk_likely(stripe_req->type == STRIPE_REQ_WRITE)) {
291 : 525263 : num_blocks = raid_bdev->strip_size;
292 : 525263 : dest_chunk = stripe_req->parity_chunk;
293 [ + - ]: 7568 : } else if (stripe_req->type == STRIPE_REQ_RECONSTRUCT) {
294 : 7568 : num_blocks = raid_io->num_blocks;
295 : 7568 : dest_chunk = stripe_req->reconstruct.chunk;
296 : : } else {
297 : 0 : assert(false);
298 : : }
299 : :
300 : 532831 : c = 0;
301 [ + + ]: 2165260 : FOR_EACH_CHUNK(stripe_req, chunk) {
302 [ + + ]: 1632433 : if (chunk == dest_chunk) {
303 : 532831 : continue;
304 : : }
305 : 1099602 : r5ch->chunk_xor_iovs[c] = chunk->iovs;
306 : 1099602 : r5ch->chunk_xor_iovcnt[c] = chunk->iovcnt;
307 : 1099602 : c++;
308 : : }
309 : 532831 : r5ch->chunk_xor_iovs[c] = dest_chunk->iovs;
310 : 532831 : r5ch->chunk_xor_iovcnt[c] = dest_chunk->iovcnt;
311 : :
312 : 1065662 : stripe_req->xor.len = spdk_ioviter_firstv(stripe_req->chunk_iov_iters,
313 : 532831 : raid_bdev->num_base_bdevs,
314 : : r5ch->chunk_xor_iovs,
315 : : r5ch->chunk_xor_iovcnt,
316 : : r5ch->chunk_xor_buffers);
317 [ - + ]: 532831 : stripe_req->xor.remaining = num_blocks << raid_bdev->blocklen_shift;
318 : 532831 : stripe_req->xor.status = 0;
319 : 532831 : stripe_req->xor.cb = cb;
320 : :
321 [ + + ]: 532831 : if (raid_io->md_buf != NULL) {
322 : 11356 : uint8_t n_src = raid5f_stripe_data_chunks_num(raid_bdev);
323 : 11356 : uint64_t len = num_blocks * spdk_bdev_get_md_size(&raid_bdev->bdev);
324 : : int ret;
325 : :
326 : 11356 : stripe_req->xor.remaining_md = len;
327 : :
328 : 11356 : c = 0;
329 [ + + ]: 60212 : FOR_EACH_CHUNK(stripe_req, chunk) {
330 [ + + ]: 48856 : if (chunk != dest_chunk) {
331 : 37500 : stripe_req->chunk_xor_md_buffers[c] = chunk->md_buf;
332 : 37500 : c++;
333 : : }
334 : : }
335 : :
336 : 11356 : ret = spdk_accel_submit_xor(stripe_req->r5ch->accel_ch, dest_chunk->md_buf,
337 : : stripe_req->chunk_xor_md_buffers, n_src, len,
338 : : raid5f_xor_stripe_md_cb, stripe_req);
339 [ - + ]: 11356 : if (spdk_unlikely(ret)) {
340 [ # # ]: 0 : if (ret == -ENOMEM) {
341 [ # # ]: 0 : TAILQ_INSERT_HEAD(&stripe_req->r5ch->xor_retry_queue, stripe_req, link);
342 : : } else {
343 : 0 : stripe_req->xor.status = ret;
344 : 0 : raid5f_xor_stripe_done(stripe_req);
345 : : }
346 : 0 : return;
347 : : }
348 : : }
349 : :
350 : 532831 : raid5f_xor_stripe_continue(stripe_req);
351 : : }
352 : :
353 : : static void
354 : 0 : raid5f_xor_stripe_retry(struct stripe_request *stripe_req)
355 : : {
356 [ # # ]: 0 : if (stripe_req->xor.remaining_md) {
357 : 0 : raid5f_xor_stripe(stripe_req, stripe_req->xor.cb);
358 : : } else {
359 : 0 : raid5f_xor_stripe_continue(stripe_req);
360 : : }
361 : 0 : }
362 : :
363 : : static void
364 : 1590237 : raid5f_stripe_request_chunk_write_complete(struct stripe_request *stripe_req,
365 : : enum spdk_bdev_io_status status)
366 : : {
367 [ + + ]: 1590237 : if (raid_bdev_io_complete_part(stripe_req->raid_io, 1, status)) {
368 : 524519 : raid5f_stripe_request_release(stripe_req);
369 : : }
370 : 1590237 : }
371 : :
372 : : static void
373 : 20724 : raid5f_stripe_request_chunk_read_complete(struct stripe_request *stripe_req,
374 : : enum spdk_bdev_io_status status)
375 : : {
376 : 20724 : struct raid_bdev_io *raid_io = stripe_req->raid_io;
377 : :
378 : 20724 : raid_bdev_io_complete_part(raid_io, 1, status);
379 : 20724 : }
380 : :
381 : : static void
382 : 1610961 : raid5f_chunk_complete_bdev_io(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
383 : : {
384 : 1610961 : struct chunk *chunk = cb_arg;
385 : 1610961 : struct stripe_request *stripe_req = raid5f_chunk_stripe_req(chunk);
386 [ + + ]: 1610961 : enum spdk_bdev_io_status status = success ? SPDK_BDEV_IO_STATUS_SUCCESS :
387 : : SPDK_BDEV_IO_STATUS_FAILED;
388 : :
389 : 1610961 : spdk_bdev_free_io(bdev_io);
390 : :
391 [ + + ]: 1610961 : if (spdk_likely(stripe_req->type == STRIPE_REQ_WRITE)) {
392 : 1590237 : raid5f_stripe_request_chunk_write_complete(stripe_req, status);
393 [ + - ]: 20724 : } else if (stripe_req->type == STRIPE_REQ_RECONSTRUCT) {
394 : 20724 : raid5f_stripe_request_chunk_read_complete(stripe_req, status);
395 : : } else {
396 : 0 : assert(false);
397 : : }
398 : 1610961 : }
399 : :
400 : : static void raid5f_stripe_request_submit_chunks(struct stripe_request *stripe_req);
401 : :
402 : : static void
403 : 10216 : raid5f_chunk_submit_retry(void *_raid_io)
404 : : {
405 : 10216 : struct raid_bdev_io *raid_io = _raid_io;
406 : 10216 : struct stripe_request *stripe_req = raid_io->module_private;
407 : :
408 : 10216 : raid5f_stripe_request_submit_chunks(stripe_req);
409 : 10216 : }
410 : :
411 : : static inline void
412 : 3036036 : raid5f_init_ext_io_opts(struct spdk_bdev_ext_io_opts *opts, struct raid_bdev_io *raid_io)
413 : : {
414 [ - + ]: 3036036 : memset(opts, 0, sizeof(*opts));
415 : 3036036 : opts->size = sizeof(*opts);
416 : 3036036 : opts->memory_domain = raid_io->memory_domain;
417 : 3036036 : opts->memory_domain_ctx = raid_io->memory_domain_ctx;
418 : 3036036 : opts->metadata = raid_io->md_buf;
419 : 3036036 : }
420 : :
421 : : static int
422 : 1636857 : raid5f_chunk_submit(struct chunk *chunk)
423 : : {
424 : 1636857 : struct stripe_request *stripe_req = raid5f_chunk_stripe_req(chunk);
425 : 1636857 : struct raid_bdev_io *raid_io = stripe_req->raid_io;
426 : 1636857 : struct raid_bdev *raid_bdev = raid_io->raid_bdev;
427 : 1636857 : struct raid_base_bdev_info *base_info = &raid_bdev->base_bdev_info[chunk->index];
428 : 1636857 : struct spdk_io_channel *base_ch = raid_bdev_channel_get_base_channel(raid_io->raid_ch,
429 : 1636857 : chunk->index);
430 [ - + ]: 1636857 : uint64_t base_offset_blocks = (stripe_req->stripe_index << raid_bdev->strip_size_shift);
431 : 1611323 : struct spdk_bdev_ext_io_opts io_opts;
432 : : int ret;
433 : :
434 : 1636857 : raid5f_init_ext_io_opts(&io_opts, raid_io);
435 : 1636857 : io_opts.metadata = chunk->md_buf;
436 : :
437 : 1636857 : raid_io->base_bdev_io_submitted++;
438 : :
439 [ + + - ]: 1636857 : switch (stripe_req->type) {
440 : 1608565 : case STRIPE_REQ_WRITE:
441 [ + + ]: 1608565 : if (base_ch == NULL) {
442 : 976 : raid_bdev_io_complete_part(raid_io, 1, SPDK_BDEV_IO_STATUS_SUCCESS);
443 : 976 : return 0;
444 : : }
445 : :
446 : 1607589 : ret = raid_bdev_writev_blocks_ext(base_info, base_ch, chunk->iovs, chunk->iovcnt,
447 : 1607589 : base_offset_blocks, raid_bdev->strip_size,
448 : : raid5f_chunk_complete_bdev_io, chunk, &io_opts);
449 : 1607589 : break;
450 : 28292 : case STRIPE_REQ_RECONSTRUCT:
451 [ + + ]: 28292 : if (chunk == stripe_req->reconstruct.chunk) {
452 : 7568 : raid_bdev_io_complete_part(raid_io, 1, SPDK_BDEV_IO_STATUS_SUCCESS);
453 : 7568 : return 0;
454 : : }
455 : :
456 : 20724 : base_offset_blocks += stripe_req->reconstruct.chunk_offset;
457 : :
458 : 20724 : ret = raid_bdev_readv_blocks_ext(base_info, base_ch, chunk->iovs, chunk->iovcnt,
459 : : base_offset_blocks, raid_io->num_blocks,
460 : : raid5f_chunk_complete_bdev_io, chunk, &io_opts);
461 : 20724 : break;
462 : 0 : default:
463 : 0 : assert(false);
464 : : ret = -EINVAL;
465 : : break;
466 : : }
467 : :
468 [ + + ]: 1628313 : if (spdk_unlikely(ret)) {
469 : 17352 : raid_io->base_bdev_io_submitted--;
470 [ + + ]: 17352 : if (ret == -ENOMEM) {
471 : 10216 : raid_bdev_queue_io_wait(raid_io, spdk_bdev_desc_get_bdev(base_info->desc),
472 : : base_ch, raid5f_chunk_submit_retry);
473 : : } else {
474 : : /*
475 : : * Implicitly complete any I/Os not yet submitted as FAILED. If completing
476 : : * these means there are no more to complete for the stripe request, we can
477 : : * release the stripe request as well.
478 : : */
479 : : uint64_t base_bdev_io_not_submitted;
480 : :
481 [ + - ]: 7136 : if (stripe_req->type == STRIPE_REQ_WRITE) {
482 : 7136 : base_bdev_io_not_submitted = raid_bdev->num_base_bdevs -
483 : 7136 : raid_io->base_bdev_io_submitted;
484 : : } else {
485 : 0 : base_bdev_io_not_submitted = raid5f_stripe_data_chunks_num(raid_bdev) -
486 : 0 : raid_io->base_bdev_io_submitted;
487 : : }
488 : :
489 [ + + ]: 7136 : if (raid_bdev_io_complete_part(raid_io, base_bdev_io_not_submitted,
490 : : SPDK_BDEV_IO_STATUS_FAILED)) {
491 : 976 : raid5f_stripe_request_release(stripe_req);
492 : : }
493 : : }
494 : : }
495 : :
496 : 1628313 : return ret;
497 : : }
498 : :
499 : : static int
500 : 1087926 : raid5f_chunk_set_iovcnt(struct chunk *chunk, int iovcnt)
501 : : {
502 [ + + ]: 1087926 : if (iovcnt > chunk->iovcnt_max) {
503 : 264 : struct iovec *iovs = chunk->iovs;
504 : :
505 : 264 : iovs = realloc(iovs, iovcnt * sizeof(*iovs));
506 [ - + ]: 264 : if (!iovs) {
507 : 0 : return -ENOMEM;
508 : : }
509 : 264 : chunk->iovs = iovs;
510 : 264 : chunk->iovcnt_max = iovcnt;
511 : : }
512 : 1087926 : chunk->iovcnt = iovcnt;
513 : :
514 : 1087926 : return 0;
515 : : }
516 : :
517 : : static int
518 : 525759 : raid5f_stripe_request_map_iovecs(struct stripe_request *stripe_req)
519 : : {
520 : 525759 : struct raid_bdev_io *raid_io = stripe_req->raid_io;
521 : 525759 : struct raid_bdev *raid_bdev = raid_io->raid_bdev;
522 : 525759 : void *raid_io_md = raid_io->md_buf;
523 : 525759 : uint32_t raid_io_md_size = spdk_bdev_get_md_size(&raid_bdev->bdev);
524 : : struct chunk *chunk;
525 : 525759 : int raid_io_iov_idx = 0;
526 : 525759 : size_t raid_io_offset = 0;
527 : 525759 : size_t raid_io_iov_offset = 0;
528 : : int i;
529 : :
530 [ + + + + : 1606117 : FOR_EACH_DATA_CHUNK(stripe_req, chunk) {
+ + ]
531 : 1080358 : int chunk_iovcnt = 0;
532 [ - + ]: 1080358 : uint64_t len = raid_bdev->strip_size << raid_bdev->blocklen_shift;
533 : 1080358 : size_t off = raid_io_iov_offset;
534 : : int ret;
535 : :
536 [ + - ]: 1202452 : for (i = raid_io_iov_idx; i < raid_io->iovcnt; i++) {
537 : 1202452 : chunk_iovcnt++;
538 : 1202452 : off += raid_io->iovs[i].iov_len;
539 [ + + ]: 1202452 : if (off >= raid_io_offset + len) {
540 : 1080358 : break;
541 : : }
542 : : }
543 : :
544 [ - + ]: 1080358 : assert(raid_io_iov_idx + chunk_iovcnt <= raid_io->iovcnt);
545 : :
546 : 1080358 : ret = raid5f_chunk_set_iovcnt(chunk, chunk_iovcnt);
547 [ - + ]: 1080358 : if (ret) {
548 : 0 : return ret;
549 : : }
550 : :
551 [ + + ]: 1080358 : if (raid_io_md) {
552 : 33560 : chunk->md_buf = raid_io_md +
553 [ - + ]: 33560 : (raid_io_offset >> raid_bdev->blocklen_shift) * raid_io_md_size;
554 : : }
555 : :
556 [ + + ]: 2282809 : for (i = 0; i < chunk_iovcnt; i++) {
557 : 1202452 : struct iovec *chunk_iov = &chunk->iovs[i];
558 : 1202452 : const struct iovec *raid_io_iov = &raid_io->iovs[raid_io_iov_idx];
559 : 1202452 : size_t chunk_iov_offset = raid_io_offset - raid_io_iov_offset;
560 : :
561 : 1202452 : chunk_iov->iov_base = raid_io_iov->iov_base + chunk_iov_offset;
562 : 1202452 : chunk_iov->iov_len = spdk_min(len, raid_io_iov->iov_len - chunk_iov_offset);
563 : 1202452 : raid_io_offset += chunk_iov->iov_len;
564 : 1202452 : len -= chunk_iov->iov_len;
565 : :
566 [ + + ]: 1202452 : if (raid_io_offset >= raid_io_iov_offset + raid_io_iov->iov_len) {
567 : 647863 : raid_io_iov_idx++;
568 : 647863 : raid_io_iov_offset += raid_io_iov->iov_len;
569 : : }
570 : : }
571 : :
572 [ - + ]: 1080358 : if (spdk_unlikely(len > 0)) {
573 : 0 : return -EINVAL;
574 : : }
575 : : }
576 : :
577 : 525759 : stripe_req->parity_chunk->iovs[0].iov_base = stripe_req->write.parity_buf;
578 [ - + ]: 525759 : stripe_req->parity_chunk->iovs[0].iov_len = raid_bdev->strip_size << raid_bdev->blocklen_shift;
579 : 525759 : stripe_req->parity_chunk->iovcnt = 1;
580 : 525759 : stripe_req->parity_chunk->md_buf = stripe_req->write.parity_md_buf;
581 : :
582 : 525759 : return 0;
583 : : }
584 : :
585 : : static void
586 : 543279 : raid5f_stripe_request_submit_chunks(struct stripe_request *stripe_req)
587 : : {
588 : 543279 : struct raid_bdev_io *raid_io = stripe_req->raid_io;
589 : 543279 : struct chunk *start = &stripe_req->chunks[raid_io->base_bdev_io_submitted];
590 : : struct chunk *chunk;
591 : :
592 [ + + ]: 2162780 : FOR_EACH_CHUNK_FROM(stripe_req, chunk, start) {
593 [ + + ]: 1636857 : if (spdk_unlikely(raid5f_chunk_submit(chunk) != 0)) {
594 : 17352 : break;
595 : : }
596 : : }
597 : 543279 : }
598 : :
599 : : static inline void
600 : 533063 : raid5f_stripe_request_init(struct stripe_request *stripe_req, struct raid_bdev_io *raid_io,
601 : : uint64_t stripe_index)
602 : : {
603 : 533063 : stripe_req->raid_io = raid_io;
604 : 533063 : stripe_req->stripe_index = stripe_index;
605 : 533063 : stripe_req->parity_chunk = &stripe_req->chunks[raid5f_stripe_parity_chunk_index(raid_io->raid_bdev,
606 : : stripe_index)];
607 : 533063 : }
608 : :
609 : : static void
610 : 525495 : raid5f_stripe_write_request_xor_done(struct stripe_request *stripe_req, int status)
611 : : {
612 : 525495 : struct raid_bdev_io *raid_io = stripe_req->raid_io;
613 : :
614 [ - + ]: 525495 : if (status != 0) {
615 : 0 : raid5f_stripe_request_release(stripe_req);
616 : 0 : raid_bdev_io_complete(raid_io, SPDK_BDEV_IO_STATUS_FAILED);
617 : : } else {
618 : 525495 : raid5f_stripe_request_submit_chunks(stripe_req);
619 : : }
620 : 525495 : }
621 : :
622 : : static int
623 : 679323 : raid5f_submit_write_request(struct raid_bdev_io *raid_io, uint64_t stripe_index)
624 : : {
625 : 679323 : struct raid_bdev *raid_bdev = raid_io->raid_bdev;
626 : 679323 : struct raid5f_io_channel *r5ch = raid_bdev_channel_get_module_ctx(raid_io->raid_ch);
627 : : struct stripe_request *stripe_req;
628 : : int ret;
629 : :
630 : 679323 : stripe_req = TAILQ_FIRST(&r5ch->free_stripe_requests.write);
631 [ + + ]: 679323 : if (!stripe_req) {
632 : 153828 : return -ENOMEM;
633 : : }
634 : :
635 : 525495 : raid5f_stripe_request_init(stripe_req, raid_io, stripe_index);
636 : :
637 : 525495 : ret = raid5f_stripe_request_map_iovecs(stripe_req);
638 [ - + ]: 525495 : if (spdk_unlikely(ret)) {
639 : 0 : return ret;
640 : : }
641 : :
642 [ + + ]: 525495 : TAILQ_REMOVE(&r5ch->free_stripe_requests.write, stripe_req, link);
643 : :
644 : 525495 : raid_io->module_private = stripe_req;
645 : 525495 : raid_io->base_bdev_io_remaining = raid_bdev->num_base_bdevs;
646 : :
647 [ + + ]: 525495 : if (raid_bdev_channel_get_base_channel(raid_io->raid_ch, stripe_req->parity_chunk->index) != NULL) {
648 : 525263 : raid5f_xor_stripe(stripe_req, raid5f_stripe_write_request_xor_done);
649 : : } else {
650 : 232 : raid5f_stripe_write_request_xor_done(stripe_req, 0);
651 : : }
652 : :
653 : 525495 : return 0;
654 : : }
655 : :
656 : : static void
657 : 1391607 : raid5f_chunk_read_complete(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
658 : : {
659 : 1391607 : struct raid_bdev_io *raid_io = cb_arg;
660 : :
661 : 1391607 : spdk_bdev_free_io(bdev_io);
662 : :
663 [ + - ]: 1391607 : raid_bdev_io_complete(raid_io, success ? SPDK_BDEV_IO_STATUS_SUCCESS :
664 : : SPDK_BDEV_IO_STATUS_FAILED);
665 : 1391607 : }
666 : :
667 : : static void raid5f_submit_rw_request(struct raid_bdev_io *raid_io);
668 : :
669 : : static void
670 : 0 : _raid5f_submit_rw_request(void *_raid_io)
671 : : {
672 : 0 : struct raid_bdev_io *raid_io = _raid_io;
673 : :
674 : 0 : raid5f_submit_rw_request(raid_io);
675 : 0 : }
676 : :
677 : : static void
678 : 2688 : raid5f_stripe_request_reconstruct_xor_done(struct stripe_request *stripe_req, int status)
679 : : {
680 : 2688 : struct raid_bdev_io *raid_io = stripe_req->raid_io;
681 : :
682 : 2688 : raid5f_stripe_request_release(stripe_req);
683 : :
684 [ + - ]: 2688 : raid_bdev_io_complete(raid_io,
685 : : status == 0 ? SPDK_BDEV_IO_STATUS_SUCCESS : SPDK_BDEV_IO_STATUS_FAILED);
686 : 2688 : }
687 : :
688 : : static void
689 : 2688 : raid5f_reconstruct_reads_completed_cb(struct raid_bdev_io *raid_io, enum spdk_bdev_io_status status)
690 : : {
691 : 2688 : struct stripe_request *stripe_req = raid_io->module_private;
692 : :
693 : 2688 : raid_io->completion_cb = NULL;
694 : :
695 [ - + ]: 2688 : if (status != SPDK_BDEV_IO_STATUS_SUCCESS) {
696 : 0 : raid5f_stripe_request_release(stripe_req);
697 : 0 : raid_bdev_io_complete(raid_io, status);
698 : 0 : return;
699 : : }
700 : :
701 : 2688 : raid5f_xor_stripe(stripe_req, raid5f_stripe_request_reconstruct_xor_done);
702 : : }
703 : :
704 : : static int
705 : 7568 : raid5f_submit_reconstruct_read(struct raid_bdev_io *raid_io, uint64_t stripe_index,
706 : : uint8_t chunk_idx, uint64_t chunk_offset,
707 : : raid_bdev_io_completion_cb completion_cb)
708 : : {
709 : 7568 : struct raid_bdev *raid_bdev = raid_io->raid_bdev;
710 : 7568 : struct raid5f_io_channel *r5ch = raid_bdev_channel_get_module_ctx(raid_io->raid_ch);
711 : 7568 : void *raid_io_md = raid_io->md_buf;
712 : : struct stripe_request *stripe_req;
713 : : struct chunk *chunk;
714 : : int buf_idx;
715 : :
716 : 7568 : stripe_req = TAILQ_FIRST(&r5ch->free_stripe_requests.reconstruct);
717 [ - + ]: 7568 : if (!stripe_req) {
718 : 0 : return -ENOMEM;
719 : : }
720 : :
721 : 7568 : raid5f_stripe_request_init(stripe_req, raid_io, stripe_index);
722 : :
723 : 7568 : stripe_req->reconstruct.chunk = &stripe_req->chunks[chunk_idx];
724 : 7568 : stripe_req->reconstruct.chunk_offset = chunk_offset;
725 : 7568 : buf_idx = 0;
726 : :
727 [ + + ]: 35860 : FOR_EACH_CHUNK(stripe_req, chunk) {
728 [ + + ]: 28292 : if (chunk == stripe_req->reconstruct.chunk) {
729 : : int i;
730 : : int ret;
731 : :
732 : 7568 : ret = raid5f_chunk_set_iovcnt(chunk, raid_io->iovcnt);
733 [ - + ]: 7568 : if (ret) {
734 : 0 : return ret;
735 : : }
736 : :
737 [ + + ]: 31120 : for (i = 0; i < raid_io->iovcnt; i++) {
738 : 23552 : chunk->iovs[i] = raid_io->iovs[i];
739 : : }
740 : :
741 : 7568 : chunk->md_buf = raid_io_md;
742 : : } else {
743 : 20724 : struct iovec *iov = &chunk->iovs[0];
744 : :
745 : 20724 : iov->iov_base = stripe_req->reconstruct.chunk_buffers[buf_idx];
746 [ - + ]: 20724 : iov->iov_len = raid_io->num_blocks << raid_bdev->blocklen_shift;
747 : 20724 : chunk->iovcnt = 1;
748 : :
749 [ + + ]: 20724 : if (raid_io_md) {
750 : 4284 : chunk->md_buf = stripe_req->reconstruct.chunk_md_buffers[buf_idx];
751 : : }
752 : :
753 : 20724 : buf_idx++;
754 : : }
755 : : }
756 : :
757 : 7568 : raid_io->module_private = stripe_req;
758 : 7568 : raid_io->base_bdev_io_remaining = raid_bdev->num_base_bdevs;
759 : 7568 : raid_io->completion_cb = completion_cb;
760 : :
761 [ + - ]: 7568 : TAILQ_REMOVE(&r5ch->free_stripe_requests.reconstruct, stripe_req, link);
762 : :
763 : 7568 : raid5f_stripe_request_submit_chunks(stripe_req);
764 : :
765 : 7568 : return 0;
766 : : }
767 : :
768 : : static int
769 : 1394295 : raid5f_submit_read_request(struct raid_bdev_io *raid_io, uint64_t stripe_index,
770 : : uint64_t stripe_offset)
771 : : {
772 : 1394295 : struct raid_bdev *raid_bdev = raid_io->raid_bdev;
773 [ - + ]: 1394295 : uint8_t chunk_data_idx = stripe_offset >> raid_bdev->strip_size_shift;
774 : 1394295 : uint8_t p_idx = raid5f_stripe_parity_chunk_index(raid_bdev, stripe_index);
775 [ + + ]: 1394295 : uint8_t chunk_idx = chunk_data_idx < p_idx ? chunk_data_idx : chunk_data_idx + 1;
776 : 1394295 : struct raid_base_bdev_info *base_info = &raid_bdev->base_bdev_info[chunk_idx];
777 : 1394295 : struct spdk_io_channel *base_ch = raid_bdev_channel_get_base_channel(raid_io->raid_ch, chunk_idx);
778 [ - + ]: 1394295 : uint64_t chunk_offset = stripe_offset - (chunk_data_idx << raid_bdev->strip_size_shift);
779 [ - + ]: 1394295 : uint64_t base_offset_blocks = (stripe_index << raid_bdev->strip_size_shift) + chunk_offset;
780 : 1388779 : struct spdk_bdev_ext_io_opts io_opts;
781 : : int ret;
782 : :
783 : 1394295 : raid5f_init_ext_io_opts(&io_opts, raid_io);
784 [ + + ]: 1394295 : if (base_ch == NULL) {
785 : 2688 : return raid5f_submit_reconstruct_read(raid_io, stripe_index, chunk_idx, chunk_offset,
786 : : raid5f_reconstruct_reads_completed_cb);
787 : : }
788 : :
789 : 1391607 : ret = raid_bdev_readv_blocks_ext(base_info, base_ch, raid_io->iovs, raid_io->iovcnt,
790 : : base_offset_blocks, raid_io->num_blocks,
791 : : raid5f_chunk_read_complete, raid_io, &io_opts);
792 [ - + ]: 1391607 : if (spdk_unlikely(ret == -ENOMEM)) {
793 : 0 : raid_bdev_queue_io_wait(raid_io, spdk_bdev_desc_get_bdev(base_info->desc),
794 : : base_ch, _raid5f_submit_rw_request);
795 : 0 : return 0;
796 : : }
797 : :
798 : 1391607 : return ret;
799 : : }
800 : :
801 : : static void
802 : 2073619 : raid5f_submit_rw_request(struct raid_bdev_io *raid_io)
803 : : {
804 : 2073619 : struct raid_bdev *raid_bdev = raid_io->raid_bdev;
805 : 2073619 : struct raid5f_info *r5f_info = raid_bdev->module_private;
806 [ - + ]: 2073619 : uint64_t stripe_index = raid_io->offset_blocks / r5f_info->stripe_blocks;
807 [ - + ]: 2073619 : uint64_t stripe_offset = raid_io->offset_blocks % r5f_info->stripe_blocks;
808 : : int ret;
809 : :
810 [ + + - ]: 2073619 : switch (raid_io->type) {
811 : 1394295 : case SPDK_BDEV_IO_TYPE_READ:
812 [ - + ]: 1394295 : assert(raid_io->num_blocks <= raid_bdev->strip_size);
813 : 1394295 : ret = raid5f_submit_read_request(raid_io, stripe_index, stripe_offset);
814 : 1394295 : break;
815 : 679323 : case SPDK_BDEV_IO_TYPE_WRITE:
816 [ - + ]: 679323 : assert(stripe_offset == 0);
817 [ - + ]: 679323 : assert(raid_io->num_blocks == r5f_info->stripe_blocks);
818 : 679323 : ret = raid5f_submit_write_request(raid_io, stripe_index);
819 : 679323 : break;
820 : 0 : default:
821 : 0 : ret = -EINVAL;
822 : 0 : break;
823 : : }
824 : :
825 [ + + ]: 2073619 : if (spdk_unlikely(ret)) {
826 [ + - ]: 153828 : raid_bdev_io_complete(raid_io, ret == -ENOMEM ? SPDK_BDEV_IO_STATUS_NOMEM :
827 : : SPDK_BDEV_IO_STATUS_FAILED);
828 : : }
829 : 2073619 : }
830 : :
831 : : static void
832 : 124680 : raid5f_stripe_request_free(struct stripe_request *stripe_req)
833 : : {
834 : : struct chunk *chunk;
835 : :
836 [ + + ]: 619176 : FOR_EACH_CHUNK(stripe_req, chunk) {
837 : 494496 : free(chunk->iovs);
838 : : }
839 : :
840 [ + + ]: 124680 : if (stripe_req->type == STRIPE_REQ_WRITE) {
841 : 62472 : spdk_dma_free(stripe_req->write.parity_buf);
842 : 62472 : spdk_dma_free(stripe_req->write.parity_md_buf);
843 [ + - ]: 62208 : } else if (stripe_req->type == STRIPE_REQ_RECONSTRUCT) {
844 : 62208 : struct raid5f_info *r5f_info = raid5f_ch_to_r5f_info(stripe_req->r5ch);
845 : 62208 : struct raid_bdev *raid_bdev = r5f_info->raid_bdev;
846 : : uint8_t i;
847 : :
848 [ + - ]: 62208 : if (stripe_req->reconstruct.chunk_buffers) {
849 [ + + ]: 246720 : for (i = 0; i < raid5f_stripe_data_chunks_num(raid_bdev); i++) {
850 : 184512 : spdk_dma_free(stripe_req->reconstruct.chunk_buffers[i]);
851 : : }
852 : 62208 : free(stripe_req->reconstruct.chunk_buffers);
853 : : }
854 : :
855 [ + + ]: 62208 : if (stripe_req->reconstruct.chunk_md_buffers) {
856 [ + + ]: 118272 : for (i = 0; i < raid5f_stripe_data_chunks_num(raid_bdev); i++) {
857 : 88704 : spdk_dma_free(stripe_req->reconstruct.chunk_md_buffers[i]);
858 : : }
859 : 29568 : free(stripe_req->reconstruct.chunk_md_buffers);
860 : : }
861 : : } else {
862 : 0 : assert(false);
863 : : }
864 : :
865 : 124680 : free(stripe_req->chunk_xor_buffers);
866 : 124680 : free(stripe_req->chunk_xor_md_buffers);
867 : 124680 : free(stripe_req->chunk_iov_iters);
868 : :
869 : 124680 : free(stripe_req);
870 : 124680 : }
871 : :
872 : : static struct stripe_request *
873 : 124680 : raid5f_stripe_request_alloc(struct raid5f_io_channel *r5ch, enum stripe_request_type type)
874 : : {
875 : 124680 : struct raid5f_info *r5f_info = raid5f_ch_to_r5f_info(r5ch);
876 : 124680 : struct raid_bdev *raid_bdev = r5f_info->raid_bdev;
877 : 124680 : uint32_t raid_io_md_size = spdk_bdev_get_md_size(&raid_bdev->bdev);
878 : : struct stripe_request *stripe_req;
879 : : struct chunk *chunk;
880 : : size_t chunk_len;
881 : :
882 : 124680 : stripe_req = calloc(1, sizeof(*stripe_req) + sizeof(*chunk) * raid_bdev->num_base_bdevs);
883 [ - + ]: 124680 : if (!stripe_req) {
884 : 0 : return NULL;
885 : : }
886 : :
887 : 124680 : stripe_req->r5ch = r5ch;
888 : 124680 : stripe_req->type = type;
889 : :
890 [ + + ]: 619176 : FOR_EACH_CHUNK(stripe_req, chunk) {
891 : 494496 : chunk->index = chunk - stripe_req->chunks;
892 : 494496 : chunk->iovcnt_max = 4;
893 : 494496 : chunk->iovs = calloc(chunk->iovcnt_max, sizeof(chunk->iovs[0]));
894 [ - + ]: 494496 : if (!chunk->iovs) {
895 : 0 : goto err;
896 : : }
897 : : }
898 : :
899 [ - + ]: 124680 : chunk_len = raid_bdev->strip_size << raid_bdev->blocklen_shift;
900 : :
901 [ + + ]: 124680 : if (type == STRIPE_REQ_WRITE) {
902 : 62472 : stripe_req->write.parity_buf = spdk_dma_malloc(chunk_len, r5f_info->buf_alignment, NULL);
903 [ - + ]: 62472 : if (!stripe_req->write.parity_buf) {
904 : 0 : goto err;
905 : : }
906 : :
907 [ + + ]: 62472 : if (raid_io_md_size != 0) {
908 : 29700 : stripe_req->write.parity_md_buf = spdk_dma_malloc(raid_bdev->strip_size * raid_io_md_size,
909 : : r5f_info->buf_alignment, NULL);
910 [ - + ]: 29700 : if (!stripe_req->write.parity_md_buf) {
911 : 0 : goto err;
912 : : }
913 : : }
914 [ + - ]: 62208 : } else if (type == STRIPE_REQ_RECONSTRUCT) {
915 : 62208 : uint8_t n = raid5f_stripe_data_chunks_num(raid_bdev);
916 : : void *buf;
917 : : uint8_t i;
918 : :
919 : 62208 : stripe_req->reconstruct.chunk_buffers = calloc(n, sizeof(void *));
920 [ - + ]: 62208 : if (!stripe_req->reconstruct.chunk_buffers) {
921 : 0 : goto err;
922 : : }
923 : :
924 [ + + ]: 246720 : for (i = 0; i < n; i++) {
925 : 184512 : buf = spdk_dma_malloc(chunk_len, r5f_info->buf_alignment, NULL);
926 [ - + ]: 184512 : if (!buf) {
927 : 0 : goto err;
928 : : }
929 : 184512 : stripe_req->reconstruct.chunk_buffers[i] = buf;
930 : : }
931 : :
932 [ + + ]: 62208 : if (raid_io_md_size != 0) {
933 : 29568 : stripe_req->reconstruct.chunk_md_buffers = calloc(n, sizeof(void *));
934 [ - + ]: 29568 : if (!stripe_req->reconstruct.chunk_md_buffers) {
935 : 0 : goto err;
936 : : }
937 : :
938 [ + + ]: 118272 : for (i = 0; i < n; i++) {
939 : 88704 : buf = spdk_dma_malloc(raid_bdev->strip_size * raid_io_md_size, r5f_info->buf_alignment, NULL);
940 [ - + ]: 88704 : if (!buf) {
941 : 0 : goto err;
942 : : }
943 : 88704 : stripe_req->reconstruct.chunk_md_buffers[i] = buf;
944 : : }
945 : : }
946 : : } else {
947 : 0 : assert(false);
948 : : return NULL;
949 : : }
950 : :
951 : 124680 : stripe_req->chunk_iov_iters = malloc(SPDK_IOVITER_SIZE(raid_bdev->num_base_bdevs));
952 [ - + ]: 124680 : if (!stripe_req->chunk_iov_iters) {
953 : 0 : goto err;
954 : : }
955 : :
956 : 124680 : stripe_req->chunk_xor_buffers = calloc(raid5f_stripe_data_chunks_num(raid_bdev),
957 : : sizeof(stripe_req->chunk_xor_buffers[0]));
958 [ - + ]: 124680 : if (!stripe_req->chunk_xor_buffers) {
959 : 0 : goto err;
960 : : }
961 : :
962 : 124680 : stripe_req->chunk_xor_md_buffers = calloc(raid5f_stripe_data_chunks_num(raid_bdev),
963 : : sizeof(stripe_req->chunk_xor_md_buffers[0]));
964 [ - + ]: 124680 : if (!stripe_req->chunk_xor_md_buffers) {
965 : 0 : goto err;
966 : : }
967 : :
968 : 124680 : return stripe_req;
969 : 0 : err:
970 : 0 : raid5f_stripe_request_free(stripe_req);
971 : 0 : return NULL;
972 : : }
973 : :
974 : : static void
975 : 1944 : raid5f_ioch_destroy(void *io_device, void *ctx_buf)
976 : : {
977 : 1944 : struct raid5f_io_channel *r5ch = ctx_buf;
978 : : struct stripe_request *stripe_req;
979 : :
980 [ - + ]: 1944 : assert(TAILQ_EMPTY(&r5ch->xor_retry_queue));
981 : :
982 [ + + ]: 64152 : while ((stripe_req = TAILQ_FIRST(&r5ch->free_stripe_requests.write))) {
983 [ + + ]: 62208 : TAILQ_REMOVE(&r5ch->free_stripe_requests.write, stripe_req, link);
984 : 62208 : raid5f_stripe_request_free(stripe_req);
985 : : }
986 : :
987 [ + + ]: 64152 : while ((stripe_req = TAILQ_FIRST(&r5ch->free_stripe_requests.reconstruct))) {
988 [ + + ]: 62208 : TAILQ_REMOVE(&r5ch->free_stripe_requests.reconstruct, stripe_req, link);
989 : 62208 : raid5f_stripe_request_free(stripe_req);
990 : : }
991 : :
992 [ + - ]: 1944 : if (r5ch->accel_ch) {
993 : 1944 : spdk_put_io_channel(r5ch->accel_ch);
994 : : }
995 : :
996 : 1944 : free(r5ch->chunk_xor_buffers);
997 : 1944 : free(r5ch->chunk_xor_iovs);
998 : 1944 : free(r5ch->chunk_xor_iovcnt);
999 : 1944 : }
1000 : :
1001 : : static int
1002 : 1944 : raid5f_ioch_create(void *io_device, void *ctx_buf)
1003 : : {
1004 : 1944 : struct raid5f_io_channel *r5ch = ctx_buf;
1005 : 1944 : struct raid5f_info *r5f_info = io_device;
1006 : 1944 : struct raid_bdev *raid_bdev = r5f_info->raid_bdev;
1007 : : struct stripe_request *stripe_req;
1008 : : int i;
1009 : :
1010 : 1944 : TAILQ_INIT(&r5ch->free_stripe_requests.write);
1011 : 1944 : TAILQ_INIT(&r5ch->free_stripe_requests.reconstruct);
1012 : 1944 : TAILQ_INIT(&r5ch->xor_retry_queue);
1013 : :
1014 [ + + ]: 64152 : for (i = 0; i < RAID5F_MAX_STRIPES; i++) {
1015 : 62208 : stripe_req = raid5f_stripe_request_alloc(r5ch, STRIPE_REQ_WRITE);
1016 [ - + ]: 62208 : if (!stripe_req) {
1017 : 0 : goto err;
1018 : : }
1019 : :
1020 [ + + ]: 62208 : TAILQ_INSERT_HEAD(&r5ch->free_stripe_requests.write, stripe_req, link);
1021 : : }
1022 : :
1023 [ + + ]: 64152 : for (i = 0; i < RAID5F_MAX_STRIPES; i++) {
1024 : 62208 : stripe_req = raid5f_stripe_request_alloc(r5ch, STRIPE_REQ_RECONSTRUCT);
1025 [ - + ]: 62208 : if (!stripe_req) {
1026 : 0 : goto err;
1027 : : }
1028 : :
1029 [ + + ]: 62208 : TAILQ_INSERT_HEAD(&r5ch->free_stripe_requests.reconstruct, stripe_req, link);
1030 : : }
1031 : :
1032 : 1944 : r5ch->accel_ch = spdk_accel_get_io_channel();
1033 [ - + ]: 1944 : if (!r5ch->accel_ch) {
1034 : 0 : SPDK_ERRLOG("Failed to get accel framework's IO channel\n");
1035 : 0 : goto err;
1036 : : }
1037 : :
1038 : 1944 : r5ch->chunk_xor_buffers = calloc(raid_bdev->num_base_bdevs, sizeof(*r5ch->chunk_xor_buffers));
1039 [ - + ]: 1944 : if (!r5ch->chunk_xor_buffers) {
1040 : 0 : goto err;
1041 : : }
1042 : :
1043 : 1944 : r5ch->chunk_xor_iovs = calloc(raid_bdev->num_base_bdevs, sizeof(*r5ch->chunk_xor_iovs));
1044 [ - + ]: 1944 : if (!r5ch->chunk_xor_iovs) {
1045 : 0 : goto err;
1046 : : }
1047 : :
1048 : 1944 : r5ch->chunk_xor_iovcnt = calloc(raid_bdev->num_base_bdevs, sizeof(*r5ch->chunk_xor_iovcnt));
1049 [ - + ]: 1944 : if (!r5ch->chunk_xor_iovcnt) {
1050 : 0 : goto err;
1051 : : }
1052 : :
1053 : 1944 : return 0;
1054 : 0 : err:
1055 : 0 : SPDK_ERRLOG("Failed to initialize io channel\n");
1056 : 0 : raid5f_ioch_destroy(r5f_info, r5ch);
1057 : 0 : return -ENOMEM;
1058 : : }
1059 : :
1060 : : static int
1061 : 2164 : raid5f_start(struct raid_bdev *raid_bdev)
1062 : : {
1063 : 2164 : uint64_t min_blockcnt = UINT64_MAX;
1064 : : uint64_t base_bdev_data_size;
1065 : : struct raid_base_bdev_info *base_info;
1066 : : struct spdk_bdev *base_bdev;
1067 : : struct raid5f_info *r5f_info;
1068 : 2164 : size_t alignment = 0;
1069 : :
1070 : 2164 : r5f_info = calloc(1, sizeof(*r5f_info));
1071 [ - + ]: 2164 : if (!r5f_info) {
1072 : 0 : SPDK_ERRLOG("Failed to allocate r5f_info\n");
1073 : 0 : return -ENOMEM;
1074 : : }
1075 : 2164 : r5f_info->raid_bdev = raid_bdev;
1076 : :
1077 [ + + ]: 10786 : RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
1078 : 8622 : min_blockcnt = spdk_min(min_blockcnt, base_info->data_size);
1079 [ + + ]: 8622 : if (base_info->desc) {
1080 : 8614 : base_bdev = spdk_bdev_desc_get_bdev(base_info->desc);
1081 [ + - ]: 8614 : alignment = spdk_max(alignment, spdk_bdev_get_buf_align(base_bdev));
1082 : : }
1083 : : }
1084 : :
1085 [ - + ]: 2164 : base_bdev_data_size = (min_blockcnt / raid_bdev->strip_size) * raid_bdev->strip_size;
1086 : :
1087 [ + + ]: 10786 : RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
1088 : 8622 : base_info->data_size = base_bdev_data_size;
1089 : : }
1090 : :
1091 [ - + ]: 2164 : r5f_info->total_stripes = min_blockcnt / raid_bdev->strip_size;
1092 : 2164 : r5f_info->stripe_blocks = raid_bdev->strip_size * raid5f_stripe_data_chunks_num(raid_bdev);
1093 : 2164 : r5f_info->buf_alignment = alignment;
1094 : :
1095 : 2164 : raid_bdev->bdev.blockcnt = r5f_info->stripe_blocks * r5f_info->total_stripes;
1096 : 2164 : raid_bdev->bdev.optimal_io_boundary = raid_bdev->strip_size;
1097 : 2164 : raid_bdev->bdev.split_on_optimal_io_boundary = true;
1098 : 2164 : raid_bdev->bdev.write_unit_size = r5f_info->stripe_blocks;
1099 : 2164 : raid_bdev->bdev.split_on_write_unit = true;
1100 : :
1101 : 2164 : raid_bdev->module_private = r5f_info;
1102 : :
1103 : 2164 : spdk_io_device_register(r5f_info, raid5f_ioch_create, raid5f_ioch_destroy,
1104 : : sizeof(struct raid5f_io_channel), NULL);
1105 : :
1106 : 2164 : return 0;
1107 : : }
1108 : :
1109 : : static void
1110 : 2164 : raid5f_io_device_unregister_done(void *io_device)
1111 : : {
1112 : 2164 : struct raid5f_info *r5f_info = io_device;
1113 : :
1114 : 2164 : raid_bdev_module_stop_done(r5f_info->raid_bdev);
1115 : :
1116 : 2164 : free(r5f_info);
1117 : 2164 : }
1118 : :
1119 : : static bool
1120 : 2164 : raid5f_stop(struct raid_bdev *raid_bdev)
1121 : : {
1122 : 2164 : struct raid5f_info *r5f_info = raid_bdev->module_private;
1123 : :
1124 : 2164 : spdk_io_device_unregister(r5f_info, raid5f_io_device_unregister_done);
1125 : :
1126 : 2164 : return false;
1127 : : }
1128 : :
1129 : : static struct spdk_io_channel *
1130 : 1944 : raid5f_get_io_channel(struct raid_bdev *raid_bdev)
1131 : : {
1132 : 1944 : struct raid5f_info *r5f_info = raid_bdev->module_private;
1133 : :
1134 : 1944 : return spdk_get_io_channel(r5f_info);
1135 : : }
1136 : :
1137 : : static void
1138 : 4880 : raid5f_process_write_completed(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
1139 : : {
1140 : 4880 : struct raid_bdev_process_request *process_req = cb_arg;
1141 : :
1142 : 4880 : spdk_bdev_free_io(bdev_io);
1143 : :
1144 [ + - ]: 4880 : raid_bdev_process_request_complete(process_req, success ? 0 : -EIO);
1145 : 4880 : }
1146 : :
1147 : : static void raid5f_process_submit_write(struct raid_bdev_process_request *process_req);
1148 : :
1149 : : static void
1150 : 0 : _raid5f_process_submit_write(void *ctx)
1151 : : {
1152 : 0 : struct raid_bdev_process_request *process_req = ctx;
1153 : :
1154 : 0 : raid5f_process_submit_write(process_req);
1155 : 0 : }
1156 : :
1157 : : static void
1158 : 4880 : raid5f_process_submit_write(struct raid_bdev_process_request *process_req)
1159 : : {
1160 : 4880 : struct raid_bdev_io *raid_io = &process_req->raid_io;
1161 : 4880 : struct raid_bdev *raid_bdev = raid_io->raid_bdev;
1162 : 4880 : struct raid5f_info *r5f_info = raid_bdev->module_private;
1163 [ - + ]: 4880 : uint64_t stripe_index = process_req->offset_blocks / r5f_info->stripe_blocks;
1164 : 4880 : struct spdk_bdev_ext_io_opts io_opts;
1165 : : int ret;
1166 : :
1167 : 4880 : raid5f_init_ext_io_opts(&io_opts, raid_io);
1168 : 4880 : ret = raid_bdev_writev_blocks_ext(process_req->target, process_req->target_ch,
1169 : : raid_io->iovs, raid_io->iovcnt,
1170 [ - + ]: 4880 : stripe_index << raid_bdev->strip_size_shift, raid_bdev->strip_size,
1171 : : raid5f_process_write_completed, process_req, &io_opts);
1172 [ - + ]: 4880 : if (spdk_unlikely(ret != 0)) {
1173 [ # # ]: 0 : if (ret == -ENOMEM) {
1174 : 0 : raid_bdev_queue_io_wait(raid_io, spdk_bdev_desc_get_bdev(process_req->target->desc),
1175 : : process_req->target_ch, _raid5f_process_submit_write);
1176 : : } else {
1177 : 0 : raid_bdev_process_request_complete(process_req, ret);
1178 : : }
1179 : : }
1180 : 4880 : }
1181 : :
1182 : : static void
1183 : 4880 : raid5f_process_stripe_request_reconstruct_xor_done(struct stripe_request *stripe_req, int status)
1184 : : {
1185 : 4880 : struct raid_bdev_io *raid_io = stripe_req->raid_io;
1186 : 4880 : struct raid_bdev_process_request *process_req = SPDK_CONTAINEROF(raid_io,
1187 : : struct raid_bdev_process_request, raid_io);
1188 : :
1189 : 4880 : raid5f_stripe_request_release(stripe_req);
1190 : :
1191 [ - + ]: 4880 : if (status != 0) {
1192 : 0 : raid_bdev_process_request_complete(process_req, status);
1193 : 0 : return;
1194 : : }
1195 : :
1196 : 4880 : raid5f_process_submit_write(process_req);
1197 : : }
1198 : :
1199 : : static void
1200 : 4880 : raid5f_process_read_completed(struct raid_bdev_io *raid_io, enum spdk_bdev_io_status status)
1201 : : {
1202 : 4880 : struct raid_bdev_process_request *process_req = SPDK_CONTAINEROF(raid_io,
1203 : : struct raid_bdev_process_request, raid_io);
1204 : 4880 : struct stripe_request *stripe_req = raid_io->module_private;
1205 : :
1206 [ - + ]: 4880 : if (status != SPDK_BDEV_IO_STATUS_SUCCESS) {
1207 : 0 : raid5f_stripe_request_release(stripe_req);
1208 : 0 : raid_bdev_process_request_complete(process_req, -EIO);
1209 : 0 : return;
1210 : : }
1211 : :
1212 : 4880 : raid5f_xor_stripe(stripe_req, raid5f_process_stripe_request_reconstruct_xor_done);
1213 : : }
1214 : :
1215 : : static int
1216 : 5346 : raid5f_submit_process_request(struct raid_bdev_process_request *process_req,
1217 : : struct raid_bdev_io_channel *raid_ch)
1218 : : {
1219 : 5346 : struct spdk_io_channel *ch = spdk_io_channel_from_ctx(raid_ch);
1220 : 5346 : struct raid_bdev *raid_bdev = spdk_io_channel_get_io_device(ch);
1221 : 5346 : struct raid5f_info *r5f_info = raid_bdev->module_private;
1222 : 5346 : struct raid_bdev_io *raid_io = &process_req->raid_io;
1223 : 5346 : uint8_t chunk_idx = raid_bdev_base_bdev_slot(process_req->target);
1224 [ - + ]: 5346 : uint64_t stripe_index = process_req->offset_blocks / r5f_info->stripe_blocks;
1225 : : int ret;
1226 : :
1227 [ - + - + ]: 5346 : assert((process_req->offset_blocks % r5f_info->stripe_blocks) == 0);
1228 : :
1229 [ + + ]: 5346 : if (process_req->num_blocks < r5f_info->stripe_blocks) {
1230 : 466 : return 0;
1231 : : }
1232 : :
1233 : 9760 : raid_bdev_io_init(raid_io, raid_ch, SPDK_BDEV_IO_TYPE_READ,
1234 : 4880 : process_req->offset_blocks, raid_bdev->strip_size,
1235 : : &process_req->iov, 1, process_req->md_buf, NULL, NULL);
1236 : :
1237 : 4880 : ret = raid5f_submit_reconstruct_read(raid_io, stripe_index, chunk_idx, 0,
1238 : : raid5f_process_read_completed);
1239 [ + - ]: 4880 : if (spdk_likely(ret == 0)) {
1240 : 4880 : return r5f_info->stripe_blocks;
1241 [ # # ]: 0 : } else if (ret < 0) {
1242 : 0 : return ret;
1243 : : } else {
1244 : 0 : return -EINVAL;
1245 : : }
1246 : : }
1247 : :
1248 : : static struct raid_bdev_module g_raid5f_module = {
1249 : : .level = RAID5F,
1250 : : .base_bdevs_min = 3,
1251 : : .base_bdevs_constraint = {CONSTRAINT_MAX_BASE_BDEVS_REMOVED, 1},
1252 : : .start = raid5f_start,
1253 : : .stop = raid5f_stop,
1254 : : .submit_rw_request = raid5f_submit_rw_request,
1255 : : .get_io_channel = raid5f_get_io_channel,
1256 : : .submit_process_request = raid5f_submit_process_request,
1257 : : };
1258 : 418 : RAID_MODULE_REGISTER(&g_raid5f_module)
1259 : :
1260 : 418 : SPDK_LOG_REGISTER_COMPONENT(bdev_raid5f)
|