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 3 : raid_bdev_alloc_superblock(struct raid_bdev *raid_bdev, uint32_t block_size)
36 : {
37 : struct raid_bdev_superblock *sb;
38 :
39 3 : assert(raid_bdev->sb == NULL);
40 :
41 3 : sb = spdk_dma_zmalloc(SPDK_ALIGN_CEIL(RAID_BDEV_SB_MAX_LENGTH, block_size), 0x1000, NULL);
42 3 : if (!sb) {
43 0 : SPDK_ERRLOG("Failed to allocate raid bdev sb buffer\n");
44 0 : return -ENOMEM;
45 : }
46 :
47 3 : raid_bdev->sb = sb;
48 :
49 3 : return 0;
50 : }
51 :
52 : void
53 3 : raid_bdev_free_superblock(struct raid_bdev *raid_bdev)
54 : {
55 3 : if (raid_bdev->sb_io_buf != NULL && raid_bdev->sb_io_buf != raid_bdev->sb) {
56 1 : assert(spdk_bdev_is_md_interleaved(&raid_bdev->bdev));
57 1 : spdk_dma_free(raid_bdev->sb_io_buf);
58 1 : raid_bdev->sb_io_buf = NULL;
59 : }
60 3 : spdk_dma_free(raid_bdev->sb);
61 3 : raid_bdev->sb = NULL;
62 3 : }
63 :
64 : void
65 3 : raid_bdev_init_superblock(struct raid_bdev *raid_bdev)
66 : {
67 3 : 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 3 : memcpy(&sb->signature, RAID_BDEV_SB_SIG, sizeof(sb->signature));
72 3 : sb->version.major = RAID_BDEV_SB_VERSION_MAJOR;
73 3 : sb->version.minor = RAID_BDEV_SB_VERSION_MINOR;
74 3 : spdk_uuid_copy(&sb->uuid, &raid_bdev->bdev.uuid);
75 3 : snprintf(sb->name, RAID_BDEV_SB_NAME_SIZE, "%s", raid_bdev->bdev.name);
76 3 : sb->raid_size = raid_bdev->bdev.blockcnt;
77 3 : sb->block_size = spdk_bdev_get_data_block_size(&raid_bdev->bdev);
78 3 : sb->level = raid_bdev->level;
79 3 : sb->strip_size = raid_bdev->strip_size;
80 : /* TODO: sb->state */
81 3 : sb->num_base_bdevs = sb->base_bdevs_size = raid_bdev->num_base_bdevs;
82 3 : sb->length = sizeof(*sb) + sizeof(*sb_base_bdev) * sb->base_bdevs_size;
83 :
84 3 : sb_base_bdev = &sb->base_bdevs[0];
85 12 : RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
86 9 : spdk_uuid_copy(&sb_base_bdev->uuid, &base_info->uuid);
87 9 : sb_base_bdev->data_offset = base_info->data_offset;
88 9 : sb_base_bdev->data_size = base_info->data_size;
89 9 : sb_base_bdev->state = RAID_SB_BASE_BDEV_CONFIGURED;
90 9 : sb_base_bdev->slot = raid_bdev_base_bdev_slot(base_info);
91 9 : sb_base_bdev++;
92 : }
93 3 : }
94 :
95 : static int
96 6 : raid_bdev_alloc_sb_io_buf(struct raid_bdev *raid_bdev)
97 : {
98 6 : struct raid_bdev_superblock *sb = raid_bdev->sb;
99 :
100 6 : if (spdk_bdev_is_md_interleaved(&raid_bdev->bdev)) {
101 4 : raid_bdev->sb_io_buf_size = spdk_divide_round_up(sb->length,
102 2 : sb->block_size) * raid_bdev->bdev.blocklen;
103 2 : raid_bdev->sb_io_buf = spdk_dma_zmalloc(raid_bdev->sb_io_buf_size, 0x1000, NULL);
104 2 : 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 4 : raid_bdev->sb_io_buf_size = SPDK_ALIGN_CEIL(sb->length, raid_bdev->bdev.blocklen);
110 4 : raid_bdev->sb_io_buf = raid_bdev->sb;
111 : }
112 :
113 6 : return 0;
114 : }
115 :
116 : static void
117 57 : raid_bdev_sb_update_crc(struct raid_bdev_superblock *sb)
118 : {
119 57 : sb->crc = 0;
120 57 : sb->crc = spdk_crc32c_update(sb, sb->length, 0);
121 57 : }
122 :
123 : static bool
124 27 : raid_bdev_sb_check_crc(struct raid_bdev_superblock *sb)
125 : {
126 27 : uint32_t crc, prev = sb->crc;
127 :
128 27 : raid_bdev_sb_update_crc(sb);
129 27 : crc = sb->crc;
130 27 : sb->crc = prev;
131 :
132 27 : return crc == prev;
133 : }
134 :
135 : static int
136 45 : raid_bdev_parse_superblock(struct raid_bdev_read_sb_ctx *ctx)
137 : {
138 45 : struct raid_bdev_superblock *sb = ctx->buf;
139 45 : 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 45 : if (memcmp(sb->signature, RAID_BDEV_SB_SIG, sizeof(sb->signature))) {
144 9 : SPDK_DEBUGLOG(bdev_raid_sb, "invalid signature\n");
145 9 : return -EINVAL;
146 : }
147 :
148 72 : if (spdk_divide_round_up(sb->length, spdk_bdev_get_data_block_size(bdev)) >
149 36 : spdk_divide_round_up(ctx->buf_size, bdev->blocklen)) {
150 9 : 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 9 : return -EAGAIN;
157 : }
158 :
159 27 : if (!raid_bdev_sb_check_crc(sb)) {
160 9 : SPDK_WARNLOG("Incorrect superblock crc on bdev %s\n", spdk_bdev_get_name(bdev));
161 9 : return -EINVAL;
162 : }
163 :
164 18 : if (sb->version.major != RAID_BDEV_SB_VERSION_MAJOR) {
165 3 : SPDK_ERRLOG("Not supported superblock major version %d on bdev %s\n",
166 : sb->version.major, spdk_bdev_get_name(bdev));
167 3 : return -EINVAL;
168 : }
169 :
170 15 : 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 15 : for (i = 0; i < sb->base_bdevs_size; i++) {
176 3 : sb_base_bdev = &sb->base_bdevs[i];
177 3 : if (sb_base_bdev->slot >= sb->num_base_bdevs) {
178 3 : SPDK_WARNLOG("Invalid superblock base bdev slot number %u on bdev %s\n",
179 : sb_base_bdev->slot, spdk_bdev_get_name(bdev));
180 3 : return -EINVAL;
181 : }
182 : }
183 :
184 12 : return 0;
185 : }
186 :
187 : static void
188 15 : raid_bdev_read_sb_ctx_free(struct raid_bdev_read_sb_ctx *ctx)
189 : {
190 15 : spdk_dma_free(ctx->buf);
191 :
192 15 : free(ctx);
193 15 : }
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 6 : raid_bdev_read_sb_remainder(struct raid_bdev_read_sb_ctx *ctx)
199 : {
200 6 : struct raid_bdev_superblock *sb = ctx->buf;
201 6 : 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 6 : buf_size_prev = ctx->buf_size;
207 6 : ctx->buf_size = spdk_divide_round_up(spdk_min(sb->length, RAID_BDEV_SB_MAX_LENGTH),
208 6 : spdk_bdev_get_data_block_size(bdev)) * bdev->blocklen;
209 6 : buf = spdk_dma_realloc(ctx->buf, ctx->buf_size, spdk_bdev_get_buf_align(bdev), NULL);
210 6 : if (buf == NULL) {
211 0 : SPDK_ERRLOG("Failed to reallocate buffer\n");
212 0 : return -ENOMEM;
213 : }
214 6 : ctx->buf = buf;
215 :
216 6 : rc = spdk_bdev_read(ctx->desc, ctx->ch, ctx->buf + buf_size_prev, buf_size_prev,
217 6 : ctx->buf_size - buf_size_prev, raid_bdev_read_sb_cb, ctx);
218 6 : 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 6 : return 0;
225 : }
226 :
227 : static void
228 21 : raid_bdev_read_sb_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
229 : {
230 21 : struct spdk_bdev *bdev = bdev_io->bdev;
231 21 : struct raid_bdev_read_sb_ctx *ctx = cb_arg;
232 21 : struct raid_bdev_superblock *sb = NULL;
233 : int status;
234 :
235 21 : if (spdk_bdev_is_md_interleaved(bdev_io->bdev) && ctx->buf_size > bdev->blocklen) {
236 2 : const uint32_t data_block_size = spdk_bdev_get_data_block_size(bdev);
237 : uint32_t i;
238 :
239 6 : for (i = 1; i < ctx->buf_size / bdev->blocklen; i++) {
240 4 : memmove(ctx->buf + (i * data_block_size),
241 4 : ctx->buf + (i * bdev->blocklen),
242 : data_block_size);
243 : }
244 : }
245 :
246 21 : spdk_bdev_free_io(bdev_io);
247 :
248 21 : if (!success) {
249 0 : status = -EIO;
250 0 : goto out;
251 : }
252 :
253 21 : status = raid_bdev_parse_superblock(ctx);
254 21 : if (status == -EAGAIN) {
255 6 : status = raid_bdev_read_sb_remainder(ctx);
256 6 : if (status == 0) {
257 6 : return;
258 : }
259 15 : } else if (status != 0) {
260 9 : 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 6 : sb = ctx->buf;
264 : }
265 15 : out:
266 15 : ctx->cb(sb, status, ctx->cb_ctx);
267 :
268 15 : raid_bdev_read_sb_ctx_free(ctx);
269 : }
270 :
271 : int
272 15 : 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 15 : struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(desc);
276 : struct raid_bdev_read_sb_ctx *ctx;
277 : int rc;
278 :
279 15 : assert(cb != NULL);
280 :
281 15 : ctx = calloc(1, sizeof(*ctx));
282 15 : if (!ctx) {
283 0 : return -ENOMEM;
284 : }
285 :
286 15 : ctx->desc = desc;
287 15 : ctx->ch = ch;
288 15 : ctx->cb = cb;
289 15 : ctx->cb_ctx = cb_ctx;
290 15 : ctx->buf_size = spdk_divide_round_up(sizeof(struct raid_bdev_superblock),
291 15 : spdk_bdev_get_data_block_size(bdev)) * bdev->blocklen;
292 15 : ctx->buf = spdk_dma_malloc(ctx->buf_size, spdk_bdev_get_buf_align(bdev), NULL);
293 15 : if (!ctx->buf) {
294 0 : rc = -ENOMEM;
295 0 : goto err;
296 : }
297 :
298 15 : rc = spdk_bdev_read(desc, ch, ctx->buf, 0, ctx->buf_size, raid_bdev_read_sb_cb, ctx);
299 15 : if (rc) {
300 0 : goto err;
301 : }
302 :
303 15 : 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 24 : raid_bdev_write_sb_base_bdev_done(int status, struct raid_bdev_write_sb_ctx *ctx)
312 : {
313 24 : if (status != 0) {
314 0 : ctx->status = status;
315 : }
316 :
317 24 : if (--ctx->remaining == 0) {
318 6 : ctx->cb(ctx->status, ctx->raid_bdev, ctx->cb_ctx);
319 6 : free(ctx);
320 : }
321 24 : }
322 :
323 : static void
324 12 : raid_bdev_write_superblock_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
325 : {
326 12 : struct raid_bdev_write_sb_ctx *ctx = cb_arg;
327 12 : int status = 0;
328 :
329 12 : 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 12 : spdk_bdev_free_io(bdev_io);
335 :
336 12 : raid_bdev_write_sb_base_bdev_done(status, ctx);
337 12 : }
338 :
339 : static void
340 6 : _raid_bdev_write_superblock(void *_ctx)
341 : {
342 6 : struct raid_bdev_write_sb_ctx *ctx = _ctx;
343 6 : 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 24 : for (i = ctx->submitted; i < raid_bdev->num_base_bdevs; i++) {
349 18 : base_info = &raid_bdev->base_bdev_info[i];
350 :
351 18 : if (!base_info->is_configured || base_info->remove_scheduled) {
352 6 : assert(ctx->remaining > 1);
353 6 : raid_bdev_write_sb_base_bdev_done(0, ctx);
354 6 : ctx->submitted++;
355 6 : continue;
356 : }
357 :
358 12 : rc = spdk_bdev_write(base_info->desc, base_info->app_thread_ch,
359 12 : raid_bdev->sb_io_buf, 0, raid_bdev->sb_io_buf_size,
360 : raid_bdev_write_superblock_cb, ctx);
361 12 : 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 12 : ctx->submitted++;
377 : }
378 :
379 6 : raid_bdev_write_sb_base_bdev_done(0, ctx);
380 : }
381 :
382 : void
383 6 : 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 6 : struct raid_bdev_superblock *sb = raid_bdev->sb;
387 : int rc;
388 :
389 6 : assert(spdk_get_thread() == spdk_thread_get_app_thread());
390 6 : assert(sb != NULL);
391 6 : assert(cb != NULL);
392 :
393 6 : if (raid_bdev->sb_io_buf == NULL) {
394 6 : rc = raid_bdev_alloc_sb_io_buf(raid_bdev);
395 6 : if (rc != 0) {
396 0 : goto err;
397 : }
398 : }
399 :
400 6 : ctx = calloc(1, sizeof(*ctx));
401 6 : if (!ctx) {
402 0 : rc = -ENOMEM;
403 0 : goto err;
404 : }
405 :
406 6 : ctx->raid_bdev = raid_bdev;
407 6 : ctx->remaining = raid_bdev->num_base_bdevs + 1;
408 6 : ctx->cb = cb;
409 6 : ctx->cb_ctx = cb_ctx;
410 :
411 6 : sb->seq_number++;
412 6 : raid_bdev_sb_update_crc(sb);
413 :
414 6 : if (spdk_bdev_is_md_interleaved(&raid_bdev->bdev)) {
415 2 : void *sb_buf = sb;
416 : uint32_t i;
417 :
418 36 : for (i = 0; i < raid_bdev->sb_io_buf_size / raid_bdev->bdev.blocklen; i++) {
419 34 : memcpy(raid_bdev->sb_io_buf + (i * raid_bdev->bdev.blocklen),
420 34 : sb_buf + (i * sb->block_size), sb->block_size);
421 : }
422 : }
423 :
424 6 : _raid_bdev_write_superblock(ctx);
425 6 : return;
426 0 : err:
427 0 : cb(rc, raid_bdev, cb_ctx);
428 : }
429 :
430 1 : SPDK_LOG_REGISTER_COMPONENT(bdev_raid_sb)
|