root / block / blkdebug.c @ fab5cf59
History | View | Annotate | Download (12.8 kB)
1 | 6a143727 | Kevin Wolf | /*
|
---|---|---|---|
2 | 6a143727 | Kevin Wolf | * Block protocol for I/O error injection
|
3 | 6a143727 | Kevin Wolf | *
|
4 | 6a143727 | Kevin Wolf | * Copyright (c) 2010 Kevin Wolf <kwolf@redhat.com>
|
5 | 6a143727 | Kevin Wolf | *
|
6 | 6a143727 | Kevin Wolf | * Permission is hereby granted, free of charge, to any person obtaining a copy
|
7 | 6a143727 | Kevin Wolf | * of this software and associated documentation files (the "Software"), to deal
|
8 | 6a143727 | Kevin Wolf | * in the Software without restriction, including without limitation the rights
|
9 | 6a143727 | Kevin Wolf | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10 | 6a143727 | Kevin Wolf | * copies of the Software, and to permit persons to whom the Software is
|
11 | 6a143727 | Kevin Wolf | * furnished to do so, subject to the following conditions:
|
12 | 6a143727 | Kevin Wolf | *
|
13 | 6a143727 | Kevin Wolf | * The above copyright notice and this permission notice shall be included in
|
14 | 6a143727 | Kevin Wolf | * all copies or substantial portions of the Software.
|
15 | 6a143727 | Kevin Wolf | *
|
16 | 6a143727 | Kevin Wolf | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17 | 6a143727 | Kevin Wolf | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18 | 6a143727 | Kevin Wolf | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
19 | 6a143727 | Kevin Wolf | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20 | 6a143727 | Kevin Wolf | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21 | 6a143727 | Kevin Wolf | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22 | 6a143727 | Kevin Wolf | * THE SOFTWARE.
|
23 | 6a143727 | Kevin Wolf | */
|
24 | 6a143727 | Kevin Wolf | |
25 | 6a143727 | Kevin Wolf | #include "qemu-common.h" |
26 | 6a143727 | Kevin Wolf | #include "block_int.h" |
27 | 6a143727 | Kevin Wolf | #include "module.h" |
28 | 6a143727 | Kevin Wolf | |
29 | b9f66d96 | Kevin Wolf | typedef struct BlkdebugVars { |
30 | b9f66d96 | Kevin Wolf | int state;
|
31 | b9f66d96 | Kevin Wolf | |
32 | b9f66d96 | Kevin Wolf | /* If inject_errno != 0, an error is injected for requests */
|
33 | b9f66d96 | Kevin Wolf | int inject_errno;
|
34 | b9f66d96 | Kevin Wolf | |
35 | b9f66d96 | Kevin Wolf | /* Decides if all future requests fail (false) or only the next one and
|
36 | b9f66d96 | Kevin Wolf | * after the next request inject_errno is reset to 0 (true) */
|
37 | b9f66d96 | Kevin Wolf | bool inject_once;
|
38 | b9f66d96 | Kevin Wolf | |
39 | b9f66d96 | Kevin Wolf | /* Decides if aio_readv/writev fails right away (true) or returns an error
|
40 | b9f66d96 | Kevin Wolf | * return value only in the callback (false) */
|
41 | b9f66d96 | Kevin Wolf | bool inject_immediately;
|
42 | b9f66d96 | Kevin Wolf | } BlkdebugVars; |
43 | b9f66d96 | Kevin Wolf | |
44 | 6a143727 | Kevin Wolf | typedef struct BDRVBlkdebugState { |
45 | b9f66d96 | Kevin Wolf | BlkdebugVars vars; |
46 | 8b9b0cc2 | Kevin Wolf | QLIST_HEAD(list, BlkdebugRule) rules[BLKDBG_EVENT_MAX]; |
47 | 6a143727 | Kevin Wolf | } BDRVBlkdebugState; |
48 | 6a143727 | Kevin Wolf | |
49 | b9f66d96 | Kevin Wolf | typedef struct BlkdebugAIOCB { |
50 | b9f66d96 | Kevin Wolf | BlockDriverAIOCB common; |
51 | b9f66d96 | Kevin Wolf | QEMUBH *bh; |
52 | b9f66d96 | Kevin Wolf | int ret;
|
53 | b9f66d96 | Kevin Wolf | } BlkdebugAIOCB; |
54 | b9f66d96 | Kevin Wolf | |
55 | b9f66d96 | Kevin Wolf | static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb); |
56 | b9f66d96 | Kevin Wolf | |
57 | b9f66d96 | Kevin Wolf | static AIOPool blkdebug_aio_pool = {
|
58 | b9f66d96 | Kevin Wolf | .aiocb_size = sizeof(BlkdebugAIOCB),
|
59 | b9f66d96 | Kevin Wolf | .cancel = blkdebug_aio_cancel, |
60 | b9f66d96 | Kevin Wolf | }; |
61 | b9f66d96 | Kevin Wolf | |
62 | 8b9b0cc2 | Kevin Wolf | enum {
|
63 | 8b9b0cc2 | Kevin Wolf | ACTION_INJECT_ERROR, |
64 | 8b9b0cc2 | Kevin Wolf | ACTION_SET_STATE, |
65 | 8b9b0cc2 | Kevin Wolf | }; |
66 | 8b9b0cc2 | Kevin Wolf | |
67 | 8b9b0cc2 | Kevin Wolf | typedef struct BlkdebugRule { |
68 | 8b9b0cc2 | Kevin Wolf | BlkDebugEvent event; |
69 | 8b9b0cc2 | Kevin Wolf | int action;
|
70 | 8b9b0cc2 | Kevin Wolf | int state;
|
71 | 8b9b0cc2 | Kevin Wolf | union {
|
72 | 8b9b0cc2 | Kevin Wolf | struct {
|
73 | 8b9b0cc2 | Kevin Wolf | int error;
|
74 | 8b9b0cc2 | Kevin Wolf | int immediately;
|
75 | 8b9b0cc2 | Kevin Wolf | int once;
|
76 | 8b9b0cc2 | Kevin Wolf | } inject; |
77 | 8b9b0cc2 | Kevin Wolf | struct {
|
78 | 8b9b0cc2 | Kevin Wolf | int new_state;
|
79 | 8b9b0cc2 | Kevin Wolf | } set_state; |
80 | 8b9b0cc2 | Kevin Wolf | } options; |
81 | 8b9b0cc2 | Kevin Wolf | QLIST_ENTRY(BlkdebugRule) next; |
82 | 8b9b0cc2 | Kevin Wolf | } BlkdebugRule; |
83 | 8b9b0cc2 | Kevin Wolf | |
84 | 8b9b0cc2 | Kevin Wolf | static QemuOptsList inject_error_opts = {
|
85 | 8b9b0cc2 | Kevin Wolf | .name = "inject-error",
|
86 | 8b9b0cc2 | Kevin Wolf | .head = QTAILQ_HEAD_INITIALIZER(inject_error_opts.head), |
87 | 8b9b0cc2 | Kevin Wolf | .desc = { |
88 | 8b9b0cc2 | Kevin Wolf | { |
89 | 8b9b0cc2 | Kevin Wolf | .name = "event",
|
90 | 8b9b0cc2 | Kevin Wolf | .type = QEMU_OPT_STRING, |
91 | 8b9b0cc2 | Kevin Wolf | }, |
92 | 8b9b0cc2 | Kevin Wolf | { |
93 | 8b9b0cc2 | Kevin Wolf | .name = "state",
|
94 | 8b9b0cc2 | Kevin Wolf | .type = QEMU_OPT_NUMBER, |
95 | 8b9b0cc2 | Kevin Wolf | }, |
96 | 8b9b0cc2 | Kevin Wolf | { |
97 | 8b9b0cc2 | Kevin Wolf | .name = "errno",
|
98 | 8b9b0cc2 | Kevin Wolf | .type = QEMU_OPT_NUMBER, |
99 | 8b9b0cc2 | Kevin Wolf | }, |
100 | 8b9b0cc2 | Kevin Wolf | { |
101 | 8b9b0cc2 | Kevin Wolf | .name = "once",
|
102 | 8b9b0cc2 | Kevin Wolf | .type = QEMU_OPT_BOOL, |
103 | 8b9b0cc2 | Kevin Wolf | }, |
104 | 8b9b0cc2 | Kevin Wolf | { |
105 | 8b9b0cc2 | Kevin Wolf | .name = "immediately",
|
106 | 8b9b0cc2 | Kevin Wolf | .type = QEMU_OPT_BOOL, |
107 | 8b9b0cc2 | Kevin Wolf | }, |
108 | 8b9b0cc2 | Kevin Wolf | { /* end of list */ }
|
109 | 8b9b0cc2 | Kevin Wolf | }, |
110 | 8b9b0cc2 | Kevin Wolf | }; |
111 | 8b9b0cc2 | Kevin Wolf | |
112 | 8b9b0cc2 | Kevin Wolf | static QemuOptsList set_state_opts = {
|
113 | 8b9b0cc2 | Kevin Wolf | .name = "set-state",
|
114 | 327cdad4 | Kevin Wolf | .head = QTAILQ_HEAD_INITIALIZER(set_state_opts.head), |
115 | 8b9b0cc2 | Kevin Wolf | .desc = { |
116 | 8b9b0cc2 | Kevin Wolf | { |
117 | 8b9b0cc2 | Kevin Wolf | .name = "event",
|
118 | 8b9b0cc2 | Kevin Wolf | .type = QEMU_OPT_STRING, |
119 | 8b9b0cc2 | Kevin Wolf | }, |
120 | 8b9b0cc2 | Kevin Wolf | { |
121 | 8b9b0cc2 | Kevin Wolf | .name = "state",
|
122 | 8b9b0cc2 | Kevin Wolf | .type = QEMU_OPT_NUMBER, |
123 | 8b9b0cc2 | Kevin Wolf | }, |
124 | 8b9b0cc2 | Kevin Wolf | { |
125 | 8b9b0cc2 | Kevin Wolf | .name = "new_state",
|
126 | 8b9b0cc2 | Kevin Wolf | .type = QEMU_OPT_NUMBER, |
127 | 8b9b0cc2 | Kevin Wolf | }, |
128 | 8b9b0cc2 | Kevin Wolf | { /* end of list */ }
|
129 | 8b9b0cc2 | Kevin Wolf | }, |
130 | 8b9b0cc2 | Kevin Wolf | }; |
131 | 8b9b0cc2 | Kevin Wolf | |
132 | 8b9b0cc2 | Kevin Wolf | static QemuOptsList *config_groups[] = {
|
133 | 8b9b0cc2 | Kevin Wolf | &inject_error_opts, |
134 | 8b9b0cc2 | Kevin Wolf | &set_state_opts, |
135 | 8b9b0cc2 | Kevin Wolf | NULL
|
136 | 8b9b0cc2 | Kevin Wolf | }; |
137 | 8b9b0cc2 | Kevin Wolf | |
138 | 8b9b0cc2 | Kevin Wolf | static const char *event_names[BLKDBG_EVENT_MAX] = { |
139 | 8252278a | Kevin Wolf | [BLKDBG_L1_UPDATE] = "l1_update",
|
140 | 8252278a | Kevin Wolf | [BLKDBG_L1_GROW_ALLOC_TABLE] = "l1_grow.alloc_table",
|
141 | 8252278a | Kevin Wolf | [BLKDBG_L1_GROW_WRITE_TABLE] = "l1_grow.write_table",
|
142 | 8252278a | Kevin Wolf | [BLKDBG_L1_GROW_ACTIVATE_TABLE] = "l1_grow.activate_table",
|
143 | 8252278a | Kevin Wolf | |
144 | 8252278a | Kevin Wolf | [BLKDBG_L2_LOAD] = "l2_load",
|
145 | 8252278a | Kevin Wolf | [BLKDBG_L2_UPDATE] = "l2_update",
|
146 | 8252278a | Kevin Wolf | [BLKDBG_L2_UPDATE_COMPRESSED] = "l2_update_compressed",
|
147 | 8252278a | Kevin Wolf | [BLKDBG_L2_ALLOC_COW_READ] = "l2_alloc.cow_read",
|
148 | 8252278a | Kevin Wolf | [BLKDBG_L2_ALLOC_WRITE] = "l2_alloc.write",
|
149 | 8252278a | Kevin Wolf | |
150 | 8252278a | Kevin Wolf | [BLKDBG_READ] = "read",
|
151 | 8252278a | Kevin Wolf | [BLKDBG_READ_AIO] = "read_aio",
|
152 | 8252278a | Kevin Wolf | [BLKDBG_READ_BACKING] = "read_backing",
|
153 | 8252278a | Kevin Wolf | [BLKDBG_READ_BACKING_AIO] = "read_backing_aio",
|
154 | 8252278a | Kevin Wolf | [BLKDBG_READ_COMPRESSED] = "read_compressed",
|
155 | 8252278a | Kevin Wolf | |
156 | 8252278a | Kevin Wolf | [BLKDBG_WRITE_AIO] = "write_aio",
|
157 | 8252278a | Kevin Wolf | [BLKDBG_WRITE_COMPRESSED] = "write_compressed",
|
158 | 8252278a | Kevin Wolf | |
159 | 8252278a | Kevin Wolf | [BLKDBG_VMSTATE_LOAD] = "vmstate_load",
|
160 | 8252278a | Kevin Wolf | [BLKDBG_VMSTATE_SAVE] = "vmstate_save",
|
161 | 8252278a | Kevin Wolf | |
162 | 8252278a | Kevin Wolf | [BLKDBG_COW_READ] = "cow_read",
|
163 | 8252278a | Kevin Wolf | [BLKDBG_COW_WRITE] = "cow_write",
|
164 | 8252278a | Kevin Wolf | |
165 | 8252278a | Kevin Wolf | [BLKDBG_REFTABLE_LOAD] = "reftable_load",
|
166 | 8252278a | Kevin Wolf | [BLKDBG_REFTABLE_GROW] = "reftable_grow",
|
167 | 8252278a | Kevin Wolf | |
168 | 8252278a | Kevin Wolf | [BLKDBG_REFBLOCK_LOAD] = "refblock_load",
|
169 | 8252278a | Kevin Wolf | [BLKDBG_REFBLOCK_UPDATE] = "refblock_update",
|
170 | 8252278a | Kevin Wolf | [BLKDBG_REFBLOCK_UPDATE_PART] = "refblock_update_part",
|
171 | 8252278a | Kevin Wolf | [BLKDBG_REFBLOCK_ALLOC] = "refblock_alloc",
|
172 | 8252278a | Kevin Wolf | [BLKDBG_REFBLOCK_ALLOC_HOOKUP] = "refblock_alloc.hookup",
|
173 | 8252278a | Kevin Wolf | [BLKDBG_REFBLOCK_ALLOC_WRITE] = "refblock_alloc.write",
|
174 | 8252278a | Kevin Wolf | [BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS] = "refblock_alloc.write_blocks",
|
175 | 8252278a | Kevin Wolf | [BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE] = "refblock_alloc.write_table",
|
176 | 8252278a | Kevin Wolf | [BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE] = "refblock_alloc.switch_table",
|
177 | 8252278a | Kevin Wolf | |
178 | 8252278a | Kevin Wolf | [BLKDBG_CLUSTER_ALLOC] = "cluster_alloc",
|
179 | 8252278a | Kevin Wolf | [BLKDBG_CLUSTER_ALLOC_BYTES] = "cluster_alloc_bytes",
|
180 | 8252278a | Kevin Wolf | [BLKDBG_CLUSTER_FREE] = "cluster_free",
|
181 | 8b9b0cc2 | Kevin Wolf | }; |
182 | 8b9b0cc2 | Kevin Wolf | |
183 | 8b9b0cc2 | Kevin Wolf | static int get_event_by_name(const char *name, BlkDebugEvent *event) |
184 | 8b9b0cc2 | Kevin Wolf | { |
185 | 8b9b0cc2 | Kevin Wolf | int i;
|
186 | 8b9b0cc2 | Kevin Wolf | |
187 | 8b9b0cc2 | Kevin Wolf | for (i = 0; i < BLKDBG_EVENT_MAX; i++) { |
188 | 8b9b0cc2 | Kevin Wolf | if (!strcmp(event_names[i], name)) {
|
189 | 8b9b0cc2 | Kevin Wolf | *event = i; |
190 | 8b9b0cc2 | Kevin Wolf | return 0; |
191 | 8b9b0cc2 | Kevin Wolf | } |
192 | 8b9b0cc2 | Kevin Wolf | } |
193 | 8b9b0cc2 | Kevin Wolf | |
194 | 8b9b0cc2 | Kevin Wolf | return -1; |
195 | 8b9b0cc2 | Kevin Wolf | } |
196 | 8b9b0cc2 | Kevin Wolf | |
197 | 8b9b0cc2 | Kevin Wolf | struct add_rule_data {
|
198 | 8b9b0cc2 | Kevin Wolf | BDRVBlkdebugState *s; |
199 | 8b9b0cc2 | Kevin Wolf | int action;
|
200 | 8b9b0cc2 | Kevin Wolf | }; |
201 | 8b9b0cc2 | Kevin Wolf | |
202 | 8b9b0cc2 | Kevin Wolf | static int add_rule(QemuOpts *opts, void *opaque) |
203 | 8b9b0cc2 | Kevin Wolf | { |
204 | 8b9b0cc2 | Kevin Wolf | struct add_rule_data *d = opaque;
|
205 | 8b9b0cc2 | Kevin Wolf | BDRVBlkdebugState *s = d->s; |
206 | 8b9b0cc2 | Kevin Wolf | const char* event_name; |
207 | 8b9b0cc2 | Kevin Wolf | BlkDebugEvent event; |
208 | 8b9b0cc2 | Kevin Wolf | struct BlkdebugRule *rule;
|
209 | 8b9b0cc2 | Kevin Wolf | |
210 | 8b9b0cc2 | Kevin Wolf | /* Find the right event for the rule */
|
211 | 8b9b0cc2 | Kevin Wolf | event_name = qemu_opt_get(opts, "event");
|
212 | 8b9b0cc2 | Kevin Wolf | if (!event_name || get_event_by_name(event_name, &event) < 0) { |
213 | 8b9b0cc2 | Kevin Wolf | return -1; |
214 | 8b9b0cc2 | Kevin Wolf | } |
215 | 8b9b0cc2 | Kevin Wolf | |
216 | 8b9b0cc2 | Kevin Wolf | /* Set attributes common for all actions */
|
217 | 8b9b0cc2 | Kevin Wolf | rule = qemu_mallocz(sizeof(*rule));
|
218 | 8b9b0cc2 | Kevin Wolf | *rule = (struct BlkdebugRule) {
|
219 | 8b9b0cc2 | Kevin Wolf | .event = event, |
220 | 8b9b0cc2 | Kevin Wolf | .action = d->action, |
221 | 8b9b0cc2 | Kevin Wolf | .state = qemu_opt_get_number(opts, "state", 0), |
222 | 8b9b0cc2 | Kevin Wolf | }; |
223 | 8b9b0cc2 | Kevin Wolf | |
224 | 8b9b0cc2 | Kevin Wolf | /* Parse action-specific options */
|
225 | 8b9b0cc2 | Kevin Wolf | switch (d->action) {
|
226 | 8b9b0cc2 | Kevin Wolf | case ACTION_INJECT_ERROR:
|
227 | 8b9b0cc2 | Kevin Wolf | rule->options.inject.error = qemu_opt_get_number(opts, "errno", EIO);
|
228 | 8b9b0cc2 | Kevin Wolf | rule->options.inject.once = qemu_opt_get_bool(opts, "once", 0); |
229 | 8b9b0cc2 | Kevin Wolf | rule->options.inject.immediately = |
230 | 8b9b0cc2 | Kevin Wolf | qemu_opt_get_bool(opts, "immediately", 0); |
231 | 8b9b0cc2 | Kevin Wolf | break;
|
232 | 8b9b0cc2 | Kevin Wolf | |
233 | 8b9b0cc2 | Kevin Wolf | case ACTION_SET_STATE:
|
234 | 8b9b0cc2 | Kevin Wolf | rule->options.set_state.new_state = |
235 | 8b9b0cc2 | Kevin Wolf | qemu_opt_get_number(opts, "new_state", 0); |
236 | 8b9b0cc2 | Kevin Wolf | break;
|
237 | 8b9b0cc2 | Kevin Wolf | }; |
238 | 8b9b0cc2 | Kevin Wolf | |
239 | 8b9b0cc2 | Kevin Wolf | /* Add the rule */
|
240 | 8b9b0cc2 | Kevin Wolf | QLIST_INSERT_HEAD(&s->rules[event], rule, next); |
241 | 8b9b0cc2 | Kevin Wolf | |
242 | 8b9b0cc2 | Kevin Wolf | return 0; |
243 | 8b9b0cc2 | Kevin Wolf | } |
244 | 8b9b0cc2 | Kevin Wolf | |
245 | 8b9b0cc2 | Kevin Wolf | static int read_config(BDRVBlkdebugState *s, const char *filename) |
246 | 8b9b0cc2 | Kevin Wolf | { |
247 | 8b9b0cc2 | Kevin Wolf | FILE *f; |
248 | 8b9b0cc2 | Kevin Wolf | int ret;
|
249 | 8b9b0cc2 | Kevin Wolf | struct add_rule_data d;
|
250 | 8b9b0cc2 | Kevin Wolf | |
251 | 8b9b0cc2 | Kevin Wolf | f = fopen(filename, "r");
|
252 | 8b9b0cc2 | Kevin Wolf | if (f == NULL) { |
253 | 8b9b0cc2 | Kevin Wolf | return -errno;
|
254 | 8b9b0cc2 | Kevin Wolf | } |
255 | 8b9b0cc2 | Kevin Wolf | |
256 | 8b9b0cc2 | Kevin Wolf | ret = qemu_config_parse(f, config_groups, filename); |
257 | 8b9b0cc2 | Kevin Wolf | if (ret < 0) { |
258 | 8b9b0cc2 | Kevin Wolf | goto fail;
|
259 | 8b9b0cc2 | Kevin Wolf | } |
260 | 8b9b0cc2 | Kevin Wolf | |
261 | 8b9b0cc2 | Kevin Wolf | d.s = s; |
262 | 8b9b0cc2 | Kevin Wolf | d.action = ACTION_INJECT_ERROR; |
263 | 8b9b0cc2 | Kevin Wolf | qemu_opts_foreach(&inject_error_opts, add_rule, &d, 0);
|
264 | 8b9b0cc2 | Kevin Wolf | |
265 | 8b9b0cc2 | Kevin Wolf | d.action = ACTION_SET_STATE; |
266 | 8b9b0cc2 | Kevin Wolf | qemu_opts_foreach(&set_state_opts, add_rule, &d, 0);
|
267 | 8b9b0cc2 | Kevin Wolf | |
268 | 8b9b0cc2 | Kevin Wolf | ret = 0;
|
269 | 8b9b0cc2 | Kevin Wolf | fail:
|
270 | 698f0d52 | Kevin Wolf | qemu_opts_reset(&inject_error_opts); |
271 | 698f0d52 | Kevin Wolf | qemu_opts_reset(&set_state_opts); |
272 | 8b9b0cc2 | Kevin Wolf | fclose(f); |
273 | 8b9b0cc2 | Kevin Wolf | return ret;
|
274 | 8b9b0cc2 | Kevin Wolf | } |
275 | 8b9b0cc2 | Kevin Wolf | |
276 | 8b9b0cc2 | Kevin Wolf | /* Valid blkdebug filenames look like blkdebug:path/to/config:path/to/image */
|
277 | 6a143727 | Kevin Wolf | static int blkdebug_open(BlockDriverState *bs, const char *filename, int flags) |
278 | 6a143727 | Kevin Wolf | { |
279 | 6a143727 | Kevin Wolf | BDRVBlkdebugState *s = bs->opaque; |
280 | 8b9b0cc2 | Kevin Wolf | int ret;
|
281 | 8b9b0cc2 | Kevin Wolf | char *config, *c;
|
282 | 6a143727 | Kevin Wolf | |
283 | 8b9b0cc2 | Kevin Wolf | /* Parse the blkdebug: prefix */
|
284 | 6a143727 | Kevin Wolf | if (strncmp(filename, "blkdebug:", strlen("blkdebug:"))) { |
285 | 6a143727 | Kevin Wolf | return -EINVAL;
|
286 | 6a143727 | Kevin Wolf | } |
287 | 6a143727 | Kevin Wolf | filename += strlen("blkdebug:");
|
288 | 6a143727 | Kevin Wolf | |
289 | 8b9b0cc2 | Kevin Wolf | /* Read rules from config file */
|
290 | 8b9b0cc2 | Kevin Wolf | c = strchr(filename, ':');
|
291 | 8b9b0cc2 | Kevin Wolf | if (c == NULL) { |
292 | 8b9b0cc2 | Kevin Wolf | return -EINVAL;
|
293 | 8b9b0cc2 | Kevin Wolf | } |
294 | 8b9b0cc2 | Kevin Wolf | |
295 | 8b9b0cc2 | Kevin Wolf | config = strdup(filename); |
296 | 8b9b0cc2 | Kevin Wolf | config[c - filename] = '\0';
|
297 | 8b9b0cc2 | Kevin Wolf | ret = read_config(s, config); |
298 | 8b9b0cc2 | Kevin Wolf | free(config); |
299 | 8b9b0cc2 | Kevin Wolf | if (ret < 0) { |
300 | 8b9b0cc2 | Kevin Wolf | return ret;
|
301 | 8b9b0cc2 | Kevin Wolf | } |
302 | 8b9b0cc2 | Kevin Wolf | filename = c + 1;
|
303 | 8b9b0cc2 | Kevin Wolf | |
304 | 8db520ce | Kevin Wolf | /* Set initial state */
|
305 | 8db520ce | Kevin Wolf | s->vars.state = 1;
|
306 | 8db520ce | Kevin Wolf | |
307 | 8b9b0cc2 | Kevin Wolf | /* Open the backing file */
|
308 | 66f82cee | Kevin Wolf | ret = bdrv_file_open(&bs->file, filename, flags); |
309 | 8b9b0cc2 | Kevin Wolf | if (ret < 0) { |
310 | 8b9b0cc2 | Kevin Wolf | return ret;
|
311 | 8b9b0cc2 | Kevin Wolf | } |
312 | 8b9b0cc2 | Kevin Wolf | |
313 | 8b9b0cc2 | Kevin Wolf | return 0; |
314 | 6a143727 | Kevin Wolf | } |
315 | 6a143727 | Kevin Wolf | |
316 | b9f66d96 | Kevin Wolf | static void error_callback_bh(void *opaque) |
317 | b9f66d96 | Kevin Wolf | { |
318 | b9f66d96 | Kevin Wolf | struct BlkdebugAIOCB *acb = opaque;
|
319 | b9f66d96 | Kevin Wolf | qemu_bh_delete(acb->bh); |
320 | b9f66d96 | Kevin Wolf | acb->common.cb(acb->common.opaque, acb->ret); |
321 | b9f66d96 | Kevin Wolf | qemu_aio_release(acb); |
322 | b9f66d96 | Kevin Wolf | } |
323 | b9f66d96 | Kevin Wolf | |
324 | b9f66d96 | Kevin Wolf | static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb) |
325 | b9f66d96 | Kevin Wolf | { |
326 | b666d239 | Kevin Wolf | BlkdebugAIOCB *acb = container_of(blockacb, BlkdebugAIOCB, common); |
327 | b9f66d96 | Kevin Wolf | qemu_aio_release(acb); |
328 | b9f66d96 | Kevin Wolf | } |
329 | b9f66d96 | Kevin Wolf | |
330 | b9f66d96 | Kevin Wolf | static BlockDriverAIOCB *inject_error(BlockDriverState *bs,
|
331 | b9f66d96 | Kevin Wolf | BlockDriverCompletionFunc *cb, void *opaque)
|
332 | b9f66d96 | Kevin Wolf | { |
333 | b9f66d96 | Kevin Wolf | BDRVBlkdebugState *s = bs->opaque; |
334 | b9f66d96 | Kevin Wolf | int error = s->vars.inject_errno;
|
335 | b9f66d96 | Kevin Wolf | struct BlkdebugAIOCB *acb;
|
336 | b9f66d96 | Kevin Wolf | QEMUBH *bh; |
337 | b9f66d96 | Kevin Wolf | |
338 | b9f66d96 | Kevin Wolf | if (s->vars.inject_once) {
|
339 | b9f66d96 | Kevin Wolf | s->vars.inject_errno = 0;
|
340 | b9f66d96 | Kevin Wolf | } |
341 | b9f66d96 | Kevin Wolf | |
342 | b9f66d96 | Kevin Wolf | if (s->vars.inject_immediately) {
|
343 | b9f66d96 | Kevin Wolf | return NULL; |
344 | b9f66d96 | Kevin Wolf | } |
345 | b9f66d96 | Kevin Wolf | |
346 | b9f66d96 | Kevin Wolf | acb = qemu_aio_get(&blkdebug_aio_pool, bs, cb, opaque); |
347 | b9f66d96 | Kevin Wolf | acb->ret = -error; |
348 | b9f66d96 | Kevin Wolf | |
349 | b9f66d96 | Kevin Wolf | bh = qemu_bh_new(error_callback_bh, acb); |
350 | b9f66d96 | Kevin Wolf | acb->bh = bh; |
351 | b9f66d96 | Kevin Wolf | qemu_bh_schedule(bh); |
352 | b9f66d96 | Kevin Wolf | |
353 | b666d239 | Kevin Wolf | return &acb->common;
|
354 | b9f66d96 | Kevin Wolf | } |
355 | b9f66d96 | Kevin Wolf | |
356 | 6a143727 | Kevin Wolf | static BlockDriverAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
|
357 | 6a143727 | Kevin Wolf | int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
358 | 6a143727 | Kevin Wolf | BlockDriverCompletionFunc *cb, void *opaque)
|
359 | 6a143727 | Kevin Wolf | { |
360 | 6a143727 | Kevin Wolf | BDRVBlkdebugState *s = bs->opaque; |
361 | b9f66d96 | Kevin Wolf | |
362 | b9f66d96 | Kevin Wolf | if (s->vars.inject_errno) {
|
363 | b9f66d96 | Kevin Wolf | return inject_error(bs, cb, opaque);
|
364 | b9f66d96 | Kevin Wolf | } |
365 | b9f66d96 | Kevin Wolf | |
366 | 6a143727 | Kevin Wolf | BlockDriverAIOCB *acb = |
367 | 66f82cee | Kevin Wolf | bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque); |
368 | 6a143727 | Kevin Wolf | return acb;
|
369 | 6a143727 | Kevin Wolf | } |
370 | 6a143727 | Kevin Wolf | |
371 | 6a143727 | Kevin Wolf | static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
|
372 | 6a143727 | Kevin Wolf | int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
373 | 6a143727 | Kevin Wolf | BlockDriverCompletionFunc *cb, void *opaque)
|
374 | 6a143727 | Kevin Wolf | { |
375 | 6a143727 | Kevin Wolf | BDRVBlkdebugState *s = bs->opaque; |
376 | b9f66d96 | Kevin Wolf | |
377 | b9f66d96 | Kevin Wolf | if (s->vars.inject_errno) {
|
378 | b9f66d96 | Kevin Wolf | return inject_error(bs, cb, opaque);
|
379 | b9f66d96 | Kevin Wolf | } |
380 | b9f66d96 | Kevin Wolf | |
381 | 6a143727 | Kevin Wolf | BlockDriverAIOCB *acb = |
382 | 66f82cee | Kevin Wolf | bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque); |
383 | 6a143727 | Kevin Wolf | return acb;
|
384 | 6a143727 | Kevin Wolf | } |
385 | 6a143727 | Kevin Wolf | |
386 | 6a143727 | Kevin Wolf | static void blkdebug_close(BlockDriverState *bs) |
387 | 6a143727 | Kevin Wolf | { |
388 | 6a143727 | Kevin Wolf | BDRVBlkdebugState *s = bs->opaque; |
389 | 8b9b0cc2 | Kevin Wolf | BlkdebugRule *rule, *next; |
390 | 8b9b0cc2 | Kevin Wolf | int i;
|
391 | 8b9b0cc2 | Kevin Wolf | |
392 | 8b9b0cc2 | Kevin Wolf | for (i = 0; i < BLKDBG_EVENT_MAX; i++) { |
393 | 8b9b0cc2 | Kevin Wolf | QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) { |
394 | 8b9b0cc2 | Kevin Wolf | QLIST_REMOVE(rule, next); |
395 | 8b9b0cc2 | Kevin Wolf | qemu_free(rule); |
396 | 8b9b0cc2 | Kevin Wolf | } |
397 | 8b9b0cc2 | Kevin Wolf | } |
398 | 6a143727 | Kevin Wolf | } |
399 | 6a143727 | Kevin Wolf | |
400 | 205ef796 | Kevin Wolf | static int blkdebug_flush(BlockDriverState *bs) |
401 | 6a143727 | Kevin Wolf | { |
402 | 205ef796 | Kevin Wolf | return bdrv_flush(bs->file);
|
403 | 6a143727 | Kevin Wolf | } |
404 | 6a143727 | Kevin Wolf | |
405 | 6a143727 | Kevin Wolf | static BlockDriverAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
|
406 | 6a143727 | Kevin Wolf | BlockDriverCompletionFunc *cb, void *opaque)
|
407 | 6a143727 | Kevin Wolf | { |
408 | 66f82cee | Kevin Wolf | return bdrv_aio_flush(bs->file, cb, opaque);
|
409 | 6a143727 | Kevin Wolf | } |
410 | 6a143727 | Kevin Wolf | |
411 | 8b9b0cc2 | Kevin Wolf | static void process_rule(BlockDriverState *bs, struct BlkdebugRule *rule, |
412 | 8b9b0cc2 | Kevin Wolf | BlkdebugVars *old_vars) |
413 | 8b9b0cc2 | Kevin Wolf | { |
414 | 8b9b0cc2 | Kevin Wolf | BDRVBlkdebugState *s = bs->opaque; |
415 | 8b9b0cc2 | Kevin Wolf | BlkdebugVars *vars = &s->vars; |
416 | 8b9b0cc2 | Kevin Wolf | |
417 | 8b9b0cc2 | Kevin Wolf | /* Only process rules for the current state */
|
418 | 8b9b0cc2 | Kevin Wolf | if (rule->state && rule->state != old_vars->state) {
|
419 | 8b9b0cc2 | Kevin Wolf | return;
|
420 | 8b9b0cc2 | Kevin Wolf | } |
421 | 8b9b0cc2 | Kevin Wolf | |
422 | 8b9b0cc2 | Kevin Wolf | /* Take the action */
|
423 | 8b9b0cc2 | Kevin Wolf | switch (rule->action) {
|
424 | 8b9b0cc2 | Kevin Wolf | case ACTION_INJECT_ERROR:
|
425 | 8b9b0cc2 | Kevin Wolf | vars->inject_errno = rule->options.inject.error; |
426 | 8b9b0cc2 | Kevin Wolf | vars->inject_once = rule->options.inject.once; |
427 | 8b9b0cc2 | Kevin Wolf | vars->inject_immediately = rule->options.inject.immediately; |
428 | 8b9b0cc2 | Kevin Wolf | break;
|
429 | 8b9b0cc2 | Kevin Wolf | |
430 | 8b9b0cc2 | Kevin Wolf | case ACTION_SET_STATE:
|
431 | 8b9b0cc2 | Kevin Wolf | vars->state = rule->options.set_state.new_state; |
432 | 8b9b0cc2 | Kevin Wolf | break;
|
433 | 8b9b0cc2 | Kevin Wolf | } |
434 | 8b9b0cc2 | Kevin Wolf | } |
435 | 8b9b0cc2 | Kevin Wolf | |
436 | 8b9b0cc2 | Kevin Wolf | static void blkdebug_debug_event(BlockDriverState *bs, BlkDebugEvent event) |
437 | 8b9b0cc2 | Kevin Wolf | { |
438 | 8b9b0cc2 | Kevin Wolf | BDRVBlkdebugState *s = bs->opaque; |
439 | 8b9b0cc2 | Kevin Wolf | struct BlkdebugRule *rule;
|
440 | 8b9b0cc2 | Kevin Wolf | BlkdebugVars old_vars = s->vars; |
441 | 8b9b0cc2 | Kevin Wolf | |
442 | 95ee3914 | Blue Swirl | assert((int)event >= 0 && event < BLKDBG_EVENT_MAX); |
443 | 8b9b0cc2 | Kevin Wolf | |
444 | 8b9b0cc2 | Kevin Wolf | QLIST_FOREACH(rule, &s->rules[event], next) { |
445 | 8b9b0cc2 | Kevin Wolf | process_rule(bs, rule, &old_vars); |
446 | 8b9b0cc2 | Kevin Wolf | } |
447 | 8b9b0cc2 | Kevin Wolf | } |
448 | 8b9b0cc2 | Kevin Wolf | |
449 | 6a143727 | Kevin Wolf | static BlockDriver bdrv_blkdebug = {
|
450 | 6a143727 | Kevin Wolf | .format_name = "blkdebug",
|
451 | 6a143727 | Kevin Wolf | .protocol_name = "blkdebug",
|
452 | 6a143727 | Kevin Wolf | |
453 | 6a143727 | Kevin Wolf | .instance_size = sizeof(BDRVBlkdebugState),
|
454 | 6a143727 | Kevin Wolf | |
455 | 66f82cee | Kevin Wolf | .bdrv_file_open = blkdebug_open, |
456 | 6a143727 | Kevin Wolf | .bdrv_close = blkdebug_close, |
457 | 6a143727 | Kevin Wolf | .bdrv_flush = blkdebug_flush, |
458 | 6a143727 | Kevin Wolf | |
459 | 6a143727 | Kevin Wolf | .bdrv_aio_readv = blkdebug_aio_readv, |
460 | 6a143727 | Kevin Wolf | .bdrv_aio_writev = blkdebug_aio_writev, |
461 | 6a143727 | Kevin Wolf | .bdrv_aio_flush = blkdebug_aio_flush, |
462 | 8b9b0cc2 | Kevin Wolf | |
463 | 8b9b0cc2 | Kevin Wolf | .bdrv_debug_event = blkdebug_debug_event, |
464 | 6a143727 | Kevin Wolf | }; |
465 | 6a143727 | Kevin Wolf | |
466 | 6a143727 | Kevin Wolf | static void bdrv_blkdebug_init(void) |
467 | 6a143727 | Kevin Wolf | { |
468 | 6a143727 | Kevin Wolf | bdrv_register(&bdrv_blkdebug); |
469 | 6a143727 | Kevin Wolf | } |
470 | 6a143727 | Kevin Wolf | |
471 | 6a143727 | Kevin Wolf | block_init(bdrv_blkdebug_init); |