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
{
64 /* Context for each error bdev */
66 struct spdk_bdev_part part
;
67 struct vbdev_error_info error_vector
[SPDK_BDEV_IO_TYPE_RESET
];
68 TAILQ_HEAD(, spdk_bdev_io
) pending_ios
;
71 struct error_channel
{
72 struct spdk_bdev_part_channel part_ch
;
75 static pthread_mutex_t g_vbdev_error_mutex
= PTHREAD_MUTEX_INITIALIZER
;
76 static SPDK_BDEV_PART_TAILQ g_error_disks
= TAILQ_HEAD_INITIALIZER(g_error_disks
);
78 static int vbdev_error_init(void);
79 static void vbdev_error_fini(void);
81 static void vbdev_error_examine(struct spdk_bdev
*bdev
);
82 static int vbdev_error_config_json(struct spdk_json_write_ctx
*w
);
84 static int vbdev_error_config_add(const char *base_bdev_name
);
85 static int vbdev_error_config_remove(const char *base_bdev_name
);
87 static struct spdk_bdev_module error_if
= {
89 .module_init
= vbdev_error_init
,
90 .module_fini
= vbdev_error_fini
,
91 .examine_config
= vbdev_error_examine
,
92 .config_json
= vbdev_error_config_json
,
96 SPDK_BDEV_MODULE_REGISTER(error
, &error_if
)
99 vbdev_error_inject_error(char *name
, uint32_t io_type
, uint32_t error_type
, uint32_t error_num
)
101 struct spdk_bdev
*bdev
;
102 struct spdk_bdev_part
*part
;
103 struct error_disk
*error_disk
= NULL
;
106 pthread_mutex_lock(&g_vbdev_error_mutex
);
107 bdev
= spdk_bdev_get_by_name(name
);
109 SPDK_ERRLOG("Could not find ErrorInjection bdev %s\n", name
);
110 pthread_mutex_unlock(&g_vbdev_error_mutex
);
114 TAILQ_FOREACH(part
, &g_error_disks
, tailq
) {
115 if (bdev
== spdk_bdev_part_get_bdev(part
)) {
116 error_disk
= (struct error_disk
*)part
;
121 if (error_disk
== NULL
) {
122 SPDK_ERRLOG("Could not find ErrorInjection bdev %s\n", name
);
123 pthread_mutex_unlock(&g_vbdev_error_mutex
);
127 if (0xffffffff == io_type
) {
128 for (i
= 0; i
< SPDK_COUNTOF(error_disk
->error_vector
); i
++) {
129 error_disk
->error_vector
[i
].error_type
= error_type
;
130 error_disk
->error_vector
[i
].error_num
= error_num
;
132 } else if (0 == io_type
) {
133 for (i
= 0; i
< SPDK_COUNTOF(error_disk
->error_vector
); i
++) {
134 error_disk
->error_vector
[i
].error_num
= 0;
137 error_disk
->error_vector
[io_type
].error_type
= error_type
;
138 error_disk
->error_vector
[io_type
].error_num
= error_num
;
140 pthread_mutex_unlock(&g_vbdev_error_mutex
);
145 vbdev_error_reset(struct error_disk
*error_disk
, struct spdk_bdev_io
*bdev_io
)
147 struct spdk_bdev_io
*pending_io
, *tmp
;
149 TAILQ_FOREACH_SAFE(pending_io
, &error_disk
->pending_ios
, module_link
, tmp
) {
150 TAILQ_REMOVE(&error_disk
->pending_ios
, pending_io
, module_link
);
151 spdk_bdev_io_complete(pending_io
, SPDK_BDEV_IO_STATUS_FAILED
);
153 spdk_bdev_io_complete(bdev_io
, SPDK_BDEV_IO_STATUS_SUCCESS
);
157 vbdev_error_get_error_type(struct error_disk
*error_disk
, uint32_t io_type
)
159 if (error_disk
->error_vector
[io_type
].error_num
) {
160 return error_disk
->error_vector
[io_type
].error_type
;
166 vbdev_error_submit_request(struct spdk_io_channel
*_ch
, struct spdk_bdev_io
*bdev_io
)
168 struct error_channel
*ch
= spdk_io_channel_get_ctx(_ch
);
169 struct error_disk
*error_disk
= bdev_io
->bdev
->ctxt
;
172 switch (bdev_io
->type
) {
173 case SPDK_BDEV_IO_TYPE_READ
:
174 case SPDK_BDEV_IO_TYPE_WRITE
:
175 case SPDK_BDEV_IO_TYPE_UNMAP
:
176 case SPDK_BDEV_IO_TYPE_FLUSH
:
178 case SPDK_BDEV_IO_TYPE_RESET
:
179 vbdev_error_reset(error_disk
, bdev_io
);
182 SPDK_ERRLOG("Error Injection: unknown I/O type %d\n", bdev_io
->type
);
183 spdk_bdev_io_complete(bdev_io
, SPDK_BDEV_IO_STATUS_FAILED
);
187 error_type
= vbdev_error_get_error_type(error_disk
, bdev_io
->type
);
188 if (error_type
== 0) {
189 int rc
= spdk_bdev_part_submit_request(&ch
->part_ch
, bdev_io
);
192 SPDK_ERRLOG("bdev_error: submit request failed, rc=%d\n", rc
);
193 spdk_bdev_io_complete(bdev_io
, SPDK_BDEV_IO_STATUS_FAILED
);
196 } else if (error_type
== VBDEV_IO_FAILURE
) {
197 error_disk
->error_vector
[bdev_io
->type
].error_num
--;
198 spdk_bdev_io_complete(bdev_io
, SPDK_BDEV_IO_STATUS_FAILED
);
199 } else if (error_type
== VBDEV_IO_PENDING
) {
200 TAILQ_INSERT_TAIL(&error_disk
->pending_ios
, bdev_io
, module_link
);
201 error_disk
->error_vector
[bdev_io
->type
].error_num
--;
206 vbdev_error_destruct(void *ctx
)
208 struct error_disk
*error_disk
= ctx
;
209 struct spdk_bdev
*base_bdev
= spdk_bdev_part_get_base_bdev(&error_disk
->part
);
212 rc
= vbdev_error_config_remove(base_bdev
->name
);
214 SPDK_ERRLOG("vbdev_error_config_remove() failed\n");
217 return spdk_bdev_part_free(&error_disk
->part
);
221 vbdev_error_dump_info_json(void *ctx
, struct spdk_json_write_ctx
*w
)
223 struct error_disk
*error_disk
= ctx
;
224 struct spdk_bdev
*base_bdev
= spdk_bdev_part_get_base_bdev(&error_disk
->part
);
226 spdk_json_write_named_object_begin(w
, "error_disk");
228 spdk_json_write_named_string(w
, "base_bdev", base_bdev
->name
);
230 spdk_json_write_object_end(w
);
236 vbdev_error_write_config_json(struct spdk_bdev
*bdev
, struct spdk_json_write_ctx
*w
)
238 /* No config per bdev. */
242 static struct spdk_bdev_fn_table vbdev_error_fn_table
= {
243 .destruct
= vbdev_error_destruct
,
244 .submit_request
= vbdev_error_submit_request
,
245 .dump_info_json
= vbdev_error_dump_info_json
,
246 .write_config_json
= vbdev_error_write_config_json
250 vbdev_error_base_bdev_hotremove_cb(void *_part_base
)
252 struct spdk_bdev_part_base
*part_base
= _part_base
;
254 spdk_bdev_part_base_hotremove(part_base
, &g_error_disks
);
258 _vbdev_error_create(struct spdk_bdev
*base_bdev
)
260 struct spdk_bdev_part_base
*base
= NULL
;
261 struct error_disk
*disk
= NULL
;
265 base
= spdk_bdev_part_base_construct(base_bdev
,
266 vbdev_error_base_bdev_hotremove_cb
,
267 &error_if
, &vbdev_error_fn_table
, &g_error_disks
,
268 NULL
, NULL
, sizeof(struct error_channel
),
271 SPDK_ERRLOG("could not construct part base for bdev %s\n", spdk_bdev_get_name(base_bdev
));
275 disk
= calloc(1, sizeof(*disk
));
277 SPDK_ERRLOG("Memory allocation failure\n");
278 spdk_bdev_part_base_free(base
);
282 name
= spdk_sprintf_alloc("EE_%s", spdk_bdev_get_name(base_bdev
));
284 SPDK_ERRLOG("name allocation failure\n");
285 spdk_bdev_part_base_free(base
);
290 rc
= spdk_bdev_part_construct(&disk
->part
, base
, name
, 0, base_bdev
->blockcnt
,
291 "Error Injection Disk");
294 SPDK_ERRLOG("could not construct part for bdev %s\n", spdk_bdev_get_name(base_bdev
));
295 /* spdk_bdev_part_construct will free name on failure */
296 spdk_bdev_part_base_free(base
);
301 TAILQ_INIT(&disk
->pending_ios
);
307 vbdev_error_create(const char *base_bdev_name
)
310 struct spdk_bdev
*base_bdev
;
312 rc
= vbdev_error_config_add(base_bdev_name
);
314 SPDK_ERRLOG("Adding config for ErrorInjection bdev %s failed (rc=%d)\n",
319 base_bdev
= spdk_bdev_get_by_name(base_bdev_name
);
324 rc
= _vbdev_error_create(base_bdev
);
326 vbdev_error_config_remove(base_bdev_name
);
327 SPDK_ERRLOG("Could not create ErrorInjection bdev %s (rc=%d)\n",
335 vbdev_error_delete(struct spdk_bdev
*vbdev
, spdk_delete_error_complete cb_fn
, void *cb_arg
)
337 if (!vbdev
|| vbdev
->module
!= &error_if
) {
338 cb_fn(cb_arg
, -ENODEV
);
342 spdk_bdev_unregister(vbdev
, cb_fn
, cb_arg
);
346 vbdev_error_clear_config(void)
348 struct spdk_vbdev_error_config
*cfg
;
350 while ((cfg
= TAILQ_FIRST(&g_error_config
))) {
351 TAILQ_REMOVE(&g_error_config
, cfg
, tailq
);
352 free(cfg
->base_bdev
);
357 static struct spdk_vbdev_error_config
*
358 vbdev_error_config_find_by_base_name(const char *base_bdev_name
)
360 struct spdk_vbdev_error_config
*cfg
;
362 TAILQ_FOREACH(cfg
, &g_error_config
, tailq
) {
363 if (strcmp(cfg
->base_bdev
, base_bdev_name
) == 0) {
372 vbdev_error_config_add(const char *base_bdev_name
)
374 struct spdk_vbdev_error_config
*cfg
;
376 cfg
= vbdev_error_config_find_by_base_name(base_bdev_name
);
378 SPDK_ERRLOG("vbdev_error_config for bdev %s already exists\n",
383 cfg
= calloc(1, sizeof(*cfg
));
385 SPDK_ERRLOG("calloc() failed for vbdev_error_config\n");
389 cfg
->base_bdev
= strdup(base_bdev_name
);
390 if (!cfg
->base_bdev
) {
392 SPDK_ERRLOG("strdup() failed for base_bdev_name\n");
396 TAILQ_INSERT_TAIL(&g_error_config
, cfg
, tailq
);
402 vbdev_error_config_remove(const char *base_bdev_name
)
404 struct spdk_vbdev_error_config
*cfg
;
406 cfg
= vbdev_error_config_find_by_base_name(base_bdev_name
);
411 TAILQ_REMOVE(&g_error_config
, cfg
, tailq
);
412 free(cfg
->base_bdev
);
418 vbdev_error_init(void)
420 struct spdk_conf_section
*sp
;
421 struct spdk_vbdev_error_config
*cfg
;
422 const char *base_bdev_name
;
425 sp
= spdk_conf_find_section(NULL
, "BdevError");
431 if (!spdk_conf_section_get_nval(sp
, "BdevError", i
)) {
435 base_bdev_name
= spdk_conf_section_get_nmval(sp
, "BdevError", i
, 0);
436 if (!base_bdev_name
) {
437 SPDK_ERRLOG("ErrorInjection configuration missing bdev name\n");
442 cfg
= calloc(1, sizeof(*cfg
));
444 SPDK_ERRLOG("calloc() failed for vbdev_error_config\n");
449 cfg
->base_bdev
= strdup(base_bdev_name
);
450 if (!cfg
->base_bdev
) {
452 SPDK_ERRLOG("strdup() failed for bdev name\n");
457 TAILQ_INSERT_TAIL(&g_error_config
, cfg
, tailq
);
463 vbdev_error_clear_config();
468 vbdev_error_fini(void)
470 vbdev_error_clear_config();
474 vbdev_error_examine(struct spdk_bdev
*bdev
)
476 struct spdk_vbdev_error_config
*cfg
;
479 cfg
= vbdev_error_config_find_by_base_name(bdev
->name
);
481 rc
= _vbdev_error_create(bdev
);
483 SPDK_ERRLOG("could not create error vbdev for bdev %s at examine\n",
488 spdk_bdev_module_examine_done(&error_if
);
492 vbdev_error_config_json(struct spdk_json_write_ctx
*w
)
494 struct spdk_vbdev_error_config
*cfg
;
496 TAILQ_FOREACH(cfg
, &g_error_config
, tailq
) {
497 spdk_json_write_object_begin(w
);
499 spdk_json_write_named_string(w
, "method", "bdev_error_create");
500 spdk_json_write_named_object_begin(w
, "params");
501 spdk_json_write_named_string(w
, "base_name", cfg
->base_bdev
);
502 spdk_json_write_object_end(w
);
504 spdk_json_write_object_end(w
);