root / qemu-io.c @ 797ac58c
History | View | Annotate | Download (6.7 kB)
1 |
/*
|
---|---|
2 |
* Command line utility to exercise the QEMU I/O path.
|
3 |
*
|
4 |
* Copyright (C) 2009 Red Hat, Inc.
|
5 |
* Copyright (c) 2003-2005 Silicon Graphics, Inc.
|
6 |
*
|
7 |
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
8 |
* See the COPYING file in the top-level directory.
|
9 |
*/
|
10 |
#include <sys/time.h> |
11 |
#include <sys/types.h> |
12 |
#include <stdarg.h> |
13 |
#include <stdio.h> |
14 |
#include <getopt.h> |
15 |
#include <libgen.h> |
16 |
|
17 |
#include "qemu-common.h" |
18 |
#include "qemu/main-loop.h" |
19 |
#include "block/block_int.h" |
20 |
#include "cmd.h" |
21 |
#include "trace/control.h" |
22 |
|
23 |
#define VERSION "0.0.1" |
24 |
|
25 |
#define CMD_NOFILE_OK 0x01 |
26 |
|
27 |
char *progname;
|
28 |
|
29 |
BlockDriverState *qemuio_bs; |
30 |
extern int qemuio_misalign; |
31 |
|
32 |
static int close_f(BlockDriverState *bs, int argc, char **argv) |
33 |
{ |
34 |
bdrv_delete(bs); |
35 |
qemuio_bs = NULL;
|
36 |
return 0; |
37 |
} |
38 |
|
39 |
static const cmdinfo_t close_cmd = { |
40 |
.name = "close",
|
41 |
.altname = "c",
|
42 |
.cfunc = close_f, |
43 |
.oneline = "close the current open file",
|
44 |
}; |
45 |
|
46 |
static int openfile(char *name, int flags, int growable) |
47 |
{ |
48 |
if (qemuio_bs) {
|
49 |
fprintf(stderr, "file open already, try 'help close'\n");
|
50 |
return 1; |
51 |
} |
52 |
|
53 |
if (growable) {
|
54 |
if (bdrv_file_open(&qemuio_bs, name, NULL, flags)) { |
55 |
fprintf(stderr, "%s: can't open device %s\n", progname, name);
|
56 |
return 1; |
57 |
} |
58 |
} else {
|
59 |
qemuio_bs = bdrv_new("hda");
|
60 |
|
61 |
if (bdrv_open(qemuio_bs, name, NULL, flags, NULL) < 0) { |
62 |
fprintf(stderr, "%s: can't open device %s\n", progname, name);
|
63 |
bdrv_delete(qemuio_bs); |
64 |
qemuio_bs = NULL;
|
65 |
return 1; |
66 |
} |
67 |
} |
68 |
|
69 |
return 0; |
70 |
} |
71 |
|
72 |
static void open_help(void) |
73 |
{ |
74 |
printf( |
75 |
"\n"
|
76 |
" opens a new file in the requested mode\n"
|
77 |
"\n"
|
78 |
" Example:\n"
|
79 |
" 'open -Cn /tmp/data' - creates/opens data file read-write and uncached\n"
|
80 |
"\n"
|
81 |
" Opens a file for subsequent use by all of the other qemu-io commands.\n"
|
82 |
" -r, -- open file read-only\n"
|
83 |
" -s, -- use snapshot file\n"
|
84 |
" -n, -- disable host cache\n"
|
85 |
" -g, -- allow file to grow (only applies to protocols)"
|
86 |
"\n");
|
87 |
} |
88 |
|
89 |
static int open_f(BlockDriverState *bs, int argc, char **argv); |
90 |
|
91 |
static const cmdinfo_t open_cmd = { |
92 |
.name = "open",
|
93 |
.altname = "o",
|
94 |
.cfunc = open_f, |
95 |
.argmin = 1,
|
96 |
.argmax = -1,
|
97 |
.flags = CMD_NOFILE_OK, |
98 |
.args = "[-Crsn] [path]",
|
99 |
.oneline = "open the file specified by path",
|
100 |
.help = open_help, |
101 |
}; |
102 |
|
103 |
static int open_f(BlockDriverState *bs, int argc, char **argv) |
104 |
{ |
105 |
int flags = 0; |
106 |
int readonly = 0; |
107 |
int growable = 0; |
108 |
int c;
|
109 |
|
110 |
while ((c = getopt(argc, argv, "snrg")) != EOF) { |
111 |
switch (c) {
|
112 |
case 's': |
113 |
flags |= BDRV_O_SNAPSHOT; |
114 |
break;
|
115 |
case 'n': |
116 |
flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB; |
117 |
break;
|
118 |
case 'r': |
119 |
readonly = 1;
|
120 |
break;
|
121 |
case 'g': |
122 |
growable = 1;
|
123 |
break;
|
124 |
default:
|
125 |
return command_usage(&open_cmd);
|
126 |
} |
127 |
} |
128 |
|
129 |
if (!readonly) {
|
130 |
flags |= BDRV_O_RDWR; |
131 |
} |
132 |
|
133 |
if (optind != argc - 1) { |
134 |
return command_usage(&open_cmd);
|
135 |
} |
136 |
|
137 |
return openfile(argv[optind], flags, growable);
|
138 |
} |
139 |
|
140 |
static void usage(const char *name) |
141 |
{ |
142 |
printf( |
143 |
"Usage: %s [-h] [-V] [-rsnm] [-c cmd] ... [file]\n"
|
144 |
"QEMU Disk exerciser\n"
|
145 |
"\n"
|
146 |
" -c, --cmd command to execute\n"
|
147 |
" -r, --read-only export read-only\n"
|
148 |
" -s, --snapshot use snapshot file\n"
|
149 |
" -n, --nocache disable host cache\n"
|
150 |
" -g, --growable allow file to grow (only applies to protocols)\n"
|
151 |
" -m, --misalign misalign allocations for O_DIRECT\n"
|
152 |
" -k, --native-aio use kernel AIO implementation (on Linux only)\n"
|
153 |
" -t, --cache=MODE use the given cache mode for the image\n"
|
154 |
" -T, --trace FILE enable trace events listed in the given file\n"
|
155 |
" -h, --help display this help and exit\n"
|
156 |
" -V, --version output version information and exit\n"
|
157 |
"\n",
|
158 |
name); |
159 |
} |
160 |
|
161 |
|
162 |
int main(int argc, char **argv) |
163 |
{ |
164 |
int readonly = 0; |
165 |
int growable = 0; |
166 |
const char *sopt = "hVc:d:rsnmgkt:T:"; |
167 |
const struct option lopt[] = { |
168 |
{ "help", 0, NULL, 'h' }, |
169 |
{ "version", 0, NULL, 'V' }, |
170 |
{ "offset", 1, NULL, 'o' }, |
171 |
{ "cmd", 1, NULL, 'c' }, |
172 |
{ "read-only", 0, NULL, 'r' }, |
173 |
{ "snapshot", 0, NULL, 's' }, |
174 |
{ "nocache", 0, NULL, 'n' }, |
175 |
{ "misalign", 0, NULL, 'm' }, |
176 |
{ "growable", 0, NULL, 'g' }, |
177 |
{ "native-aio", 0, NULL, 'k' }, |
178 |
{ "discard", 1, NULL, 'd' }, |
179 |
{ "cache", 1, NULL, 't' }, |
180 |
{ "trace", 1, NULL, 'T' }, |
181 |
{ NULL, 0, NULL, 0 } |
182 |
}; |
183 |
int c;
|
184 |
int opt_index = 0; |
185 |
int flags = BDRV_O_UNMAP;
|
186 |
|
187 |
progname = basename(argv[0]);
|
188 |
|
189 |
while ((c = getopt_long(argc, argv, sopt, lopt, &opt_index)) != -1) { |
190 |
switch (c) {
|
191 |
case 's': |
192 |
flags |= BDRV_O_SNAPSHOT; |
193 |
break;
|
194 |
case 'n': |
195 |
flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB; |
196 |
break;
|
197 |
case 'd': |
198 |
if (bdrv_parse_discard_flags(optarg, &flags) < 0) { |
199 |
error_report("Invalid discard option: %s", optarg);
|
200 |
exit(1);
|
201 |
} |
202 |
break;
|
203 |
case 'c': |
204 |
add_user_command(optarg); |
205 |
break;
|
206 |
case 'r': |
207 |
readonly = 1;
|
208 |
break;
|
209 |
case 'm': |
210 |
qemuio_misalign = 1;
|
211 |
break;
|
212 |
case 'g': |
213 |
growable = 1;
|
214 |
break;
|
215 |
case 'k': |
216 |
flags |= BDRV_O_NATIVE_AIO; |
217 |
break;
|
218 |
case 't': |
219 |
if (bdrv_parse_cache_flags(optarg, &flags) < 0) { |
220 |
error_report("Invalid cache option: %s", optarg);
|
221 |
exit(1);
|
222 |
} |
223 |
break;
|
224 |
case 'T': |
225 |
if (!trace_backend_init(optarg, NULL)) { |
226 |
exit(1); /* error message will have been printed */ |
227 |
} |
228 |
break;
|
229 |
case 'V': |
230 |
printf("%s version %s\n", progname, VERSION);
|
231 |
exit(0);
|
232 |
case 'h': |
233 |
usage(progname); |
234 |
exit(0);
|
235 |
default:
|
236 |
usage(progname); |
237 |
exit(1);
|
238 |
} |
239 |
} |
240 |
|
241 |
if ((argc - optind) > 1) { |
242 |
usage(progname); |
243 |
exit(1);
|
244 |
} |
245 |
|
246 |
qemu_init_main_loop(); |
247 |
bdrv_init(); |
248 |
|
249 |
/* initialize commands */
|
250 |
quit_init(); |
251 |
add_command(&open_cmd); |
252 |
add_command(&close_cmd); |
253 |
|
254 |
/* open the device */
|
255 |
if (!readonly) {
|
256 |
flags |= BDRV_O_RDWR; |
257 |
} |
258 |
|
259 |
if ((argc - optind) == 1) { |
260 |
openfile(argv[optind], flags, growable); |
261 |
} |
262 |
command_loop(); |
263 |
|
264 |
/*
|
265 |
* Make sure all outstanding requests complete before the program exits.
|
266 |
*/
|
267 |
bdrv_drain_all(); |
268 |
|
269 |
if (qemuio_bs) {
|
270 |
bdrv_delete(qemuio_bs); |
271 |
} |
272 |
return 0; |
273 |
} |