xref: /spdk/module/bdev/error/vbdev_error.c (revision 698e22d8f01efc297c322d003daea2b83294c1ca)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2017 Intel Corporation.
3  *   All rights reserved.
4  */
5 
6 /*
7  * This is a module for test purpose which will simulate error cases for bdev.
8  */
9 
10 #include "spdk/stdinc.h"
11 #include "spdk/rpc.h"
12 #include "spdk/util.h"
13 #include "spdk/endian.h"
14 #include "spdk/nvme_spec.h"
15 #include "spdk/string.h"
16 
17 #include "spdk/bdev_module.h"
18 #include "spdk/log.h"
19 
20 #include "vbdev_error.h"
21 
22 struct spdk_vbdev_error_config {
23 	char *base_bdev;
24 	struct spdk_uuid uuid;
25 	TAILQ_ENTRY(spdk_vbdev_error_config) tailq;
26 };
27 
28 static TAILQ_HEAD(, spdk_vbdev_error_config) g_error_config
29 	= TAILQ_HEAD_INITIALIZER(g_error_config);
30 
31 struct vbdev_error_info {
32 	uint32_t			error_type;
33 	uint32_t			error_num;
34 	uint64_t			error_qd;
35 	uint64_t			corrupt_offset;
36 	uint8_t				corrupt_value;
37 };
38 
39 struct error_io {
40 	TAILQ_ENTRY(error_io) link;
41 };
42 
43 /* Context for each error bdev */
44 struct error_disk {
45 	struct spdk_bdev_part		part;
46 	struct vbdev_error_info		error_vector[SPDK_BDEV_IO_TYPE_RESET];
47 	TAILQ_HEAD(, error_io)	pending_ios;
48 };
49 
50 struct error_channel {
51 	struct spdk_bdev_part_channel	part_ch;
52 	uint64_t			io_inflight;
53 };
54 
55 static pthread_mutex_t g_vbdev_error_mutex = PTHREAD_MUTEX_INITIALIZER;
56 static SPDK_BDEV_PART_TAILQ g_error_disks = TAILQ_HEAD_INITIALIZER(g_error_disks);
57 
58 static int vbdev_error_init(void);
59 static void vbdev_error_fini(void);
60 
61 static void vbdev_error_examine(struct spdk_bdev *bdev);
62 static int vbdev_error_config_json(struct spdk_json_write_ctx *w);
63 
64 static int vbdev_error_config_add(const char *base_bdev_name, const struct spdk_uuid *uuid);
65 static int vbdev_error_config_remove(const char *base_bdev_name);
66 
67 static int
68 vbdev_error_get_ctx_size(void)
69 {
70 	return sizeof(struct error_io);
71 }
72 
73 static struct spdk_bdev_module error_if = {
74 	.name = "error",
75 	.module_init = vbdev_error_init,
76 	.module_fini = vbdev_error_fini,
77 	.examine_config = vbdev_error_examine,
78 	.config_json = vbdev_error_config_json,
79 	.get_ctx_size = vbdev_error_get_ctx_size,
80 
81 };
82 
83 SPDK_BDEV_MODULE_REGISTER(error, &error_if)
84 
85 static void
86 dummy_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *ctx)
87 {
88 }
89 
90 int
91 vbdev_error_inject_error(char *name, const struct vbdev_error_inject_opts *opts)
92 {
93 	struct spdk_bdev_desc *desc;
94 	struct spdk_bdev *bdev;
95 	struct spdk_bdev_part *part;
96 	struct error_disk *error_disk = NULL;
97 	uint32_t i;
98 	int rc = 0;
99 
100 	if (opts->error_type == VBDEV_IO_CORRUPT_DATA) {
101 		if (opts->corrupt_value == 0) {
102 			/* If corrupt_value is 0, XOR cannot cause data corruption. */
103 			SPDK_ERRLOG("corrupt_value should be non-zero.\n");
104 			return -EINVAL;
105 		}
106 	}
107 
108 	pthread_mutex_lock(&g_vbdev_error_mutex);
109 
110 	rc = spdk_bdev_open_ext(name, false, dummy_bdev_event_cb, NULL, &desc);
111 	if (rc != 0) {
112 		SPDK_ERRLOG("Could not open ErrorInjection bdev %s\n", name);
113 		pthread_mutex_unlock(&g_vbdev_error_mutex);
114 		return rc;
115 	}
116 
117 	bdev = spdk_bdev_desc_get_bdev(desc);
118 
119 	TAILQ_FOREACH(part, &g_error_disks, tailq) {
120 		if (bdev == spdk_bdev_part_get_bdev(part)) {
121 			error_disk = (struct error_disk *)part;
122 			break;
123 		}
124 	}
125 
126 	if (error_disk == NULL) {
127 		SPDK_ERRLOG("Could not find ErrorInjection bdev %s\n", name);
128 		rc = -ENODEV;
129 		goto exit;
130 	}
131 
132 	if (0xffffffff == opts->io_type) {
133 		for (i = 0; i < SPDK_COUNTOF(error_disk->error_vector); i++) {
134 			error_disk->error_vector[i].error_type = opts->error_type;
135 			error_disk->error_vector[i].error_num = opts->error_num;
136 			error_disk->error_vector[i].error_qd = opts->error_qd;
137 			error_disk->error_vector[i].corrupt_offset = opts->corrupt_offset;
138 			error_disk->error_vector[i].corrupt_value = opts->corrupt_value;
139 		}
140 	} else if (0 == opts->io_type) {
141 		for (i = 0; i < SPDK_COUNTOF(error_disk->error_vector); i++) {
142 			error_disk->error_vector[i].error_num = 0;
143 		}
144 	} else {
145 		error_disk->error_vector[opts->io_type].error_type = opts->error_type;
146 		error_disk->error_vector[opts->io_type].error_num = opts->error_num;
147 		error_disk->error_vector[opts->io_type].error_qd = opts->error_qd;
148 		error_disk->error_vector[opts->io_type].corrupt_offset = opts->corrupt_offset;
149 		error_disk->error_vector[opts->io_type].corrupt_value = opts->corrupt_value;
150 	}
151 
152 exit:
153 	spdk_bdev_close(desc);
154 	pthread_mutex_unlock(&g_vbdev_error_mutex);
155 	return rc;
156 }
157 
158 static void
159 vbdev_error_reset(struct error_disk *error_disk, struct spdk_bdev_io *bdev_io)
160 {
161 	struct error_io *pending_io, *tmp;
162 
163 	TAILQ_FOREACH_SAFE(pending_io, &error_disk->pending_ios, link, tmp) {
164 		TAILQ_REMOVE(&error_disk->pending_ios, pending_io, link);
165 		spdk_bdev_io_complete(spdk_bdev_io_from_ctx(pending_io), SPDK_BDEV_IO_STATUS_FAILED);
166 	}
167 	spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS);
168 }
169 
170 static uint32_t
171 vbdev_error_get_error_type(struct error_disk *error_disk, uint32_t io_type)
172 {
173 	switch (io_type) {
174 	case SPDK_BDEV_IO_TYPE_READ:
175 	case SPDK_BDEV_IO_TYPE_WRITE:
176 	case SPDK_BDEV_IO_TYPE_UNMAP:
177 	case SPDK_BDEV_IO_TYPE_FLUSH:
178 		break;
179 	default:
180 		return 0;
181 	}
182 
183 	if (error_disk->error_vector[io_type].error_num) {
184 		return error_disk->error_vector[io_type].error_type;
185 	}
186 	return 0;
187 }
188 
189 static void
190 vbdev_error_corrupt_io_data(struct spdk_bdev_io *bdev_io, uint64_t corrupt_offset,
191 			    uint8_t corrupt_value)
192 {
193 	uint8_t *buf;
194 	int i;
195 
196 	if (bdev_io->u.bdev.iovs == NULL || bdev_io->u.bdev.iovs[0].iov_base == NULL) {
197 		return;
198 	}
199 
200 	for (i = 0; i < bdev_io->u.bdev.iovcnt; i++) {
201 		if (bdev_io->u.bdev.iovs[i].iov_len > corrupt_offset) {
202 			buf = (uint8_t *)bdev_io->u.bdev.iovs[i].iov_base;
203 
204 			buf[corrupt_offset] ^= corrupt_value;
205 			break;
206 		}
207 
208 		corrupt_offset -= bdev_io->u.bdev.iovs[i].iov_len;
209 	}
210 }
211 
212 static void
213 vbdev_error_complete_request(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
214 {
215 	int status = success ? SPDK_BDEV_IO_STATUS_SUCCESS : SPDK_BDEV_IO_STATUS_FAILED;
216 	struct error_disk *error_disk = bdev_io->bdev->ctxt;
217 	struct error_channel *ch = spdk_io_channel_get_ctx(spdk_bdev_io_get_io_channel(bdev_io));
218 	uint32_t error_type;
219 
220 	assert(ch->io_inflight > 0);
221 	ch->io_inflight--;
222 
223 	if (success && bdev_io->type == SPDK_BDEV_IO_TYPE_READ) {
224 		error_type = vbdev_error_get_error_type(error_disk, bdev_io->type);
225 		if (error_type == VBDEV_IO_CORRUPT_DATA) {
226 			error_disk->error_vector[bdev_io->type].error_num--;
227 
228 			vbdev_error_corrupt_io_data(bdev_io,
229 						    error_disk->error_vector[bdev_io->type].corrupt_offset,
230 						    error_disk->error_vector[bdev_io->type].corrupt_value);
231 		}
232 	}
233 
234 	spdk_bdev_io_complete(bdev_io, status);
235 }
236 
237 static void
238 vbdev_error_submit_request(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io)
239 {
240 	struct error_io *error_io = (struct error_io *)bdev_io->driver_ctx;
241 	struct error_channel *ch = spdk_io_channel_get_ctx(_ch);
242 	struct error_disk *error_disk = bdev_io->bdev->ctxt;
243 	uint32_t error_type;
244 	int rc;
245 
246 	if (bdev_io->type == SPDK_BDEV_IO_TYPE_RESET) {
247 		vbdev_error_reset(error_disk, bdev_io);
248 		return;
249 	}
250 
251 	error_type = vbdev_error_get_error_type(error_disk, bdev_io->type);
252 
253 	if (ch->io_inflight < error_disk->error_vector[bdev_io->type].error_qd) {
254 		error_type = 0;
255 	}
256 
257 	switch (error_type) {
258 	case VBDEV_IO_FAILURE:
259 		error_disk->error_vector[bdev_io->type].error_num--;
260 		spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
261 		break;
262 	case VBDEV_IO_NOMEM:
263 		error_disk->error_vector[bdev_io->type].error_num--;
264 		spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_NOMEM);
265 		break;
266 	case VBDEV_IO_PENDING:
267 		TAILQ_INSERT_TAIL(&error_disk->pending_ios, error_io, link);
268 		error_disk->error_vector[bdev_io->type].error_num--;
269 		break;
270 	case VBDEV_IO_CORRUPT_DATA:
271 		if (bdev_io->type == SPDK_BDEV_IO_TYPE_WRITE) {
272 			error_disk->error_vector[bdev_io->type].error_num--;
273 
274 			vbdev_error_corrupt_io_data(bdev_io,
275 						    error_disk->error_vector[bdev_io->type].corrupt_offset,
276 						    error_disk->error_vector[bdev_io->type].corrupt_value);
277 		}
278 	/* fallthrough */
279 	case 0:
280 		rc = spdk_bdev_part_submit_request_ext(&ch->part_ch, bdev_io,
281 						       vbdev_error_complete_request);
282 
283 		if (rc) {
284 			SPDK_ERRLOG("bdev_error: submit request failed, rc=%d\n", rc);
285 			spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
286 		}
287 		ch->io_inflight++;
288 		break;
289 	default:
290 		assert(false);
291 		break;
292 	}
293 }
294 
295 static int
296 vbdev_error_destruct(void *ctx)
297 {
298 	struct error_disk *error_disk = ctx;
299 	struct spdk_bdev *base_bdev = spdk_bdev_part_get_base_bdev(&error_disk->part);
300 	int rc;
301 
302 	rc = vbdev_error_config_remove(base_bdev->name);
303 	if (rc != 0) {
304 		SPDK_ERRLOG("vbdev_error_config_remove() failed\n");
305 	}
306 
307 	return spdk_bdev_part_free(&error_disk->part);
308 }
309 
310 static int
311 vbdev_error_dump_info_json(void *ctx, struct spdk_json_write_ctx *w)
312 {
313 	struct error_disk *error_disk = ctx;
314 	struct spdk_bdev *base_bdev = spdk_bdev_part_get_base_bdev(&error_disk->part);
315 
316 	spdk_json_write_named_object_begin(w, "error_disk");
317 
318 	spdk_json_write_named_string(w, "base_bdev", base_bdev->name);
319 
320 	spdk_json_write_object_end(w);
321 
322 	return 0;
323 }
324 
325 static void
326 vbdev_error_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w)
327 {
328 	/* No config per bdev. */
329 }
330 
331 
332 static struct spdk_bdev_fn_table vbdev_error_fn_table = {
333 	.destruct		= vbdev_error_destruct,
334 	.submit_request		= vbdev_error_submit_request,
335 	.dump_info_json		= vbdev_error_dump_info_json,
336 	.write_config_json	= vbdev_error_write_config_json
337 };
338 
339 static void
340 vbdev_error_base_bdev_hotremove_cb(void *_part_base)
341 {
342 	struct spdk_bdev_part_base *part_base = _part_base;
343 
344 	spdk_bdev_part_base_hotremove(part_base, &g_error_disks);
345 }
346 
347 static int
348 _vbdev_error_create(const char *base_bdev_name, const struct spdk_uuid *uuid)
349 {
350 	struct spdk_bdev_part_base *base = NULL;
351 	struct error_disk *disk = NULL;
352 	struct spdk_bdev *base_bdev, *bdev;
353 	char *name;
354 	int rc;
355 
356 	rc = spdk_bdev_part_base_construct_ext(base_bdev_name,
357 					       vbdev_error_base_bdev_hotremove_cb,
358 					       &error_if, &vbdev_error_fn_table, &g_error_disks,
359 					       NULL, NULL, sizeof(struct error_channel),
360 					       NULL, NULL, &base);
361 	if (rc != 0) {
362 		if (rc != -ENODEV) {
363 			SPDK_ERRLOG("could not construct part base for bdev %s\n", base_bdev_name);
364 		}
365 		return rc;
366 	}
367 
368 	base_bdev = spdk_bdev_part_base_get_bdev(base);
369 
370 	disk = calloc(1, sizeof(*disk));
371 	if (!disk) {
372 		SPDK_ERRLOG("Memory allocation failure\n");
373 		spdk_bdev_part_base_free(base);
374 		return -ENOMEM;
375 	}
376 
377 	name = spdk_sprintf_alloc("EE_%s", base_bdev_name);
378 	if (!name) {
379 		SPDK_ERRLOG("name allocation failure\n");
380 		spdk_bdev_part_base_free(base);
381 		free(disk);
382 		return -ENOMEM;
383 	}
384 
385 	if (!spdk_uuid_is_null(uuid)) {
386 		bdev = spdk_bdev_part_get_bdev(&disk->part);
387 		spdk_uuid_copy(&bdev->uuid, uuid);
388 	}
389 
390 	rc = spdk_bdev_part_construct(&disk->part, base, name, 0, base_bdev->blockcnt,
391 				      "Error Injection Disk");
392 	free(name);
393 	if (rc) {
394 		SPDK_ERRLOG("could not construct part for bdev %s\n", base_bdev_name);
395 		/* spdk_bdev_part_construct will free name on failure */
396 		spdk_bdev_part_base_free(base);
397 		free(disk);
398 		return rc;
399 	}
400 
401 	TAILQ_INIT(&disk->pending_ios);
402 
403 	return 0;
404 }
405 
406 int
407 vbdev_error_create(const char *base_bdev_name, const struct spdk_uuid *uuid)
408 {
409 	int rc;
410 
411 	rc = vbdev_error_config_add(base_bdev_name, uuid);
412 	if (rc != 0) {
413 		SPDK_ERRLOG("Adding config for ErrorInjection bdev %s failed (rc=%d)\n",
414 			    base_bdev_name, rc);
415 		return rc;
416 	}
417 
418 	rc = _vbdev_error_create(base_bdev_name, uuid);
419 	if (rc == -ENODEV) {
420 		rc = 0;
421 	} else if (rc != 0) {
422 		vbdev_error_config_remove(base_bdev_name);
423 		SPDK_ERRLOG("Could not create ErrorInjection bdev %s (rc=%d)\n",
424 			    base_bdev_name, rc);
425 	}
426 
427 	return rc;
428 }
429 
430 void
431 vbdev_error_delete(const char *error_vbdev_name, spdk_delete_error_complete cb_fn, void *cb_arg)
432 {
433 	int rc;
434 
435 	rc = spdk_bdev_unregister_by_name(error_vbdev_name, &error_if, cb_fn, cb_arg);
436 	if (rc != 0) {
437 		cb_fn(cb_arg, rc);
438 	}
439 }
440 
441 static void
442 vbdev_error_clear_config(void)
443 {
444 	struct spdk_vbdev_error_config *cfg;
445 
446 	while ((cfg = TAILQ_FIRST(&g_error_config))) {
447 		TAILQ_REMOVE(&g_error_config, cfg, tailq);
448 		free(cfg->base_bdev);
449 		free(cfg);
450 	}
451 }
452 
453 static struct spdk_vbdev_error_config *
454 vbdev_error_config_find_by_base_name(const char *base_bdev_name)
455 {
456 	struct spdk_vbdev_error_config *cfg;
457 
458 	TAILQ_FOREACH(cfg, &g_error_config, tailq) {
459 		if (strcmp(cfg->base_bdev, base_bdev_name) == 0) {
460 			return cfg;
461 		}
462 	}
463 
464 	return NULL;
465 }
466 
467 static int
468 vbdev_error_config_add(const char *base_bdev_name, const struct spdk_uuid *uuid)
469 {
470 	struct spdk_vbdev_error_config *cfg;
471 
472 	cfg = vbdev_error_config_find_by_base_name(base_bdev_name);
473 	if (cfg) {
474 		SPDK_ERRLOG("vbdev_error_config for bdev %s already exists\n",
475 			    base_bdev_name);
476 		return -EEXIST;
477 	}
478 
479 	cfg = calloc(1, sizeof(*cfg));
480 	if (!cfg) {
481 		SPDK_ERRLOG("calloc() failed for vbdev_error_config\n");
482 		return -ENOMEM;
483 	}
484 
485 	cfg->base_bdev = strdup(base_bdev_name);
486 	if (!cfg->base_bdev) {
487 		free(cfg);
488 		SPDK_ERRLOG("strdup() failed for base_bdev_name\n");
489 		return -ENOMEM;
490 	}
491 
492 	spdk_uuid_copy(&cfg->uuid, uuid);
493 	TAILQ_INSERT_TAIL(&g_error_config, cfg, tailq);
494 
495 	return 0;
496 }
497 
498 static int
499 vbdev_error_config_remove(const char *base_bdev_name)
500 {
501 	struct spdk_vbdev_error_config *cfg;
502 
503 	cfg = vbdev_error_config_find_by_base_name(base_bdev_name);
504 	if (!cfg) {
505 		return -ENOENT;
506 	}
507 
508 	TAILQ_REMOVE(&g_error_config, cfg, tailq);
509 	free(cfg->base_bdev);
510 	free(cfg);
511 	return 0;
512 }
513 
514 static int
515 vbdev_error_init(void)
516 {
517 	return 0;
518 }
519 
520 static void
521 vbdev_error_fini(void)
522 {
523 	vbdev_error_clear_config();
524 }
525 
526 static void
527 vbdev_error_examine(struct spdk_bdev *bdev)
528 {
529 	struct spdk_vbdev_error_config *cfg;
530 	int rc;
531 
532 	cfg = vbdev_error_config_find_by_base_name(bdev->name);
533 	if (cfg != NULL) {
534 		rc = _vbdev_error_create(bdev->name, &cfg->uuid);
535 		if (rc != 0) {
536 			SPDK_ERRLOG("could not create error vbdev for bdev %s at examine\n",
537 				    bdev->name);
538 		}
539 	}
540 
541 	spdk_bdev_module_examine_done(&error_if);
542 }
543 
544 static int
545 vbdev_error_config_json(struct spdk_json_write_ctx *w)
546 {
547 	struct spdk_vbdev_error_config *cfg;
548 
549 	TAILQ_FOREACH(cfg, &g_error_config, tailq) {
550 		spdk_json_write_object_begin(w);
551 
552 		spdk_json_write_named_string(w, "method", "bdev_error_create");
553 		spdk_json_write_named_object_begin(w, "params");
554 		spdk_json_write_named_string(w, "base_name", cfg->base_bdev);
555 		if (!spdk_uuid_is_null(&cfg->uuid)) {
556 			spdk_json_write_named_uuid(w, "uuid", &cfg->uuid);
557 		}
558 		spdk_json_write_object_end(w);
559 
560 		spdk_json_write_object_end(w);
561 	}
562 
563 	return 0;
564 }
565