xref: /qemu/qemu-io.c (revision b46578555c4bce64e3daba4591334aba2d12c156)
1e3aff4f6Saliguori /*
2e3aff4f6Saliguori  * Command line utility to exercise the QEMU I/O path.
3e3aff4f6Saliguori  *
4e3aff4f6Saliguori  * Copyright (C) 2009 Red Hat, Inc.
5e3aff4f6Saliguori  * Copyright (c) 2003-2005 Silicon Graphics, Inc.
6e3aff4f6Saliguori  *
7e3aff4f6Saliguori  * This work is licensed under the terms of the GNU GPL, version 2 or later.
8e3aff4f6Saliguori  * See the COPYING file in the top-level directory.
9e3aff4f6Saliguori  */
10c32d766aSStefan Weil #include <sys/time.h>
11e3aff4f6Saliguori #include <sys/types.h>
12e3aff4f6Saliguori #include <stdarg.h>
13e3aff4f6Saliguori #include <stdio.h>
14e3aff4f6Saliguori #include <getopt.h>
15c32d766aSStefan Weil #include <libgen.h>
16e3aff4f6Saliguori 
17e3aff4f6Saliguori #include "qemu-common.h"
18e3aff4f6Saliguori #include "block_int.h"
19e3aff4f6Saliguori #include "cmd.h"
20e3aff4f6Saliguori 
21e3aff4f6Saliguori #define VERSION	"0.0.1"
22e3aff4f6Saliguori 
23e3aff4f6Saliguori #define CMD_NOFILE_OK   0x01
24e3aff4f6Saliguori 
25e3aff4f6Saliguori char *progname;
26e3aff4f6Saliguori static BlockDriverState *bs;
27e3aff4f6Saliguori 
28e3aff4f6Saliguori static int misalign;
29e3aff4f6Saliguori 
30e3aff4f6Saliguori /*
31cf070d7eSChristoph Hellwig  * Parse the pattern argument to various sub-commands.
32cf070d7eSChristoph Hellwig  *
33cf070d7eSChristoph Hellwig  * Because the pattern is used as an argument to memset it must evaluate
34cf070d7eSChristoph Hellwig  * to an unsigned integer that fits into a single byte.
35cf070d7eSChristoph Hellwig  */
36cf070d7eSChristoph Hellwig static int parse_pattern(const char *arg)
37cf070d7eSChristoph Hellwig {
38cf070d7eSChristoph Hellwig     char *endptr = NULL;
39cf070d7eSChristoph Hellwig     long pattern;
40cf070d7eSChristoph Hellwig 
41cf070d7eSChristoph Hellwig     pattern = strtol(arg, &endptr, 0);
42cf070d7eSChristoph Hellwig     if (pattern < 0 || pattern > UCHAR_MAX || *endptr != '\0') {
43cf070d7eSChristoph Hellwig         printf("%s is not a valid pattern byte\n", arg);
44cf070d7eSChristoph Hellwig         return -1;
45cf070d7eSChristoph Hellwig     }
46cf070d7eSChristoph Hellwig 
47cf070d7eSChristoph Hellwig     return pattern;
48cf070d7eSChristoph Hellwig }
49cf070d7eSChristoph Hellwig 
50cf070d7eSChristoph Hellwig /*
51e3aff4f6Saliguori  * Memory allocation helpers.
52e3aff4f6Saliguori  *
53e3aff4f6Saliguori  * Make sure memory is aligned by default, or purposefully misaligned if
54e3aff4f6Saliguori  * that is specified on the command line.
55e3aff4f6Saliguori  */
56e3aff4f6Saliguori 
57e3aff4f6Saliguori #define MISALIGN_OFFSET     16
58e3aff4f6Saliguori static void *qemu_io_alloc(size_t len, int pattern)
59e3aff4f6Saliguori {
60e3aff4f6Saliguori     void *buf;
61e3aff4f6Saliguori 
6243642b38SDevin Nakamura     if (misalign) {
63e3aff4f6Saliguori         len += MISALIGN_OFFSET;
6443642b38SDevin Nakamura     }
6572aef731SChristoph Hellwig     buf = qemu_blockalign(bs, len);
66e3aff4f6Saliguori     memset(buf, pattern, len);
6743642b38SDevin Nakamura     if (misalign) {
68e3aff4f6Saliguori         buf += MISALIGN_OFFSET;
6943642b38SDevin Nakamura     }
70e3aff4f6Saliguori     return buf;
71e3aff4f6Saliguori }
72e3aff4f6Saliguori 
73e3aff4f6Saliguori static void qemu_io_free(void *p)
74e3aff4f6Saliguori {
7543642b38SDevin Nakamura     if (misalign) {
76e3aff4f6Saliguori         p -= MISALIGN_OFFSET;
7743642b38SDevin Nakamura     }
78e3aff4f6Saliguori     qemu_vfree(p);
79e3aff4f6Saliguori }
80e3aff4f6Saliguori 
8143642b38SDevin Nakamura static void dump_buffer(const void *buffer, int64_t offset, int len)
82e3aff4f6Saliguori {
83e3aff4f6Saliguori     int i, j;
843abcdf49SStefan Weil     const uint8_t *p;
85e3aff4f6Saliguori 
86e3aff4f6Saliguori     for (i = 0, p = buffer; i < len; i += 16) {
873abcdf49SStefan Weil         const uint8_t *s = p;
88e3aff4f6Saliguori 
890bfcd599SBlue Swirl         printf("%08" PRIx64 ":  ", offset + i);
9043642b38SDevin Nakamura         for (j = 0; j < 16 && i + j < len; j++, p++) {
91e3aff4f6Saliguori             printf("%02x ", *p);
9243642b38SDevin Nakamura         }
93e3aff4f6Saliguori         printf(" ");
94e3aff4f6Saliguori         for (j = 0; j < 16 && i + j < len; j++, s++) {
9543642b38SDevin Nakamura             if (isalnum(*s)) {
96e3aff4f6Saliguori                 printf("%c", *s);
9743642b38SDevin Nakamura             } else {
98e3aff4f6Saliguori                 printf(".");
99e3aff4f6Saliguori             }
10043642b38SDevin Nakamura         }
101e3aff4f6Saliguori         printf("\n");
102e3aff4f6Saliguori     }
103e3aff4f6Saliguori }
104e3aff4f6Saliguori 
10543642b38SDevin Nakamura static void print_report(const char *op, struct timeval *t, int64_t offset,
106e3aff4f6Saliguori                          int count, int total, int cnt, int Cflag)
107e3aff4f6Saliguori {
108e3aff4f6Saliguori     char s1[64], s2[64], ts[64];
109e3aff4f6Saliguori 
110e3aff4f6Saliguori     timestr(t, ts, sizeof(ts), Cflag ? VERBOSE_FIXED_TIME : 0);
111e3aff4f6Saliguori     if (!Cflag) {
112e3aff4f6Saliguori         cvtstr((double)total, s1, sizeof(s1));
113e3aff4f6Saliguori         cvtstr(tdiv((double)total, *t), s2, sizeof(s2));
1140bfcd599SBlue Swirl         printf("%s %d/%d bytes at offset %" PRId64 "\n",
1150bfcd599SBlue Swirl                op, total, count, offset);
116e3aff4f6Saliguori         printf("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n",
117e3aff4f6Saliguori                s1, cnt, ts, s2, tdiv((double)cnt, *t));
118e3aff4f6Saliguori     } else {/* bytes,ops,time,bytes/sec,ops/sec */
119e3aff4f6Saliguori         printf("%d,%d,%s,%.3f,%.3f\n",
120e3aff4f6Saliguori             total, cnt, ts,
121e3aff4f6Saliguori             tdiv((double)total, *t),
122e3aff4f6Saliguori             tdiv((double)cnt, *t));
123e3aff4f6Saliguori     }
124e3aff4f6Saliguori }
125e3aff4f6Saliguori 
126cf57298aSChristoph Hellwig /*
127cf57298aSChristoph Hellwig  * Parse multiple length statements for vectored I/O, and construct an I/O
128cf57298aSChristoph Hellwig  * vector matching it.
129cf57298aSChristoph Hellwig  */
130cf57298aSChristoph Hellwig static void *
131cf57298aSChristoph Hellwig create_iovec(QEMUIOVector *qiov, char **argv, int nr_iov, int pattern)
132cf57298aSChristoph Hellwig {
133cf57298aSChristoph Hellwig     size_t *sizes = calloc(nr_iov, sizeof(size_t));
134cf57298aSChristoph Hellwig     size_t count = 0;
13540a0d7c3SKevin Wolf     void *buf = NULL;
13640a0d7c3SKevin Wolf     void *p;
137cf57298aSChristoph Hellwig     int i;
138cf57298aSChristoph Hellwig 
139cf57298aSChristoph Hellwig     for (i = 0; i < nr_iov; i++) {
140cf57298aSChristoph Hellwig         char *arg = argv[i];
141ca1d6ac6SJoel Schopp         int64_t len;
142cf57298aSChristoph Hellwig 
143cf57298aSChristoph Hellwig         len = cvtnum(arg);
144cf57298aSChristoph Hellwig         if (len < 0) {
145cf57298aSChristoph Hellwig             printf("non-numeric length argument -- %s\n", arg);
14640a0d7c3SKevin Wolf             goto fail;
147cf57298aSChristoph Hellwig         }
148cf57298aSChristoph Hellwig 
149cf57298aSChristoph Hellwig         /* should be SIZE_T_MAX, but that doesn't exist */
150ca1d6ac6SJoel Schopp         if (len > INT_MAX) {
151cf57298aSChristoph Hellwig             printf("too large length argument -- %s\n", arg);
15240a0d7c3SKevin Wolf             goto fail;
153cf57298aSChristoph Hellwig         }
154cf57298aSChristoph Hellwig 
155cf57298aSChristoph Hellwig         if (len & 0x1ff) {
1560bfcd599SBlue Swirl             printf("length argument %" PRId64
1570bfcd599SBlue Swirl                    " is not sector aligned\n", len);
15840a0d7c3SKevin Wolf             goto fail;
159cf57298aSChristoph Hellwig         }
160cf57298aSChristoph Hellwig 
161cf57298aSChristoph Hellwig         sizes[i] = len;
162cf57298aSChristoph Hellwig         count += len;
163cf57298aSChristoph Hellwig     }
164cf57298aSChristoph Hellwig 
165cf57298aSChristoph Hellwig     qemu_iovec_init(qiov, nr_iov);
166cf57298aSChristoph Hellwig 
167cf57298aSChristoph Hellwig     buf = p = qemu_io_alloc(count, pattern);
168cf57298aSChristoph Hellwig 
169cf57298aSChristoph Hellwig     for (i = 0; i < nr_iov; i++) {
170cf57298aSChristoph Hellwig         qemu_iovec_add(qiov, p, sizes[i]);
171cf57298aSChristoph Hellwig         p += sizes[i];
172cf57298aSChristoph Hellwig     }
173cf57298aSChristoph Hellwig 
17440a0d7c3SKevin Wolf fail:
175cf57298aSChristoph Hellwig     free(sizes);
176cf57298aSChristoph Hellwig     return buf;
177cf57298aSChristoph Hellwig }
178cf57298aSChristoph Hellwig 
179e3aff4f6Saliguori static int do_read(char *buf, int64_t offset, int count, int *total)
180e3aff4f6Saliguori {
181e3aff4f6Saliguori     int ret;
182e3aff4f6Saliguori 
183e3aff4f6Saliguori     ret = bdrv_read(bs, offset >> 9, (uint8_t *)buf, count >> 9);
18443642b38SDevin Nakamura     if (ret < 0) {
185e3aff4f6Saliguori         return ret;
18643642b38SDevin Nakamura     }
187e3aff4f6Saliguori     *total = count;
188e3aff4f6Saliguori     return 1;
189e3aff4f6Saliguori }
190e3aff4f6Saliguori 
191e3aff4f6Saliguori static int do_write(char *buf, int64_t offset, int count, int *total)
192e3aff4f6Saliguori {
193e3aff4f6Saliguori     int ret;
194e3aff4f6Saliguori 
195e3aff4f6Saliguori     ret = bdrv_write(bs, offset >> 9, (uint8_t *)buf, count >> 9);
19643642b38SDevin Nakamura     if (ret < 0) {
197e3aff4f6Saliguori         return ret;
19843642b38SDevin Nakamura     }
199e3aff4f6Saliguori     *total = count;
200e3aff4f6Saliguori     return 1;
201e3aff4f6Saliguori }
202e3aff4f6Saliguori 
203e3aff4f6Saliguori static int do_pread(char *buf, int64_t offset, int count, int *total)
204e3aff4f6Saliguori {
205e3aff4f6Saliguori     *total = bdrv_pread(bs, offset, (uint8_t *)buf, count);
20643642b38SDevin Nakamura     if (*total < 0) {
207e3aff4f6Saliguori         return *total;
20843642b38SDevin Nakamura     }
209e3aff4f6Saliguori     return 1;
210e3aff4f6Saliguori }
211e3aff4f6Saliguori 
212e3aff4f6Saliguori static int do_pwrite(char *buf, int64_t offset, int count, int *total)
213e3aff4f6Saliguori {
214e3aff4f6Saliguori     *total = bdrv_pwrite(bs, offset, (uint8_t *)buf, count);
21543642b38SDevin Nakamura     if (*total < 0) {
216e3aff4f6Saliguori         return *total;
21743642b38SDevin Nakamura     }
218e3aff4f6Saliguori     return 1;
219e3aff4f6Saliguori }
220e3aff4f6Saliguori 
221ca94dbc7SKevin Wolf static int do_load_vmstate(char *buf, int64_t offset, int count, int *total)
222ca94dbc7SKevin Wolf {
223ca94dbc7SKevin Wolf     *total = bdrv_load_vmstate(bs, (uint8_t *)buf, offset, count);
22443642b38SDevin Nakamura     if (*total < 0) {
225ca94dbc7SKevin Wolf         return *total;
22643642b38SDevin Nakamura     }
227ca94dbc7SKevin Wolf     return 1;
228ca94dbc7SKevin Wolf }
229ca94dbc7SKevin Wolf 
230ca94dbc7SKevin Wolf static int do_save_vmstate(char *buf, int64_t offset, int count, int *total)
231ca94dbc7SKevin Wolf {
232ca94dbc7SKevin Wolf     *total = bdrv_save_vmstate(bs, (uint8_t *)buf, offset, count);
23343642b38SDevin Nakamura     if (*total < 0) {
234ca94dbc7SKevin Wolf         return *total;
23543642b38SDevin Nakamura     }
236ca94dbc7SKevin Wolf     return 1;
237ca94dbc7SKevin Wolf }
238ca94dbc7SKevin Wolf 
239e3aff4f6Saliguori #define NOT_DONE 0x7fffffff
240e3aff4f6Saliguori static void aio_rw_done(void *opaque, int ret)
241e3aff4f6Saliguori {
242e3aff4f6Saliguori     *(int *)opaque = ret;
243e3aff4f6Saliguori }
244e3aff4f6Saliguori 
245e3aff4f6Saliguori static int do_aio_readv(QEMUIOVector *qiov, int64_t offset, int *total)
246e3aff4f6Saliguori {
247e3aff4f6Saliguori     BlockDriverAIOCB *acb;
248e3aff4f6Saliguori     int async_ret = NOT_DONE;
249e3aff4f6Saliguori 
250e3aff4f6Saliguori     acb = bdrv_aio_readv(bs, offset >> 9, qiov, qiov->size >> 9,
251e3aff4f6Saliguori                          aio_rw_done, &async_ret);
25243642b38SDevin Nakamura     if (!acb) {
253e3aff4f6Saliguori         return -EIO;
25443642b38SDevin Nakamura     }
25543642b38SDevin Nakamura     while (async_ret == NOT_DONE) {
256e3aff4f6Saliguori         qemu_aio_wait();
25743642b38SDevin Nakamura     }
258e3aff4f6Saliguori 
259e3aff4f6Saliguori     *total = qiov->size;
260e3aff4f6Saliguori     return async_ret < 0 ? async_ret : 1;
261e3aff4f6Saliguori }
262e3aff4f6Saliguori 
263e3aff4f6Saliguori static int do_aio_writev(QEMUIOVector *qiov, int64_t offset, int *total)
264e3aff4f6Saliguori {
265e3aff4f6Saliguori     BlockDriverAIOCB *acb;
266e3aff4f6Saliguori     int async_ret = NOT_DONE;
267e3aff4f6Saliguori 
268e3aff4f6Saliguori     acb = bdrv_aio_writev(bs, offset >> 9, qiov, qiov->size >> 9,
269e3aff4f6Saliguori                           aio_rw_done, &async_ret);
27043642b38SDevin Nakamura     if (!acb) {
271e3aff4f6Saliguori         return -EIO;
27243642b38SDevin Nakamura     }
273e3aff4f6Saliguori 
27443642b38SDevin Nakamura     while (async_ret == NOT_DONE) {
275e3aff4f6Saliguori         qemu_aio_wait();
27643642b38SDevin Nakamura     }
277e3aff4f6Saliguori 
2787e9bbc9fSaliguori     *total = qiov->size;
279e3aff4f6Saliguori     return async_ret < 0 ? async_ret : 1;
280e3aff4f6Saliguori }
281e3aff4f6Saliguori 
282776cbbbdSKevin Wolf struct multiwrite_async_ret {
283776cbbbdSKevin Wolf     int num_done;
284776cbbbdSKevin Wolf     int error;
285776cbbbdSKevin Wolf };
286776cbbbdSKevin Wolf 
287776cbbbdSKevin Wolf static void multiwrite_cb(void *opaque, int ret)
288776cbbbdSKevin Wolf {
289776cbbbdSKevin Wolf     struct multiwrite_async_ret *async_ret = opaque;
290776cbbbdSKevin Wolf 
291776cbbbdSKevin Wolf     async_ret->num_done++;
292776cbbbdSKevin Wolf     if (ret < 0) {
293776cbbbdSKevin Wolf         async_ret->error = ret;
294776cbbbdSKevin Wolf     }
295776cbbbdSKevin Wolf }
296776cbbbdSKevin Wolf 
297776cbbbdSKevin Wolf static int do_aio_multiwrite(BlockRequest* reqs, int num_reqs, int *total)
298776cbbbdSKevin Wolf {
299776cbbbdSKevin Wolf     int i, ret;
300776cbbbdSKevin Wolf     struct multiwrite_async_ret async_ret = {
301776cbbbdSKevin Wolf         .num_done = 0,
302776cbbbdSKevin Wolf         .error = 0,
303776cbbbdSKevin Wolf     };
304776cbbbdSKevin Wolf 
305776cbbbdSKevin Wolf     *total = 0;
306776cbbbdSKevin Wolf     for (i = 0; i < num_reqs; i++) {
307776cbbbdSKevin Wolf         reqs[i].cb = multiwrite_cb;
308776cbbbdSKevin Wolf         reqs[i].opaque = &async_ret;
309776cbbbdSKevin Wolf         *total += reqs[i].qiov->size;
310776cbbbdSKevin Wolf     }
311776cbbbdSKevin Wolf 
312776cbbbdSKevin Wolf     ret = bdrv_aio_multiwrite(bs, reqs, num_reqs);
313776cbbbdSKevin Wolf     if (ret < 0) {
314776cbbbdSKevin Wolf         return ret;
315776cbbbdSKevin Wolf     }
316776cbbbdSKevin Wolf 
317776cbbbdSKevin Wolf     while (async_ret.num_done < num_reqs) {
318776cbbbdSKevin Wolf         qemu_aio_wait();
319776cbbbdSKevin Wolf     }
320776cbbbdSKevin Wolf 
321776cbbbdSKevin Wolf     return async_ret.error < 0 ? async_ret.error : 1;
322776cbbbdSKevin Wolf }
323e3aff4f6Saliguori 
32443642b38SDevin Nakamura static void read_help(void)
325e3aff4f6Saliguori {
326e3aff4f6Saliguori     printf(
327e3aff4f6Saliguori "\n"
328e3aff4f6Saliguori " reads a range of bytes from the given offset\n"
329e3aff4f6Saliguori "\n"
330e3aff4f6Saliguori " Example:\n"
331e3aff4f6Saliguori " 'read -v 512 1k' - dumps 1 kilobyte read from 512 bytes into the file\n"
332e3aff4f6Saliguori "\n"
333e3aff4f6Saliguori " Reads a segment of the currently open file, optionally dumping it to the\n"
334e3aff4f6Saliguori " standard output stream (with -v option) for subsequent inspection.\n"
335ca94dbc7SKevin Wolf " -b, -- read from the VM state rather than the virtual disk\n"
336d9654a58SKevin Wolf " -C, -- report statistics in a machine parsable format\n"
337d9654a58SKevin Wolf " -l, -- length for pattern verification (only with -P)\n"
338e3aff4f6Saliguori " -p, -- use bdrv_pread to read the file\n"
339c48101aeSaliguori " -P, -- use a pattern to verify read data\n"
340095343adSKevin Wolf " -q, -- quiet mode, do not show I/O statistics\n"
341d9654a58SKevin Wolf " -s, -- start offset for pattern verification (only with -P)\n"
342d9654a58SKevin Wolf " -v, -- dump buffer to standard output\n"
343e3aff4f6Saliguori "\n");
344e3aff4f6Saliguori }
345e3aff4f6Saliguori 
34622a2bdcbSBlue Swirl static int read_f(int argc, char **argv);
34722a2bdcbSBlue Swirl 
34822a2bdcbSBlue Swirl static const cmdinfo_t read_cmd = {
34922a2bdcbSBlue Swirl     .name       = "read",
35022a2bdcbSBlue Swirl     .altname    = "r",
35122a2bdcbSBlue Swirl     .cfunc      = read_f,
35222a2bdcbSBlue Swirl     .argmin     = 2,
35322a2bdcbSBlue Swirl     .argmax     = -1,
35422a2bdcbSBlue Swirl     .args       = "[-abCpqv] [-P pattern [-s off] [-l len]] off len",
35522a2bdcbSBlue Swirl     .oneline    = "reads a number of bytes at a specified offset",
35622a2bdcbSBlue Swirl     .help       = read_help,
35722a2bdcbSBlue Swirl };
35822a2bdcbSBlue Swirl 
35943642b38SDevin Nakamura static int read_f(int argc, char **argv)
360e3aff4f6Saliguori {
361e3aff4f6Saliguori     struct timeval t1, t2;
362e3aff4f6Saliguori     int Cflag = 0, pflag = 0, qflag = 0, vflag = 0;
363ca94dbc7SKevin Wolf     int Pflag = 0, sflag = 0, lflag = 0, bflag = 0;
364e3aff4f6Saliguori     int c, cnt;
365e3aff4f6Saliguori     char *buf;
366e3aff4f6Saliguori     int64_t offset;
367d4ec5228SPaul Brook     int count;
368d4ec5228SPaul Brook     /* Some compilers get confused and warn if this is not initialized.  */
369d4ec5228SPaul Brook     int total = 0;
370d9654a58SKevin Wolf     int pattern = 0, pattern_offset = 0, pattern_count = 0;
371e3aff4f6Saliguori 
372ca94dbc7SKevin Wolf     while ((c = getopt(argc, argv, "bCl:pP:qs:v")) != EOF) {
373e3aff4f6Saliguori         switch (c) {
374ca94dbc7SKevin Wolf         case 'b':
375ca94dbc7SKevin Wolf             bflag = 1;
376ca94dbc7SKevin Wolf             break;
377e3aff4f6Saliguori         case 'C':
378e3aff4f6Saliguori             Cflag = 1;
379e3aff4f6Saliguori             break;
380d9654a58SKevin Wolf         case 'l':
381d9654a58SKevin Wolf             lflag = 1;
382d9654a58SKevin Wolf             pattern_count = cvtnum(optarg);
383d9654a58SKevin Wolf             if (pattern_count < 0) {
384d9654a58SKevin Wolf                 printf("non-numeric length argument -- %s\n", optarg);
385d9654a58SKevin Wolf                 return 0;
386d9654a58SKevin Wolf             }
387d9654a58SKevin Wolf             break;
388e3aff4f6Saliguori         case 'p':
389e3aff4f6Saliguori             pflag = 1;
390e3aff4f6Saliguori             break;
391c48101aeSaliguori         case 'P':
392c48101aeSaliguori             Pflag = 1;
393cf070d7eSChristoph Hellwig             pattern = parse_pattern(optarg);
39443642b38SDevin Nakamura             if (pattern < 0) {
395cf070d7eSChristoph Hellwig                 return 0;
39643642b38SDevin Nakamura             }
397c48101aeSaliguori             break;
398e3aff4f6Saliguori         case 'q':
399e3aff4f6Saliguori             qflag = 1;
400e3aff4f6Saliguori             break;
401d9654a58SKevin Wolf         case 's':
402d9654a58SKevin Wolf             sflag = 1;
403d9654a58SKevin Wolf             pattern_offset = cvtnum(optarg);
404d9654a58SKevin Wolf             if (pattern_offset < 0) {
405d9654a58SKevin Wolf                 printf("non-numeric length argument -- %s\n", optarg);
406d9654a58SKevin Wolf                 return 0;
407d9654a58SKevin Wolf             }
408d9654a58SKevin Wolf             break;
409e3aff4f6Saliguori         case 'v':
410e3aff4f6Saliguori             vflag = 1;
411e3aff4f6Saliguori             break;
412e3aff4f6Saliguori         default:
413e3aff4f6Saliguori             return command_usage(&read_cmd);
414e3aff4f6Saliguori         }
415e3aff4f6Saliguori     }
416e3aff4f6Saliguori 
41743642b38SDevin Nakamura     if (optind != argc - 2) {
418e3aff4f6Saliguori         return command_usage(&read_cmd);
41943642b38SDevin Nakamura     }
420e3aff4f6Saliguori 
421ca94dbc7SKevin Wolf     if (bflag && pflag) {
422ca94dbc7SKevin Wolf         printf("-b and -p cannot be specified at the same time\n");
423ca94dbc7SKevin Wolf         return 0;
424ca94dbc7SKevin Wolf     }
425ca94dbc7SKevin Wolf 
426e3aff4f6Saliguori     offset = cvtnum(argv[optind]);
427e3aff4f6Saliguori     if (offset < 0) {
428e3aff4f6Saliguori         printf("non-numeric length argument -- %s\n", argv[optind]);
429e3aff4f6Saliguori         return 0;
430e3aff4f6Saliguori     }
431e3aff4f6Saliguori 
432e3aff4f6Saliguori     optind++;
433e3aff4f6Saliguori     count = cvtnum(argv[optind]);
434e3aff4f6Saliguori     if (count < 0) {
435e3aff4f6Saliguori         printf("non-numeric length argument -- %s\n", argv[optind]);
436e3aff4f6Saliguori         return 0;
437e3aff4f6Saliguori     }
438e3aff4f6Saliguori 
439d9654a58SKevin Wolf     if (!Pflag && (lflag || sflag)) {
440d9654a58SKevin Wolf         return command_usage(&read_cmd);
441d9654a58SKevin Wolf     }
442d9654a58SKevin Wolf 
443d9654a58SKevin Wolf     if (!lflag) {
444d9654a58SKevin Wolf         pattern_count = count - pattern_offset;
445d9654a58SKevin Wolf     }
446d9654a58SKevin Wolf 
447d9654a58SKevin Wolf     if ((pattern_count < 0) || (pattern_count + pattern_offset > count))  {
448d9654a58SKevin Wolf         printf("pattern verfication range exceeds end of read data\n");
449d9654a58SKevin Wolf         return 0;
450d9654a58SKevin Wolf     }
451d9654a58SKevin Wolf 
4525afc8b3dSDevin Nakamura     if (!pflag) {
453e3aff4f6Saliguori         if (offset & 0x1ff) {
4540bfcd599SBlue Swirl             printf("offset %" PRId64 " is not sector aligned\n",
4550bfcd599SBlue Swirl                    offset);
456e3aff4f6Saliguori             return 0;
45743642b38SDevin Nakamura         }
458e3aff4f6Saliguori         if (count & 0x1ff) {
459e3aff4f6Saliguori             printf("count %d is not sector aligned\n",
460e3aff4f6Saliguori                    count);
461e3aff4f6Saliguori             return 0;
462e3aff4f6Saliguori         }
4635afc8b3dSDevin Nakamura     }
464e3aff4f6Saliguori 
465e3aff4f6Saliguori     buf = qemu_io_alloc(count, 0xab);
466e3aff4f6Saliguori 
467e3aff4f6Saliguori     gettimeofday(&t1, NULL);
46843642b38SDevin Nakamura     if (pflag) {
469e3aff4f6Saliguori         cnt = do_pread(buf, offset, count, &total);
47043642b38SDevin Nakamura     } else if (bflag) {
471ca94dbc7SKevin Wolf         cnt = do_load_vmstate(buf, offset, count, &total);
47243642b38SDevin Nakamura     } else {
473e3aff4f6Saliguori         cnt = do_read(buf, offset, count, &total);
47443642b38SDevin Nakamura     }
475e3aff4f6Saliguori     gettimeofday(&t2, NULL);
476e3aff4f6Saliguori 
477e3aff4f6Saliguori     if (cnt < 0) {
478e3aff4f6Saliguori         printf("read failed: %s\n", strerror(-cnt));
4797d8abfcbSKevin Wolf         goto out;
480e3aff4f6Saliguori     }
481e3aff4f6Saliguori 
482c48101aeSaliguori     if (Pflag) {
483d9654a58SKevin Wolf         void *cmp_buf = malloc(pattern_count);
484d9654a58SKevin Wolf         memset(cmp_buf, pattern, pattern_count);
485d9654a58SKevin Wolf         if (memcmp(buf + pattern_offset, cmp_buf, pattern_count)) {
4860bfcd599SBlue Swirl             printf("Pattern verification failed at offset %"
4870bfcd599SBlue Swirl                    PRId64 ", %d bytes\n",
4880bfcd599SBlue Swirl                    offset + pattern_offset, pattern_count);
489c48101aeSaliguori         }
490c48101aeSaliguori         free(cmp_buf);
491c48101aeSaliguori     }
492c48101aeSaliguori 
49343642b38SDevin Nakamura     if (qflag) {
4947d8abfcbSKevin Wolf         goto out;
49543642b38SDevin Nakamura     }
496e3aff4f6Saliguori 
49743642b38SDevin Nakamura     if (vflag) {
498e3aff4f6Saliguori         dump_buffer(buf, offset, count);
49943642b38SDevin Nakamura     }
500e3aff4f6Saliguori 
501e3aff4f6Saliguori     /* Finally, report back -- -C gives a parsable format */
502e3aff4f6Saliguori     t2 = tsub(t2, t1);
503e3aff4f6Saliguori     print_report("read", &t2, offset, count, total, cnt, Cflag);
504e3aff4f6Saliguori 
5057d8abfcbSKevin Wolf out:
506e3aff4f6Saliguori     qemu_io_free(buf);
507e3aff4f6Saliguori 
508e3aff4f6Saliguori     return 0;
509e3aff4f6Saliguori }
510e3aff4f6Saliguori 
51143642b38SDevin Nakamura static void readv_help(void)
512e3aff4f6Saliguori {
513e3aff4f6Saliguori     printf(
514e3aff4f6Saliguori "\n"
515e3aff4f6Saliguori " reads a range of bytes from the given offset into multiple buffers\n"
516e3aff4f6Saliguori "\n"
517e3aff4f6Saliguori " Example:\n"
518e3aff4f6Saliguori " 'readv -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n"
519e3aff4f6Saliguori "\n"
520e3aff4f6Saliguori " Reads a segment of the currently open file, optionally dumping it to the\n"
521e3aff4f6Saliguori " standard output stream (with -v option) for subsequent inspection.\n"
522e3aff4f6Saliguori " Uses multiple iovec buffers if more than one byte range is specified.\n"
523e3aff4f6Saliguori " -C, -- report statistics in a machine parsable format\n"
524c48101aeSaliguori " -P, -- use a pattern to verify read data\n"
525e3aff4f6Saliguori " -v, -- dump buffer to standard output\n"
526095343adSKevin Wolf " -q, -- quiet mode, do not show I/O statistics\n"
527e3aff4f6Saliguori "\n");
528e3aff4f6Saliguori }
529e3aff4f6Saliguori 
53022a2bdcbSBlue Swirl static int readv_f(int argc, char **argv);
53122a2bdcbSBlue Swirl 
53222a2bdcbSBlue Swirl static const cmdinfo_t readv_cmd = {
53322a2bdcbSBlue Swirl     .name       = "readv",
53422a2bdcbSBlue Swirl     .cfunc      = readv_f,
53522a2bdcbSBlue Swirl     .argmin     = 2,
53622a2bdcbSBlue Swirl     .argmax     = -1,
53722a2bdcbSBlue Swirl     .args       = "[-Cqv] [-P pattern ] off len [len..]",
53822a2bdcbSBlue Swirl     .oneline    = "reads a number of bytes at a specified offset",
53922a2bdcbSBlue Swirl     .help       = readv_help,
54022a2bdcbSBlue Swirl };
54122a2bdcbSBlue Swirl 
54243642b38SDevin Nakamura static int readv_f(int argc, char **argv)
543e3aff4f6Saliguori {
544e3aff4f6Saliguori     struct timeval t1, t2;
545e3aff4f6Saliguori     int Cflag = 0, qflag = 0, vflag = 0;
546e3aff4f6Saliguori     int c, cnt;
547cf57298aSChristoph Hellwig     char *buf;
548e3aff4f6Saliguori     int64_t offset;
5496474bd69SBlue Swirl     /* Some compilers get confused and warn if this is not initialized.  */
5506474bd69SBlue Swirl     int total = 0;
551cf57298aSChristoph Hellwig     int nr_iov;
552e3aff4f6Saliguori     QEMUIOVector qiov;
553c48101aeSaliguori     int pattern = 0;
554c48101aeSaliguori     int Pflag = 0;
555e3aff4f6Saliguori 
556c48101aeSaliguori     while ((c = getopt(argc, argv, "CP:qv")) != EOF) {
557e3aff4f6Saliguori         switch (c) {
558e3aff4f6Saliguori         case 'C':
559e3aff4f6Saliguori             Cflag = 1;
560e3aff4f6Saliguori             break;
561c48101aeSaliguori         case 'P':
562c48101aeSaliguori             Pflag = 1;
563cf070d7eSChristoph Hellwig             pattern = parse_pattern(optarg);
56443642b38SDevin Nakamura             if (pattern < 0) {
565cf070d7eSChristoph Hellwig                 return 0;
56643642b38SDevin Nakamura             }
567c48101aeSaliguori             break;
568e3aff4f6Saliguori         case 'q':
569e3aff4f6Saliguori             qflag = 1;
570e3aff4f6Saliguori             break;
571e3aff4f6Saliguori         case 'v':
572e3aff4f6Saliguori             vflag = 1;
573e3aff4f6Saliguori             break;
574e3aff4f6Saliguori         default:
575e3aff4f6Saliguori             return command_usage(&readv_cmd);
576e3aff4f6Saliguori         }
577e3aff4f6Saliguori     }
578e3aff4f6Saliguori 
57943642b38SDevin Nakamura     if (optind > argc - 2) {
580e3aff4f6Saliguori         return command_usage(&readv_cmd);
58143642b38SDevin Nakamura     }
582e3aff4f6Saliguori 
583e3aff4f6Saliguori 
584e3aff4f6Saliguori     offset = cvtnum(argv[optind]);
585e3aff4f6Saliguori     if (offset < 0) {
586e3aff4f6Saliguori         printf("non-numeric length argument -- %s\n", argv[optind]);
587e3aff4f6Saliguori         return 0;
588e3aff4f6Saliguori     }
589e3aff4f6Saliguori     optind++;
590e3aff4f6Saliguori 
591e3aff4f6Saliguori     if (offset & 0x1ff) {
5920bfcd599SBlue Swirl         printf("offset %" PRId64 " is not sector aligned\n",
5930bfcd599SBlue Swirl                offset);
594e3aff4f6Saliguori         return 0;
595e3aff4f6Saliguori     }
596e3aff4f6Saliguori 
597e3aff4f6Saliguori     nr_iov = argc - optind;
598cf57298aSChristoph Hellwig     buf = create_iovec(&qiov, &argv[optind], nr_iov, 0xab);
599e3aff4f6Saliguori 
600e3aff4f6Saliguori     gettimeofday(&t1, NULL);
601e3aff4f6Saliguori     cnt = do_aio_readv(&qiov, offset, &total);
602e3aff4f6Saliguori     gettimeofday(&t2, NULL);
603e3aff4f6Saliguori 
604e3aff4f6Saliguori     if (cnt < 0) {
605e3aff4f6Saliguori         printf("readv failed: %s\n", strerror(-cnt));
6067d8abfcbSKevin Wolf         goto out;
607e3aff4f6Saliguori     }
608e3aff4f6Saliguori 
609c48101aeSaliguori     if (Pflag) {
610cf57298aSChristoph Hellwig         void *cmp_buf = malloc(qiov.size);
611cf57298aSChristoph Hellwig         memset(cmp_buf, pattern, qiov.size);
612cf57298aSChristoph Hellwig         if (memcmp(buf, cmp_buf, qiov.size)) {
6130bfcd599SBlue Swirl             printf("Pattern verification failed at offset %"
61443642b38SDevin Nakamura                    PRId64 ", %zd bytes\n", offset, qiov.size);
615c48101aeSaliguori         }
616c48101aeSaliguori         free(cmp_buf);
617c48101aeSaliguori     }
618c48101aeSaliguori 
61943642b38SDevin Nakamura     if (qflag) {
6207d8abfcbSKevin Wolf         goto out;
62143642b38SDevin Nakamura     }
622e3aff4f6Saliguori 
62343642b38SDevin Nakamura     if (vflag) {
624e3aff4f6Saliguori         dump_buffer(buf, offset, qiov.size);
62543642b38SDevin Nakamura     }
626e3aff4f6Saliguori 
627e3aff4f6Saliguori     /* Finally, report back -- -C gives a parsable format */
628e3aff4f6Saliguori     t2 = tsub(t2, t1);
629e3aff4f6Saliguori     print_report("read", &t2, offset, qiov.size, total, cnt, Cflag);
630e3aff4f6Saliguori 
6317d8abfcbSKevin Wolf out:
632e3aff4f6Saliguori     qemu_io_free(buf);
633e3aff4f6Saliguori     return 0;
634e3aff4f6Saliguori }
635e3aff4f6Saliguori 
63643642b38SDevin Nakamura static void write_help(void)
637e3aff4f6Saliguori {
638e3aff4f6Saliguori     printf(
639e3aff4f6Saliguori "\n"
640e3aff4f6Saliguori " writes a range of bytes from the given offset\n"
641e3aff4f6Saliguori "\n"
642e3aff4f6Saliguori " Example:\n"
643e3aff4f6Saliguori " 'write 512 1k' - writes 1 kilobyte at 512 bytes into the open file\n"
644e3aff4f6Saliguori "\n"
645e3aff4f6Saliguori " Writes into a segment of the currently open file, using a buffer\n"
646e3aff4f6Saliguori " filled with a set pattern (0xcdcdcdcd).\n"
647ca94dbc7SKevin Wolf " -b, -- write to the VM state rather than the virtual disk\n"
648e3aff4f6Saliguori " -p, -- use bdrv_pwrite to write the file\n"
649e3aff4f6Saliguori " -P, -- use different pattern to fill file\n"
650e3aff4f6Saliguori " -C, -- report statistics in a machine parsable format\n"
651095343adSKevin Wolf " -q, -- quiet mode, do not show I/O statistics\n"
652e3aff4f6Saliguori "\n");
653e3aff4f6Saliguori }
654e3aff4f6Saliguori 
65522a2bdcbSBlue Swirl static int write_f(int argc, char **argv);
65622a2bdcbSBlue Swirl 
65722a2bdcbSBlue Swirl static const cmdinfo_t write_cmd = {
65822a2bdcbSBlue Swirl     .name       = "write",
65922a2bdcbSBlue Swirl     .altname    = "w",
66022a2bdcbSBlue Swirl     .cfunc      = write_f,
66122a2bdcbSBlue Swirl     .argmin     = 2,
66222a2bdcbSBlue Swirl     .argmax     = -1,
66322a2bdcbSBlue Swirl     .args       = "[-abCpq] [-P pattern ] off len",
66422a2bdcbSBlue Swirl     .oneline    = "writes a number of bytes at a specified offset",
66522a2bdcbSBlue Swirl     .help       = write_help,
66622a2bdcbSBlue Swirl };
66722a2bdcbSBlue Swirl 
66843642b38SDevin Nakamura static int write_f(int argc, char **argv)
669e3aff4f6Saliguori {
670e3aff4f6Saliguori     struct timeval t1, t2;
671ca94dbc7SKevin Wolf     int Cflag = 0, pflag = 0, qflag = 0, bflag = 0;
672e3aff4f6Saliguori     int c, cnt;
673e3aff4f6Saliguori     char *buf;
674e3aff4f6Saliguori     int64_t offset;
675d4ec5228SPaul Brook     int count;
676d4ec5228SPaul Brook     /* Some compilers get confused and warn if this is not initialized.  */
677d4ec5228SPaul Brook     int total = 0;
678e3aff4f6Saliguori     int pattern = 0xcd;
679e3aff4f6Saliguori 
680ca94dbc7SKevin Wolf     while ((c = getopt(argc, argv, "bCpP:q")) != EOF) {
681e3aff4f6Saliguori         switch (c) {
682ca94dbc7SKevin Wolf         case 'b':
683ca94dbc7SKevin Wolf             bflag = 1;
684ca94dbc7SKevin Wolf             break;
685e3aff4f6Saliguori         case 'C':
686e3aff4f6Saliguori             Cflag = 1;
687e3aff4f6Saliguori             break;
688e3aff4f6Saliguori         case 'p':
689e3aff4f6Saliguori             pflag = 1;
690e3aff4f6Saliguori             break;
691e3aff4f6Saliguori         case 'P':
692cf070d7eSChristoph Hellwig             pattern = parse_pattern(optarg);
69343642b38SDevin Nakamura             if (pattern < 0) {
694cf070d7eSChristoph Hellwig                 return 0;
69543642b38SDevin Nakamura             }
696e3aff4f6Saliguori             break;
697e3aff4f6Saliguori         case 'q':
698e3aff4f6Saliguori             qflag = 1;
699e3aff4f6Saliguori             break;
700e3aff4f6Saliguori         default:
701e3aff4f6Saliguori             return command_usage(&write_cmd);
702e3aff4f6Saliguori         }
703e3aff4f6Saliguori     }
704e3aff4f6Saliguori 
70543642b38SDevin Nakamura     if (optind != argc - 2) {
706e3aff4f6Saliguori         return command_usage(&write_cmd);
70743642b38SDevin Nakamura     }
708e3aff4f6Saliguori 
709ca94dbc7SKevin Wolf     if (bflag && pflag) {
710ca94dbc7SKevin Wolf         printf("-b and -p cannot be specified at the same time\n");
711ca94dbc7SKevin Wolf         return 0;
712ca94dbc7SKevin Wolf     }
713ca94dbc7SKevin Wolf 
714e3aff4f6Saliguori     offset = cvtnum(argv[optind]);
715e3aff4f6Saliguori     if (offset < 0) {
716e3aff4f6Saliguori         printf("non-numeric length argument -- %s\n", argv[optind]);
717e3aff4f6Saliguori         return 0;
718e3aff4f6Saliguori     }
719e3aff4f6Saliguori 
720e3aff4f6Saliguori     optind++;
721e3aff4f6Saliguori     count = cvtnum(argv[optind]);
722e3aff4f6Saliguori     if (count < 0) {
723e3aff4f6Saliguori         printf("non-numeric length argument -- %s\n", argv[optind]);
724e3aff4f6Saliguori         return 0;
725e3aff4f6Saliguori     }
726e3aff4f6Saliguori 
727e3aff4f6Saliguori     if (!pflag) {
728e3aff4f6Saliguori         if (offset & 0x1ff) {
7290bfcd599SBlue Swirl             printf("offset %" PRId64 " is not sector aligned\n",
7300bfcd599SBlue Swirl                    offset);
731e3aff4f6Saliguori             return 0;
732e3aff4f6Saliguori         }
733e3aff4f6Saliguori 
734e3aff4f6Saliguori         if (count & 0x1ff) {
735e3aff4f6Saliguori             printf("count %d is not sector aligned\n",
736e3aff4f6Saliguori                    count);
737e3aff4f6Saliguori             return 0;
738e3aff4f6Saliguori         }
739e3aff4f6Saliguori     }
740e3aff4f6Saliguori 
741e3aff4f6Saliguori     buf = qemu_io_alloc(count, pattern);
742e3aff4f6Saliguori 
743e3aff4f6Saliguori     gettimeofday(&t1, NULL);
74443642b38SDevin Nakamura     if (pflag) {
745e3aff4f6Saliguori         cnt = do_pwrite(buf, offset, count, &total);
74643642b38SDevin Nakamura     } else if (bflag) {
747ca94dbc7SKevin Wolf         cnt = do_save_vmstate(buf, offset, count, &total);
74843642b38SDevin Nakamura     } else {
749e3aff4f6Saliguori         cnt = do_write(buf, offset, count, &total);
75043642b38SDevin Nakamura     }
751e3aff4f6Saliguori     gettimeofday(&t2, NULL);
752e3aff4f6Saliguori 
753e3aff4f6Saliguori     if (cnt < 0) {
754e3aff4f6Saliguori         printf("write failed: %s\n", strerror(-cnt));
7557d8abfcbSKevin Wolf         goto out;
756e3aff4f6Saliguori     }
757e3aff4f6Saliguori 
75843642b38SDevin Nakamura     if (qflag) {
7597d8abfcbSKevin Wolf         goto out;
76043642b38SDevin Nakamura     }
761e3aff4f6Saliguori 
762e3aff4f6Saliguori     /* Finally, report back -- -C gives a parsable format */
763e3aff4f6Saliguori     t2 = tsub(t2, t1);
764e3aff4f6Saliguori     print_report("wrote", &t2, offset, count, total, cnt, Cflag);
765e3aff4f6Saliguori 
7667d8abfcbSKevin Wolf out:
767e3aff4f6Saliguori     qemu_io_free(buf);
768e3aff4f6Saliguori 
769e3aff4f6Saliguori     return 0;
770e3aff4f6Saliguori }
771e3aff4f6Saliguori 
772e3aff4f6Saliguori static void
773e3aff4f6Saliguori writev_help(void)
774e3aff4f6Saliguori {
775e3aff4f6Saliguori     printf(
776e3aff4f6Saliguori "\n"
777e3aff4f6Saliguori " writes a range of bytes from the given offset source from multiple buffers\n"
778e3aff4f6Saliguori "\n"
779e3aff4f6Saliguori " Example:\n"
780e3aff4f6Saliguori " 'write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n"
781e3aff4f6Saliguori "\n"
782e3aff4f6Saliguori " Writes into a segment of the currently open file, using a buffer\n"
783e3aff4f6Saliguori " filled with a set pattern (0xcdcdcdcd).\n"
784e3aff4f6Saliguori " -P, -- use different pattern to fill file\n"
785e3aff4f6Saliguori " -C, -- report statistics in a machine parsable format\n"
786095343adSKevin Wolf " -q, -- quiet mode, do not show I/O statistics\n"
787e3aff4f6Saliguori "\n");
788e3aff4f6Saliguori }
789e3aff4f6Saliguori 
79022a2bdcbSBlue Swirl static int writev_f(int argc, char **argv);
79122a2bdcbSBlue Swirl 
79222a2bdcbSBlue Swirl static const cmdinfo_t writev_cmd = {
79322a2bdcbSBlue Swirl     .name       = "writev",
79422a2bdcbSBlue Swirl     .cfunc      = writev_f,
79522a2bdcbSBlue Swirl     .argmin     = 2,
79622a2bdcbSBlue Swirl     .argmax     = -1,
79722a2bdcbSBlue Swirl     .args       = "[-Cq] [-P pattern ] off len [len..]",
79822a2bdcbSBlue Swirl     .oneline    = "writes a number of bytes at a specified offset",
79922a2bdcbSBlue Swirl     .help       = writev_help,
80022a2bdcbSBlue Swirl };
80122a2bdcbSBlue Swirl 
80243642b38SDevin Nakamura static int writev_f(int argc, char **argv)
803e3aff4f6Saliguori {
804e3aff4f6Saliguori     struct timeval t1, t2;
805e3aff4f6Saliguori     int Cflag = 0, qflag = 0;
806e3aff4f6Saliguori     int c, cnt;
807cf57298aSChristoph Hellwig     char *buf;
808e3aff4f6Saliguori     int64_t offset;
8096474bd69SBlue Swirl     /* Some compilers get confused and warn if this is not initialized.  */
8106474bd69SBlue Swirl     int total = 0;
811cf57298aSChristoph Hellwig     int nr_iov;
812e3aff4f6Saliguori     int pattern = 0xcd;
813e3aff4f6Saliguori     QEMUIOVector qiov;
814e3aff4f6Saliguori 
815e3aff4f6Saliguori     while ((c = getopt(argc, argv, "CqP:")) != EOF) {
816e3aff4f6Saliguori         switch (c) {
817e3aff4f6Saliguori         case 'C':
818e3aff4f6Saliguori             Cflag = 1;
819e3aff4f6Saliguori             break;
820e3aff4f6Saliguori         case 'q':
821e3aff4f6Saliguori             qflag = 1;
822e3aff4f6Saliguori             break;
823e3aff4f6Saliguori         case 'P':
824cf070d7eSChristoph Hellwig             pattern = parse_pattern(optarg);
82543642b38SDevin Nakamura             if (pattern < 0) {
826cf070d7eSChristoph Hellwig                 return 0;
82743642b38SDevin Nakamura             }
828e3aff4f6Saliguori             break;
829e3aff4f6Saliguori         default:
830e3aff4f6Saliguori             return command_usage(&writev_cmd);
831e3aff4f6Saliguori         }
832e3aff4f6Saliguori     }
833e3aff4f6Saliguori 
83443642b38SDevin Nakamura     if (optind > argc - 2) {
835e3aff4f6Saliguori         return command_usage(&writev_cmd);
83643642b38SDevin Nakamura     }
837e3aff4f6Saliguori 
838e3aff4f6Saliguori     offset = cvtnum(argv[optind]);
839e3aff4f6Saliguori     if (offset < 0) {
840e3aff4f6Saliguori         printf("non-numeric length argument -- %s\n", argv[optind]);
841e3aff4f6Saliguori         return 0;
842e3aff4f6Saliguori     }
843e3aff4f6Saliguori     optind++;
844e3aff4f6Saliguori 
845e3aff4f6Saliguori     if (offset & 0x1ff) {
8460bfcd599SBlue Swirl         printf("offset %" PRId64 " is not sector aligned\n",
8470bfcd599SBlue Swirl                offset);
848e3aff4f6Saliguori         return 0;
849e3aff4f6Saliguori     }
850e3aff4f6Saliguori 
851e3aff4f6Saliguori     nr_iov = argc - optind;
852cf57298aSChristoph Hellwig     buf = create_iovec(&qiov, &argv[optind], nr_iov, pattern);
853e3aff4f6Saliguori 
854e3aff4f6Saliguori     gettimeofday(&t1, NULL);
855e3aff4f6Saliguori     cnt = do_aio_writev(&qiov, offset, &total);
856e3aff4f6Saliguori     gettimeofday(&t2, NULL);
857e3aff4f6Saliguori 
858e3aff4f6Saliguori     if (cnt < 0) {
859e3aff4f6Saliguori         printf("writev failed: %s\n", strerror(-cnt));
8607d8abfcbSKevin Wolf         goto out;
861e3aff4f6Saliguori     }
862e3aff4f6Saliguori 
86343642b38SDevin Nakamura     if (qflag) {
8647d8abfcbSKevin Wolf         goto out;
86543642b38SDevin Nakamura     }
866e3aff4f6Saliguori 
867e3aff4f6Saliguori     /* Finally, report back -- -C gives a parsable format */
868e3aff4f6Saliguori     t2 = tsub(t2, t1);
869e3aff4f6Saliguori     print_report("wrote", &t2, offset, qiov.size, total, cnt, Cflag);
8707d8abfcbSKevin Wolf out:
871e3aff4f6Saliguori     qemu_io_free(buf);
872e3aff4f6Saliguori     return 0;
873e3aff4f6Saliguori }
874e3aff4f6Saliguori 
87543642b38SDevin Nakamura static void multiwrite_help(void)
876776cbbbdSKevin Wolf {
877776cbbbdSKevin Wolf     printf(
878776cbbbdSKevin Wolf "\n"
879776cbbbdSKevin Wolf " writes a range of bytes from the given offset source from multiple buffers,\n"
880776cbbbdSKevin Wolf " in a batch of requests that may be merged by qemu\n"
881776cbbbdSKevin Wolf "\n"
882776cbbbdSKevin Wolf " Example:\n"
883776cbbbdSKevin Wolf " 'multiwrite 512 1k 1k ; 4k 1k'\n"
884776cbbbdSKevin Wolf "  writes 2 kB at 512 bytes and 1 kB at 4 kB into the open file\n"
885776cbbbdSKevin Wolf "\n"
886776cbbbdSKevin Wolf " Writes into a segment of the currently open file, using a buffer\n"
887776cbbbdSKevin Wolf " filled with a set pattern (0xcdcdcdcd). The pattern byte is increased\n"
888776cbbbdSKevin Wolf " by one for each request contained in the multiwrite command.\n"
889776cbbbdSKevin Wolf " -P, -- use different pattern to fill file\n"
890776cbbbdSKevin Wolf " -C, -- report statistics in a machine parsable format\n"
891776cbbbdSKevin Wolf " -q, -- quiet mode, do not show I/O statistics\n"
892776cbbbdSKevin Wolf "\n");
893776cbbbdSKevin Wolf }
894776cbbbdSKevin Wolf 
895776cbbbdSKevin Wolf static int multiwrite_f(int argc, char **argv);
896776cbbbdSKevin Wolf 
897776cbbbdSKevin Wolf static const cmdinfo_t multiwrite_cmd = {
898776cbbbdSKevin Wolf     .name       = "multiwrite",
899776cbbbdSKevin Wolf     .cfunc      = multiwrite_f,
900776cbbbdSKevin Wolf     .argmin     = 2,
901776cbbbdSKevin Wolf     .argmax     = -1,
902776cbbbdSKevin Wolf     .args       = "[-Cq] [-P pattern ] off len [len..] [; off len [len..]..]",
903776cbbbdSKevin Wolf     .oneline    = "issues multiple write requests at once",
904776cbbbdSKevin Wolf     .help       = multiwrite_help,
905776cbbbdSKevin Wolf };
906776cbbbdSKevin Wolf 
90743642b38SDevin Nakamura static int multiwrite_f(int argc, char **argv)
908776cbbbdSKevin Wolf {
909776cbbbdSKevin Wolf     struct timeval t1, t2;
910776cbbbdSKevin Wolf     int Cflag = 0, qflag = 0;
911776cbbbdSKevin Wolf     int c, cnt;
912776cbbbdSKevin Wolf     char **buf;
913776cbbbdSKevin Wolf     int64_t offset, first_offset = 0;
914776cbbbdSKevin Wolf     /* Some compilers get confused and warn if this is not initialized.  */
915776cbbbdSKevin Wolf     int total = 0;
916776cbbbdSKevin Wolf     int nr_iov;
917776cbbbdSKevin Wolf     int nr_reqs;
918776cbbbdSKevin Wolf     int pattern = 0xcd;
919776cbbbdSKevin Wolf     QEMUIOVector *qiovs;
920776cbbbdSKevin Wolf     int i;
921776cbbbdSKevin Wolf     BlockRequest *reqs;
922776cbbbdSKevin Wolf 
923776cbbbdSKevin Wolf     while ((c = getopt(argc, argv, "CqP:")) != EOF) {
924776cbbbdSKevin Wolf         switch (c) {
925776cbbbdSKevin Wolf         case 'C':
926776cbbbdSKevin Wolf             Cflag = 1;
927776cbbbdSKevin Wolf             break;
928776cbbbdSKevin Wolf         case 'q':
929776cbbbdSKevin Wolf             qflag = 1;
930776cbbbdSKevin Wolf             break;
931776cbbbdSKevin Wolf         case 'P':
932776cbbbdSKevin Wolf             pattern = parse_pattern(optarg);
93343642b38SDevin Nakamura             if (pattern < 0) {
934776cbbbdSKevin Wolf                 return 0;
93543642b38SDevin Nakamura             }
936776cbbbdSKevin Wolf             break;
937776cbbbdSKevin Wolf         default:
938776cbbbdSKevin Wolf             return command_usage(&writev_cmd);
939776cbbbdSKevin Wolf         }
940776cbbbdSKevin Wolf     }
941776cbbbdSKevin Wolf 
94243642b38SDevin Nakamura     if (optind > argc - 2) {
943776cbbbdSKevin Wolf         return command_usage(&writev_cmd);
94443642b38SDevin Nakamura     }
945776cbbbdSKevin Wolf 
946776cbbbdSKevin Wolf     nr_reqs = 1;
947776cbbbdSKevin Wolf     for (i = optind; i < argc; i++) {
948776cbbbdSKevin Wolf         if (!strcmp(argv[i], ";")) {
949776cbbbdSKevin Wolf             nr_reqs++;
950776cbbbdSKevin Wolf         }
951776cbbbdSKevin Wolf     }
952776cbbbdSKevin Wolf 
9537267c094SAnthony Liguori     reqs = g_malloc(nr_reqs * sizeof(*reqs));
9547267c094SAnthony Liguori     buf = g_malloc(nr_reqs * sizeof(*buf));
9557267c094SAnthony Liguori     qiovs = g_malloc(nr_reqs * sizeof(*qiovs));
956776cbbbdSKevin Wolf 
957776cbbbdSKevin Wolf     for (i = 0; i < nr_reqs; i++) {
958776cbbbdSKevin Wolf         int j;
959776cbbbdSKevin Wolf 
960776cbbbdSKevin Wolf         /* Read the offset of the request */
961776cbbbdSKevin Wolf         offset = cvtnum(argv[optind]);
962776cbbbdSKevin Wolf         if (offset < 0) {
963776cbbbdSKevin Wolf             printf("non-numeric offset argument -- %s\n", argv[optind]);
964776cbbbdSKevin Wolf             return 0;
965776cbbbdSKevin Wolf         }
966776cbbbdSKevin Wolf         optind++;
967776cbbbdSKevin Wolf 
968776cbbbdSKevin Wolf         if (offset & 0x1ff) {
969776cbbbdSKevin Wolf             printf("offset %lld is not sector aligned\n",
970776cbbbdSKevin Wolf                    (long long)offset);
971776cbbbdSKevin Wolf             return 0;
972776cbbbdSKevin Wolf         }
973776cbbbdSKevin Wolf 
974776cbbbdSKevin Wolf         if (i == 0) {
975776cbbbdSKevin Wolf             first_offset = offset;
976776cbbbdSKevin Wolf         }
977776cbbbdSKevin Wolf 
978776cbbbdSKevin Wolf         /* Read lengths for qiov entries */
979776cbbbdSKevin Wolf         for (j = optind; j < argc; j++) {
980776cbbbdSKevin Wolf             if (!strcmp(argv[j], ";")) {
981776cbbbdSKevin Wolf                 break;
982776cbbbdSKevin Wolf             }
983776cbbbdSKevin Wolf         }
984776cbbbdSKevin Wolf 
985776cbbbdSKevin Wolf         nr_iov = j - optind;
986776cbbbdSKevin Wolf 
987776cbbbdSKevin Wolf         /* Build request */
988776cbbbdSKevin Wolf         reqs[i].qiov = &qiovs[i];
989776cbbbdSKevin Wolf         buf[i] = create_iovec(reqs[i].qiov, &argv[optind], nr_iov, pattern);
990776cbbbdSKevin Wolf         reqs[i].sector = offset >> 9;
991776cbbbdSKevin Wolf         reqs[i].nb_sectors = reqs[i].qiov->size >> 9;
992776cbbbdSKevin Wolf 
993776cbbbdSKevin Wolf         optind = j + 1;
994776cbbbdSKevin Wolf 
995776cbbbdSKevin Wolf         pattern++;
996776cbbbdSKevin Wolf     }
997776cbbbdSKevin Wolf 
998776cbbbdSKevin Wolf     gettimeofday(&t1, NULL);
999776cbbbdSKevin Wolf     cnt = do_aio_multiwrite(reqs, nr_reqs, &total);
1000776cbbbdSKevin Wolf     gettimeofday(&t2, NULL);
1001776cbbbdSKevin Wolf 
1002776cbbbdSKevin Wolf     if (cnt < 0) {
1003776cbbbdSKevin Wolf         printf("aio_multiwrite failed: %s\n", strerror(-cnt));
1004776cbbbdSKevin Wolf         goto out;
1005776cbbbdSKevin Wolf     }
1006776cbbbdSKevin Wolf 
100743642b38SDevin Nakamura     if (qflag) {
1008776cbbbdSKevin Wolf         goto out;
100943642b38SDevin Nakamura     }
1010776cbbbdSKevin Wolf 
1011776cbbbdSKevin Wolf     /* Finally, report back -- -C gives a parsable format */
1012776cbbbdSKevin Wolf     t2 = tsub(t2, t1);
1013776cbbbdSKevin Wolf     print_report("wrote", &t2, first_offset, total, total, cnt, Cflag);
1014776cbbbdSKevin Wolf out:
1015776cbbbdSKevin Wolf     for (i = 0; i < nr_reqs; i++) {
1016776cbbbdSKevin Wolf         qemu_io_free(buf[i]);
1017776cbbbdSKevin Wolf         qemu_iovec_destroy(&qiovs[i]);
1018776cbbbdSKevin Wolf     }
10197267c094SAnthony Liguori     g_free(buf);
10207267c094SAnthony Liguori     g_free(reqs);
10217267c094SAnthony Liguori     g_free(qiovs);
1022776cbbbdSKevin Wolf     return 0;
1023776cbbbdSKevin Wolf }
1024776cbbbdSKevin Wolf 
102595533d5fSChristoph Hellwig struct aio_ctx {
102695533d5fSChristoph Hellwig     QEMUIOVector qiov;
102795533d5fSChristoph Hellwig     int64_t offset;
102895533d5fSChristoph Hellwig     char *buf;
102995533d5fSChristoph Hellwig     int qflag;
103095533d5fSChristoph Hellwig     int vflag;
103195533d5fSChristoph Hellwig     int Cflag;
103295533d5fSChristoph Hellwig     int Pflag;
103395533d5fSChristoph Hellwig     int pattern;
103495533d5fSChristoph Hellwig     struct timeval t1;
103595533d5fSChristoph Hellwig };
103695533d5fSChristoph Hellwig 
103743642b38SDevin Nakamura static void aio_write_done(void *opaque, int ret)
103895533d5fSChristoph Hellwig {
103995533d5fSChristoph Hellwig     struct aio_ctx *ctx = opaque;
104095533d5fSChristoph Hellwig     struct timeval t2;
104195533d5fSChristoph Hellwig 
104295533d5fSChristoph Hellwig     gettimeofday(&t2, NULL);
104395533d5fSChristoph Hellwig 
104495533d5fSChristoph Hellwig 
104595533d5fSChristoph Hellwig     if (ret < 0) {
104695533d5fSChristoph Hellwig         printf("aio_write failed: %s\n", strerror(-ret));
10477d8abfcbSKevin Wolf         goto out;
104895533d5fSChristoph Hellwig     }
104995533d5fSChristoph Hellwig 
1050230d4fa4SChristoph Hellwig     if (ctx->qflag) {
10517d8abfcbSKevin Wolf         goto out;
1052230d4fa4SChristoph Hellwig     }
105395533d5fSChristoph Hellwig 
105495533d5fSChristoph Hellwig     /* Finally, report back -- -C gives a parsable format */
105595533d5fSChristoph Hellwig     t2 = tsub(t2, ctx->t1);
1056230d4fa4SChristoph Hellwig     print_report("wrote", &t2, ctx->offset, ctx->qiov.size,
1057230d4fa4SChristoph Hellwig                  ctx->qiov.size, 1, ctx->Cflag);
10587d8abfcbSKevin Wolf out:
105995533d5fSChristoph Hellwig     qemu_io_free(ctx->buf);
106095533d5fSChristoph Hellwig     free(ctx);
106195533d5fSChristoph Hellwig }
106295533d5fSChristoph Hellwig 
106343642b38SDevin Nakamura static void aio_read_done(void *opaque, int ret)
106495533d5fSChristoph Hellwig {
106595533d5fSChristoph Hellwig     struct aio_ctx *ctx = opaque;
106695533d5fSChristoph Hellwig     struct timeval t2;
106795533d5fSChristoph Hellwig 
106895533d5fSChristoph Hellwig     gettimeofday(&t2, NULL);
106995533d5fSChristoph Hellwig 
107095533d5fSChristoph Hellwig     if (ret < 0) {
107195533d5fSChristoph Hellwig         printf("readv failed: %s\n", strerror(-ret));
10727d8abfcbSKevin Wolf         goto out;
107395533d5fSChristoph Hellwig     }
107495533d5fSChristoph Hellwig 
107595533d5fSChristoph Hellwig     if (ctx->Pflag) {
1076230d4fa4SChristoph Hellwig         void *cmp_buf = malloc(ctx->qiov.size);
107795533d5fSChristoph Hellwig 
1078230d4fa4SChristoph Hellwig         memset(cmp_buf, ctx->pattern, ctx->qiov.size);
1079230d4fa4SChristoph Hellwig         if (memcmp(ctx->buf, cmp_buf, ctx->qiov.size)) {
10800bfcd599SBlue Swirl             printf("Pattern verification failed at offset %"
108143642b38SDevin Nakamura                    PRId64 ", %zd bytes\n", ctx->offset, ctx->qiov.size);
108295533d5fSChristoph Hellwig         }
108395533d5fSChristoph Hellwig         free(cmp_buf);
108495533d5fSChristoph Hellwig     }
108595533d5fSChristoph Hellwig 
1086230d4fa4SChristoph Hellwig     if (ctx->qflag) {
10877d8abfcbSKevin Wolf         goto out;
1088230d4fa4SChristoph Hellwig     }
108995533d5fSChristoph Hellwig 
1090230d4fa4SChristoph Hellwig     if (ctx->vflag) {
1091230d4fa4SChristoph Hellwig         dump_buffer(ctx->buf, ctx->offset, ctx->qiov.size);
1092230d4fa4SChristoph Hellwig     }
109395533d5fSChristoph Hellwig 
109495533d5fSChristoph Hellwig     /* Finally, report back -- -C gives a parsable format */
109595533d5fSChristoph Hellwig     t2 = tsub(t2, ctx->t1);
1096230d4fa4SChristoph Hellwig     print_report("read", &t2, ctx->offset, ctx->qiov.size,
1097230d4fa4SChristoph Hellwig                  ctx->qiov.size, 1, ctx->Cflag);
10987d8abfcbSKevin Wolf out:
109995533d5fSChristoph Hellwig     qemu_io_free(ctx->buf);
110095533d5fSChristoph Hellwig     free(ctx);
110195533d5fSChristoph Hellwig }
110295533d5fSChristoph Hellwig 
110343642b38SDevin Nakamura static void aio_read_help(void)
110495533d5fSChristoph Hellwig {
110595533d5fSChristoph Hellwig     printf(
110695533d5fSChristoph Hellwig "\n"
110795533d5fSChristoph Hellwig " asynchronously reads a range of bytes from the given offset\n"
110895533d5fSChristoph Hellwig "\n"
110995533d5fSChristoph Hellwig " Example:\n"
111095533d5fSChristoph Hellwig " 'aio_read -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n"
111195533d5fSChristoph Hellwig "\n"
111295533d5fSChristoph Hellwig " Reads a segment of the currently open file, optionally dumping it to the\n"
111395533d5fSChristoph Hellwig " standard output stream (with -v option) for subsequent inspection.\n"
1114e432cef9SChristoph Hellwig " The read is performed asynchronously and the aio_flush command must be\n"
1115e432cef9SChristoph Hellwig " used to ensure all outstanding aio requests have been completed\n"
111695533d5fSChristoph Hellwig " -C, -- report statistics in a machine parsable format\n"
111795533d5fSChristoph Hellwig " -P, -- use a pattern to verify read data\n"
111895533d5fSChristoph Hellwig " -v, -- dump buffer to standard output\n"
1119095343adSKevin Wolf " -q, -- quiet mode, do not show I/O statistics\n"
112095533d5fSChristoph Hellwig "\n");
112195533d5fSChristoph Hellwig }
112295533d5fSChristoph Hellwig 
112322a2bdcbSBlue Swirl static int aio_read_f(int argc, char **argv);
112422a2bdcbSBlue Swirl 
112522a2bdcbSBlue Swirl static const cmdinfo_t aio_read_cmd = {
112622a2bdcbSBlue Swirl     .name       = "aio_read",
112722a2bdcbSBlue Swirl     .cfunc      = aio_read_f,
112822a2bdcbSBlue Swirl     .argmin     = 2,
112922a2bdcbSBlue Swirl     .argmax     = -1,
113022a2bdcbSBlue Swirl     .args       = "[-Cqv] [-P pattern ] off len [len..]",
113122a2bdcbSBlue Swirl     .oneline    = "asynchronously reads a number of bytes",
113222a2bdcbSBlue Swirl     .help       = aio_read_help,
113322a2bdcbSBlue Swirl };
113422a2bdcbSBlue Swirl 
113543642b38SDevin Nakamura static int aio_read_f(int argc, char **argv)
113695533d5fSChristoph Hellwig {
1137cf57298aSChristoph Hellwig     int nr_iov, c;
113895533d5fSChristoph Hellwig     struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx));
113995533d5fSChristoph Hellwig     BlockDriverAIOCB *acb;
114095533d5fSChristoph Hellwig 
114195533d5fSChristoph Hellwig     while ((c = getopt(argc, argv, "CP:qv")) != EOF) {
114295533d5fSChristoph Hellwig         switch (c) {
114395533d5fSChristoph Hellwig         case 'C':
114495533d5fSChristoph Hellwig             ctx->Cflag = 1;
114595533d5fSChristoph Hellwig             break;
114695533d5fSChristoph Hellwig         case 'P':
114795533d5fSChristoph Hellwig             ctx->Pflag = 1;
1148cf070d7eSChristoph Hellwig             ctx->pattern = parse_pattern(optarg);
11491afec913SBlue Swirl             if (ctx->pattern < 0) {
11501afec913SBlue Swirl                 free(ctx);
1151cf070d7eSChristoph Hellwig                 return 0;
11521afec913SBlue Swirl             }
115395533d5fSChristoph Hellwig             break;
115495533d5fSChristoph Hellwig         case 'q':
115595533d5fSChristoph Hellwig             ctx->qflag = 1;
115695533d5fSChristoph Hellwig             break;
115795533d5fSChristoph Hellwig         case 'v':
115895533d5fSChristoph Hellwig             ctx->vflag = 1;
115995533d5fSChristoph Hellwig             break;
116095533d5fSChristoph Hellwig         default:
11617d8abfcbSKevin Wolf             free(ctx);
116295533d5fSChristoph Hellwig             return command_usage(&aio_read_cmd);
116395533d5fSChristoph Hellwig         }
116495533d5fSChristoph Hellwig     }
116595533d5fSChristoph Hellwig 
11667d8abfcbSKevin Wolf     if (optind > argc - 2) {
11677d8abfcbSKevin Wolf         free(ctx);
116895533d5fSChristoph Hellwig         return command_usage(&aio_read_cmd);
11697d8abfcbSKevin Wolf     }
117095533d5fSChristoph Hellwig 
117195533d5fSChristoph Hellwig     ctx->offset = cvtnum(argv[optind]);
117295533d5fSChristoph Hellwig     if (ctx->offset < 0) {
117395533d5fSChristoph Hellwig         printf("non-numeric length argument -- %s\n", argv[optind]);
11747d8abfcbSKevin Wolf         free(ctx);
117595533d5fSChristoph Hellwig         return 0;
117695533d5fSChristoph Hellwig     }
117795533d5fSChristoph Hellwig     optind++;
117895533d5fSChristoph Hellwig 
117995533d5fSChristoph Hellwig     if (ctx->offset & 0x1ff) {
11800bfcd599SBlue Swirl         printf("offset %" PRId64 " is not sector aligned\n",
11810bfcd599SBlue Swirl                ctx->offset);
11827d8abfcbSKevin Wolf         free(ctx);
118395533d5fSChristoph Hellwig         return 0;
118495533d5fSChristoph Hellwig     }
118595533d5fSChristoph Hellwig 
118695533d5fSChristoph Hellwig     nr_iov = argc - optind;
1187cf57298aSChristoph Hellwig     ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, 0xab);
118895533d5fSChristoph Hellwig 
118995533d5fSChristoph Hellwig     gettimeofday(&ctx->t1, NULL);
119095533d5fSChristoph Hellwig     acb = bdrv_aio_readv(bs, ctx->offset >> 9, &ctx->qiov,
119195533d5fSChristoph Hellwig                          ctx->qiov.size >> 9, aio_read_done, ctx);
11927d8abfcbSKevin Wolf     if (!acb) {
11937d8abfcbSKevin Wolf         free(ctx->buf);
11947d8abfcbSKevin Wolf         free(ctx);
119595533d5fSChristoph Hellwig         return -EIO;
11967d8abfcbSKevin Wolf     }
119795533d5fSChristoph Hellwig 
119895533d5fSChristoph Hellwig     return 0;
119995533d5fSChristoph Hellwig }
120095533d5fSChristoph Hellwig 
120143642b38SDevin Nakamura static void aio_write_help(void)
120295533d5fSChristoph Hellwig {
120395533d5fSChristoph Hellwig     printf(
120495533d5fSChristoph Hellwig "\n"
120595533d5fSChristoph Hellwig " asynchronously writes a range of bytes from the given offset source\n"
120695533d5fSChristoph Hellwig " from multiple buffers\n"
120795533d5fSChristoph Hellwig "\n"
120895533d5fSChristoph Hellwig " Example:\n"
120995533d5fSChristoph Hellwig " 'aio_write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n"
121095533d5fSChristoph Hellwig "\n"
121195533d5fSChristoph Hellwig " Writes into a segment of the currently open file, using a buffer\n"
121295533d5fSChristoph Hellwig " filled with a set pattern (0xcdcdcdcd).\n"
1213e432cef9SChristoph Hellwig " The write is performed asynchronously and the aio_flush command must be\n"
1214e432cef9SChristoph Hellwig " used to ensure all outstanding aio requests have been completed\n"
121595533d5fSChristoph Hellwig " -P, -- use different pattern to fill file\n"
121695533d5fSChristoph Hellwig " -C, -- report statistics in a machine parsable format\n"
1217095343adSKevin Wolf " -q, -- quiet mode, do not show I/O statistics\n"
121895533d5fSChristoph Hellwig "\n");
121995533d5fSChristoph Hellwig }
122095533d5fSChristoph Hellwig 
122122a2bdcbSBlue Swirl static int aio_write_f(int argc, char **argv);
122222a2bdcbSBlue Swirl 
122322a2bdcbSBlue Swirl static const cmdinfo_t aio_write_cmd = {
122422a2bdcbSBlue Swirl     .name       = "aio_write",
122522a2bdcbSBlue Swirl     .cfunc      = aio_write_f,
122622a2bdcbSBlue Swirl     .argmin     = 2,
122722a2bdcbSBlue Swirl     .argmax     = -1,
122822a2bdcbSBlue Swirl     .args       = "[-Cq] [-P pattern ] off len [len..]",
122922a2bdcbSBlue Swirl     .oneline    = "asynchronously writes a number of bytes",
123022a2bdcbSBlue Swirl     .help       = aio_write_help,
123122a2bdcbSBlue Swirl };
123295533d5fSChristoph Hellwig 
123343642b38SDevin Nakamura static int aio_write_f(int argc, char **argv)
123495533d5fSChristoph Hellwig {
1235cf57298aSChristoph Hellwig     int nr_iov, c;
123695533d5fSChristoph Hellwig     int pattern = 0xcd;
123795533d5fSChristoph Hellwig     struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx));
123895533d5fSChristoph Hellwig     BlockDriverAIOCB *acb;
123995533d5fSChristoph Hellwig 
124095533d5fSChristoph Hellwig     while ((c = getopt(argc, argv, "CqP:")) != EOF) {
124195533d5fSChristoph Hellwig         switch (c) {
124295533d5fSChristoph Hellwig         case 'C':
124395533d5fSChristoph Hellwig             ctx->Cflag = 1;
124495533d5fSChristoph Hellwig             break;
124595533d5fSChristoph Hellwig         case 'q':
124695533d5fSChristoph Hellwig             ctx->qflag = 1;
124795533d5fSChristoph Hellwig             break;
124895533d5fSChristoph Hellwig         case 'P':
1249cf070d7eSChristoph Hellwig             pattern = parse_pattern(optarg);
125043642b38SDevin Nakamura             if (pattern < 0) {
1251b1b1dad3SAlex Jia                 free(ctx);
1252cf070d7eSChristoph Hellwig                 return 0;
125343642b38SDevin Nakamura             }
125495533d5fSChristoph Hellwig             break;
125595533d5fSChristoph Hellwig         default:
12567d8abfcbSKevin Wolf             free(ctx);
125795533d5fSChristoph Hellwig             return command_usage(&aio_write_cmd);
125895533d5fSChristoph Hellwig         }
125995533d5fSChristoph Hellwig     }
126095533d5fSChristoph Hellwig 
12617d8abfcbSKevin Wolf     if (optind > argc - 2) {
12627d8abfcbSKevin Wolf         free(ctx);
126395533d5fSChristoph Hellwig         return command_usage(&aio_write_cmd);
12647d8abfcbSKevin Wolf     }
126595533d5fSChristoph Hellwig 
126695533d5fSChristoph Hellwig     ctx->offset = cvtnum(argv[optind]);
126795533d5fSChristoph Hellwig     if (ctx->offset < 0) {
126895533d5fSChristoph Hellwig         printf("non-numeric length argument -- %s\n", argv[optind]);
12697d8abfcbSKevin Wolf         free(ctx);
127095533d5fSChristoph Hellwig         return 0;
127195533d5fSChristoph Hellwig     }
127295533d5fSChristoph Hellwig     optind++;
127395533d5fSChristoph Hellwig 
127495533d5fSChristoph Hellwig     if (ctx->offset & 0x1ff) {
12750bfcd599SBlue Swirl         printf("offset %" PRId64 " is not sector aligned\n",
12760bfcd599SBlue Swirl                ctx->offset);
12777d8abfcbSKevin Wolf         free(ctx);
127895533d5fSChristoph Hellwig         return 0;
127995533d5fSChristoph Hellwig     }
128095533d5fSChristoph Hellwig 
128195533d5fSChristoph Hellwig     nr_iov = argc - optind;
1282cf57298aSChristoph Hellwig     ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, pattern);
128395533d5fSChristoph Hellwig 
128495533d5fSChristoph Hellwig     gettimeofday(&ctx->t1, NULL);
128595533d5fSChristoph Hellwig     acb = bdrv_aio_writev(bs, ctx->offset >> 9, &ctx->qiov,
128695533d5fSChristoph Hellwig                           ctx->qiov.size >> 9, aio_write_done, ctx);
12877d8abfcbSKevin Wolf     if (!acb) {
12887d8abfcbSKevin Wolf         free(ctx->buf);
12897d8abfcbSKevin Wolf         free(ctx);
129095533d5fSChristoph Hellwig         return -EIO;
12917d8abfcbSKevin Wolf     }
129295533d5fSChristoph Hellwig 
129395533d5fSChristoph Hellwig     return 0;
129495533d5fSChristoph Hellwig }
129595533d5fSChristoph Hellwig 
129643642b38SDevin Nakamura static int aio_flush_f(int argc, char **argv)
129795533d5fSChristoph Hellwig {
129895533d5fSChristoph Hellwig     qemu_aio_flush();
129995533d5fSChristoph Hellwig     return 0;
130095533d5fSChristoph Hellwig }
130195533d5fSChristoph Hellwig 
130295533d5fSChristoph Hellwig static const cmdinfo_t aio_flush_cmd = {
130395533d5fSChristoph Hellwig     .name       = "aio_flush",
130495533d5fSChristoph Hellwig     .cfunc      = aio_flush_f,
1305e432cef9SChristoph Hellwig     .oneline    = "completes all outstanding aio requests"
130695533d5fSChristoph Hellwig };
130795533d5fSChristoph Hellwig 
130843642b38SDevin Nakamura static int flush_f(int argc, char **argv)
1309e3aff4f6Saliguori {
1310e3aff4f6Saliguori     bdrv_flush(bs);
1311e3aff4f6Saliguori     return 0;
1312e3aff4f6Saliguori }
1313e3aff4f6Saliguori 
1314e3aff4f6Saliguori static const cmdinfo_t flush_cmd = {
1315e3aff4f6Saliguori     .name       = "flush",
1316e3aff4f6Saliguori     .altname    = "f",
1317e3aff4f6Saliguori     .cfunc      = flush_f,
1318e3aff4f6Saliguori     .oneline    = "flush all in-core file state to disk",
1319e3aff4f6Saliguori };
1320e3aff4f6Saliguori 
132143642b38SDevin Nakamura static int truncate_f(int argc, char **argv)
1322e3aff4f6Saliguori {
1323e3aff4f6Saliguori     int64_t offset;
1324e3aff4f6Saliguori     int ret;
1325e3aff4f6Saliguori 
1326e3aff4f6Saliguori     offset = cvtnum(argv[1]);
1327e3aff4f6Saliguori     if (offset < 0) {
1328e3aff4f6Saliguori         printf("non-numeric truncate argument -- %s\n", argv[1]);
1329e3aff4f6Saliguori         return 0;
1330e3aff4f6Saliguori     }
1331e3aff4f6Saliguori 
1332e3aff4f6Saliguori     ret = bdrv_truncate(bs, offset);
1333e3aff4f6Saliguori     if (ret < 0) {
13340923c577SKevin Wolf         printf("truncate: %s\n", strerror(-ret));
1335e3aff4f6Saliguori         return 0;
1336e3aff4f6Saliguori     }
1337e3aff4f6Saliguori 
1338e3aff4f6Saliguori     return 0;
1339e3aff4f6Saliguori }
1340e3aff4f6Saliguori 
1341e3aff4f6Saliguori static const cmdinfo_t truncate_cmd = {
1342e3aff4f6Saliguori     .name       = "truncate",
1343e3aff4f6Saliguori     .altname    = "t",
1344e3aff4f6Saliguori     .cfunc      = truncate_f,
1345e3aff4f6Saliguori     .argmin     = 1,
1346e3aff4f6Saliguori     .argmax     = 1,
1347e3aff4f6Saliguori     .args       = "off",
1348e3aff4f6Saliguori     .oneline    = "truncates the current file at the given offset",
1349e3aff4f6Saliguori };
1350e3aff4f6Saliguori 
135143642b38SDevin Nakamura static int length_f(int argc, char **argv)
1352e3aff4f6Saliguori {
1353e3aff4f6Saliguori     int64_t size;
1354e3aff4f6Saliguori     char s1[64];
1355e3aff4f6Saliguori 
1356e3aff4f6Saliguori     size = bdrv_getlength(bs);
1357e3aff4f6Saliguori     if (size < 0) {
13580923c577SKevin Wolf         printf("getlength: %s\n", strerror(-size));
1359e3aff4f6Saliguori         return 0;
1360e3aff4f6Saliguori     }
1361e3aff4f6Saliguori 
1362e3aff4f6Saliguori     cvtstr(size, s1, sizeof(s1));
1363e3aff4f6Saliguori     printf("%s\n", s1);
1364e3aff4f6Saliguori     return 0;
1365e3aff4f6Saliguori }
1366e3aff4f6Saliguori 
1367e3aff4f6Saliguori 
1368e3aff4f6Saliguori static const cmdinfo_t length_cmd = {
1369e3aff4f6Saliguori     .name   = "length",
1370e3aff4f6Saliguori     .altname    = "l",
1371e3aff4f6Saliguori     .cfunc      = length_f,
1372e3aff4f6Saliguori     .oneline    = "gets the length of the current file",
1373e3aff4f6Saliguori };
1374e3aff4f6Saliguori 
1375e3aff4f6Saliguori 
137643642b38SDevin Nakamura static int info_f(int argc, char **argv)
1377e3aff4f6Saliguori {
1378e3aff4f6Saliguori     BlockDriverInfo bdi;
1379e3aff4f6Saliguori     char s1[64], s2[64];
1380e3aff4f6Saliguori     int ret;
1381e3aff4f6Saliguori 
138243642b38SDevin Nakamura     if (bs->drv && bs->drv->format_name) {
1383e3aff4f6Saliguori         printf("format name: %s\n", bs->drv->format_name);
138443642b38SDevin Nakamura     }
138543642b38SDevin Nakamura     if (bs->drv && bs->drv->protocol_name) {
1386e3aff4f6Saliguori         printf("format name: %s\n", bs->drv->protocol_name);
138743642b38SDevin Nakamura     }
1388e3aff4f6Saliguori 
1389e3aff4f6Saliguori     ret = bdrv_get_info(bs, &bdi);
139043642b38SDevin Nakamura     if (ret) {
1391e3aff4f6Saliguori         return 0;
139243642b38SDevin Nakamura     }
1393e3aff4f6Saliguori 
1394e3aff4f6Saliguori     cvtstr(bdi.cluster_size, s1, sizeof(s1));
1395e3aff4f6Saliguori     cvtstr(bdi.vm_state_offset, s2, sizeof(s2));
1396e3aff4f6Saliguori 
1397e3aff4f6Saliguori     printf("cluster size: %s\n", s1);
1398e3aff4f6Saliguori     printf("vm state offset: %s\n", s2);
1399e3aff4f6Saliguori 
1400e3aff4f6Saliguori     return 0;
1401e3aff4f6Saliguori }
1402e3aff4f6Saliguori 
1403e3aff4f6Saliguori 
1404e3aff4f6Saliguori 
1405e3aff4f6Saliguori static const cmdinfo_t info_cmd = {
1406e3aff4f6Saliguori     .name       = "info",
1407e3aff4f6Saliguori     .altname    = "i",
1408e3aff4f6Saliguori     .cfunc      = info_f,
1409e3aff4f6Saliguori     .oneline    = "prints information about the current file",
1410e3aff4f6Saliguori };
1411e3aff4f6Saliguori 
141243642b38SDevin Nakamura static void discard_help(void)
1413edff5db1SStefan Hajnoczi {
1414edff5db1SStefan Hajnoczi     printf(
1415edff5db1SStefan Hajnoczi "\n"
1416edff5db1SStefan Hajnoczi " discards a range of bytes from the given offset\n"
1417edff5db1SStefan Hajnoczi "\n"
1418edff5db1SStefan Hajnoczi " Example:\n"
1419edff5db1SStefan Hajnoczi " 'discard 512 1k' - discards 1 kilobyte from 512 bytes into the file\n"
1420edff5db1SStefan Hajnoczi "\n"
1421edff5db1SStefan Hajnoczi " Discards a segment of the currently open file.\n"
1422edff5db1SStefan Hajnoczi " -C, -- report statistics in a machine parsable format\n"
1423095343adSKevin Wolf " -q, -- quiet mode, do not show I/O statistics\n"
1424edff5db1SStefan Hajnoczi "\n");
1425edff5db1SStefan Hajnoczi }
1426edff5db1SStefan Hajnoczi 
1427edff5db1SStefan Hajnoczi static int discard_f(int argc, char **argv);
1428edff5db1SStefan Hajnoczi 
1429edff5db1SStefan Hajnoczi static const cmdinfo_t discard_cmd = {
1430edff5db1SStefan Hajnoczi     .name       = "discard",
1431edff5db1SStefan Hajnoczi     .altname    = "d",
1432edff5db1SStefan Hajnoczi     .cfunc      = discard_f,
1433edff5db1SStefan Hajnoczi     .argmin     = 2,
1434edff5db1SStefan Hajnoczi     .argmax     = -1,
1435edff5db1SStefan Hajnoczi     .args       = "[-Cq] off len",
1436edff5db1SStefan Hajnoczi     .oneline    = "discards a number of bytes at a specified offset",
1437edff5db1SStefan Hajnoczi     .help       = discard_help,
1438edff5db1SStefan Hajnoczi };
1439edff5db1SStefan Hajnoczi 
144043642b38SDevin Nakamura static int discard_f(int argc, char **argv)
1441edff5db1SStefan Hajnoczi {
1442edff5db1SStefan Hajnoczi     struct timeval t1, t2;
1443edff5db1SStefan Hajnoczi     int Cflag = 0, qflag = 0;
1444edff5db1SStefan Hajnoczi     int c, ret;
1445edff5db1SStefan Hajnoczi     int64_t offset;
1446edff5db1SStefan Hajnoczi     int count;
1447edff5db1SStefan Hajnoczi 
1448edff5db1SStefan Hajnoczi     while ((c = getopt(argc, argv, "Cq")) != EOF) {
1449edff5db1SStefan Hajnoczi         switch (c) {
1450edff5db1SStefan Hajnoczi         case 'C':
1451edff5db1SStefan Hajnoczi             Cflag = 1;
1452edff5db1SStefan Hajnoczi             break;
1453edff5db1SStefan Hajnoczi         case 'q':
1454edff5db1SStefan Hajnoczi             qflag = 1;
1455edff5db1SStefan Hajnoczi             break;
1456edff5db1SStefan Hajnoczi         default:
1457edff5db1SStefan Hajnoczi             return command_usage(&discard_cmd);
1458edff5db1SStefan Hajnoczi         }
1459edff5db1SStefan Hajnoczi     }
1460edff5db1SStefan Hajnoczi 
1461edff5db1SStefan Hajnoczi     if (optind != argc - 2) {
1462edff5db1SStefan Hajnoczi         return command_usage(&discard_cmd);
1463edff5db1SStefan Hajnoczi     }
1464edff5db1SStefan Hajnoczi 
1465edff5db1SStefan Hajnoczi     offset = cvtnum(argv[optind]);
1466edff5db1SStefan Hajnoczi     if (offset < 0) {
1467edff5db1SStefan Hajnoczi         printf("non-numeric length argument -- %s\n", argv[optind]);
1468edff5db1SStefan Hajnoczi         return 0;
1469edff5db1SStefan Hajnoczi     }
1470edff5db1SStefan Hajnoczi 
1471edff5db1SStefan Hajnoczi     optind++;
1472edff5db1SStefan Hajnoczi     count = cvtnum(argv[optind]);
1473edff5db1SStefan Hajnoczi     if (count < 0) {
1474edff5db1SStefan Hajnoczi         printf("non-numeric length argument -- %s\n", argv[optind]);
1475edff5db1SStefan Hajnoczi         return 0;
1476edff5db1SStefan Hajnoczi     }
1477edff5db1SStefan Hajnoczi 
1478edff5db1SStefan Hajnoczi     gettimeofday(&t1, NULL);
147943642b38SDevin Nakamura     ret = bdrv_discard(bs, offset >> BDRV_SECTOR_BITS,
148043642b38SDevin Nakamura                        count >> BDRV_SECTOR_BITS);
1481edff5db1SStefan Hajnoczi     gettimeofday(&t2, NULL);
1482edff5db1SStefan Hajnoczi 
1483edff5db1SStefan Hajnoczi     if (ret < 0) {
1484edff5db1SStefan Hajnoczi         printf("discard failed: %s\n", strerror(-ret));
1485edff5db1SStefan Hajnoczi         goto out;
1486edff5db1SStefan Hajnoczi     }
1487edff5db1SStefan Hajnoczi 
1488edff5db1SStefan Hajnoczi     /* Finally, report back -- -C gives a parsable format */
1489edff5db1SStefan Hajnoczi     if (!qflag) {
1490edff5db1SStefan Hajnoczi         t2 = tsub(t2, t1);
1491edff5db1SStefan Hajnoczi         print_report("discard", &t2, offset, count, count, 1, Cflag);
1492edff5db1SStefan Hajnoczi     }
1493edff5db1SStefan Hajnoczi 
1494edff5db1SStefan Hajnoczi out:
1495edff5db1SStefan Hajnoczi     return 0;
1496edff5db1SStefan Hajnoczi }
1497edff5db1SStefan Hajnoczi 
149843642b38SDevin Nakamura static int alloc_f(int argc, char **argv)
1499e3aff4f6Saliguori {
1500e3aff4f6Saliguori     int64_t offset;
1501a7824a88SKevin Wolf     int nb_sectors, remaining;
1502e3aff4f6Saliguori     char s1[64];
1503a7824a88SKevin Wolf     int num, sum_alloc;
1504e3aff4f6Saliguori     int ret;
1505e3aff4f6Saliguori 
1506e3aff4f6Saliguori     offset = cvtnum(argv[1]);
1507e3aff4f6Saliguori     if (offset & 0x1ff) {
15080bfcd599SBlue Swirl         printf("offset %" PRId64 " is not sector aligned\n",
15090bfcd599SBlue Swirl                offset);
1510e3aff4f6Saliguori         return 0;
1511e3aff4f6Saliguori     }
1512e3aff4f6Saliguori 
151343642b38SDevin Nakamura     if (argc == 3) {
1514e3aff4f6Saliguori         nb_sectors = cvtnum(argv[2]);
151543642b38SDevin Nakamura     } else {
1516e3aff4f6Saliguori         nb_sectors = 1;
151743642b38SDevin Nakamura     }
1518e3aff4f6Saliguori 
1519a7824a88SKevin Wolf     remaining = nb_sectors;
1520a7824a88SKevin Wolf     sum_alloc = 0;
1521a7824a88SKevin Wolf     while (remaining) {
1522e3aff4f6Saliguori         ret = bdrv_is_allocated(bs, offset >> 9, nb_sectors, &num);
1523a7824a88SKevin Wolf         remaining -= num;
1524a7824a88SKevin Wolf         if (ret) {
1525a7824a88SKevin Wolf             sum_alloc += num;
1526a7824a88SKevin Wolf         }
1527a7824a88SKevin Wolf     }
1528e3aff4f6Saliguori 
1529e3aff4f6Saliguori     cvtstr(offset, s1, sizeof(s1));
1530e3aff4f6Saliguori 
1531a7824a88SKevin Wolf     printf("%d/%d sectors allocated at offset %s\n",
1532a7824a88SKevin Wolf            sum_alloc, nb_sectors, s1);
1533e3aff4f6Saliguori     return 0;
1534e3aff4f6Saliguori }
1535e3aff4f6Saliguori 
1536e3aff4f6Saliguori static const cmdinfo_t alloc_cmd = {
1537e3aff4f6Saliguori     .name       = "alloc",
1538e3aff4f6Saliguori     .altname    = "a",
1539e3aff4f6Saliguori     .argmin     = 1,
1540e3aff4f6Saliguori     .argmax     = 2,
1541e3aff4f6Saliguori     .cfunc      = alloc_f,
1542e3aff4f6Saliguori     .args       = "off [sectors]",
1543e3aff4f6Saliguori     .oneline    = "checks if a sector is present in the file",
1544e3aff4f6Saliguori };
1545e3aff4f6Saliguori 
154643642b38SDevin Nakamura static int map_f(int argc, char **argv)
1547191c2890SKevin Wolf {
1548191c2890SKevin Wolf     int64_t offset;
1549191c2890SKevin Wolf     int64_t nb_sectors;
1550191c2890SKevin Wolf     char s1[64];
1551191c2890SKevin Wolf     int num, num_checked;
1552191c2890SKevin Wolf     int ret;
1553191c2890SKevin Wolf     const char *retstr;
1554191c2890SKevin Wolf 
1555191c2890SKevin Wolf     offset = 0;
1556191c2890SKevin Wolf     nb_sectors = bs->total_sectors;
1557191c2890SKevin Wolf 
1558191c2890SKevin Wolf     do {
1559191c2890SKevin Wolf         num_checked = MIN(nb_sectors, INT_MAX);
1560191c2890SKevin Wolf         ret = bdrv_is_allocated(bs, offset, num_checked, &num);
1561191c2890SKevin Wolf         retstr = ret ? "    allocated" : "not allocated";
1562191c2890SKevin Wolf         cvtstr(offset << 9ULL, s1, sizeof(s1));
1563191c2890SKevin Wolf         printf("[% 24" PRId64 "] % 8d/% 8d sectors %s at offset %s (%d)\n",
1564191c2890SKevin Wolf                offset << 9ULL, num, num_checked, retstr, s1, ret);
1565191c2890SKevin Wolf 
1566191c2890SKevin Wolf         offset += num;
1567191c2890SKevin Wolf         nb_sectors -= num;
1568191c2890SKevin Wolf     } while (offset < bs->total_sectors);
1569191c2890SKevin Wolf 
1570191c2890SKevin Wolf     return 0;
1571191c2890SKevin Wolf }
1572191c2890SKevin Wolf 
1573191c2890SKevin Wolf static const cmdinfo_t map_cmd = {
1574191c2890SKevin Wolf        .name           = "map",
1575191c2890SKevin Wolf        .argmin         = 0,
1576191c2890SKevin Wolf        .argmax         = 0,
1577191c2890SKevin Wolf        .cfunc          = map_f,
1578191c2890SKevin Wolf        .args           = "",
1579191c2890SKevin Wolf        .oneline        = "prints the allocated areas of a file",
1580191c2890SKevin Wolf };
1581191c2890SKevin Wolf 
1582191c2890SKevin Wolf 
158343642b38SDevin Nakamura static int close_f(int argc, char **argv)
1584e3aff4f6Saliguori {
1585*b4657855SStefan Hajnoczi     bdrv_delete(bs);
1586e3aff4f6Saliguori     bs = NULL;
1587e3aff4f6Saliguori     return 0;
1588e3aff4f6Saliguori }
1589e3aff4f6Saliguori 
1590e3aff4f6Saliguori static const cmdinfo_t close_cmd = {
1591e3aff4f6Saliguori     .name       = "close",
1592e3aff4f6Saliguori     .altname    = "c",
1593e3aff4f6Saliguori     .cfunc      = close_f,
1594e3aff4f6Saliguori     .oneline    = "close the current open file",
1595e3aff4f6Saliguori };
1596e3aff4f6Saliguori 
15979c4bab26SChristoph Hellwig static int openfile(char *name, int flags, int growable)
1598e3aff4f6Saliguori {
1599e3aff4f6Saliguori     if (bs) {
1600e3aff4f6Saliguori         fprintf(stderr, "file open already, try 'help close'\n");
1601e3aff4f6Saliguori         return 1;
1602e3aff4f6Saliguori     }
1603e3aff4f6Saliguori 
16046db95603SChristoph Hellwig     if (growable) {
16056db95603SChristoph Hellwig         if (bdrv_file_open(&bs, name, flags)) {
16066db95603SChristoph Hellwig             fprintf(stderr, "%s: can't open device %s\n", progname, name);
16076db95603SChristoph Hellwig             return 1;
16086db95603SChristoph Hellwig         }
16096db95603SChristoph Hellwig     } else {
1610e3aff4f6Saliguori         bs = bdrv_new("hda");
1611e3aff4f6Saliguori 
1612d6e9098eSKevin Wolf         if (bdrv_open(bs, name, flags, NULL) < 0) {
1613e3aff4f6Saliguori             fprintf(stderr, "%s: can't open device %s\n", progname, name);
1614*b4657855SStefan Hajnoczi             bdrv_delete(bs);
1615e3aff4f6Saliguori             bs = NULL;
1616e3aff4f6Saliguori             return 1;
1617e3aff4f6Saliguori         }
16189c4bab26SChristoph Hellwig     }
16196db95603SChristoph Hellwig 
1620e3aff4f6Saliguori     return 0;
1621e3aff4f6Saliguori }
1622e3aff4f6Saliguori 
162343642b38SDevin Nakamura static void open_help(void)
1624e3aff4f6Saliguori {
1625e3aff4f6Saliguori     printf(
1626e3aff4f6Saliguori "\n"
1627e3aff4f6Saliguori " opens a new file in the requested mode\n"
1628e3aff4f6Saliguori "\n"
1629e3aff4f6Saliguori " Example:\n"
1630e3aff4f6Saliguori " 'open -Cn /tmp/data' - creates/opens data file read-write and uncached\n"
1631e3aff4f6Saliguori "\n"
1632e3aff4f6Saliguori " Opens a file for subsequent use by all of the other qemu-io commands.\n"
1633e3aff4f6Saliguori " -r, -- open file read-only\n"
1634e3aff4f6Saliguori " -s, -- use snapshot file\n"
1635e3aff4f6Saliguori " -n, -- disable host cache\n"
16369c4bab26SChristoph Hellwig " -g, -- allow file to grow (only applies to protocols)"
1637e3aff4f6Saliguori "\n");
1638e3aff4f6Saliguori }
1639e3aff4f6Saliguori 
164022a2bdcbSBlue Swirl static int open_f(int argc, char **argv);
164122a2bdcbSBlue Swirl 
164222a2bdcbSBlue Swirl static const cmdinfo_t open_cmd = {
164322a2bdcbSBlue Swirl     .name       = "open",
164422a2bdcbSBlue Swirl     .altname    = "o",
164522a2bdcbSBlue Swirl     .cfunc      = open_f,
164622a2bdcbSBlue Swirl     .argmin     = 1,
164722a2bdcbSBlue Swirl     .argmax     = -1,
164822a2bdcbSBlue Swirl     .flags      = CMD_NOFILE_OK,
164922a2bdcbSBlue Swirl     .args       = "[-Crsn] [path]",
165022a2bdcbSBlue Swirl     .oneline    = "open the file specified by path",
165122a2bdcbSBlue Swirl     .help       = open_help,
165222a2bdcbSBlue Swirl };
1653e3aff4f6Saliguori 
165443642b38SDevin Nakamura static int open_f(int argc, char **argv)
1655e3aff4f6Saliguori {
1656e3aff4f6Saliguori     int flags = 0;
1657e3aff4f6Saliguori     int readonly = 0;
16589c4bab26SChristoph Hellwig     int growable = 0;
1659e3aff4f6Saliguori     int c;
1660e3aff4f6Saliguori 
16619a2d77adSChristoph Hellwig     while ((c = getopt(argc, argv, "snrg")) != EOF) {
1662e3aff4f6Saliguori         switch (c) {
1663e3aff4f6Saliguori         case 's':
1664e3aff4f6Saliguori             flags |= BDRV_O_SNAPSHOT;
1665e3aff4f6Saliguori             break;
1666e3aff4f6Saliguori         case 'n':
1667a6599793SChristoph Hellwig             flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
1668e3aff4f6Saliguori             break;
1669e3aff4f6Saliguori         case 'r':
1670e3aff4f6Saliguori             readonly = 1;
1671e3aff4f6Saliguori             break;
16729c4bab26SChristoph Hellwig         case 'g':
16739c4bab26SChristoph Hellwig             growable = 1;
16749c4bab26SChristoph Hellwig             break;
1675e3aff4f6Saliguori         default:
1676e3aff4f6Saliguori             return command_usage(&open_cmd);
1677e3aff4f6Saliguori         }
1678e3aff4f6Saliguori     }
1679e3aff4f6Saliguori 
1680f5edb014SNaphtali Sprei     if (!readonly) {
1681e3aff4f6Saliguori         flags |= BDRV_O_RDWR;
1682f5edb014SNaphtali Sprei     }
1683e3aff4f6Saliguori 
168443642b38SDevin Nakamura     if (optind != argc - 1) {
1685e3aff4f6Saliguori         return command_usage(&open_cmd);
168643642b38SDevin Nakamura     }
1687e3aff4f6Saliguori 
16889c4bab26SChristoph Hellwig     return openfile(argv[optind], flags, growable);
1689e3aff4f6Saliguori }
1690e3aff4f6Saliguori 
169143642b38SDevin Nakamura static int init_args_command(int index)
1692e3aff4f6Saliguori {
1693e3aff4f6Saliguori     /* only one device allowed so far */
169443642b38SDevin Nakamura     if (index >= 1) {
1695e3aff4f6Saliguori         return 0;
169643642b38SDevin Nakamura     }
1697e3aff4f6Saliguori     return ++index;
1698e3aff4f6Saliguori }
1699e3aff4f6Saliguori 
170043642b38SDevin Nakamura static int init_check_command(const cmdinfo_t *ct)
1701e3aff4f6Saliguori {
170243642b38SDevin Nakamura     if (ct->flags & CMD_FLAG_GLOBAL) {
1703e3aff4f6Saliguori         return 1;
170443642b38SDevin Nakamura     }
1705e3aff4f6Saliguori     if (!(ct->flags & CMD_NOFILE_OK) && !bs) {
1706e3aff4f6Saliguori         fprintf(stderr, "no file open, try 'help open'\n");
1707e3aff4f6Saliguori         return 0;
1708e3aff4f6Saliguori     }
1709e3aff4f6Saliguori     return 1;
1710e3aff4f6Saliguori }
1711e3aff4f6Saliguori 
1712e3aff4f6Saliguori static void usage(const char *name)
1713e3aff4f6Saliguori {
1714e3aff4f6Saliguori     printf(
17159a2d77adSChristoph Hellwig "Usage: %s [-h] [-V] [-rsnm] [-c cmd] ... [file]\n"
171684844a20SStefan Weil "QEMU Disk exerciser\n"
1717e3aff4f6Saliguori "\n"
1718e3aff4f6Saliguori "  -c, --cmd            command to execute\n"
1719e3aff4f6Saliguori "  -r, --read-only      export read-only\n"
1720e3aff4f6Saliguori "  -s, --snapshot       use snapshot file\n"
1721e3aff4f6Saliguori "  -n, --nocache        disable host cache\n"
17221db6947dSChristoph Hellwig "  -g, --growable       allow file to grow (only applies to protocols)\n"
1723e3aff4f6Saliguori "  -m, --misalign       misalign allocations for O_DIRECT\n"
17245c6c3a6cSChristoph Hellwig "  -k, --native-aio     use kernel AIO implementation (on Linux only)\n"
1725e3aff4f6Saliguori "  -h, --help           display this help and exit\n"
1726e3aff4f6Saliguori "  -V, --version        output version information and exit\n"
1727e3aff4f6Saliguori "\n",
1728e3aff4f6Saliguori     name);
1729e3aff4f6Saliguori }
1730e3aff4f6Saliguori 
1731e3aff4f6Saliguori 
1732e3aff4f6Saliguori int main(int argc, char **argv)
1733e3aff4f6Saliguori {
1734e3aff4f6Saliguori     int readonly = 0;
17359c4bab26SChristoph Hellwig     int growable = 0;
17369a2d77adSChristoph Hellwig     const char *sopt = "hVc:rsnmgk";
1737b32bb952SBlue Swirl     const struct option lopt[] = {
1738660f11beSBlue Swirl         { "help", 0, NULL, 'h' },
1739660f11beSBlue Swirl         { "version", 0, NULL, 'V' },
1740660f11beSBlue Swirl         { "offset", 1, NULL, 'o' },
1741660f11beSBlue Swirl         { "cmd", 1, NULL, 'c' },
1742660f11beSBlue Swirl         { "read-only", 0, NULL, 'r' },
1743660f11beSBlue Swirl         { "snapshot", 0, NULL, 's' },
1744660f11beSBlue Swirl         { "nocache", 0, NULL, 'n' },
1745660f11beSBlue Swirl         { "misalign", 0, NULL, 'm' },
1746660f11beSBlue Swirl         { "growable", 0, NULL, 'g' },
17475c6c3a6cSChristoph Hellwig         { "native-aio", 0, NULL, 'k' },
1748660f11beSBlue Swirl         { NULL, 0, NULL, 0 }
1749e3aff4f6Saliguori     };
1750e3aff4f6Saliguori     int c;
1751e3aff4f6Saliguori     int opt_index = 0;
1752e3aff4f6Saliguori     int flags = 0;
1753e3aff4f6Saliguori 
1754e3aff4f6Saliguori     progname = basename(argv[0]);
1755e3aff4f6Saliguori 
1756e3aff4f6Saliguori     while ((c = getopt_long(argc, argv, sopt, lopt, &opt_index)) != -1) {
1757e3aff4f6Saliguori         switch (c) {
1758e3aff4f6Saliguori         case 's':
1759e3aff4f6Saliguori             flags |= BDRV_O_SNAPSHOT;
1760e3aff4f6Saliguori             break;
1761e3aff4f6Saliguori         case 'n':
1762a6599793SChristoph Hellwig             flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
1763e3aff4f6Saliguori             break;
1764e3aff4f6Saliguori         case 'c':
1765e3aff4f6Saliguori             add_user_command(optarg);
1766e3aff4f6Saliguori             break;
1767e3aff4f6Saliguori         case 'r':
1768e3aff4f6Saliguori             readonly = 1;
1769e3aff4f6Saliguori             break;
1770e3aff4f6Saliguori         case 'm':
1771e3aff4f6Saliguori             misalign = 1;
1772e3aff4f6Saliguori             break;
17739c4bab26SChristoph Hellwig         case 'g':
17749c4bab26SChristoph Hellwig             growable = 1;
17759c4bab26SChristoph Hellwig             break;
17765c6c3a6cSChristoph Hellwig         case 'k':
17775c6c3a6cSChristoph Hellwig             flags |= BDRV_O_NATIVE_AIO;
17785c6c3a6cSChristoph Hellwig             break;
1779e3aff4f6Saliguori         case 'V':
1780e3aff4f6Saliguori             printf("%s version %s\n", progname, VERSION);
1781e3aff4f6Saliguori             exit(0);
1782e3aff4f6Saliguori         case 'h':
1783e3aff4f6Saliguori             usage(progname);
1784e3aff4f6Saliguori             exit(0);
1785e3aff4f6Saliguori         default:
1786e3aff4f6Saliguori             usage(progname);
1787e3aff4f6Saliguori             exit(1);
1788e3aff4f6Saliguori         }
1789e3aff4f6Saliguori     }
1790e3aff4f6Saliguori 
1791e3aff4f6Saliguori     if ((argc - optind) > 1) {
1792e3aff4f6Saliguori         usage(progname);
1793e3aff4f6Saliguori         exit(1);
1794e3aff4f6Saliguori     }
1795e3aff4f6Saliguori 
1796e3aff4f6Saliguori     bdrv_init();
1797e3aff4f6Saliguori 
1798e3aff4f6Saliguori     /* initialize commands */
1799e3aff4f6Saliguori     quit_init();
1800e3aff4f6Saliguori     help_init();
1801e3aff4f6Saliguori     add_command(&open_cmd);
1802e3aff4f6Saliguori     add_command(&close_cmd);
1803e3aff4f6Saliguori     add_command(&read_cmd);
1804e3aff4f6Saliguori     add_command(&readv_cmd);
1805e3aff4f6Saliguori     add_command(&write_cmd);
1806e3aff4f6Saliguori     add_command(&writev_cmd);
1807776cbbbdSKevin Wolf     add_command(&multiwrite_cmd);
180895533d5fSChristoph Hellwig     add_command(&aio_read_cmd);
180995533d5fSChristoph Hellwig     add_command(&aio_write_cmd);
181095533d5fSChristoph Hellwig     add_command(&aio_flush_cmd);
1811e3aff4f6Saliguori     add_command(&flush_cmd);
1812e3aff4f6Saliguori     add_command(&truncate_cmd);
1813e3aff4f6Saliguori     add_command(&length_cmd);
1814e3aff4f6Saliguori     add_command(&info_cmd);
1815edff5db1SStefan Hajnoczi     add_command(&discard_cmd);
1816e3aff4f6Saliguori     add_command(&alloc_cmd);
1817191c2890SKevin Wolf     add_command(&map_cmd);
1818e3aff4f6Saliguori 
1819e3aff4f6Saliguori     add_args_command(init_args_command);
1820e3aff4f6Saliguori     add_check_command(init_check_command);
1821e3aff4f6Saliguori 
1822e3aff4f6Saliguori     /* open the device */
1823f5edb014SNaphtali Sprei     if (!readonly) {
1824e3aff4f6Saliguori         flags |= BDRV_O_RDWR;
1825f5edb014SNaphtali Sprei     }
1826e3aff4f6Saliguori 
182743642b38SDevin Nakamura     if ((argc - optind) == 1) {
18289c4bab26SChristoph Hellwig         openfile(argv[optind], flags, growable);
182943642b38SDevin Nakamura     }
1830e3aff4f6Saliguori     command_loop();
1831e3aff4f6Saliguori 
183295533d5fSChristoph Hellwig     /*
183395533d5fSChristoph Hellwig      * Make sure all outstanding requests get flushed the program exits.
183495533d5fSChristoph Hellwig      */
183595533d5fSChristoph Hellwig     qemu_aio_flush();
183695533d5fSChristoph Hellwig 
183743642b38SDevin Nakamura     if (bs) {
1838*b4657855SStefan Hajnoczi         bdrv_delete(bs);
183943642b38SDevin Nakamura     }
1840e3aff4f6Saliguori     return 0;
1841e3aff4f6Saliguori }
1842