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/bdev_module.h"
7 : : #include "spdk/crc32.h"
8 : : #include "spdk/env.h"
9 : : #include "spdk/log.h"
10 : : #include "spdk/string.h"
11 : : #include "spdk/util.h"
12 : :
13 : : #include "bdev_raid.h"
14 : :
15 : : struct raid_bdev_write_sb_ctx {
16 : : struct raid_bdev *raid_bdev;
17 : : int status;
18 : : uint8_t submitted;
19 : : uint8_t remaining;
20 : : raid_bdev_write_sb_cb cb;
21 : : void *cb_ctx;
22 : : struct spdk_bdev_io_wait_entry wait_entry;
23 : : };
24 : :
25 : : struct raid_bdev_read_sb_ctx {
26 : : struct spdk_bdev_desc *desc;
27 : : struct spdk_io_channel *ch;
28 : : raid_bdev_load_sb_cb cb;
29 : : void *cb_ctx;
30 : : void *buf;
31 : : uint32_t buf_size;
32 : : };
33 : :
34 : : int
35 : 413 : raid_bdev_alloc_superblock(struct raid_bdev *raid_bdev, uint32_t block_size)
36 : : {
37 : : struct raid_bdev_superblock *sb;
38 : :
39 [ - + ]: 413 : assert(raid_bdev->sb == NULL);
40 : :
41 : 413 : sb = spdk_dma_zmalloc(SPDK_ALIGN_CEIL(RAID_BDEV_SB_MAX_LENGTH, block_size), 0x1000, NULL);
42 [ - + ]: 413 : if (!sb) {
43 : 0 : SPDK_ERRLOG("Failed to allocate raid bdev sb buffer\n");
44 : 0 : return -ENOMEM;
45 : : }
46 : :
47 : 413 : raid_bdev->sb = sb;
48 : :
49 : 413 : return 0;
50 : : }
51 : :
52 : : void
53 : 906 : raid_bdev_free_superblock(struct raid_bdev *raid_bdev)
54 : : {
55 [ + + + + ]: 906 : if (raid_bdev->sb_io_buf != NULL && raid_bdev->sb_io_buf != raid_bdev->sb) {
56 [ - + ]: 31 : assert(spdk_bdev_is_md_interleaved(&raid_bdev->bdev));
57 : 31 : spdk_dma_free(raid_bdev->sb_io_buf);
58 : 31 : raid_bdev->sb_io_buf = NULL;
59 : : }
60 : 906 : spdk_dma_free(raid_bdev->sb);
61 : 906 : raid_bdev->sb = NULL;
62 : 906 : }
63 : :
64 : : void
65 : 245 : raid_bdev_init_superblock(struct raid_bdev *raid_bdev)
66 : : {
67 : 245 : struct raid_bdev_superblock *sb = raid_bdev->sb;
68 : : struct raid_base_bdev_info *base_info;
69 : : struct raid_bdev_sb_base_bdev *sb_base_bdev;
70 : :
71 [ - + - + ]: 245 : memcpy(&sb->signature, RAID_BDEV_SB_SIG, sizeof(sb->signature));
72 : 245 : sb->version.major = RAID_BDEV_SB_VERSION_MAJOR;
73 : 245 : sb->version.minor = RAID_BDEV_SB_VERSION_MINOR;
74 : 245 : spdk_uuid_copy(&sb->uuid, &raid_bdev->bdev.uuid);
75 [ - + ]: 245 : snprintf(sb->name, RAID_BDEV_SB_NAME_SIZE, "%s", raid_bdev->bdev.name);
76 : 245 : sb->raid_size = raid_bdev->bdev.blockcnt;
77 : 245 : sb->block_size = spdk_bdev_get_data_block_size(&raid_bdev->bdev);
78 : 245 : sb->level = raid_bdev->level;
79 : 245 : sb->strip_size = raid_bdev->strip_size;
80 : : /* TODO: sb->state */
81 : 245 : sb->num_base_bdevs = sb->base_bdevs_size = raid_bdev->num_base_bdevs;
82 : 245 : sb->length = sizeof(*sb) + sizeof(*sb_base_bdev) * sb->base_bdevs_size;
83 : :
84 : 245 : sb_base_bdev = &sb->base_bdevs[0];
85 [ + + ]: 964 : RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
86 : 719 : spdk_uuid_copy(&sb_base_bdev->uuid, &base_info->uuid);
87 : 719 : sb_base_bdev->data_offset = base_info->data_offset;
88 : 719 : sb_base_bdev->data_size = base_info->data_size;
89 : 719 : sb_base_bdev->state = RAID_SB_BASE_BDEV_CONFIGURED;
90 : 719 : sb_base_bdev->slot = raid_bdev_base_bdev_slot(base_info);
91 : 719 : sb_base_bdev++;
92 : : }
93 : 245 : }
94 : :
95 : : static int
96 : 394 : raid_bdev_alloc_sb_io_buf(struct raid_bdev *raid_bdev)
97 : : {
98 : 394 : struct raid_bdev_superblock *sb = raid_bdev->sb;
99 : :
100 [ + + ]: 394 : if (spdk_bdev_is_md_interleaved(&raid_bdev->bdev)) {
101 : 68 : raid_bdev->sb_io_buf_size = spdk_divide_round_up(sb->length,
102 : 68 : sb->block_size) * raid_bdev->bdev.blocklen;
103 : 34 : raid_bdev->sb_io_buf = spdk_dma_zmalloc(raid_bdev->sb_io_buf_size, 0x1000, NULL);
104 [ - + ]: 34 : if (!raid_bdev->sb_io_buf) {
105 : 0 : SPDK_ERRLOG("Failed to allocate raid bdev sb io buffer\n");
106 : 0 : return -ENOMEM;
107 : : }
108 : : } else {
109 : 360 : raid_bdev->sb_io_buf_size = SPDK_ALIGN_CEIL(sb->length, raid_bdev->bdev.blocklen);
110 : 360 : raid_bdev->sb_io_buf = raid_bdev->sb;
111 : : }
112 : :
113 : 394 : return 0;
114 : : }
115 : :
116 : : static void
117 : 1405 : raid_bdev_sb_update_crc(struct raid_bdev_superblock *sb)
118 : : {
119 : 1405 : sb->crc = 0;
120 : 1405 : sb->crc = spdk_crc32c_update(sb, sb->length, 0);
121 : 1405 : }
122 : :
123 : : static bool
124 : 727 : raid_bdev_sb_check_crc(struct raid_bdev_superblock *sb)
125 : : {
126 : 727 : uint32_t crc, prev = sb->crc;
127 : :
128 : 727 : raid_bdev_sb_update_crc(sb);
129 : 727 : crc = sb->crc;
130 : 727 : sb->crc = prev;
131 : :
132 : 727 : return crc == prev;
133 : : }
134 : :
135 : : static int
136 : 9224 : raid_bdev_parse_superblock(struct raid_bdev_read_sb_ctx *ctx)
137 : : {
138 : 9224 : struct raid_bdev_superblock *sb = ctx->buf;
139 : 9224 : struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(ctx->desc);
140 : : struct raid_bdev_sb_base_bdev *sb_base_bdev;
141 : : uint8_t i;
142 : :
143 [ - + + + ]: 9224 : if (memcmp(sb->signature, RAID_BDEV_SB_SIG, sizeof(sb->signature))) {
144 [ - + - + ]: 8470 : SPDK_DEBUGLOG(bdev_raid_sb, "invalid signature\n");
145 : 8470 : return -EINVAL;
146 : : }
147 : :
148 [ + + ]: 1508 : if (spdk_divide_round_up(sb->length, spdk_bdev_get_data_block_size(bdev)) >
149 : 754 : spdk_divide_round_up(ctx->buf_size, bdev->blocklen)) {
150 [ - + ]: 27 : if (sb->length > RAID_BDEV_SB_MAX_LENGTH) {
151 : 0 : SPDK_WARNLOG("Incorrect superblock length on bdev %s\n",
152 : : spdk_bdev_get_name(bdev));
153 : 0 : return -EINVAL;
154 : : }
155 : :
156 : 27 : return -EAGAIN;
157 : : }
158 : :
159 [ + + ]: 727 : if (!raid_bdev_sb_check_crc(sb)) {
160 : 27 : SPDK_WARNLOG("Incorrect superblock crc on bdev %s\n", spdk_bdev_get_name(bdev));
161 : 27 : return -EINVAL;
162 : : }
163 : :
164 [ + + ]: 700 : if (sb->version.major != RAID_BDEV_SB_VERSION_MAJOR) {
165 : 9 : SPDK_ERRLOG("Not supported superblock major version %d on bdev %s\n",
166 : : sb->version.major, spdk_bdev_get_name(bdev));
167 : 9 : return -EINVAL;
168 : : }
169 : :
170 [ - + ]: 691 : if (sb->version.minor > RAID_BDEV_SB_VERSION_MINOR) {
171 : 0 : SPDK_WARNLOG("Superblock minor version %d on bdev %s is higher than the currently supported: %d\n",
172 : : sb->version.minor, spdk_bdev_get_name(bdev), RAID_BDEV_SB_VERSION_MINOR);
173 : : }
174 : :
175 [ + + ]: 2605 : for (i = 0; i < sb->base_bdevs_size; i++) {
176 : 1923 : sb_base_bdev = &sb->base_bdevs[i];
177 [ + + ]: 1923 : if (sb_base_bdev->slot >= sb->num_base_bdevs) {
178 : 9 : SPDK_WARNLOG("Invalid superblock base bdev slot number %u on bdev %s\n",
179 : : sb_base_bdev->slot, spdk_bdev_get_name(bdev));
180 : 9 : return -EINVAL;
181 : : }
182 : : }
183 : :
184 : 682 : return 0;
185 : : }
186 : :
187 : : static void
188 : 9134 : raid_bdev_read_sb_ctx_free(struct raid_bdev_read_sb_ctx *ctx)
189 : : {
190 : 9134 : spdk_dma_free(ctx->buf);
191 : :
192 : 9134 : free(ctx);
193 : 9134 : }
194 : :
195 : : static void raid_bdev_read_sb_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg);
196 : :
197 : : static int
198 : 18 : raid_bdev_read_sb_remainder(struct raid_bdev_read_sb_ctx *ctx)
199 : : {
200 : 18 : struct raid_bdev_superblock *sb = ctx->buf;
201 : 18 : struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(ctx->desc);
202 : : uint32_t buf_size_prev;
203 : : void *buf;
204 : : int rc;
205 : :
206 : 18 : buf_size_prev = ctx->buf_size;
207 : 36 : ctx->buf_size = spdk_divide_round_up(spdk_min(sb->length, RAID_BDEV_SB_MAX_LENGTH),
208 : 36 : spdk_bdev_get_data_block_size(bdev)) * bdev->blocklen;
209 : 18 : buf = spdk_dma_realloc(ctx->buf, ctx->buf_size, spdk_bdev_get_buf_align(bdev), NULL);
210 [ - + ]: 18 : if (buf == NULL) {
211 : 0 : SPDK_ERRLOG("Failed to reallocate buffer\n");
212 : 0 : return -ENOMEM;
213 : : }
214 : 18 : ctx->buf = buf;
215 : :
216 : 18 : rc = spdk_bdev_read(ctx->desc, ctx->ch, ctx->buf + buf_size_prev, buf_size_prev,
217 : 18 : ctx->buf_size - buf_size_prev, raid_bdev_read_sb_cb, ctx);
218 [ - + ]: 18 : if (rc != 0) {
219 : 0 : SPDK_ERRLOG("Failed to read bdev %s superblock remainder: %s\n",
220 : : spdk_bdev_get_name(bdev), spdk_strerror(-rc));
221 : 0 : return rc;
222 : : }
223 : :
224 : 18 : return 0;
225 : : }
226 : :
227 : : static void
228 : 9152 : raid_bdev_read_sb_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
229 : : {
230 : 9152 : struct spdk_bdev *bdev = bdev_io->bdev;
231 : 9152 : struct raid_bdev_read_sb_ctx *ctx = cb_arg;
232 : 9152 : struct raid_bdev_superblock *sb = NULL;
233 : : int status;
234 : :
235 [ + + + + ]: 9152 : if (spdk_bdev_is_md_interleaved(bdev_io->bdev) && ctx->buf_size > bdev->blocklen) {
236 : 6 : const uint32_t data_block_size = spdk_bdev_get_data_block_size(bdev);
237 : : uint32_t i;
238 : :
239 [ - + + + ]: 18 : for (i = 1; i < ctx->buf_size / bdev->blocklen; i++) {
240 [ - + - + ]: 12 : memmove(ctx->buf + (i * data_block_size),
241 : 12 : ctx->buf + (i * bdev->blocklen),
242 : : data_block_size);
243 : : }
244 : : }
245 : :
246 : 9152 : spdk_bdev_free_io(bdev_io);
247 : :
248 [ - + ]: 9152 : if (!success) {
249 : 0 : status = -EIO;
250 : 0 : goto out;
251 : : }
252 : :
253 : 9152 : status = raid_bdev_parse_superblock(ctx);
254 [ + + ]: 9152 : if (status == -EAGAIN) {
255 : 18 : status = raid_bdev_read_sb_remainder(ctx);
256 [ + - ]: 18 : if (status == 0) {
257 : 18 : return;
258 : : }
259 [ + + ]: 9134 : } else if (status != 0) {
260 [ - + - + ]: 8470 : SPDK_DEBUGLOG(bdev_raid_sb, "failed to parse bdev %s superblock\n",
261 : : spdk_bdev_get_name(spdk_bdev_desc_get_bdev(ctx->desc)));
262 : : } else {
263 : 664 : sb = ctx->buf;
264 : : }
265 : 9134 : out:
266 : 9134 : ctx->cb(sb, status, ctx->cb_ctx);
267 : :
268 : 9134 : raid_bdev_read_sb_ctx_free(ctx);
269 : : }
270 : :
271 : : int
272 : 9134 : raid_bdev_load_base_bdev_superblock(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
273 : : raid_bdev_load_sb_cb cb, void *cb_ctx)
274 : : {
275 : 9134 : struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(desc);
276 : : struct raid_bdev_read_sb_ctx *ctx;
277 : : int rc;
278 : :
279 [ - + ]: 9134 : assert(cb != NULL);
280 : :
281 : 9134 : ctx = calloc(1, sizeof(*ctx));
282 [ - + ]: 9134 : if (!ctx) {
283 : 0 : return -ENOMEM;
284 : : }
285 : :
286 : 9134 : ctx->desc = desc;
287 : 9134 : ctx->ch = ch;
288 : 9134 : ctx->cb = cb;
289 : 9134 : ctx->cb_ctx = cb_ctx;
290 : 18268 : ctx->buf_size = spdk_divide_round_up(sizeof(struct raid_bdev_superblock),
291 : 18268 : spdk_bdev_get_data_block_size(bdev)) * bdev->blocklen;
292 : 9134 : ctx->buf = spdk_dma_malloc(ctx->buf_size, spdk_bdev_get_buf_align(bdev), NULL);
293 [ - + ]: 9134 : if (!ctx->buf) {
294 : 0 : rc = -ENOMEM;
295 : 0 : goto err;
296 : : }
297 : :
298 : 9134 : rc = spdk_bdev_read(desc, ch, ctx->buf, 0, ctx->buf_size, raid_bdev_read_sb_cb, ctx);
299 [ - + ]: 9134 : if (rc) {
300 : 0 : goto err;
301 : : }
302 : :
303 : 9134 : return 0;
304 : 0 : err:
305 : 0 : raid_bdev_read_sb_ctx_free(ctx);
306 : :
307 : 0 : return rc;
308 : : }
309 : :
310 : : static void
311 : 2324 : raid_bdev_write_sb_base_bdev_done(int status, struct raid_bdev_write_sb_ctx *ctx)
312 : : {
313 [ - + ]: 2324 : if (status != 0) {
314 : 0 : ctx->status = status;
315 : : }
316 : :
317 [ + + ]: 2324 : if (--ctx->remaining == 0) {
318 : 606 : ctx->cb(ctx->status, ctx->raid_bdev, ctx->cb_ctx);
319 : 606 : free(ctx);
320 : : }
321 : 2324 : }
322 : :
323 : : static void
324 : 1384 : raid_bdev_write_superblock_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
325 : : {
326 : 1384 : struct raid_bdev_write_sb_ctx *ctx = cb_arg;
327 : 1384 : int status = 0;
328 : :
329 [ - + ]: 1384 : if (!success) {
330 : 0 : SPDK_ERRLOG("Failed to save superblock on bdev %s\n", bdev_io->bdev->name);
331 : 0 : status = -EIO;
332 : : }
333 : :
334 : 1384 : spdk_bdev_free_io(bdev_io);
335 : :
336 : 1384 : raid_bdev_write_sb_base_bdev_done(status, ctx);
337 : 1384 : }
338 : :
339 : : static void
340 : 606 : _raid_bdev_write_superblock(void *_ctx)
341 : : {
342 : 606 : struct raid_bdev_write_sb_ctx *ctx = _ctx;
343 : 606 : struct raid_bdev *raid_bdev = ctx->raid_bdev;
344 : : struct raid_base_bdev_info *base_info;
345 : : uint8_t i;
346 : : int rc;
347 : :
348 [ + + ]: 2324 : for (i = ctx->submitted; i < raid_bdev->num_base_bdevs; i++) {
349 : 1718 : base_info = &raid_bdev->base_bdev_info[i];
350 : :
351 [ - + + + : 1718 : if (!base_info->is_configured || base_info->remove_scheduled) {
- + + + ]
352 [ - + ]: 334 : assert(ctx->remaining > 1);
353 : 334 : raid_bdev_write_sb_base_bdev_done(0, ctx);
354 : 334 : ctx->submitted++;
355 : 334 : continue;
356 : : }
357 : :
358 : 1384 : rc = spdk_bdev_write(base_info->desc, base_info->app_thread_ch,
359 : 1384 : raid_bdev->sb_io_buf, 0, raid_bdev->sb_io_buf_size,
360 : : raid_bdev_write_superblock_cb, ctx);
361 [ - + ]: 1384 : if (rc != 0) {
362 : 0 : struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(base_info->desc);
363 : :
364 [ # # ]: 0 : if (rc == -ENOMEM) {
365 : 0 : ctx->wait_entry.bdev = bdev;
366 : 0 : ctx->wait_entry.cb_fn = _raid_bdev_write_superblock;
367 : 0 : ctx->wait_entry.cb_arg = ctx;
368 : 0 : spdk_bdev_queue_io_wait(bdev, base_info->app_thread_ch, &ctx->wait_entry);
369 : 0 : return;
370 : : }
371 : :
372 [ # # ]: 0 : assert(ctx->remaining > 1);
373 : 0 : raid_bdev_write_sb_base_bdev_done(rc, ctx);
374 : : }
375 : :
376 : 1384 : ctx->submitted++;
377 : : }
378 : :
379 : 606 : raid_bdev_write_sb_base_bdev_done(0, ctx);
380 : : }
381 : :
382 : : void
383 : 606 : raid_bdev_write_superblock(struct raid_bdev *raid_bdev, raid_bdev_write_sb_cb cb, void *cb_ctx)
384 : : {
385 : : struct raid_bdev_write_sb_ctx *ctx;
386 : 606 : struct raid_bdev_superblock *sb = raid_bdev->sb;
387 : : int rc;
388 : :
389 [ - + ]: 606 : assert(spdk_get_thread() == spdk_thread_get_app_thread());
390 [ - + ]: 606 : assert(sb != NULL);
391 [ - + ]: 606 : assert(cb != NULL);
392 : :
393 [ + + ]: 606 : if (raid_bdev->sb_io_buf == NULL) {
394 : 394 : rc = raid_bdev_alloc_sb_io_buf(raid_bdev);
395 [ - + ]: 394 : if (rc != 0) {
396 : 0 : goto err;
397 : : }
398 : : }
399 : :
400 : 606 : ctx = calloc(1, sizeof(*ctx));
401 [ - + ]: 606 : if (!ctx) {
402 : 0 : rc = -ENOMEM;
403 : 0 : goto err;
404 : : }
405 : :
406 : 606 : ctx->raid_bdev = raid_bdev;
407 : 606 : ctx->remaining = raid_bdev->num_base_bdevs + 1;
408 : 606 : ctx->cb = cb;
409 : 606 : ctx->cb_ctx = cb_ctx;
410 : :
411 : 606 : sb->seq_number++;
412 : 606 : raid_bdev_sb_update_crc(sb);
413 : :
414 [ + + ]: 606 : if (spdk_bdev_is_md_interleaved(&raid_bdev->bdev)) {
415 : 58 : void *sb_buf = sb;
416 : : uint32_t i;
417 : :
418 [ - + + + ]: 212 : for (i = 0; i < raid_bdev->sb_io_buf_size / raid_bdev->bdev.blocklen; i++) {
419 [ - + - + ]: 154 : memcpy(raid_bdev->sb_io_buf + (i * raid_bdev->bdev.blocklen),
420 : 154 : sb_buf + (i * sb->block_size), sb->block_size);
421 : : }
422 : : }
423 : :
424 : 606 : _raid_bdev_write_superblock(ctx);
425 : 606 : return;
426 : 0 : err:
427 : 0 : cb(rc, raid_bdev, cb_ctx);
428 : : }
429 : :
430 : 2314 : SPDK_LOG_REGISTER_COMPONENT(bdev_raid_sb)
|