4 * Copyright (c) Intel Corporation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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.
35 * This is a module for test purpose which will simulate error cases for bdev.
38 #include "spdk/stdinc.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"
46 #include "spdk/bdev_module.h"
47 #include "spdk_internal/log.h"
49 #include "vbdev_error.h"
51 struct spdk_vbdev_error_config
{
53 TAILQ_ENTRY(spdk_vbdev_error_config
) tailq
;
56 static TAILQ_HEAD(, spdk_vbdev_error_config
) g_error_config
57 = TAILQ_HEAD_INITIALIZER(g_error_config
);
59 struct vbdev_error_info
{
65 /* Context for each error bdev */
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
;
72 struct error_channel
{
73 struct spdk_bdev_part_channel part_ch
;
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
);
79 static int vbdev_error_init(void);
80 static void vbdev_error_fini(void);
82 static void vbdev_error_examine(struct spdk_bdev
*bdev
);
83 static int vbdev_error_config_json(struct spdk_json_write_ctx
*w
);
85 static int vbdev_error_config_add(const char *base_bdev_name
);
86 static int vbdev_error_config_remove(const char *base_bdev_name
);
88 static struct spdk_bdev_module error_if
= {
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
,
97 SPDK_BDEV_MODULE_REGISTER(&error_if
)
100 spdk_vbdev_inject_error(char *name
, uint32_t io_type
, uint32_t error_type
, uint32_t error_num
)
102 struct spdk_bdev
*bdev
;
103 struct spdk_bdev_part
*part
;
104 struct error_disk
*error_disk
= NULL
;
107 pthread_mutex_lock(&g_vbdev_error_mutex
);
108 bdev
= spdk_bdev_get_by_name(name
);
110 SPDK_ERRLOG("Could not find ErrorInjection bdev %s\n", name
);
111 pthread_mutex_unlock(&g_vbdev_error_mutex
);
115 TAILQ_FOREACH(part
, &g_error_disks
, tailq
) {
116 if (bdev
== spdk_bdev_part_get_bdev(part
)) {
117 error_disk
= (struct error_disk
*)part
;
122 if (error_disk
== NULL
) {
123 SPDK_ERRLOG("Could not find ErrorInjection bdev %s\n", name
);
124 pthread_mutex_unlock(&g_vbdev_error_mutex
);
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
;
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;
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
;
144 pthread_mutex_unlock(&g_vbdev_error_mutex
);
149 vbdev_error_reset(struct error_disk
*error_disk
, struct spdk_bdev_io
*bdev_io
)
151 struct spdk_bdev_io
*pending_io
, *tmp
;
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
);
157 spdk_bdev_io_complete(bdev_io
, SPDK_BDEV_IO_STATUS_SUCCESS
);
161 vbdev_error_get_error_type(struct error_disk
*error_disk
, uint32_t io_type
)
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
;
171 vbdev_error_submit_request(struct spdk_io_channel
*_ch
, struct spdk_bdev_io
*bdev_io
)
173 struct error_channel
*ch
= spdk_io_channel_get_ctx(_ch
);
174 struct error_disk
*error_disk
= bdev_io
->bdev
->ctxt
;
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
:
183 case SPDK_BDEV_IO_TYPE_RESET
:
184 vbdev_error_reset(error_disk
, bdev_io
);
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
);
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
);
197 SPDK_ERRLOG("bdev_error: submit request failed, rc=%d\n", rc
);
198 spdk_bdev_io_complete(bdev_io
, SPDK_BDEV_IO_STATUS_FAILED
);
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
--;
211 vbdev_error_destruct(void *ctx
)
213 struct error_disk
*error_disk
= ctx
;
214 struct spdk_bdev
*base_bdev
= spdk_bdev_part_get_base_bdev(&error_disk
->part
);
217 rc
= vbdev_error_config_remove(base_bdev
->name
);
219 SPDK_ERRLOG("vbdev_error_config_remove() failed\n");
222 return spdk_bdev_part_free(&error_disk
->part
);
226 vbdev_error_dump_info_json(void *ctx
, struct spdk_json_write_ctx
*w
)
228 struct error_disk
*error_disk
= ctx
;
229 struct spdk_bdev
*base_bdev
= spdk_bdev_part_get_base_bdev(&error_disk
->part
);
231 spdk_json_write_name(w
, "error_disk");
232 spdk_json_write_object_begin(w
);
234 spdk_json_write_name(w
, "base_bdev");
235 spdk_json_write_string(w
, base_bdev
->name
);
237 spdk_json_write_object_end(w
);
243 vbdev_error_write_config_json(struct spdk_bdev
*bdev
, struct spdk_json_write_ctx
*w
)
245 /* No config per bdev. */
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
257 spdk_vbdev_error_base_bdev_hotremove_cb(void *_base_bdev
)
259 spdk_bdev_part_base_hotremove(_base_bdev
, &g_error_disks
);
263 _spdk_vbdev_error_create(struct spdk_bdev
*base_bdev
)
265 struct spdk_bdev_part_base
*base
= NULL
;
266 struct error_disk
*disk
= NULL
;
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
),
276 SPDK_ERRLOG("could not construct part base for bdev %s\n", spdk_bdev_get_name(base_bdev
));
280 disk
= calloc(1, sizeof(*disk
));
282 SPDK_ERRLOG("Memory allocation failure\n");
283 spdk_bdev_part_base_free(base
);
287 name
= spdk_sprintf_alloc("EE_%s", spdk_bdev_get_name(base_bdev
));
289 SPDK_ERRLOG("name allocation failure\n");
290 spdk_bdev_part_base_free(base
);
295 rc
= spdk_bdev_part_construct(&disk
->part
, base
, name
, 0, base_bdev
->blockcnt
,
296 "Error Injection Disk");
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
);
306 TAILQ_INIT(&disk
->pending_ios
);
312 spdk_vbdev_error_create(const char *base_bdev_name
)
315 struct spdk_bdev
*base_bdev
;
317 rc
= vbdev_error_config_add(base_bdev_name
);
319 SPDK_ERRLOG("Adding config for ErrorInjection bdev %s failed (rc=%d)\n",
324 base_bdev
= spdk_bdev_get_by_name(base_bdev_name
);
329 rc
= _spdk_vbdev_error_create(base_bdev
);
331 vbdev_error_config_remove(base_bdev_name
);
332 SPDK_ERRLOG("Could not create ErrorInjection bdev %s (rc=%d)\n",
340 spdk_vbdev_error_delete(struct spdk_bdev
*vbdev
, spdk_delete_error_complete cb_fn
, void *cb_arg
)
342 if (!vbdev
|| vbdev
->module
!= &error_if
) {
343 cb_fn(cb_arg
, -ENODEV
);
347 spdk_bdev_unregister(vbdev
, cb_fn
, cb_arg
);
351 vbdev_error_clear_config(void)
353 struct spdk_vbdev_error_config
*cfg
;
355 while ((cfg
= TAILQ_FIRST(&g_error_config
))) {
356 TAILQ_REMOVE(&g_error_config
, cfg
, tailq
);
357 free(cfg
->base_bdev
);
362 static struct spdk_vbdev_error_config
*
363 vbdev_error_config_find_by_base_name(const char *base_bdev_name
)
365 struct spdk_vbdev_error_config
*cfg
;
367 TAILQ_FOREACH(cfg
, &g_error_config
, tailq
) {
368 if (strcmp(cfg
->base_bdev
, base_bdev_name
) == 0) {
377 vbdev_error_config_add(const char *base_bdev_name
)
379 struct spdk_vbdev_error_config
*cfg
;
381 cfg
= vbdev_error_config_find_by_base_name(base_bdev_name
);
383 SPDK_ERRLOG("vbdev_error_config for bdev %s already exists\n",
388 cfg
= calloc(1, sizeof(*cfg
));
390 SPDK_ERRLOG("calloc() failed for vbdev_error_config\n");
394 cfg
->base_bdev
= strdup(base_bdev_name
);
395 if (!cfg
->base_bdev
) {
397 SPDK_ERRLOG("strdup() failed for base_bdev_name\n");
401 TAILQ_INSERT_TAIL(&g_error_config
, cfg
, tailq
);
407 vbdev_error_config_remove(const char *base_bdev_name
)
409 struct spdk_vbdev_error_config
*cfg
;
411 cfg
= vbdev_error_config_find_by_base_name(base_bdev_name
);
416 TAILQ_REMOVE(&g_error_config
, cfg
, tailq
);
417 free(cfg
->base_bdev
);
423 vbdev_error_init(void)
425 struct spdk_conf_section
*sp
;
426 struct spdk_vbdev_error_config
*cfg
;
427 const char *base_bdev_name
;
430 sp
= spdk_conf_find_section(NULL
, "BdevError");
436 if (!spdk_conf_section_get_nval(sp
, "BdevError", i
)) {
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");
447 cfg
= calloc(1, sizeof(*cfg
));
449 SPDK_ERRLOG("calloc() failed for vbdev_error_config\n");
454 cfg
->base_bdev
= strdup(base_bdev_name
);
455 if (!cfg
->base_bdev
) {
457 SPDK_ERRLOG("strdup() failed for bdev name\n");
462 TAILQ_INSERT_TAIL(&g_error_config
, cfg
, tailq
);
468 vbdev_error_clear_config();
473 vbdev_error_fini(void)
475 vbdev_error_clear_config();
479 vbdev_error_examine(struct spdk_bdev
*bdev
)
481 struct spdk_vbdev_error_config
*cfg
;
484 cfg
= vbdev_error_config_find_by_base_name(bdev
->name
);
486 rc
= _spdk_vbdev_error_create(bdev
);
488 SPDK_ERRLOG("could not create error vbdev for bdev %s at examine\n",
493 spdk_bdev_module_examine_done(&error_if
);
497 vbdev_error_config_json(struct spdk_json_write_ctx
*w
)
499 struct spdk_vbdev_error_config
*cfg
;
501 TAILQ_FOREACH(cfg
, &g_error_config
, tailq
) {
502 spdk_json_write_object_begin(w
);
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
);
509 spdk_json_write_object_end(w
);