]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/lib/bdev/error/vbdev_error.c
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / spdk / lib / bdev / error / vbdev_error.c
1 /*-
2 * BSD LICENSE
3 *
4 * Copyright (c) Intel Corporation.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 /*
35 * This is a module for test purpose which will simulate error cases for bdev.
36 */
37
38 #include "spdk/stdinc.h"
39 #include "spdk/rpc.h"
40 #include "spdk/conf.h"
41 #include "spdk/util.h"
42 #include "spdk/endian.h"
43 #include "spdk/nvme_spec.h"
44 #include "spdk/string.h"
45
46 #include "spdk/bdev_module.h"
47 #include "spdk_internal/log.h"
48
49 #include "vbdev_error.h"
50
51 struct spdk_vbdev_error_config {
52 char *base_bdev;
53 TAILQ_ENTRY(spdk_vbdev_error_config) tailq;
54 };
55
56 static TAILQ_HEAD(, spdk_vbdev_error_config) g_error_config
57 = TAILQ_HEAD_INITIALIZER(g_error_config);
58
59 struct vbdev_error_info {
60 bool enabled;
61 uint32_t error_type;
62 uint32_t error_num;
63 };
64
65 /* Context for each error bdev */
66 struct error_disk {
67 struct spdk_bdev_part part;
68 struct vbdev_error_info error_vector[SPDK_BDEV_IO_TYPE_RESET];
69 TAILQ_HEAD(, spdk_bdev_io) pending_ios;
70 };
71
72 struct error_channel {
73 struct spdk_bdev_part_channel part_ch;
74 };
75
76 static pthread_mutex_t g_vbdev_error_mutex = PTHREAD_MUTEX_INITIALIZER;
77 static SPDK_BDEV_PART_TAILQ g_error_disks = TAILQ_HEAD_INITIALIZER(g_error_disks);
78
79 static int vbdev_error_init(void);
80 static void vbdev_error_fini(void);
81
82 static void vbdev_error_examine(struct spdk_bdev *bdev);
83 static int vbdev_error_config_json(struct spdk_json_write_ctx *w);
84
85 static int vbdev_error_config_add(const char *base_bdev_name);
86 static int vbdev_error_config_remove(const char *base_bdev_name);
87
88 static struct spdk_bdev_module error_if = {
89 .name = "error",
90 .module_init = vbdev_error_init,
91 .module_fini = vbdev_error_fini,
92 .examine_config = vbdev_error_examine,
93 .config_json = vbdev_error_config_json,
94
95 };
96
97 SPDK_BDEV_MODULE_REGISTER(&error_if)
98
99 int
100 spdk_vbdev_inject_error(char *name, uint32_t io_type, uint32_t error_type, uint32_t error_num)
101 {
102 struct spdk_bdev *bdev;
103 struct spdk_bdev_part *part;
104 struct error_disk *error_disk = NULL;
105 uint32_t i;
106
107 pthread_mutex_lock(&g_vbdev_error_mutex);
108 bdev = spdk_bdev_get_by_name(name);
109 if (!bdev) {
110 SPDK_ERRLOG("Could not find ErrorInjection bdev %s\n", name);
111 pthread_mutex_unlock(&g_vbdev_error_mutex);
112 return -1;
113 }
114
115 TAILQ_FOREACH(part, &g_error_disks, tailq) {
116 if (bdev == spdk_bdev_part_get_bdev(part)) {
117 error_disk = (struct error_disk *)part;
118 break;
119 }
120 }
121
122 if (error_disk == NULL) {
123 SPDK_ERRLOG("Could not find ErrorInjection bdev %s\n", name);
124 pthread_mutex_unlock(&g_vbdev_error_mutex);
125 return -1;
126 }
127
128 if (0xffffffff == io_type) {
129 for (i = 0; i < SPDK_COUNTOF(error_disk->error_vector); i++) {
130 error_disk->error_vector[i].enabled = true;
131 error_disk->error_vector[i].error_type = error_type;
132 error_disk->error_vector[i].error_num = error_num;
133 }
134 } else if (0 == io_type) {
135 for (i = 0; i < SPDK_COUNTOF(error_disk->error_vector); i++) {
136 error_disk->error_vector[i].enabled = false;
137 error_disk->error_vector[i].error_num = 0;
138 }
139 } else {
140 error_disk->error_vector[io_type].enabled = true;
141 error_disk->error_vector[io_type].error_type = error_type;
142 error_disk->error_vector[io_type].error_num = error_num;
143 }
144 pthread_mutex_unlock(&g_vbdev_error_mutex);
145 return 0;
146 }
147
148 static void
149 vbdev_error_reset(struct error_disk *error_disk, struct spdk_bdev_io *bdev_io)
150 {
151 struct spdk_bdev_io *pending_io, *tmp;
152
153 TAILQ_FOREACH_SAFE(pending_io, &error_disk->pending_ios, module_link, tmp) {
154 TAILQ_REMOVE(&error_disk->pending_ios, pending_io, module_link);
155 spdk_bdev_io_complete(pending_io, SPDK_BDEV_IO_STATUS_FAILED);
156 }
157 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS);
158 }
159
160 static uint32_t
161 vbdev_error_get_error_type(struct error_disk *error_disk, uint32_t io_type)
162 {
163 if (error_disk->error_vector[io_type].enabled &&
164 error_disk->error_vector[io_type].error_num) {
165 return error_disk->error_vector[io_type].error_type;
166 }
167 return 0;
168 }
169
170 static void
171 vbdev_error_submit_request(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io)
172 {
173 struct error_channel *ch = spdk_io_channel_get_ctx(_ch);
174 struct error_disk *error_disk = bdev_io->bdev->ctxt;
175 uint32_t error_type;
176
177 switch (bdev_io->type) {
178 case SPDK_BDEV_IO_TYPE_READ:
179 case SPDK_BDEV_IO_TYPE_WRITE:
180 case SPDK_BDEV_IO_TYPE_UNMAP:
181 case SPDK_BDEV_IO_TYPE_FLUSH:
182 break;
183 case SPDK_BDEV_IO_TYPE_RESET:
184 vbdev_error_reset(error_disk, bdev_io);
185 return;
186 default:
187 SPDK_ERRLOG("Error Injection: unknown I/O type %d\n", bdev_io->type);
188 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
189 return;
190 }
191
192 error_type = vbdev_error_get_error_type(error_disk, bdev_io->type);
193 if (error_type == 0) {
194 int rc = spdk_bdev_part_submit_request(&ch->part_ch, bdev_io);
195
196 if (rc) {
197 SPDK_ERRLOG("bdev_error: submit request failed, rc=%d\n", rc);
198 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
199 }
200 return;
201 } else if (error_type == VBDEV_IO_FAILURE) {
202 error_disk->error_vector[bdev_io->type].error_num--;
203 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
204 } else if (error_type == VBDEV_IO_PENDING) {
205 TAILQ_INSERT_TAIL(&error_disk->pending_ios, bdev_io, module_link);
206 error_disk->error_vector[bdev_io->type].error_num--;
207 }
208 }
209
210 static int
211 vbdev_error_destruct(void *ctx)
212 {
213 struct error_disk *error_disk = ctx;
214 struct spdk_bdev *base_bdev = spdk_bdev_part_get_base_bdev(&error_disk->part);
215 int rc;
216
217 rc = vbdev_error_config_remove(base_bdev->name);
218 if (rc != 0) {
219 SPDK_ERRLOG("vbdev_error_config_remove() failed\n");
220 }
221
222 return spdk_bdev_part_free(&error_disk->part);
223 }
224
225 static int
226 vbdev_error_dump_info_json(void *ctx, struct spdk_json_write_ctx *w)
227 {
228 struct error_disk *error_disk = ctx;
229 struct spdk_bdev *base_bdev = spdk_bdev_part_get_base_bdev(&error_disk->part);
230
231 spdk_json_write_name(w, "error_disk");
232 spdk_json_write_object_begin(w);
233
234 spdk_json_write_name(w, "base_bdev");
235 spdk_json_write_string(w, base_bdev->name);
236
237 spdk_json_write_object_end(w);
238
239 return 0;
240 }
241
242 static void
243 vbdev_error_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w)
244 {
245 /* No config per bdev. */
246 }
247
248
249 static struct spdk_bdev_fn_table vbdev_error_fn_table = {
250 .destruct = vbdev_error_destruct,
251 .submit_request = vbdev_error_submit_request,
252 .dump_info_json = vbdev_error_dump_info_json,
253 .write_config_json = vbdev_error_write_config_json
254 };
255
256 static void
257 spdk_vbdev_error_base_bdev_hotremove_cb(void *_base_bdev)
258 {
259 spdk_bdev_part_base_hotremove(_base_bdev, &g_error_disks);
260 }
261
262 static int
263 _spdk_vbdev_error_create(struct spdk_bdev *base_bdev)
264 {
265 struct spdk_bdev_part_base *base = NULL;
266 struct error_disk *disk = NULL;
267 char *name;
268 int rc;
269
270 base = spdk_bdev_part_base_construct(base_bdev,
271 spdk_vbdev_error_base_bdev_hotremove_cb,
272 &error_if, &vbdev_error_fn_table, &g_error_disks,
273 NULL, NULL, sizeof(struct error_channel),
274 NULL, NULL);
275 if (!base) {
276 SPDK_ERRLOG("could not construct part base for bdev %s\n", spdk_bdev_get_name(base_bdev));
277 return -ENOMEM;
278 }
279
280 disk = calloc(1, sizeof(*disk));
281 if (!disk) {
282 SPDK_ERRLOG("Memory allocation failure\n");
283 spdk_bdev_part_base_free(base);
284 return -ENOMEM;
285 }
286
287 name = spdk_sprintf_alloc("EE_%s", spdk_bdev_get_name(base_bdev));
288 if (!name) {
289 SPDK_ERRLOG("name allocation failure\n");
290 spdk_bdev_part_base_free(base);
291 free(disk);
292 return -ENOMEM;
293 }
294
295 rc = spdk_bdev_part_construct(&disk->part, base, name, 0, base_bdev->blockcnt,
296 "Error Injection Disk");
297 free(name);
298 if (rc) {
299 SPDK_ERRLOG("could not construct part for bdev %s\n", spdk_bdev_get_name(base_bdev));
300 /* spdk_bdev_part_construct will free name on failure */
301 spdk_bdev_part_base_free(base);
302 free(disk);
303 return rc;
304 }
305
306 TAILQ_INIT(&disk->pending_ios);
307
308 return 0;
309 }
310
311 int
312 spdk_vbdev_error_create(const char *base_bdev_name)
313 {
314 int rc;
315 struct spdk_bdev *base_bdev;
316
317 rc = vbdev_error_config_add(base_bdev_name);
318 if (rc != 0) {
319 SPDK_ERRLOG("Adding config for ErrorInjection bdev %s failed (rc=%d)\n",
320 base_bdev_name, rc);
321 return rc;
322 }
323
324 base_bdev = spdk_bdev_get_by_name(base_bdev_name);
325 if (!base_bdev) {
326 return 0;
327 }
328
329 rc = _spdk_vbdev_error_create(base_bdev);
330 if (rc != 0) {
331 vbdev_error_config_remove(base_bdev_name);
332 SPDK_ERRLOG("Could not create ErrorInjection bdev %s (rc=%d)\n",
333 base_bdev_name, rc);
334 }
335
336 return rc;
337 }
338
339 void
340 spdk_vbdev_error_delete(struct spdk_bdev *vbdev, spdk_delete_error_complete cb_fn, void *cb_arg)
341 {
342 if (!vbdev || vbdev->module != &error_if) {
343 cb_fn(cb_arg, -ENODEV);
344 return;
345 }
346
347 spdk_bdev_unregister(vbdev, cb_fn, cb_arg);
348 }
349
350 static void
351 vbdev_error_clear_config(void)
352 {
353 struct spdk_vbdev_error_config *cfg;
354
355 while ((cfg = TAILQ_FIRST(&g_error_config))) {
356 TAILQ_REMOVE(&g_error_config, cfg, tailq);
357 free(cfg->base_bdev);
358 free(cfg);
359 }
360 }
361
362 static struct spdk_vbdev_error_config *
363 vbdev_error_config_find_by_base_name(const char *base_bdev_name)
364 {
365 struct spdk_vbdev_error_config *cfg;
366
367 TAILQ_FOREACH(cfg, &g_error_config, tailq) {
368 if (strcmp(cfg->base_bdev, base_bdev_name) == 0) {
369 return cfg;
370 }
371 }
372
373 return NULL;
374 }
375
376 static int
377 vbdev_error_config_add(const char *base_bdev_name)
378 {
379 struct spdk_vbdev_error_config *cfg;
380
381 cfg = vbdev_error_config_find_by_base_name(base_bdev_name);
382 if (cfg) {
383 SPDK_ERRLOG("vbdev_error_config for bdev %s already exists\n",
384 base_bdev_name);
385 return -EEXIST;
386 }
387
388 cfg = calloc(1, sizeof(*cfg));
389 if (!cfg) {
390 SPDK_ERRLOG("calloc() failed for vbdev_error_config\n");
391 return -ENOMEM;
392 }
393
394 cfg->base_bdev = strdup(base_bdev_name);
395 if (!cfg->base_bdev) {
396 free(cfg);
397 SPDK_ERRLOG("strdup() failed for base_bdev_name\n");
398 return -ENOMEM;
399 }
400
401 TAILQ_INSERT_TAIL(&g_error_config, cfg, tailq);
402
403 return 0;
404 }
405
406 static int
407 vbdev_error_config_remove(const char *base_bdev_name)
408 {
409 struct spdk_vbdev_error_config *cfg;
410
411 cfg = vbdev_error_config_find_by_base_name(base_bdev_name);
412 if (!cfg) {
413 return -ENOENT;
414 }
415
416 TAILQ_REMOVE(&g_error_config, cfg, tailq);
417 free(cfg->base_bdev);
418 free(cfg);
419 return 0;
420 }
421
422 static int
423 vbdev_error_init(void)
424 {
425 struct spdk_conf_section *sp;
426 struct spdk_vbdev_error_config *cfg;
427 const char *base_bdev_name;
428 int i, rc;
429
430 sp = spdk_conf_find_section(NULL, "BdevError");
431 if (sp == NULL) {
432 return 0;
433 }
434
435 for (i = 0; ; i++) {
436 if (!spdk_conf_section_get_nval(sp, "BdevError", i)) {
437 break;
438 }
439
440 base_bdev_name = spdk_conf_section_get_nmval(sp, "BdevError", i, 0);
441 if (!base_bdev_name) {
442 SPDK_ERRLOG("ErrorInjection configuration missing bdev name\n");
443 rc = -EINVAL;
444 goto error;
445 }
446
447 cfg = calloc(1, sizeof(*cfg));
448 if (!cfg) {
449 SPDK_ERRLOG("calloc() failed for vbdev_error_config\n");
450 rc = -ENOMEM;
451 goto error;
452 }
453
454 cfg->base_bdev = strdup(base_bdev_name);
455 if (!cfg->base_bdev) {
456 free(cfg);
457 SPDK_ERRLOG("strdup() failed for bdev name\n");
458 rc = -ENOMEM;
459 goto error;
460 }
461
462 TAILQ_INSERT_TAIL(&g_error_config, cfg, tailq);
463 }
464
465 return 0;
466
467 error:
468 vbdev_error_clear_config();
469 return rc;
470 }
471
472 static void
473 vbdev_error_fini(void)
474 {
475 vbdev_error_clear_config();
476 }
477
478 static void
479 vbdev_error_examine(struct spdk_bdev *bdev)
480 {
481 struct spdk_vbdev_error_config *cfg;
482 int rc;
483
484 cfg = vbdev_error_config_find_by_base_name(bdev->name);
485 if (cfg != NULL) {
486 rc = _spdk_vbdev_error_create(bdev);
487 if (rc != 0) {
488 SPDK_ERRLOG("could not create error vbdev for bdev %s at examine\n",
489 bdev->name);
490 }
491 }
492
493 spdk_bdev_module_examine_done(&error_if);
494 }
495
496 static int
497 vbdev_error_config_json(struct spdk_json_write_ctx *w)
498 {
499 struct spdk_vbdev_error_config *cfg;
500
501 TAILQ_FOREACH(cfg, &g_error_config, tailq) {
502 spdk_json_write_object_begin(w);
503
504 spdk_json_write_named_string(w, "method", "construct_error_bdev");
505 spdk_json_write_named_object_begin(w, "params");
506 spdk_json_write_named_string(w, "base_name", cfg->base_bdev);
507 spdk_json_write_object_end(w);
508
509 spdk_json_write_object_end(w);
510 }
511
512 return 0;
513 }