xref: /spdk/module/bdev/raid/bdev_raid_sb.c (revision 6eeabe6986acd8b06bb018fb314de1ddc14f8517)
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 	uint64_t nbytes;
19 	uint8_t submitted;
20 	uint8_t remaining;
21 	raid_bdev_write_sb_cb cb;
22 	void *cb_ctx;
23 	struct spdk_bdev_io_wait_entry wait_entry;
24 };
25 
26 struct raid_bdev_read_sb_ctx {
27 	struct spdk_bdev_desc *desc;
28 	struct spdk_io_channel *ch;
29 	raid_bdev_load_sb_cb cb;
30 	void *cb_ctx;
31 	void *buf;
32 	uint32_t buf_size;
33 };
34 
35 static inline uint64_t
36 align_ceil(uint64_t val, uint64_t align)
37 {
38 	return spdk_divide_round_up(val, align) * align;
39 }
40 
41 int
42 raid_bdev_alloc_superblock(struct raid_bdev *raid_bdev, uint32_t block_size)
43 {
44 	struct raid_bdev_superblock *sb;
45 
46 	sb = spdk_dma_zmalloc(SPDK_ALIGN_CEIL(RAID_BDEV_SB_MAX_LENGTH, block_size), 0x1000, NULL);
47 	if (!sb) {
48 		SPDK_ERRLOG("Failed to allocate raid bdev sb buffer\n");
49 		return -ENOMEM;
50 	}
51 
52 	raid_bdev->sb = sb;
53 
54 	return 0;
55 }
56 
57 void
58 raid_bdev_free_superblock(struct raid_bdev *raid_bdev)
59 {
60 	spdk_dma_free(raid_bdev->sb);
61 	raid_bdev->sb = NULL;
62 }
63 
64 void
65 raid_bdev_init_superblock(struct raid_bdev *raid_bdev)
66 {
67 	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 	memcpy(&sb->signature, RAID_BDEV_SB_SIG, sizeof(sb->signature));
72 	sb->version.major = RAID_BDEV_SB_VERSION_MAJOR;
73 	sb->version.minor = RAID_BDEV_SB_VERSION_MINOR;
74 	spdk_uuid_copy(&sb->uuid, &raid_bdev->bdev.uuid);
75 	snprintf(sb->name, RAID_BDEV_SB_NAME_SIZE, "%s", raid_bdev->bdev.name);
76 	sb->raid_size = raid_bdev->bdev.blockcnt;
77 	sb->block_size = raid_bdev->bdev.blocklen;
78 	sb->level = raid_bdev->level;
79 	sb->strip_size = raid_bdev->strip_size;
80 	/* TODO: sb->state */
81 	sb->num_base_bdevs = sb->base_bdevs_size = raid_bdev->num_base_bdevs;
82 	sb->length = sizeof(*sb) + sizeof(*sb_base_bdev) * sb->base_bdevs_size;
83 
84 	sb_base_bdev = &sb->base_bdevs[0];
85 	RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
86 		spdk_uuid_copy(&sb_base_bdev->uuid, &base_info->uuid);
87 		sb_base_bdev->data_offset = base_info->data_offset;
88 		sb_base_bdev->data_size = base_info->data_size;
89 		sb_base_bdev->state = RAID_SB_BASE_BDEV_CONFIGURED;
90 		sb_base_bdev->slot = raid_bdev_base_bdev_slot(base_info);
91 		sb_base_bdev++;
92 	}
93 }
94 
95 static void
96 raid_bdev_sb_update_crc(struct raid_bdev_superblock *sb)
97 {
98 	sb->crc = 0;
99 	sb->crc = spdk_crc32c_update(sb, sb->length, 0);
100 }
101 
102 static bool
103 raid_bdev_sb_check_crc(struct raid_bdev_superblock *sb)
104 {
105 	uint32_t crc, prev = sb->crc;
106 
107 	raid_bdev_sb_update_crc(sb);
108 	crc = sb->crc;
109 	sb->crc = prev;
110 
111 	return crc == prev;
112 }
113 
114 static int
115 raid_bdev_parse_superblock(struct raid_bdev_read_sb_ctx *ctx)
116 {
117 	struct raid_bdev_superblock *sb = ctx->buf;
118 	struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(ctx->desc);
119 
120 	if (memcmp(sb->signature, RAID_BDEV_SB_SIG, sizeof(sb->signature))) {
121 		SPDK_DEBUGLOG(bdev_raid_sb, "invalid signature\n");
122 		return -EINVAL;
123 	}
124 
125 	if (sb->length > ctx->buf_size) {
126 		if (sb->length > RAID_BDEV_SB_MAX_LENGTH) {
127 			SPDK_WARNLOG("Incorrect superblock length on bdev %s\n",
128 				     spdk_bdev_get_name(bdev));
129 			return -EINVAL;
130 		}
131 
132 		return -EAGAIN;
133 	}
134 
135 	if (!raid_bdev_sb_check_crc(sb)) {
136 		SPDK_WARNLOG("Incorrect superblock crc on bdev %s\n", spdk_bdev_get_name(bdev));
137 		return -EINVAL;
138 	}
139 
140 	if (sb->version.major != RAID_BDEV_SB_VERSION_MAJOR) {
141 		SPDK_ERRLOG("Not supported superblock major version %d on bdev %s\n",
142 			    sb->version.major, spdk_bdev_get_name(bdev));
143 		return -EINVAL;
144 	}
145 
146 	if (sb->version.minor > RAID_BDEV_SB_VERSION_MINOR) {
147 		SPDK_WARNLOG("Superblock minor version %d on bdev %s is higher than the currently supported: %d\n",
148 			     sb->version.minor, spdk_bdev_get_name(bdev), RAID_BDEV_SB_VERSION_MINOR);
149 	}
150 
151 	return 0;
152 }
153 
154 static void
155 raid_bdev_read_sb_ctx_free(struct raid_bdev_read_sb_ctx *ctx)
156 {
157 	spdk_dma_free(ctx->buf);
158 
159 	free(ctx);
160 }
161 
162 static void raid_bdev_read_sb_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg);
163 
164 static int
165 raid_bdev_read_sb_remainder(struct raid_bdev_read_sb_ctx *ctx)
166 {
167 	struct raid_bdev_superblock *sb = ctx->buf;
168 	struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(ctx->desc);
169 	uint32_t buf_size_prev;
170 	void *buf;
171 	int rc;
172 
173 	buf_size_prev = ctx->buf_size;
174 	ctx->buf_size = align_ceil(sb->length, spdk_bdev_get_block_size(bdev));
175 	buf = spdk_dma_realloc(ctx->buf, ctx->buf_size, spdk_bdev_get_buf_align(bdev), NULL);
176 	if (buf == NULL) {
177 		SPDK_ERRLOG("Failed to reallocate buffer\n");
178 		return -ENOMEM;
179 	}
180 	ctx->buf = buf;
181 
182 	rc = spdk_bdev_read(ctx->desc, ctx->ch, ctx->buf + buf_size_prev, buf_size_prev,
183 			    ctx->buf_size - buf_size_prev, raid_bdev_read_sb_cb, ctx);
184 	if (rc != 0) {
185 		SPDK_ERRLOG("Failed to read bdev %s superblock remainder: %s\n",
186 			    spdk_bdev_get_name(bdev), spdk_strerror(-rc));
187 		return rc;
188 	}
189 
190 	return 0;
191 }
192 
193 static void
194 raid_bdev_read_sb_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
195 {
196 	struct raid_bdev_read_sb_ctx *ctx = cb_arg;
197 	struct raid_bdev_superblock *sb = NULL;
198 	int status;
199 
200 	spdk_bdev_free_io(bdev_io);
201 
202 	if (!success) {
203 		status = -EIO;
204 		goto out;
205 	}
206 
207 	status = raid_bdev_parse_superblock(ctx);
208 	if (status == -EAGAIN) {
209 		status = raid_bdev_read_sb_remainder(ctx);
210 		if (status == 0) {
211 			return;
212 		}
213 	} else if (status != 0) {
214 		SPDK_DEBUGLOG(bdev_raid_sb, "failed to parse bdev %s superblock\n",
215 			      spdk_bdev_get_name(spdk_bdev_desc_get_bdev(ctx->desc)));
216 	} else {
217 		sb = ctx->buf;
218 	}
219 out:
220 	ctx->cb(sb, status, ctx->cb_ctx);
221 
222 	raid_bdev_read_sb_ctx_free(ctx);
223 }
224 
225 int
226 raid_bdev_load_base_bdev_superblock(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
227 				    raid_bdev_load_sb_cb cb, void *cb_ctx)
228 {
229 	struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(desc);
230 	struct raid_bdev_read_sb_ctx *ctx;
231 	int rc;
232 
233 	assert(cb != NULL);
234 
235 	ctx = calloc(1, sizeof(*ctx));
236 	if (!ctx) {
237 		return -ENOMEM;
238 	}
239 
240 	ctx->desc = desc;
241 	ctx->ch = ch;
242 	ctx->cb = cb;
243 	ctx->cb_ctx = cb_ctx;
244 	ctx->buf_size = align_ceil(sizeof(struct raid_bdev_superblock), spdk_bdev_get_block_size(bdev));
245 	ctx->buf = spdk_dma_malloc(ctx->buf_size, spdk_bdev_get_buf_align(bdev), NULL);
246 	if (!ctx->buf) {
247 		rc = -ENOMEM;
248 		goto err;
249 	}
250 
251 	rc = spdk_bdev_read(desc, ch, ctx->buf, 0, ctx->buf_size, raid_bdev_read_sb_cb, ctx);
252 	if (rc) {
253 		goto err;
254 	}
255 
256 	return 0;
257 err:
258 	raid_bdev_read_sb_ctx_free(ctx);
259 
260 	return rc;
261 }
262 
263 static void
264 raid_bdev_write_sb_base_bdev_done(int status, struct raid_bdev_write_sb_ctx *ctx)
265 {
266 	if (status != 0) {
267 		ctx->status = status;
268 	}
269 
270 	if (--ctx->remaining == 0) {
271 		ctx->cb(ctx->status, ctx->raid_bdev, ctx->cb_ctx);
272 		free(ctx);
273 	}
274 }
275 
276 static void
277 raid_bdev_write_superblock_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
278 {
279 	struct raid_bdev_write_sb_ctx *ctx = cb_arg;
280 	int status = 0;
281 
282 	if (!success) {
283 		SPDK_ERRLOG("Failed to save superblock on bdev %s\n", bdev_io->bdev->name);
284 		status = -EIO;
285 	}
286 
287 	spdk_bdev_free_io(bdev_io);
288 
289 	raid_bdev_write_sb_base_bdev_done(status, ctx);
290 }
291 
292 static void
293 _raid_bdev_write_superblock(void *_ctx)
294 {
295 	struct raid_bdev_write_sb_ctx *ctx = _ctx;
296 	struct raid_bdev *raid_bdev = ctx->raid_bdev;
297 	struct raid_base_bdev_info *base_info;
298 	uint8_t i;
299 	int rc;
300 
301 	for (i = ctx->submitted; i < raid_bdev->num_base_bdevs; i++) {
302 		base_info = &raid_bdev->base_bdev_info[i];
303 
304 		if (base_info->desc == NULL) {
305 			assert(ctx->remaining > 1);
306 			raid_bdev_write_sb_base_bdev_done(0, ctx);
307 			ctx->submitted++;
308 			continue;
309 		}
310 
311 		rc = spdk_bdev_write(base_info->desc, base_info->app_thread_ch,
312 				     (void *)raid_bdev->sb, 0, ctx->nbytes,
313 				     raid_bdev_write_superblock_cb, ctx);
314 		if (rc != 0) {
315 			struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(base_info->desc);
316 
317 			if (rc == -ENOMEM) {
318 				ctx->wait_entry.bdev = bdev;
319 				ctx->wait_entry.cb_fn = _raid_bdev_write_superblock;
320 				ctx->wait_entry.cb_arg = ctx;
321 				spdk_bdev_queue_io_wait(bdev, base_info->app_thread_ch, &ctx->wait_entry);
322 				return;
323 			}
324 
325 			assert(ctx->remaining > 1);
326 			raid_bdev_write_sb_base_bdev_done(rc, ctx);
327 		}
328 
329 		ctx->submitted++;
330 	}
331 
332 	raid_bdev_write_sb_base_bdev_done(0, ctx);
333 }
334 
335 void
336 raid_bdev_write_superblock(struct raid_bdev *raid_bdev, raid_bdev_write_sb_cb cb, void *cb_ctx)
337 {
338 	struct raid_bdev_write_sb_ctx *ctx;
339 	struct raid_bdev_superblock *sb = raid_bdev->sb;
340 
341 	assert(spdk_get_thread() == spdk_thread_get_app_thread());
342 	assert(sb != NULL);
343 	assert(cb != NULL);
344 
345 	ctx = calloc(1, sizeof(*ctx));
346 	if (!ctx) {
347 		cb(-ENOMEM, raid_bdev, cb_ctx);
348 		return;
349 	}
350 
351 	ctx->raid_bdev = raid_bdev;
352 	ctx->nbytes = align_ceil(sb->length, spdk_bdev_get_block_size(&raid_bdev->bdev));
353 	ctx->remaining = raid_bdev->num_base_bdevs + 1;
354 	ctx->cb = cb;
355 	ctx->cb_ctx = cb_ctx;
356 
357 	sb->seq_number++;
358 	raid_bdev_sb_update_crc(sb);
359 
360 	_raid_bdev_write_superblock(ctx);
361 }
362 
363 SPDK_LOG_REGISTER_COMPONENT(bdev_raid_sb)
364