xref: /qemu/qemu-io-cmds.c (revision 887354bd)
1797ac58cSKevin Wolf /*
2797ac58cSKevin Wolf  * Command line utility to exercise the QEMU I/O path.
3797ac58cSKevin Wolf  *
4093ea232SEric Blake  * Copyright (C) 2009-2016 Red Hat, Inc.
5797ac58cSKevin Wolf  * Copyright (c) 2003-2005 Silicon Graphics, Inc.
6797ac58cSKevin Wolf  *
7797ac58cSKevin Wolf  * This work is licensed under the terms of the GNU GPL, version 2 or later.
8797ac58cSKevin Wolf  * See the COPYING file in the top-level directory.
9797ac58cSKevin Wolf  */
10797ac58cSKevin Wolf 
1180c71a24SPeter Maydell #include "qemu/osdep.h"
12da34e65cSMarkus Armbruster #include "qapi/error.h"
133d21994fSKevin Wolf #include "qemu-io.h"
144c7b7e9bSMax Reitz #include "sysemu/block-backend.h"
154c7b7e9bSMax Reitz #include "block/block.h"
164c7b7e9bSMax Reitz #include "block/block_int.h" /* for info_f() */
17a8d8ecb7SMax Reitz #include "block/qapi.h"
18d49b6836SMarkus Armbruster #include "qemu/error-report.h"
196a1751b7SAlex Bligh #include "qemu/main-loop.h"
20cd33d02aSKevin Wolf #include "qemu/timer.h"
21f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
22797ac58cSKevin Wolf 
23797ac58cSKevin Wolf #define CMD_NOFILE_OK   0x01
24797ac58cSKevin Wolf 
25f9883880SStefan Weil bool qemuio_misalign;
26797ac58cSKevin Wolf 
27c2cdf5c5SKevin Wolf static cmdinfo_t *cmdtab;
28c2cdf5c5SKevin Wolf static int ncmds;
29c2cdf5c5SKevin Wolf 
30c2cdf5c5SKevin Wolf static int compare_cmdname(const void *a, const void *b)
31c2cdf5c5SKevin Wolf {
32c2cdf5c5SKevin Wolf     return strcmp(((const cmdinfo_t *)a)->name,
33c2cdf5c5SKevin Wolf                   ((const cmdinfo_t *)b)->name);
34c2cdf5c5SKevin Wolf }
35c2cdf5c5SKevin Wolf 
36c2cdf5c5SKevin Wolf void qemuio_add_command(const cmdinfo_t *ci)
37c2cdf5c5SKevin Wolf {
3802c4f26bSMarkus Armbruster     cmdtab = g_renew(cmdinfo_t, cmdtab, ++ncmds);
39c2cdf5c5SKevin Wolf     cmdtab[ncmds - 1] = *ci;
40c2cdf5c5SKevin Wolf     qsort(cmdtab, ncmds, sizeof(*cmdtab), compare_cmdname);
41c2cdf5c5SKevin Wolf }
42c2cdf5c5SKevin Wolf 
43c2cdf5c5SKevin Wolf int qemuio_command_usage(const cmdinfo_t *ci)
44c2cdf5c5SKevin Wolf {
45c2cdf5c5SKevin Wolf     printf("%s %s -- %s\n", ci->name, ci->args, ci->oneline);
46c2cdf5c5SKevin Wolf     return 0;
47c2cdf5c5SKevin Wolf }
48c2cdf5c5SKevin Wolf 
494c7b7e9bSMax Reitz static int init_check_command(BlockBackend *blk, const cmdinfo_t *ct)
50c2cdf5c5SKevin Wolf {
51c2cdf5c5SKevin Wolf     if (ct->flags & CMD_FLAG_GLOBAL) {
52c2cdf5c5SKevin Wolf         return 1;
53c2cdf5c5SKevin Wolf     }
544c7b7e9bSMax Reitz     if (!(ct->flags & CMD_NOFILE_OK) && !blk) {
55c2cdf5c5SKevin Wolf         fprintf(stderr, "no file open, try 'help open'\n");
56c2cdf5c5SKevin Wolf         return 0;
57c2cdf5c5SKevin Wolf     }
58c2cdf5c5SKevin Wolf     return 1;
59c2cdf5c5SKevin Wolf }
60c2cdf5c5SKevin Wolf 
614c7b7e9bSMax Reitz static int command(BlockBackend *blk, const cmdinfo_t *ct, int argc,
623d21994fSKevin Wolf                    char **argv)
63c2cdf5c5SKevin Wolf {
64c2cdf5c5SKevin Wolf     char *cmd = argv[0];
65c2cdf5c5SKevin Wolf 
664c7b7e9bSMax Reitz     if (!init_check_command(blk, ct)) {
67c2cdf5c5SKevin Wolf         return 0;
68c2cdf5c5SKevin Wolf     }
69c2cdf5c5SKevin Wolf 
70c2cdf5c5SKevin Wolf     if (argc - 1 < ct->argmin || (ct->argmax != -1 && argc - 1 > ct->argmax)) {
71c2cdf5c5SKevin Wolf         if (ct->argmax == -1) {
72c2cdf5c5SKevin Wolf             fprintf(stderr,
73c2cdf5c5SKevin Wolf                     "bad argument count %d to %s, expected at least %d arguments\n",
74c2cdf5c5SKevin Wolf                     argc-1, cmd, ct->argmin);
75c2cdf5c5SKevin Wolf         } else if (ct->argmin == ct->argmax) {
76c2cdf5c5SKevin Wolf             fprintf(stderr,
77c2cdf5c5SKevin Wolf                     "bad argument count %d to %s, expected %d arguments\n",
78c2cdf5c5SKevin Wolf                     argc-1, cmd, ct->argmin);
79c2cdf5c5SKevin Wolf         } else {
80c2cdf5c5SKevin Wolf             fprintf(stderr,
81c2cdf5c5SKevin Wolf                     "bad argument count %d to %s, expected between %d and %d arguments\n",
82c2cdf5c5SKevin Wolf                     argc-1, cmd, ct->argmin, ct->argmax);
83c2cdf5c5SKevin Wolf         }
84c2cdf5c5SKevin Wolf         return 0;
85c2cdf5c5SKevin Wolf     }
86*887354bdSKevin Wolf 
87*887354bdSKevin Wolf     /* Request additional permissions if necessary for this command. The caller
88*887354bdSKevin Wolf      * is responsible for restoring the original permissions afterwards if this
89*887354bdSKevin Wolf      * is what it wants. */
90*887354bdSKevin Wolf     if (ct->perm && blk_is_available(blk)) {
91*887354bdSKevin Wolf         uint64_t orig_perm, orig_shared_perm;
92*887354bdSKevin Wolf         blk_get_perm(blk, &orig_perm, &orig_shared_perm);
93*887354bdSKevin Wolf 
94*887354bdSKevin Wolf         if (ct->perm & ~orig_perm) {
95*887354bdSKevin Wolf             uint64_t new_perm;
96*887354bdSKevin Wolf             Error *local_err = NULL;
97*887354bdSKevin Wolf             int ret;
98*887354bdSKevin Wolf 
99*887354bdSKevin Wolf             new_perm = orig_perm | ct->perm;
100*887354bdSKevin Wolf 
101*887354bdSKevin Wolf             ret = blk_set_perm(blk, new_perm, orig_shared_perm, &local_err);
102*887354bdSKevin Wolf             if (ret < 0) {
103*887354bdSKevin Wolf                 error_report_err(local_err);
104*887354bdSKevin Wolf                 return 0;
105*887354bdSKevin Wolf             }
106*887354bdSKevin Wolf         }
107*887354bdSKevin Wolf     }
108*887354bdSKevin Wolf 
109c2cdf5c5SKevin Wolf     optind = 0;
1104c7b7e9bSMax Reitz     return ct->cfunc(blk, argc, argv);
111c2cdf5c5SKevin Wolf }
112c2cdf5c5SKevin Wolf 
113c2cdf5c5SKevin Wolf static const cmdinfo_t *find_command(const char *cmd)
114c2cdf5c5SKevin Wolf {
115c2cdf5c5SKevin Wolf     cmdinfo_t *ct;
116c2cdf5c5SKevin Wolf 
117c2cdf5c5SKevin Wolf     for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) {
118c2cdf5c5SKevin Wolf         if (strcmp(ct->name, cmd) == 0 ||
119c2cdf5c5SKevin Wolf             (ct->altname && strcmp(ct->altname, cmd) == 0))
120c2cdf5c5SKevin Wolf         {
121c2cdf5c5SKevin Wolf             return (const cmdinfo_t *)ct;
122c2cdf5c5SKevin Wolf         }
123c2cdf5c5SKevin Wolf     }
124c2cdf5c5SKevin Wolf     return NULL;
125c2cdf5c5SKevin Wolf }
126c2cdf5c5SKevin Wolf 
1274694020dSStefan Hajnoczi /* Invoke fn() for commands with a matching prefix */
1284694020dSStefan Hajnoczi void qemuio_complete_command(const char *input,
1294694020dSStefan Hajnoczi                              void (*fn)(const char *cmd, void *opaque),
1304694020dSStefan Hajnoczi                              void *opaque)
1314694020dSStefan Hajnoczi {
1324694020dSStefan Hajnoczi     cmdinfo_t *ct;
1334694020dSStefan Hajnoczi     size_t input_len = strlen(input);
1344694020dSStefan Hajnoczi 
1354694020dSStefan Hajnoczi     for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) {
1364694020dSStefan Hajnoczi         if (strncmp(input, ct->name, input_len) == 0) {
1374694020dSStefan Hajnoczi             fn(ct->name, opaque);
1384694020dSStefan Hajnoczi         }
1394694020dSStefan Hajnoczi     }
1404694020dSStefan Hajnoczi }
1414694020dSStefan Hajnoczi 
142c2cdf5c5SKevin Wolf static char **breakline(char *input, int *count)
143c2cdf5c5SKevin Wolf {
144c2cdf5c5SKevin Wolf     int c = 0;
145c2cdf5c5SKevin Wolf     char *p;
1465839e53bSMarkus Armbruster     char **rval = g_new0(char *, 1);
147c2cdf5c5SKevin Wolf 
148c2cdf5c5SKevin Wolf     while (rval && (p = qemu_strsep(&input, " ")) != NULL) {
149c2cdf5c5SKevin Wolf         if (!*p) {
150c2cdf5c5SKevin Wolf             continue;
151c2cdf5c5SKevin Wolf         }
152c2cdf5c5SKevin Wolf         c++;
15308193dd5SMarkus Armbruster         rval = g_renew(char *, rval, (c + 1));
154c2cdf5c5SKevin Wolf         rval[c - 1] = p;
155c2cdf5c5SKevin Wolf         rval[c] = NULL;
156c2cdf5c5SKevin Wolf     }
157c2cdf5c5SKevin Wolf     *count = c;
158c2cdf5c5SKevin Wolf     return rval;
159c2cdf5c5SKevin Wolf }
160c2cdf5c5SKevin Wolf 
161797ac58cSKevin Wolf static int64_t cvtnum(const char *s)
162797ac58cSKevin Wolf {
163f17fd4fdSMarkus Armbruster     int err;
164f46bfdbfSMarkus Armbruster     uint64_t value;
165ef5a7885SJohn Snow 
166f17fd4fdSMarkus Armbruster     err = qemu_strtosz(s, NULL, &value);
167f17fd4fdSMarkus Armbruster     if (err < 0) {
168f17fd4fdSMarkus Armbruster         return err;
169f17fd4fdSMarkus Armbruster     }
170f46bfdbfSMarkus Armbruster     if (value > INT64_MAX) {
171f46bfdbfSMarkus Armbruster         return -ERANGE;
172f46bfdbfSMarkus Armbruster     }
173f17fd4fdSMarkus Armbruster     return value;
174797ac58cSKevin Wolf }
175797ac58cSKevin Wolf 
176a9ecfa00SJohn Snow static void print_cvtnum_err(int64_t rc, const char *arg)
177a9ecfa00SJohn Snow {
178a9ecfa00SJohn Snow     switch (rc) {
179a9ecfa00SJohn Snow     case -EINVAL:
180a9ecfa00SJohn Snow         printf("Parsing error: non-numeric argument,"
181a9ecfa00SJohn Snow                " or extraneous/unrecognized suffix -- %s\n", arg);
182a9ecfa00SJohn Snow         break;
183a9ecfa00SJohn Snow     case -ERANGE:
184a9ecfa00SJohn Snow         printf("Parsing error: argument too large -- %s\n", arg);
185a9ecfa00SJohn Snow         break;
186a9ecfa00SJohn Snow     default:
187a9ecfa00SJohn Snow         printf("Parsing error: %s\n", arg);
188a9ecfa00SJohn Snow     }
189a9ecfa00SJohn Snow }
190a9ecfa00SJohn Snow 
1910b613881SKevin Wolf #define EXABYTES(x)     ((long long)(x) << 60)
1920b613881SKevin Wolf #define PETABYTES(x)    ((long long)(x) << 50)
1930b613881SKevin Wolf #define TERABYTES(x)    ((long long)(x) << 40)
1940b613881SKevin Wolf #define GIGABYTES(x)    ((long long)(x) << 30)
1950b613881SKevin Wolf #define MEGABYTES(x)    ((long long)(x) << 20)
1960b613881SKevin Wolf #define KILOBYTES(x)    ((long long)(x) << 10)
1970b613881SKevin Wolf 
1980b613881SKevin Wolf #define TO_EXABYTES(x)  ((x) / EXABYTES(1))
1990b613881SKevin Wolf #define TO_PETABYTES(x) ((x) / PETABYTES(1))
2000b613881SKevin Wolf #define TO_TERABYTES(x) ((x) / TERABYTES(1))
2010b613881SKevin Wolf #define TO_GIGABYTES(x) ((x) / GIGABYTES(1))
2020b613881SKevin Wolf #define TO_MEGABYTES(x) ((x) / MEGABYTES(1))
2030b613881SKevin Wolf #define TO_KILOBYTES(x) ((x) / KILOBYTES(1))
2040b613881SKevin Wolf 
2050b613881SKevin Wolf static void cvtstr(double value, char *str, size_t size)
2060b613881SKevin Wolf {
2070b613881SKevin Wolf     char *trim;
2080b613881SKevin Wolf     const char *suffix;
2090b613881SKevin Wolf 
2100b613881SKevin Wolf     if (value >= EXABYTES(1)) {
2110b613881SKevin Wolf         suffix = " EiB";
2120b613881SKevin Wolf         snprintf(str, size - 4, "%.3f", TO_EXABYTES(value));
2130b613881SKevin Wolf     } else if (value >= PETABYTES(1)) {
2140b613881SKevin Wolf         suffix = " PiB";
2150b613881SKevin Wolf         snprintf(str, size - 4, "%.3f", TO_PETABYTES(value));
2160b613881SKevin Wolf     } else if (value >= TERABYTES(1)) {
2170b613881SKevin Wolf         suffix = " TiB";
2180b613881SKevin Wolf         snprintf(str, size - 4, "%.3f", TO_TERABYTES(value));
2190b613881SKevin Wolf     } else if (value >= GIGABYTES(1)) {
2200b613881SKevin Wolf         suffix = " GiB";
2210b613881SKevin Wolf         snprintf(str, size - 4, "%.3f", TO_GIGABYTES(value));
2220b613881SKevin Wolf     } else if (value >= MEGABYTES(1)) {
2230b613881SKevin Wolf         suffix = " MiB";
2240b613881SKevin Wolf         snprintf(str, size - 4, "%.3f", TO_MEGABYTES(value));
2250b613881SKevin Wolf     } else if (value >= KILOBYTES(1)) {
2260b613881SKevin Wolf         suffix = " KiB";
2270b613881SKevin Wolf         snprintf(str, size - 4, "%.3f", TO_KILOBYTES(value));
2280b613881SKevin Wolf     } else {
2290b613881SKevin Wolf         suffix = " bytes";
2300b613881SKevin Wolf         snprintf(str, size - 6, "%f", value);
2310b613881SKevin Wolf     }
2320b613881SKevin Wolf 
2330b613881SKevin Wolf     trim = strstr(str, ".000");
2340b613881SKevin Wolf     if (trim) {
2350b613881SKevin Wolf         strcpy(trim, suffix);
2360b613881SKevin Wolf     } else {
2370b613881SKevin Wolf         strcat(str, suffix);
2380b613881SKevin Wolf     }
2390b613881SKevin Wolf }
2400b613881SKevin Wolf 
2410b613881SKevin Wolf 
2420b613881SKevin Wolf 
2430b613881SKevin Wolf static struct timeval tsub(struct timeval t1, struct timeval t2)
2440b613881SKevin Wolf {
2450b613881SKevin Wolf     t1.tv_usec -= t2.tv_usec;
2460b613881SKevin Wolf     if (t1.tv_usec < 0) {
2470b613881SKevin Wolf         t1.tv_usec += 1000000;
2480b613881SKevin Wolf         t1.tv_sec--;
2490b613881SKevin Wolf     }
2500b613881SKevin Wolf     t1.tv_sec -= t2.tv_sec;
2510b613881SKevin Wolf     return t1;
2520b613881SKevin Wolf }
2530b613881SKevin Wolf 
2540b613881SKevin Wolf static double tdiv(double value, struct timeval tv)
2550b613881SKevin Wolf {
2560b613881SKevin Wolf     return value / ((double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0));
2570b613881SKevin Wolf }
2580b613881SKevin Wolf 
2590b613881SKevin Wolf #define HOURS(sec)      ((sec) / (60 * 60))
2600b613881SKevin Wolf #define MINUTES(sec)    (((sec) % (60 * 60)) / 60)
2610b613881SKevin Wolf #define SECONDS(sec)    ((sec) % 60)
2620b613881SKevin Wolf 
2630b613881SKevin Wolf enum {
2640b613881SKevin Wolf     DEFAULT_TIME        = 0x0,
2650b613881SKevin Wolf     TERSE_FIXED_TIME    = 0x1,
2660b613881SKevin Wolf     VERBOSE_FIXED_TIME  = 0x2,
2670b613881SKevin Wolf };
2680b613881SKevin Wolf 
2690b613881SKevin Wolf static void timestr(struct timeval *tv, char *ts, size_t size, int format)
2700b613881SKevin Wolf {
2710b613881SKevin Wolf     double usec = (double)tv->tv_usec / 1000000.0;
2720b613881SKevin Wolf 
2730b613881SKevin Wolf     if (format & TERSE_FIXED_TIME) {
2740b613881SKevin Wolf         if (!HOURS(tv->tv_sec)) {
2750b613881SKevin Wolf             snprintf(ts, size, "%u:%02u.%02u",
2760b613881SKevin Wolf                     (unsigned int) MINUTES(tv->tv_sec),
2770b613881SKevin Wolf                     (unsigned int) SECONDS(tv->tv_sec),
2780b613881SKevin Wolf                     (unsigned int) (usec * 100));
2790b613881SKevin Wolf             return;
2800b613881SKevin Wolf         }
2810b613881SKevin Wolf         format |= VERBOSE_FIXED_TIME; /* fallback if hours needed */
2820b613881SKevin Wolf     }
2830b613881SKevin Wolf 
2840b613881SKevin Wolf     if ((format & VERBOSE_FIXED_TIME) || tv->tv_sec) {
2850b613881SKevin Wolf         snprintf(ts, size, "%u:%02u:%02u.%02u",
2860b613881SKevin Wolf                 (unsigned int) HOURS(tv->tv_sec),
2870b613881SKevin Wolf                 (unsigned int) MINUTES(tv->tv_sec),
2880b613881SKevin Wolf                 (unsigned int) SECONDS(tv->tv_sec),
2890b613881SKevin Wolf                 (unsigned int) (usec * 100));
2900b613881SKevin Wolf     } else {
2910b613881SKevin Wolf         snprintf(ts, size, "0.%04u sec", (unsigned int) (usec * 10000));
2920b613881SKevin Wolf     }
2930b613881SKevin Wolf }
2940b613881SKevin Wolf 
295797ac58cSKevin Wolf /*
296797ac58cSKevin Wolf  * Parse the pattern argument to various sub-commands.
297797ac58cSKevin Wolf  *
298797ac58cSKevin Wolf  * Because the pattern is used as an argument to memset it must evaluate
299797ac58cSKevin Wolf  * to an unsigned integer that fits into a single byte.
300797ac58cSKevin Wolf  */
301797ac58cSKevin Wolf static int parse_pattern(const char *arg)
302797ac58cSKevin Wolf {
303797ac58cSKevin Wolf     char *endptr = NULL;
304797ac58cSKevin Wolf     long pattern;
305797ac58cSKevin Wolf 
306797ac58cSKevin Wolf     pattern = strtol(arg, &endptr, 0);
307797ac58cSKevin Wolf     if (pattern < 0 || pattern > UCHAR_MAX || *endptr != '\0') {
308797ac58cSKevin Wolf         printf("%s is not a valid pattern byte\n", arg);
309797ac58cSKevin Wolf         return -1;
310797ac58cSKevin Wolf     }
311797ac58cSKevin Wolf 
312797ac58cSKevin Wolf     return pattern;
313797ac58cSKevin Wolf }
314797ac58cSKevin Wolf 
315797ac58cSKevin Wolf /*
316797ac58cSKevin Wolf  * Memory allocation helpers.
317797ac58cSKevin Wolf  *
318797ac58cSKevin Wolf  * Make sure memory is aligned by default, or purposefully misaligned if
319797ac58cSKevin Wolf  * that is specified on the command line.
320797ac58cSKevin Wolf  */
321797ac58cSKevin Wolf 
322797ac58cSKevin Wolf #define MISALIGN_OFFSET     16
3234c7b7e9bSMax Reitz static void *qemu_io_alloc(BlockBackend *blk, size_t len, int pattern)
324797ac58cSKevin Wolf {
325797ac58cSKevin Wolf     void *buf;
326797ac58cSKevin Wolf 
327797ac58cSKevin Wolf     if (qemuio_misalign) {
328797ac58cSKevin Wolf         len += MISALIGN_OFFSET;
329797ac58cSKevin Wolf     }
3304c7b7e9bSMax Reitz     buf = blk_blockalign(blk, len);
331797ac58cSKevin Wolf     memset(buf, pattern, len);
332797ac58cSKevin Wolf     if (qemuio_misalign) {
333797ac58cSKevin Wolf         buf += MISALIGN_OFFSET;
334797ac58cSKevin Wolf     }
335797ac58cSKevin Wolf     return buf;
336797ac58cSKevin Wolf }
337797ac58cSKevin Wolf 
338797ac58cSKevin Wolf static void qemu_io_free(void *p)
339797ac58cSKevin Wolf {
340797ac58cSKevin Wolf     if (qemuio_misalign) {
341797ac58cSKevin Wolf         p -= MISALIGN_OFFSET;
342797ac58cSKevin Wolf     }
343797ac58cSKevin Wolf     qemu_vfree(p);
344797ac58cSKevin Wolf }
345797ac58cSKevin Wolf 
3469b0beaf3SJohn Snow static void dump_buffer(const void *buffer, int64_t offset, int64_t len)
347797ac58cSKevin Wolf {
3489b0beaf3SJohn Snow     uint64_t i;
3499b0beaf3SJohn Snow     int j;
350797ac58cSKevin Wolf     const uint8_t *p;
351797ac58cSKevin Wolf 
352797ac58cSKevin Wolf     for (i = 0, p = buffer; i < len; i += 16) {
353797ac58cSKevin Wolf         const uint8_t *s = p;
354797ac58cSKevin Wolf 
355797ac58cSKevin Wolf         printf("%08" PRIx64 ":  ", offset + i);
356797ac58cSKevin Wolf         for (j = 0; j < 16 && i + j < len; j++, p++) {
357797ac58cSKevin Wolf             printf("%02x ", *p);
358797ac58cSKevin Wolf         }
359797ac58cSKevin Wolf         printf(" ");
360797ac58cSKevin Wolf         for (j = 0; j < 16 && i + j < len; j++, s++) {
361797ac58cSKevin Wolf             if (isalnum(*s)) {
362797ac58cSKevin Wolf                 printf("%c", *s);
363797ac58cSKevin Wolf             } else {
364797ac58cSKevin Wolf                 printf(".");
365797ac58cSKevin Wolf             }
366797ac58cSKevin Wolf         }
367797ac58cSKevin Wolf         printf("\n");
368797ac58cSKevin Wolf     }
369797ac58cSKevin Wolf }
370797ac58cSKevin Wolf 
371797ac58cSKevin Wolf static void print_report(const char *op, struct timeval *t, int64_t offset,
372dc38852aSEric Blake                          int64_t count, int64_t total, int cnt, bool Cflag)
373797ac58cSKevin Wolf {
374797ac58cSKevin Wolf     char s1[64], s2[64], ts[64];
375797ac58cSKevin Wolf 
376797ac58cSKevin Wolf     timestr(t, ts, sizeof(ts), Cflag ? VERBOSE_FIXED_TIME : 0);
377797ac58cSKevin Wolf     if (!Cflag) {
378797ac58cSKevin Wolf         cvtstr((double)total, s1, sizeof(s1));
379797ac58cSKevin Wolf         cvtstr(tdiv((double)total, *t), s2, sizeof(s2));
3809b0beaf3SJohn Snow         printf("%s %"PRId64"/%"PRId64" bytes at offset %" PRId64 "\n",
381797ac58cSKevin Wolf                op, total, count, offset);
382797ac58cSKevin Wolf         printf("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n",
383797ac58cSKevin Wolf                s1, cnt, ts, s2, tdiv((double)cnt, *t));
384797ac58cSKevin Wolf     } else {/* bytes,ops,time,bytes/sec,ops/sec */
3859b0beaf3SJohn Snow         printf("%"PRId64",%d,%s,%.3f,%.3f\n",
386797ac58cSKevin Wolf             total, cnt, ts,
387797ac58cSKevin Wolf             tdiv((double)total, *t),
388797ac58cSKevin Wolf             tdiv((double)cnt, *t));
389797ac58cSKevin Wolf     }
390797ac58cSKevin Wolf }
391797ac58cSKevin Wolf 
392797ac58cSKevin Wolf /*
393797ac58cSKevin Wolf  * Parse multiple length statements for vectored I/O, and construct an I/O
394797ac58cSKevin Wolf  * vector matching it.
395797ac58cSKevin Wolf  */
396797ac58cSKevin Wolf static void *
3974c7b7e9bSMax Reitz create_iovec(BlockBackend *blk, QEMUIOVector *qiov, char **argv, int nr_iov,
398797ac58cSKevin Wolf              int pattern)
399797ac58cSKevin Wolf {
400797ac58cSKevin Wolf     size_t *sizes = g_new0(size_t, nr_iov);
401797ac58cSKevin Wolf     size_t count = 0;
402797ac58cSKevin Wolf     void *buf = NULL;
403797ac58cSKevin Wolf     void *p;
404797ac58cSKevin Wolf     int i;
405797ac58cSKevin Wolf 
406797ac58cSKevin Wolf     for (i = 0; i < nr_iov; i++) {
407797ac58cSKevin Wolf         char *arg = argv[i];
408797ac58cSKevin Wolf         int64_t len;
409797ac58cSKevin Wolf 
410797ac58cSKevin Wolf         len = cvtnum(arg);
411797ac58cSKevin Wolf         if (len < 0) {
412a9ecfa00SJohn Snow             print_cvtnum_err(len, arg);
413797ac58cSKevin Wolf             goto fail;
414797ac58cSKevin Wolf         }
415797ac58cSKevin Wolf 
4163026c468SAlberto Garcia         if (len > BDRV_REQUEST_MAX_BYTES) {
4173026c468SAlberto Garcia             printf("Argument '%s' exceeds maximum size %" PRIu64 "\n", arg,
4183026c468SAlberto Garcia                    (uint64_t)BDRV_REQUEST_MAX_BYTES);
4193026c468SAlberto Garcia             goto fail;
4203026c468SAlberto Garcia         }
4213026c468SAlberto Garcia 
4223026c468SAlberto Garcia         if (count > BDRV_REQUEST_MAX_BYTES - len) {
4233026c468SAlberto Garcia             printf("The total number of bytes exceed the maximum size %" PRIu64
4243026c468SAlberto Garcia                    "\n", (uint64_t)BDRV_REQUEST_MAX_BYTES);
425797ac58cSKevin Wolf             goto fail;
426797ac58cSKevin Wolf         }
427797ac58cSKevin Wolf 
428797ac58cSKevin Wolf         sizes[i] = len;
429797ac58cSKevin Wolf         count += len;
430797ac58cSKevin Wolf     }
431797ac58cSKevin Wolf 
432797ac58cSKevin Wolf     qemu_iovec_init(qiov, nr_iov);
433797ac58cSKevin Wolf 
4344c7b7e9bSMax Reitz     buf = p = qemu_io_alloc(blk, count, pattern);
435797ac58cSKevin Wolf 
436797ac58cSKevin Wolf     for (i = 0; i < nr_iov; i++) {
437797ac58cSKevin Wolf         qemu_iovec_add(qiov, p, sizes[i]);
438797ac58cSKevin Wolf         p += sizes[i];
439797ac58cSKevin Wolf     }
440797ac58cSKevin Wolf 
441797ac58cSKevin Wolf fail:
442797ac58cSKevin Wolf     g_free(sizes);
443797ac58cSKevin Wolf     return buf;
444797ac58cSKevin Wolf }
445797ac58cSKevin Wolf 
4469b0beaf3SJohn Snow static int do_pread(BlockBackend *blk, char *buf, int64_t offset,
4479b0beaf3SJohn Snow                     int64_t count, int64_t *total)
448797ac58cSKevin Wolf {
4499b0beaf3SJohn Snow     if (count > INT_MAX) {
4509b0beaf3SJohn Snow         return -ERANGE;
4519b0beaf3SJohn Snow     }
4529b0beaf3SJohn Snow 
4534c7b7e9bSMax Reitz     *total = blk_pread(blk, offset, (uint8_t *)buf, count);
454797ac58cSKevin Wolf     if (*total < 0) {
455797ac58cSKevin Wolf         return *total;
456797ac58cSKevin Wolf     }
457797ac58cSKevin Wolf     return 1;
458797ac58cSKevin Wolf }
459797ac58cSKevin Wolf 
4609b0beaf3SJohn Snow static int do_pwrite(BlockBackend *blk, char *buf, int64_t offset,
461770e0e0eSEric Blake                      int64_t count, int flags, int64_t *total)
462797ac58cSKevin Wolf {
4639b0beaf3SJohn Snow     if (count > INT_MAX) {
4649b0beaf3SJohn Snow         return -ERANGE;
4659b0beaf3SJohn Snow     }
4669b0beaf3SJohn Snow 
467770e0e0eSEric Blake     *total = blk_pwrite(blk, offset, (uint8_t *)buf, count, flags);
468797ac58cSKevin Wolf     if (*total < 0) {
469797ac58cSKevin Wolf         return *total;
470797ac58cSKevin Wolf     }
471797ac58cSKevin Wolf     return 1;
472797ac58cSKevin Wolf }
473797ac58cSKevin Wolf 
474797ac58cSKevin Wolf typedef struct {
4754c7b7e9bSMax Reitz     BlockBackend *blk;
476797ac58cSKevin Wolf     int64_t offset;
4779b0beaf3SJohn Snow     int64_t count;
4789b0beaf3SJohn Snow     int64_t *total;
479770e0e0eSEric Blake     int flags;
480797ac58cSKevin Wolf     int ret;
481797ac58cSKevin Wolf     bool done;
482797ac58cSKevin Wolf } CoWriteZeroes;
483797ac58cSKevin Wolf 
484d004bd52SEric Blake static void coroutine_fn co_pwrite_zeroes_entry(void *opaque)
485797ac58cSKevin Wolf {
486797ac58cSKevin Wolf     CoWriteZeroes *data = opaque;
487797ac58cSKevin Wolf 
488d004bd52SEric Blake     data->ret = blk_co_pwrite_zeroes(data->blk, data->offset, data->count,
489770e0e0eSEric Blake                                      data->flags);
490797ac58cSKevin Wolf     data->done = true;
491797ac58cSKevin Wolf     if (data->ret < 0) {
492797ac58cSKevin Wolf         *data->total = data->ret;
493797ac58cSKevin Wolf         return;
494797ac58cSKevin Wolf     }
495797ac58cSKevin Wolf 
496797ac58cSKevin Wolf     *data->total = data->count;
497797ac58cSKevin Wolf }
498797ac58cSKevin Wolf 
499d004bd52SEric Blake static int do_co_pwrite_zeroes(BlockBackend *blk, int64_t offset,
500d004bd52SEric Blake                                int64_t count, int flags, int64_t *total)
501797ac58cSKevin Wolf {
502797ac58cSKevin Wolf     Coroutine *co;
503797ac58cSKevin Wolf     CoWriteZeroes data = {
5044c7b7e9bSMax Reitz         .blk    = blk,
505797ac58cSKevin Wolf         .offset = offset,
506797ac58cSKevin Wolf         .count  = count,
507797ac58cSKevin Wolf         .total  = total,
508770e0e0eSEric Blake         .flags  = flags,
509797ac58cSKevin Wolf         .done   = false,
510797ac58cSKevin Wolf     };
511797ac58cSKevin Wolf 
512a3674679SMax Reitz     if (count > INT_MAX) {
5139b0beaf3SJohn Snow         return -ERANGE;
5149b0beaf3SJohn Snow     }
5159b0beaf3SJohn Snow 
5160b8b8753SPaolo Bonzini     co = qemu_coroutine_create(co_pwrite_zeroes_entry, &data);
5170b8b8753SPaolo Bonzini     qemu_coroutine_enter(co);
518797ac58cSKevin Wolf     while (!data.done) {
5194c7b7e9bSMax Reitz         aio_poll(blk_get_aio_context(blk), true);
520797ac58cSKevin Wolf     }
521797ac58cSKevin Wolf     if (data.ret < 0) {
522797ac58cSKevin Wolf         return data.ret;
523797ac58cSKevin Wolf     } else {
524797ac58cSKevin Wolf         return 1;
525797ac58cSKevin Wolf     }
526797ac58cSKevin Wolf }
527797ac58cSKevin Wolf 
5284c7b7e9bSMax Reitz static int do_write_compressed(BlockBackend *blk, char *buf, int64_t offset,
5299b0beaf3SJohn Snow                                int64_t count, int64_t *total)
530797ac58cSKevin Wolf {
531797ac58cSKevin Wolf     int ret;
532797ac58cSKevin Wolf 
533a3674679SMax Reitz     if (count >> 9 > BDRV_REQUEST_MAX_SECTORS) {
5349b0beaf3SJohn Snow         return -ERANGE;
5359b0beaf3SJohn Snow     }
5369b0beaf3SJohn Snow 
537fe5c1355SPavel Butsykin     ret = blk_pwrite_compressed(blk, offset, buf, count);
538797ac58cSKevin Wolf     if (ret < 0) {
539797ac58cSKevin Wolf         return ret;
540797ac58cSKevin Wolf     }
541797ac58cSKevin Wolf     *total = count;
542797ac58cSKevin Wolf     return 1;
543797ac58cSKevin Wolf }
544797ac58cSKevin Wolf 
5454c7b7e9bSMax Reitz static int do_load_vmstate(BlockBackend *blk, char *buf, int64_t offset,
5469b0beaf3SJohn Snow                            int64_t count, int64_t *total)
547797ac58cSKevin Wolf {
5489b0beaf3SJohn Snow     if (count > INT_MAX) {
5499b0beaf3SJohn Snow         return -ERANGE;
5509b0beaf3SJohn Snow     }
5519b0beaf3SJohn Snow 
5524c7b7e9bSMax Reitz     *total = blk_load_vmstate(blk, (uint8_t *)buf, offset, count);
553797ac58cSKevin Wolf     if (*total < 0) {
554797ac58cSKevin Wolf         return *total;
555797ac58cSKevin Wolf     }
556797ac58cSKevin Wolf     return 1;
557797ac58cSKevin Wolf }
558797ac58cSKevin Wolf 
5594c7b7e9bSMax Reitz static int do_save_vmstate(BlockBackend *blk, char *buf, int64_t offset,
5609b0beaf3SJohn Snow                            int64_t count, int64_t *total)
561797ac58cSKevin Wolf {
5629b0beaf3SJohn Snow     if (count > INT_MAX) {
5639b0beaf3SJohn Snow         return -ERANGE;
5649b0beaf3SJohn Snow     }
5659b0beaf3SJohn Snow 
5664c7b7e9bSMax Reitz     *total = blk_save_vmstate(blk, (uint8_t *)buf, offset, count);
567797ac58cSKevin Wolf     if (*total < 0) {
568797ac58cSKevin Wolf         return *total;
569797ac58cSKevin Wolf     }
570797ac58cSKevin Wolf     return 1;
571797ac58cSKevin Wolf }
572797ac58cSKevin Wolf 
573797ac58cSKevin Wolf #define NOT_DONE 0x7fffffff
574797ac58cSKevin Wolf static void aio_rw_done(void *opaque, int ret)
575797ac58cSKevin Wolf {
576797ac58cSKevin Wolf     *(int *)opaque = ret;
577797ac58cSKevin Wolf }
578797ac58cSKevin Wolf 
5794c7b7e9bSMax Reitz static int do_aio_readv(BlockBackend *blk, QEMUIOVector *qiov,
580797ac58cSKevin Wolf                         int64_t offset, int *total)
581797ac58cSKevin Wolf {
582797ac58cSKevin Wolf     int async_ret = NOT_DONE;
583797ac58cSKevin Wolf 
5847b3f9712SEric Blake     blk_aio_preadv(blk, offset, qiov, 0, aio_rw_done, &async_ret);
585797ac58cSKevin Wolf     while (async_ret == NOT_DONE) {
586797ac58cSKevin Wolf         main_loop_wait(false);
587797ac58cSKevin Wolf     }
588797ac58cSKevin Wolf 
589797ac58cSKevin Wolf     *total = qiov->size;
590797ac58cSKevin Wolf     return async_ret < 0 ? async_ret : 1;
591797ac58cSKevin Wolf }
592797ac58cSKevin Wolf 
5934c7b7e9bSMax Reitz static int do_aio_writev(BlockBackend *blk, QEMUIOVector *qiov,
594770e0e0eSEric Blake                          int64_t offset, int flags, int *total)
595797ac58cSKevin Wolf {
596797ac58cSKevin Wolf     int async_ret = NOT_DONE;
597797ac58cSKevin Wolf 
598770e0e0eSEric Blake     blk_aio_pwritev(blk, offset, qiov, flags, aio_rw_done, &async_ret);
599797ac58cSKevin Wolf     while (async_ret == NOT_DONE) {
600797ac58cSKevin Wolf         main_loop_wait(false);
601797ac58cSKevin Wolf     }
602797ac58cSKevin Wolf 
603797ac58cSKevin Wolf     *total = qiov->size;
604797ac58cSKevin Wolf     return async_ret < 0 ? async_ret : 1;
605797ac58cSKevin Wolf }
606797ac58cSKevin Wolf 
607797ac58cSKevin Wolf static void read_help(void)
608797ac58cSKevin Wolf {
609797ac58cSKevin Wolf     printf(
610797ac58cSKevin Wolf "\n"
611797ac58cSKevin Wolf " reads a range of bytes from the given offset\n"
612797ac58cSKevin Wolf "\n"
613797ac58cSKevin Wolf " Example:\n"
614797ac58cSKevin Wolf " 'read -v 512 1k' - dumps 1 kilobyte read from 512 bytes into the file\n"
615797ac58cSKevin Wolf "\n"
616797ac58cSKevin Wolf " Reads a segment of the currently open file, optionally dumping it to the\n"
617797ac58cSKevin Wolf " standard output stream (with -v option) for subsequent inspection.\n"
618797ac58cSKevin Wolf " -b, -- read from the VM state rather than the virtual disk\n"
619797ac58cSKevin Wolf " -C, -- report statistics in a machine parsable format\n"
620797ac58cSKevin Wolf " -l, -- length for pattern verification (only with -P)\n"
621093ea232SEric Blake " -p, -- ignored for backwards compatibility\n"
622797ac58cSKevin Wolf " -P, -- use a pattern to verify read data\n"
623797ac58cSKevin Wolf " -q, -- quiet mode, do not show I/O statistics\n"
624797ac58cSKevin Wolf " -s, -- start offset for pattern verification (only with -P)\n"
625797ac58cSKevin Wolf " -v, -- dump buffer to standard output\n"
626797ac58cSKevin Wolf "\n");
627797ac58cSKevin Wolf }
628797ac58cSKevin Wolf 
6294c7b7e9bSMax Reitz static int read_f(BlockBackend *blk, int argc, char **argv);
630797ac58cSKevin Wolf 
631797ac58cSKevin Wolf static const cmdinfo_t read_cmd = {
632797ac58cSKevin Wolf     .name       = "read",
633797ac58cSKevin Wolf     .altname    = "r",
634797ac58cSKevin Wolf     .cfunc      = read_f,
635797ac58cSKevin Wolf     .argmin     = 2,
636797ac58cSKevin Wolf     .argmax     = -1,
637093ea232SEric Blake     .args       = "[-abCqv] [-P pattern [-s off] [-l len]] off len",
638797ac58cSKevin Wolf     .oneline    = "reads a number of bytes at a specified offset",
639797ac58cSKevin Wolf     .help       = read_help,
640797ac58cSKevin Wolf };
641797ac58cSKevin Wolf 
6424c7b7e9bSMax Reitz static int read_f(BlockBackend *blk, int argc, char **argv)
643797ac58cSKevin Wolf {
644797ac58cSKevin Wolf     struct timeval t1, t2;
645093ea232SEric Blake     bool Cflag = false, qflag = false, vflag = false;
646dc38852aSEric Blake     bool Pflag = false, sflag = false, lflag = false, bflag = false;
647797ac58cSKevin Wolf     int c, cnt;
648797ac58cSKevin Wolf     char *buf;
649797ac58cSKevin Wolf     int64_t offset;
6509b0beaf3SJohn Snow     int64_t count;
651797ac58cSKevin Wolf     /* Some compilers get confused and warn if this is not initialized.  */
6529b0beaf3SJohn Snow     int64_t total = 0;
6539b0beaf3SJohn Snow     int pattern = 0;
6549b0beaf3SJohn Snow     int64_t pattern_offset = 0, pattern_count = 0;
655797ac58cSKevin Wolf 
656b062ad86SEric Blake     while ((c = getopt(argc, argv, "bCl:pP:qs:v")) != -1) {
657797ac58cSKevin Wolf         switch (c) {
658797ac58cSKevin Wolf         case 'b':
659dc38852aSEric Blake             bflag = true;
660797ac58cSKevin Wolf             break;
661797ac58cSKevin Wolf         case 'C':
662dc38852aSEric Blake             Cflag = true;
663797ac58cSKevin Wolf             break;
664797ac58cSKevin Wolf         case 'l':
665dc38852aSEric Blake             lflag = true;
666797ac58cSKevin Wolf             pattern_count = cvtnum(optarg);
667797ac58cSKevin Wolf             if (pattern_count < 0) {
668a9ecfa00SJohn Snow                 print_cvtnum_err(pattern_count, optarg);
669797ac58cSKevin Wolf                 return 0;
670797ac58cSKevin Wolf             }
671797ac58cSKevin Wolf             break;
672797ac58cSKevin Wolf         case 'p':
673093ea232SEric Blake             /* Ignored for backwards compatibility */
674797ac58cSKevin Wolf             break;
675797ac58cSKevin Wolf         case 'P':
676dc38852aSEric Blake             Pflag = true;
677797ac58cSKevin Wolf             pattern = parse_pattern(optarg);
678797ac58cSKevin Wolf             if (pattern < 0) {
679797ac58cSKevin Wolf                 return 0;
680797ac58cSKevin Wolf             }
681797ac58cSKevin Wolf             break;
682797ac58cSKevin Wolf         case 'q':
683dc38852aSEric Blake             qflag = true;
684797ac58cSKevin Wolf             break;
685797ac58cSKevin Wolf         case 's':
686dc38852aSEric Blake             sflag = true;
687797ac58cSKevin Wolf             pattern_offset = cvtnum(optarg);
688797ac58cSKevin Wolf             if (pattern_offset < 0) {
689a9ecfa00SJohn Snow                 print_cvtnum_err(pattern_offset, optarg);
690797ac58cSKevin Wolf                 return 0;
691797ac58cSKevin Wolf             }
692797ac58cSKevin Wolf             break;
693797ac58cSKevin Wolf         case 'v':
694dc38852aSEric Blake             vflag = true;
695797ac58cSKevin Wolf             break;
696797ac58cSKevin Wolf         default:
697c2cdf5c5SKevin Wolf             return qemuio_command_usage(&read_cmd);
698797ac58cSKevin Wolf         }
699797ac58cSKevin Wolf     }
700797ac58cSKevin Wolf 
701797ac58cSKevin Wolf     if (optind != argc - 2) {
702c2cdf5c5SKevin Wolf         return qemuio_command_usage(&read_cmd);
703797ac58cSKevin Wolf     }
704797ac58cSKevin Wolf 
705797ac58cSKevin Wolf     offset = cvtnum(argv[optind]);
706797ac58cSKevin Wolf     if (offset < 0) {
707a9ecfa00SJohn Snow         print_cvtnum_err(offset, argv[optind]);
708797ac58cSKevin Wolf         return 0;
709797ac58cSKevin Wolf     }
710797ac58cSKevin Wolf 
711797ac58cSKevin Wolf     optind++;
712797ac58cSKevin Wolf     count = cvtnum(argv[optind]);
713797ac58cSKevin Wolf     if (count < 0) {
714a9ecfa00SJohn Snow         print_cvtnum_err(count, argv[optind]);
715797ac58cSKevin Wolf         return 0;
7163026c468SAlberto Garcia     } else if (count > BDRV_REQUEST_MAX_BYTES) {
7179b0beaf3SJohn Snow         printf("length cannot exceed %" PRIu64 ", given %s\n",
7183026c468SAlberto Garcia                (uint64_t)BDRV_REQUEST_MAX_BYTES, argv[optind]);
7199b0beaf3SJohn Snow         return 0;
720797ac58cSKevin Wolf     }
721797ac58cSKevin Wolf 
722797ac58cSKevin Wolf     if (!Pflag && (lflag || sflag)) {
723c2cdf5c5SKevin Wolf         return qemuio_command_usage(&read_cmd);
724797ac58cSKevin Wolf     }
725797ac58cSKevin Wolf 
726797ac58cSKevin Wolf     if (!lflag) {
727797ac58cSKevin Wolf         pattern_count = count - pattern_offset;
728797ac58cSKevin Wolf     }
729797ac58cSKevin Wolf 
730797ac58cSKevin Wolf     if ((pattern_count < 0) || (pattern_count + pattern_offset > count))  {
731797ac58cSKevin Wolf         printf("pattern verification range exceeds end of read data\n");
732797ac58cSKevin Wolf         return 0;
733797ac58cSKevin Wolf     }
734797ac58cSKevin Wolf 
735093ea232SEric Blake     if (bflag) {
736797ac58cSKevin Wolf         if (offset & 0x1ff) {
737797ac58cSKevin Wolf             printf("offset %" PRId64 " is not sector aligned\n",
738797ac58cSKevin Wolf                    offset);
739797ac58cSKevin Wolf             return 0;
740797ac58cSKevin Wolf         }
741797ac58cSKevin Wolf         if (count & 0x1ff) {
7429b0beaf3SJohn Snow             printf("count %"PRId64" is not sector aligned\n",
743797ac58cSKevin Wolf                    count);
744797ac58cSKevin Wolf             return 0;
745797ac58cSKevin Wolf         }
746797ac58cSKevin Wolf     }
747797ac58cSKevin Wolf 
7484c7b7e9bSMax Reitz     buf = qemu_io_alloc(blk, count, 0xab);
749797ac58cSKevin Wolf 
750797ac58cSKevin Wolf     gettimeofday(&t1, NULL);
7517b3f9712SEric Blake     if (bflag) {
7524c7b7e9bSMax Reitz         cnt = do_load_vmstate(blk, buf, offset, count, &total);
753797ac58cSKevin Wolf     } else {
7547b3f9712SEric Blake         cnt = do_pread(blk, buf, offset, count, &total);
755797ac58cSKevin Wolf     }
756797ac58cSKevin Wolf     gettimeofday(&t2, NULL);
757797ac58cSKevin Wolf 
758797ac58cSKevin Wolf     if (cnt < 0) {
759797ac58cSKevin Wolf         printf("read failed: %s\n", strerror(-cnt));
760797ac58cSKevin Wolf         goto out;
761797ac58cSKevin Wolf     }
762797ac58cSKevin Wolf 
763797ac58cSKevin Wolf     if (Pflag) {
764797ac58cSKevin Wolf         void *cmp_buf = g_malloc(pattern_count);
765797ac58cSKevin Wolf         memset(cmp_buf, pattern, pattern_count);
766797ac58cSKevin Wolf         if (memcmp(buf + pattern_offset, cmp_buf, pattern_count)) {
767797ac58cSKevin Wolf             printf("Pattern verification failed at offset %"
7689b0beaf3SJohn Snow                    PRId64 ", %"PRId64" bytes\n",
769797ac58cSKevin Wolf                    offset + pattern_offset, pattern_count);
770797ac58cSKevin Wolf         }
771797ac58cSKevin Wolf         g_free(cmp_buf);
772797ac58cSKevin Wolf     }
773797ac58cSKevin Wolf 
774797ac58cSKevin Wolf     if (qflag) {
775797ac58cSKevin Wolf         goto out;
776797ac58cSKevin Wolf     }
777797ac58cSKevin Wolf 
778797ac58cSKevin Wolf     if (vflag) {
779797ac58cSKevin Wolf         dump_buffer(buf, offset, count);
780797ac58cSKevin Wolf     }
781797ac58cSKevin Wolf 
782797ac58cSKevin Wolf     /* Finally, report back -- -C gives a parsable format */
783797ac58cSKevin Wolf     t2 = tsub(t2, t1);
784797ac58cSKevin Wolf     print_report("read", &t2, offset, count, total, cnt, Cflag);
785797ac58cSKevin Wolf 
786797ac58cSKevin Wolf out:
787797ac58cSKevin Wolf     qemu_io_free(buf);
788797ac58cSKevin Wolf 
789797ac58cSKevin Wolf     return 0;
790797ac58cSKevin Wolf }
791797ac58cSKevin Wolf 
792797ac58cSKevin Wolf static void readv_help(void)
793797ac58cSKevin Wolf {
794797ac58cSKevin Wolf     printf(
795797ac58cSKevin Wolf "\n"
796797ac58cSKevin Wolf " reads a range of bytes from the given offset into multiple buffers\n"
797797ac58cSKevin Wolf "\n"
798797ac58cSKevin Wolf " Example:\n"
799797ac58cSKevin Wolf " 'readv -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n"
800797ac58cSKevin Wolf "\n"
801797ac58cSKevin Wolf " Reads a segment of the currently open file, optionally dumping it to the\n"
802797ac58cSKevin Wolf " standard output stream (with -v option) for subsequent inspection.\n"
803797ac58cSKevin Wolf " Uses multiple iovec buffers if more than one byte range is specified.\n"
804797ac58cSKevin Wolf " -C, -- report statistics in a machine parsable format\n"
805797ac58cSKevin Wolf " -P, -- use a pattern to verify read data\n"
806797ac58cSKevin Wolf " -v, -- dump buffer to standard output\n"
807797ac58cSKevin Wolf " -q, -- quiet mode, do not show I/O statistics\n"
808797ac58cSKevin Wolf "\n");
809797ac58cSKevin Wolf }
810797ac58cSKevin Wolf 
8114c7b7e9bSMax Reitz static int readv_f(BlockBackend *blk, int argc, char **argv);
812797ac58cSKevin Wolf 
813797ac58cSKevin Wolf static const cmdinfo_t readv_cmd = {
814797ac58cSKevin Wolf     .name       = "readv",
815797ac58cSKevin Wolf     .cfunc      = readv_f,
816797ac58cSKevin Wolf     .argmin     = 2,
817797ac58cSKevin Wolf     .argmax     = -1,
818797ac58cSKevin Wolf     .args       = "[-Cqv] [-P pattern] off len [len..]",
819797ac58cSKevin Wolf     .oneline    = "reads a number of bytes at a specified offset",
820797ac58cSKevin Wolf     .help       = readv_help,
821797ac58cSKevin Wolf };
822797ac58cSKevin Wolf 
8234c7b7e9bSMax Reitz static int readv_f(BlockBackend *blk, int argc, char **argv)
824797ac58cSKevin Wolf {
825797ac58cSKevin Wolf     struct timeval t1, t2;
826dc38852aSEric Blake     bool Cflag = false, qflag = false, vflag = false;
827797ac58cSKevin Wolf     int c, cnt;
828797ac58cSKevin Wolf     char *buf;
829797ac58cSKevin Wolf     int64_t offset;
830797ac58cSKevin Wolf     /* Some compilers get confused and warn if this is not initialized.  */
831797ac58cSKevin Wolf     int total = 0;
832797ac58cSKevin Wolf     int nr_iov;
833797ac58cSKevin Wolf     QEMUIOVector qiov;
834797ac58cSKevin Wolf     int pattern = 0;
835dc38852aSEric Blake     bool Pflag = false;
836797ac58cSKevin Wolf 
837b062ad86SEric Blake     while ((c = getopt(argc, argv, "CP:qv")) != -1) {
838797ac58cSKevin Wolf         switch (c) {
839797ac58cSKevin Wolf         case 'C':
840dc38852aSEric Blake             Cflag = true;
841797ac58cSKevin Wolf             break;
842797ac58cSKevin Wolf         case 'P':
843dc38852aSEric Blake             Pflag = true;
844797ac58cSKevin Wolf             pattern = parse_pattern(optarg);
845797ac58cSKevin Wolf             if (pattern < 0) {
846797ac58cSKevin Wolf                 return 0;
847797ac58cSKevin Wolf             }
848797ac58cSKevin Wolf             break;
849797ac58cSKevin Wolf         case 'q':
850dc38852aSEric Blake             qflag = true;
851797ac58cSKevin Wolf             break;
852797ac58cSKevin Wolf         case 'v':
853dc38852aSEric Blake             vflag = true;
854797ac58cSKevin Wolf             break;
855797ac58cSKevin Wolf         default:
856c2cdf5c5SKevin Wolf             return qemuio_command_usage(&readv_cmd);
857797ac58cSKevin Wolf         }
858797ac58cSKevin Wolf     }
859797ac58cSKevin Wolf 
860797ac58cSKevin Wolf     if (optind > argc - 2) {
861c2cdf5c5SKevin Wolf         return qemuio_command_usage(&readv_cmd);
862797ac58cSKevin Wolf     }
863797ac58cSKevin Wolf 
864797ac58cSKevin Wolf 
865797ac58cSKevin Wolf     offset = cvtnum(argv[optind]);
866797ac58cSKevin Wolf     if (offset < 0) {
867a9ecfa00SJohn Snow         print_cvtnum_err(offset, argv[optind]);
868797ac58cSKevin Wolf         return 0;
869797ac58cSKevin Wolf     }
870797ac58cSKevin Wolf     optind++;
871797ac58cSKevin Wolf 
872797ac58cSKevin Wolf     nr_iov = argc - optind;
8734c7b7e9bSMax Reitz     buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, 0xab);
874797ac58cSKevin Wolf     if (buf == NULL) {
875797ac58cSKevin Wolf         return 0;
876797ac58cSKevin Wolf     }
877797ac58cSKevin Wolf 
878797ac58cSKevin Wolf     gettimeofday(&t1, NULL);
8794c7b7e9bSMax Reitz     cnt = do_aio_readv(blk, &qiov, offset, &total);
880797ac58cSKevin Wolf     gettimeofday(&t2, NULL);
881797ac58cSKevin Wolf 
882797ac58cSKevin Wolf     if (cnt < 0) {
883797ac58cSKevin Wolf         printf("readv failed: %s\n", strerror(-cnt));
884797ac58cSKevin Wolf         goto out;
885797ac58cSKevin Wolf     }
886797ac58cSKevin Wolf 
887797ac58cSKevin Wolf     if (Pflag) {
888797ac58cSKevin Wolf         void *cmp_buf = g_malloc(qiov.size);
889797ac58cSKevin Wolf         memset(cmp_buf, pattern, qiov.size);
890797ac58cSKevin Wolf         if (memcmp(buf, cmp_buf, qiov.size)) {
891797ac58cSKevin Wolf             printf("Pattern verification failed at offset %"
892797ac58cSKevin Wolf                    PRId64 ", %zd bytes\n", offset, qiov.size);
893797ac58cSKevin Wolf         }
894797ac58cSKevin Wolf         g_free(cmp_buf);
895797ac58cSKevin Wolf     }
896797ac58cSKevin Wolf 
897797ac58cSKevin Wolf     if (qflag) {
898797ac58cSKevin Wolf         goto out;
899797ac58cSKevin Wolf     }
900797ac58cSKevin Wolf 
901797ac58cSKevin Wolf     if (vflag) {
902797ac58cSKevin Wolf         dump_buffer(buf, offset, qiov.size);
903797ac58cSKevin Wolf     }
904797ac58cSKevin Wolf 
905797ac58cSKevin Wolf     /* Finally, report back -- -C gives a parsable format */
906797ac58cSKevin Wolf     t2 = tsub(t2, t1);
907797ac58cSKevin Wolf     print_report("read", &t2, offset, qiov.size, total, cnt, Cflag);
908797ac58cSKevin Wolf 
909797ac58cSKevin Wolf out:
910797ac58cSKevin Wolf     qemu_iovec_destroy(&qiov);
911797ac58cSKevin Wolf     qemu_io_free(buf);
912797ac58cSKevin Wolf     return 0;
913797ac58cSKevin Wolf }
914797ac58cSKevin Wolf 
915797ac58cSKevin Wolf static void write_help(void)
916797ac58cSKevin Wolf {
917797ac58cSKevin Wolf     printf(
918797ac58cSKevin Wolf "\n"
919797ac58cSKevin Wolf " writes a range of bytes from the given offset\n"
920797ac58cSKevin Wolf "\n"
921797ac58cSKevin Wolf " Example:\n"
922797ac58cSKevin Wolf " 'write 512 1k' - writes 1 kilobyte at 512 bytes into the open file\n"
923797ac58cSKevin Wolf "\n"
924797ac58cSKevin Wolf " Writes into a segment of the currently open file, using a buffer\n"
925797ac58cSKevin Wolf " filled with a set pattern (0xcdcdcdcd).\n"
926797ac58cSKevin Wolf " -b, -- write to the VM state rather than the virtual disk\n"
9274c7b7e9bSMax Reitz " -c, -- write compressed data with blk_write_compressed\n"
928770e0e0eSEric Blake " -f, -- use Force Unit Access semantics\n"
929093ea232SEric Blake " -p, -- ignored for backwards compatibility\n"
930797ac58cSKevin Wolf " -P, -- use different pattern to fill file\n"
931797ac58cSKevin Wolf " -C, -- report statistics in a machine parsable format\n"
932797ac58cSKevin Wolf " -q, -- quiet mode, do not show I/O statistics\n"
933c2e001ccSEric Blake " -u, -- with -z, allow unmapping\n"
934d004bd52SEric Blake " -z, -- write zeroes using blk_co_pwrite_zeroes\n"
935797ac58cSKevin Wolf "\n");
936797ac58cSKevin Wolf }
937797ac58cSKevin Wolf 
9384c7b7e9bSMax Reitz static int write_f(BlockBackend *blk, int argc, char **argv);
939797ac58cSKevin Wolf 
940797ac58cSKevin Wolf static const cmdinfo_t write_cmd = {
941797ac58cSKevin Wolf     .name       = "write",
942797ac58cSKevin Wolf     .altname    = "w",
943797ac58cSKevin Wolf     .cfunc      = write_f,
944*887354bdSKevin Wolf     .perm       = BLK_PERM_WRITE,
945797ac58cSKevin Wolf     .argmin     = 2,
946797ac58cSKevin Wolf     .argmax     = -1,
947c2e001ccSEric Blake     .args       = "[-bcCfquz] [-P pattern] off len",
948797ac58cSKevin Wolf     .oneline    = "writes a number of bytes at a specified offset",
949797ac58cSKevin Wolf     .help       = write_help,
950797ac58cSKevin Wolf };
951797ac58cSKevin Wolf 
9524c7b7e9bSMax Reitz static int write_f(BlockBackend *blk, int argc, char **argv)
953797ac58cSKevin Wolf {
954797ac58cSKevin Wolf     struct timeval t1, t2;
955093ea232SEric Blake     bool Cflag = false, qflag = false, bflag = false;
956dc38852aSEric Blake     bool Pflag = false, zflag = false, cflag = false;
957770e0e0eSEric Blake     int flags = 0;
958797ac58cSKevin Wolf     int c, cnt;
959797ac58cSKevin Wolf     char *buf = NULL;
960797ac58cSKevin Wolf     int64_t offset;
9619b0beaf3SJohn Snow     int64_t count;
962797ac58cSKevin Wolf     /* Some compilers get confused and warn if this is not initialized.  */
9639b0beaf3SJohn Snow     int64_t total = 0;
964797ac58cSKevin Wolf     int pattern = 0xcd;
965797ac58cSKevin Wolf 
966c2e001ccSEric Blake     while ((c = getopt(argc, argv, "bcCfpP:quz")) != -1) {
967797ac58cSKevin Wolf         switch (c) {
968797ac58cSKevin Wolf         case 'b':
969dc38852aSEric Blake             bflag = true;
970797ac58cSKevin Wolf             break;
971797ac58cSKevin Wolf         case 'c':
972dc38852aSEric Blake             cflag = true;
973797ac58cSKevin Wolf             break;
974797ac58cSKevin Wolf         case 'C':
975dc38852aSEric Blake             Cflag = true;
976797ac58cSKevin Wolf             break;
977770e0e0eSEric Blake         case 'f':
978770e0e0eSEric Blake             flags |= BDRV_REQ_FUA;
979770e0e0eSEric Blake             break;
980797ac58cSKevin Wolf         case 'p':
981093ea232SEric Blake             /* Ignored for backwards compatibility */
982797ac58cSKevin Wolf             break;
983797ac58cSKevin Wolf         case 'P':
984dc38852aSEric Blake             Pflag = true;
985797ac58cSKevin Wolf             pattern = parse_pattern(optarg);
986797ac58cSKevin Wolf             if (pattern < 0) {
987797ac58cSKevin Wolf                 return 0;
988797ac58cSKevin Wolf             }
989797ac58cSKevin Wolf             break;
990797ac58cSKevin Wolf         case 'q':
991dc38852aSEric Blake             qflag = true;
992797ac58cSKevin Wolf             break;
993c2e001ccSEric Blake         case 'u':
994c2e001ccSEric Blake             flags |= BDRV_REQ_MAY_UNMAP;
995c2e001ccSEric Blake             break;
996797ac58cSKevin Wolf         case 'z':
997dc38852aSEric Blake             zflag = true;
998797ac58cSKevin Wolf             break;
999797ac58cSKevin Wolf         default:
1000c2cdf5c5SKevin Wolf             return qemuio_command_usage(&write_cmd);
1001797ac58cSKevin Wolf         }
1002797ac58cSKevin Wolf     }
1003797ac58cSKevin Wolf 
1004797ac58cSKevin Wolf     if (optind != argc - 2) {
1005c2cdf5c5SKevin Wolf         return qemuio_command_usage(&write_cmd);
1006797ac58cSKevin Wolf     }
1007797ac58cSKevin Wolf 
1008093ea232SEric Blake     if (bflag && zflag) {
1009093ea232SEric Blake         printf("-b and -z cannot be specified at the same time\n");
1010797ac58cSKevin Wolf         return 0;
1011797ac58cSKevin Wolf     }
1012797ac58cSKevin Wolf 
1013770e0e0eSEric Blake     if ((flags & BDRV_REQ_FUA) && (bflag || cflag)) {
1014770e0e0eSEric Blake         printf("-f and -b or -c cannot be specified at the same time\n");
1015770e0e0eSEric Blake         return 0;
1016770e0e0eSEric Blake     }
1017770e0e0eSEric Blake 
1018c2e001ccSEric Blake     if ((flags & BDRV_REQ_MAY_UNMAP) && !zflag) {
1019c2e001ccSEric Blake         printf("-u requires -z to be specified\n");
1020c2e001ccSEric Blake         return 0;
1021c2e001ccSEric Blake     }
1022c2e001ccSEric Blake 
1023797ac58cSKevin Wolf     if (zflag && Pflag) {
1024797ac58cSKevin Wolf         printf("-z and -P cannot be specified at the same time\n");
1025797ac58cSKevin Wolf         return 0;
1026797ac58cSKevin Wolf     }
1027797ac58cSKevin Wolf 
1028797ac58cSKevin Wolf     offset = cvtnum(argv[optind]);
1029797ac58cSKevin Wolf     if (offset < 0) {
1030a9ecfa00SJohn Snow         print_cvtnum_err(offset, argv[optind]);
1031797ac58cSKevin Wolf         return 0;
1032797ac58cSKevin Wolf     }
1033797ac58cSKevin Wolf 
1034797ac58cSKevin Wolf     optind++;
1035797ac58cSKevin Wolf     count = cvtnum(argv[optind]);
1036797ac58cSKevin Wolf     if (count < 0) {
1037a9ecfa00SJohn Snow         print_cvtnum_err(count, argv[optind]);
1038797ac58cSKevin Wolf         return 0;
10393026c468SAlberto Garcia     } else if (count > BDRV_REQUEST_MAX_BYTES) {
10409b0beaf3SJohn Snow         printf("length cannot exceed %" PRIu64 ", given %s\n",
10413026c468SAlberto Garcia                (uint64_t)BDRV_REQUEST_MAX_BYTES, argv[optind]);
10429b0beaf3SJohn Snow         return 0;
1043797ac58cSKevin Wolf     }
1044797ac58cSKevin Wolf 
1045093ea232SEric Blake     if (bflag || cflag) {
1046797ac58cSKevin Wolf         if (offset & 0x1ff) {
1047797ac58cSKevin Wolf             printf("offset %" PRId64 " is not sector aligned\n",
1048797ac58cSKevin Wolf                    offset);
1049797ac58cSKevin Wolf             return 0;
1050797ac58cSKevin Wolf         }
1051797ac58cSKevin Wolf 
1052797ac58cSKevin Wolf         if (count & 0x1ff) {
10539b0beaf3SJohn Snow             printf("count %"PRId64" is not sector aligned\n",
1054797ac58cSKevin Wolf                    count);
1055797ac58cSKevin Wolf             return 0;
1056797ac58cSKevin Wolf         }
1057797ac58cSKevin Wolf     }
1058797ac58cSKevin Wolf 
1059797ac58cSKevin Wolf     if (!zflag) {
10604c7b7e9bSMax Reitz         buf = qemu_io_alloc(blk, count, pattern);
1061797ac58cSKevin Wolf     }
1062797ac58cSKevin Wolf 
1063797ac58cSKevin Wolf     gettimeofday(&t1, NULL);
10647b3f9712SEric Blake     if (bflag) {
10654c7b7e9bSMax Reitz         cnt = do_save_vmstate(blk, buf, offset, count, &total);
1066797ac58cSKevin Wolf     } else if (zflag) {
1067d004bd52SEric Blake         cnt = do_co_pwrite_zeroes(blk, offset, count, flags, &total);
1068797ac58cSKevin Wolf     } else if (cflag) {
10694c7b7e9bSMax Reitz         cnt = do_write_compressed(blk, buf, offset, count, &total);
1070797ac58cSKevin Wolf     } else {
1071770e0e0eSEric Blake         cnt = do_pwrite(blk, buf, offset, count, flags, &total);
1072797ac58cSKevin Wolf     }
1073797ac58cSKevin Wolf     gettimeofday(&t2, NULL);
1074797ac58cSKevin Wolf 
1075797ac58cSKevin Wolf     if (cnt < 0) {
1076797ac58cSKevin Wolf         printf("write failed: %s\n", strerror(-cnt));
1077797ac58cSKevin Wolf         goto out;
1078797ac58cSKevin Wolf     }
1079797ac58cSKevin Wolf 
1080797ac58cSKevin Wolf     if (qflag) {
1081797ac58cSKevin Wolf         goto out;
1082797ac58cSKevin Wolf     }
1083797ac58cSKevin Wolf 
1084797ac58cSKevin Wolf     /* Finally, report back -- -C gives a parsable format */
1085797ac58cSKevin Wolf     t2 = tsub(t2, t1);
1086797ac58cSKevin Wolf     print_report("wrote", &t2, offset, count, total, cnt, Cflag);
1087797ac58cSKevin Wolf 
1088797ac58cSKevin Wolf out:
1089797ac58cSKevin Wolf     if (!zflag) {
1090797ac58cSKevin Wolf         qemu_io_free(buf);
1091797ac58cSKevin Wolf     }
1092797ac58cSKevin Wolf 
1093797ac58cSKevin Wolf     return 0;
1094797ac58cSKevin Wolf }
1095797ac58cSKevin Wolf 
1096797ac58cSKevin Wolf static void
1097797ac58cSKevin Wolf writev_help(void)
1098797ac58cSKevin Wolf {
1099797ac58cSKevin Wolf     printf(
1100797ac58cSKevin Wolf "\n"
1101797ac58cSKevin Wolf " writes a range of bytes from the given offset source from multiple buffers\n"
1102797ac58cSKevin Wolf "\n"
1103797ac58cSKevin Wolf " Example:\n"
11046e6507c0SMaria Kustova " 'writev 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n"
1105797ac58cSKevin Wolf "\n"
1106797ac58cSKevin Wolf " Writes into a segment of the currently open file, using a buffer\n"
1107797ac58cSKevin Wolf " filled with a set pattern (0xcdcdcdcd).\n"
1108797ac58cSKevin Wolf " -P, -- use different pattern to fill file\n"
1109797ac58cSKevin Wolf " -C, -- report statistics in a machine parsable format\n"
1110770e0e0eSEric Blake " -f, -- use Force Unit Access semantics\n"
1111797ac58cSKevin Wolf " -q, -- quiet mode, do not show I/O statistics\n"
1112797ac58cSKevin Wolf "\n");
1113797ac58cSKevin Wolf }
1114797ac58cSKevin Wolf 
11154c7b7e9bSMax Reitz static int writev_f(BlockBackend *blk, int argc, char **argv);
1116797ac58cSKevin Wolf 
1117797ac58cSKevin Wolf static const cmdinfo_t writev_cmd = {
1118797ac58cSKevin Wolf     .name       = "writev",
1119797ac58cSKevin Wolf     .cfunc      = writev_f,
1120*887354bdSKevin Wolf     .perm       = BLK_PERM_WRITE,
1121797ac58cSKevin Wolf     .argmin     = 2,
1122797ac58cSKevin Wolf     .argmax     = -1,
1123770e0e0eSEric Blake     .args       = "[-Cfq] [-P pattern] off len [len..]",
1124797ac58cSKevin Wolf     .oneline    = "writes a number of bytes at a specified offset",
1125797ac58cSKevin Wolf     .help       = writev_help,
1126797ac58cSKevin Wolf };
1127797ac58cSKevin Wolf 
11284c7b7e9bSMax Reitz static int writev_f(BlockBackend *blk, int argc, char **argv)
1129797ac58cSKevin Wolf {
1130797ac58cSKevin Wolf     struct timeval t1, t2;
1131dc38852aSEric Blake     bool Cflag = false, qflag = false;
1132770e0e0eSEric Blake     int flags = 0;
1133797ac58cSKevin Wolf     int c, cnt;
1134797ac58cSKevin Wolf     char *buf;
1135797ac58cSKevin Wolf     int64_t offset;
1136797ac58cSKevin Wolf     /* Some compilers get confused and warn if this is not initialized.  */
1137797ac58cSKevin Wolf     int total = 0;
1138797ac58cSKevin Wolf     int nr_iov;
1139797ac58cSKevin Wolf     int pattern = 0xcd;
1140797ac58cSKevin Wolf     QEMUIOVector qiov;
1141797ac58cSKevin Wolf 
11424ca1d340SEric Blake     while ((c = getopt(argc, argv, "CfqP:")) != -1) {
1143797ac58cSKevin Wolf         switch (c) {
1144797ac58cSKevin Wolf         case 'C':
1145dc38852aSEric Blake             Cflag = true;
1146797ac58cSKevin Wolf             break;
1147770e0e0eSEric Blake         case 'f':
1148770e0e0eSEric Blake             flags |= BDRV_REQ_FUA;
1149770e0e0eSEric Blake             break;
1150797ac58cSKevin Wolf         case 'q':
1151dc38852aSEric Blake             qflag = true;
1152797ac58cSKevin Wolf             break;
1153797ac58cSKevin Wolf         case 'P':
1154797ac58cSKevin Wolf             pattern = parse_pattern(optarg);
1155797ac58cSKevin Wolf             if (pattern < 0) {
1156797ac58cSKevin Wolf                 return 0;
1157797ac58cSKevin Wolf             }
1158797ac58cSKevin Wolf             break;
1159797ac58cSKevin Wolf         default:
1160c2cdf5c5SKevin Wolf             return qemuio_command_usage(&writev_cmd);
1161797ac58cSKevin Wolf         }
1162797ac58cSKevin Wolf     }
1163797ac58cSKevin Wolf 
1164797ac58cSKevin Wolf     if (optind > argc - 2) {
1165c2cdf5c5SKevin Wolf         return qemuio_command_usage(&writev_cmd);
1166797ac58cSKevin Wolf     }
1167797ac58cSKevin Wolf 
1168797ac58cSKevin Wolf     offset = cvtnum(argv[optind]);
1169797ac58cSKevin Wolf     if (offset < 0) {
1170a9ecfa00SJohn Snow         print_cvtnum_err(offset, argv[optind]);
1171797ac58cSKevin Wolf         return 0;
1172797ac58cSKevin Wolf     }
1173797ac58cSKevin Wolf     optind++;
1174797ac58cSKevin Wolf 
1175797ac58cSKevin Wolf     nr_iov = argc - optind;
11764c7b7e9bSMax Reitz     buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, pattern);
1177797ac58cSKevin Wolf     if (buf == NULL) {
1178797ac58cSKevin Wolf         return 0;
1179797ac58cSKevin Wolf     }
1180797ac58cSKevin Wolf 
1181797ac58cSKevin Wolf     gettimeofday(&t1, NULL);
1182770e0e0eSEric Blake     cnt = do_aio_writev(blk, &qiov, offset, flags, &total);
1183797ac58cSKevin Wolf     gettimeofday(&t2, NULL);
1184797ac58cSKevin Wolf 
1185797ac58cSKevin Wolf     if (cnt < 0) {
1186797ac58cSKevin Wolf         printf("writev failed: %s\n", strerror(-cnt));
1187797ac58cSKevin Wolf         goto out;
1188797ac58cSKevin Wolf     }
1189797ac58cSKevin Wolf 
1190797ac58cSKevin Wolf     if (qflag) {
1191797ac58cSKevin Wolf         goto out;
1192797ac58cSKevin Wolf     }
1193797ac58cSKevin Wolf 
1194797ac58cSKevin Wolf     /* Finally, report back -- -C gives a parsable format */
1195797ac58cSKevin Wolf     t2 = tsub(t2, t1);
1196797ac58cSKevin Wolf     print_report("wrote", &t2, offset, qiov.size, total, cnt, Cflag);
1197797ac58cSKevin Wolf out:
1198797ac58cSKevin Wolf     qemu_iovec_destroy(&qiov);
1199797ac58cSKevin Wolf     qemu_io_free(buf);
1200797ac58cSKevin Wolf     return 0;
1201797ac58cSKevin Wolf }
1202797ac58cSKevin Wolf 
1203797ac58cSKevin Wolf struct aio_ctx {
12044c7b7e9bSMax Reitz     BlockBackend *blk;
1205797ac58cSKevin Wolf     QEMUIOVector qiov;
1206797ac58cSKevin Wolf     int64_t offset;
1207797ac58cSKevin Wolf     char *buf;
1208dc38852aSEric Blake     bool qflag;
1209dc38852aSEric Blake     bool vflag;
1210dc38852aSEric Blake     bool Cflag;
1211dc38852aSEric Blake     bool Pflag;
1212dc38852aSEric Blake     bool zflag;
1213a91f9584SFam Zheng     BlockAcctCookie acct;
1214797ac58cSKevin Wolf     int pattern;
1215797ac58cSKevin Wolf     struct timeval t1;
1216797ac58cSKevin Wolf };
1217797ac58cSKevin Wolf 
1218797ac58cSKevin Wolf static void aio_write_done(void *opaque, int ret)
1219797ac58cSKevin Wolf {
1220797ac58cSKevin Wolf     struct aio_ctx *ctx = opaque;
1221797ac58cSKevin Wolf     struct timeval t2;
1222797ac58cSKevin Wolf 
1223797ac58cSKevin Wolf     gettimeofday(&t2, NULL);
1224797ac58cSKevin Wolf 
1225797ac58cSKevin Wolf 
1226797ac58cSKevin Wolf     if (ret < 0) {
1227797ac58cSKevin Wolf         printf("aio_write failed: %s\n", strerror(-ret));
1228556c2b60SAlberto Garcia         block_acct_failed(blk_get_stats(ctx->blk), &ctx->acct);
1229797ac58cSKevin Wolf         goto out;
1230797ac58cSKevin Wolf     }
1231797ac58cSKevin Wolf 
12324c7b7e9bSMax Reitz     block_acct_done(blk_get_stats(ctx->blk), &ctx->acct);
1233a91f9584SFam Zheng 
1234797ac58cSKevin Wolf     if (ctx->qflag) {
1235797ac58cSKevin Wolf         goto out;
1236797ac58cSKevin Wolf     }
1237797ac58cSKevin Wolf 
1238797ac58cSKevin Wolf     /* Finally, report back -- -C gives a parsable format */
1239797ac58cSKevin Wolf     t2 = tsub(t2, ctx->t1);
1240797ac58cSKevin Wolf     print_report("wrote", &t2, ctx->offset, ctx->qiov.size,
1241797ac58cSKevin Wolf                  ctx->qiov.size, 1, ctx->Cflag);
1242797ac58cSKevin Wolf out:
12435ceb7765SKevin Wolf     if (!ctx->zflag) {
1244797ac58cSKevin Wolf         qemu_io_free(ctx->buf);
1245797ac58cSKevin Wolf         qemu_iovec_destroy(&ctx->qiov);
12465ceb7765SKevin Wolf     }
1247797ac58cSKevin Wolf     g_free(ctx);
1248797ac58cSKevin Wolf }
1249797ac58cSKevin Wolf 
1250797ac58cSKevin Wolf static void aio_read_done(void *opaque, int ret)
1251797ac58cSKevin Wolf {
1252797ac58cSKevin Wolf     struct aio_ctx *ctx = opaque;
1253797ac58cSKevin Wolf     struct timeval t2;
1254797ac58cSKevin Wolf 
1255797ac58cSKevin Wolf     gettimeofday(&t2, NULL);
1256797ac58cSKevin Wolf 
1257797ac58cSKevin Wolf     if (ret < 0) {
1258797ac58cSKevin Wolf         printf("readv failed: %s\n", strerror(-ret));
1259556c2b60SAlberto Garcia         block_acct_failed(blk_get_stats(ctx->blk), &ctx->acct);
1260797ac58cSKevin Wolf         goto out;
1261797ac58cSKevin Wolf     }
1262797ac58cSKevin Wolf 
1263797ac58cSKevin Wolf     if (ctx->Pflag) {
1264797ac58cSKevin Wolf         void *cmp_buf = g_malloc(ctx->qiov.size);
1265797ac58cSKevin Wolf 
1266797ac58cSKevin Wolf         memset(cmp_buf, ctx->pattern, ctx->qiov.size);
1267797ac58cSKevin Wolf         if (memcmp(ctx->buf, cmp_buf, ctx->qiov.size)) {
1268797ac58cSKevin Wolf             printf("Pattern verification failed at offset %"
1269797ac58cSKevin Wolf                    PRId64 ", %zd bytes\n", ctx->offset, ctx->qiov.size);
1270797ac58cSKevin Wolf         }
1271797ac58cSKevin Wolf         g_free(cmp_buf);
1272797ac58cSKevin Wolf     }
1273797ac58cSKevin Wolf 
12744c7b7e9bSMax Reitz     block_acct_done(blk_get_stats(ctx->blk), &ctx->acct);
1275a91f9584SFam Zheng 
1276797ac58cSKevin Wolf     if (ctx->qflag) {
1277797ac58cSKevin Wolf         goto out;
1278797ac58cSKevin Wolf     }
1279797ac58cSKevin Wolf 
1280797ac58cSKevin Wolf     if (ctx->vflag) {
1281797ac58cSKevin Wolf         dump_buffer(ctx->buf, ctx->offset, ctx->qiov.size);
1282797ac58cSKevin Wolf     }
1283797ac58cSKevin Wolf 
1284797ac58cSKevin Wolf     /* Finally, report back -- -C gives a parsable format */
1285797ac58cSKevin Wolf     t2 = tsub(t2, ctx->t1);
1286797ac58cSKevin Wolf     print_report("read", &t2, ctx->offset, ctx->qiov.size,
1287797ac58cSKevin Wolf                  ctx->qiov.size, 1, ctx->Cflag);
1288797ac58cSKevin Wolf out:
1289797ac58cSKevin Wolf     qemu_io_free(ctx->buf);
1290797ac58cSKevin Wolf     qemu_iovec_destroy(&ctx->qiov);
1291797ac58cSKevin Wolf     g_free(ctx);
1292797ac58cSKevin Wolf }
1293797ac58cSKevin Wolf 
1294797ac58cSKevin Wolf static void aio_read_help(void)
1295797ac58cSKevin Wolf {
1296797ac58cSKevin Wolf     printf(
1297797ac58cSKevin Wolf "\n"
1298797ac58cSKevin Wolf " asynchronously reads a range of bytes from the given offset\n"
1299797ac58cSKevin Wolf "\n"
1300797ac58cSKevin Wolf " Example:\n"
1301797ac58cSKevin Wolf " 'aio_read -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n"
1302797ac58cSKevin Wolf "\n"
1303797ac58cSKevin Wolf " Reads a segment of the currently open file, optionally dumping it to the\n"
1304797ac58cSKevin Wolf " standard output stream (with -v option) for subsequent inspection.\n"
1305797ac58cSKevin Wolf " The read is performed asynchronously and the aio_flush command must be\n"
1306797ac58cSKevin Wolf " used to ensure all outstanding aio requests have been completed.\n"
1307797ac58cSKevin Wolf " -C, -- report statistics in a machine parsable format\n"
1308797ac58cSKevin Wolf " -P, -- use a pattern to verify read data\n"
130937546ff2SEric Blake " -i, -- treat request as invalid, for exercising stats\n"
1310797ac58cSKevin Wolf " -v, -- dump buffer to standard output\n"
1311797ac58cSKevin Wolf " -q, -- quiet mode, do not show I/O statistics\n"
1312797ac58cSKevin Wolf "\n");
1313797ac58cSKevin Wolf }
1314797ac58cSKevin Wolf 
13154c7b7e9bSMax Reitz static int aio_read_f(BlockBackend *blk, int argc, char **argv);
1316797ac58cSKevin Wolf 
1317797ac58cSKevin Wolf static const cmdinfo_t aio_read_cmd = {
1318797ac58cSKevin Wolf     .name       = "aio_read",
1319797ac58cSKevin Wolf     .cfunc      = aio_read_f,
1320797ac58cSKevin Wolf     .argmin     = 2,
1321797ac58cSKevin Wolf     .argmax     = -1,
132237546ff2SEric Blake     .args       = "[-Ciqv] [-P pattern] off len [len..]",
1323797ac58cSKevin Wolf     .oneline    = "asynchronously reads a number of bytes",
1324797ac58cSKevin Wolf     .help       = aio_read_help,
1325797ac58cSKevin Wolf };
1326797ac58cSKevin Wolf 
13274c7b7e9bSMax Reitz static int aio_read_f(BlockBackend *blk, int argc, char **argv)
1328797ac58cSKevin Wolf {
1329797ac58cSKevin Wolf     int nr_iov, c;
1330797ac58cSKevin Wolf     struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
1331797ac58cSKevin Wolf 
13324c7b7e9bSMax Reitz     ctx->blk = blk;
133337546ff2SEric Blake     while ((c = getopt(argc, argv, "CP:iqv")) != -1) {
1334797ac58cSKevin Wolf         switch (c) {
1335797ac58cSKevin Wolf         case 'C':
1336dc38852aSEric Blake             ctx->Cflag = true;
1337797ac58cSKevin Wolf             break;
1338797ac58cSKevin Wolf         case 'P':
1339dc38852aSEric Blake             ctx->Pflag = true;
1340797ac58cSKevin Wolf             ctx->pattern = parse_pattern(optarg);
1341797ac58cSKevin Wolf             if (ctx->pattern < 0) {
1342797ac58cSKevin Wolf                 g_free(ctx);
1343797ac58cSKevin Wolf                 return 0;
1344797ac58cSKevin Wolf             }
1345797ac58cSKevin Wolf             break;
134637546ff2SEric Blake         case 'i':
134737546ff2SEric Blake             printf("injecting invalid read request\n");
134837546ff2SEric Blake             block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_READ);
134937546ff2SEric Blake             g_free(ctx);
135037546ff2SEric Blake             return 0;
1351797ac58cSKevin Wolf         case 'q':
1352dc38852aSEric Blake             ctx->qflag = true;
1353797ac58cSKevin Wolf             break;
1354797ac58cSKevin Wolf         case 'v':
1355dc38852aSEric Blake             ctx->vflag = true;
1356797ac58cSKevin Wolf             break;
1357797ac58cSKevin Wolf         default:
1358797ac58cSKevin Wolf             g_free(ctx);
1359c2cdf5c5SKevin Wolf             return qemuio_command_usage(&aio_read_cmd);
1360797ac58cSKevin Wolf         }
1361797ac58cSKevin Wolf     }
1362797ac58cSKevin Wolf 
1363797ac58cSKevin Wolf     if (optind > argc - 2) {
1364797ac58cSKevin Wolf         g_free(ctx);
1365c2cdf5c5SKevin Wolf         return qemuio_command_usage(&aio_read_cmd);
1366797ac58cSKevin Wolf     }
1367797ac58cSKevin Wolf 
1368797ac58cSKevin Wolf     ctx->offset = cvtnum(argv[optind]);
1369797ac58cSKevin Wolf     if (ctx->offset < 0) {
1370a9ecfa00SJohn Snow         print_cvtnum_err(ctx->offset, argv[optind]);
1371797ac58cSKevin Wolf         g_free(ctx);
1372797ac58cSKevin Wolf         return 0;
1373797ac58cSKevin Wolf     }
1374797ac58cSKevin Wolf     optind++;
1375797ac58cSKevin Wolf 
1376797ac58cSKevin Wolf     nr_iov = argc - optind;
13774c7b7e9bSMax Reitz     ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov, 0xab);
1378797ac58cSKevin Wolf     if (ctx->buf == NULL) {
1379556c2b60SAlberto Garcia         block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_READ);
1380797ac58cSKevin Wolf         g_free(ctx);
1381797ac58cSKevin Wolf         return 0;
1382797ac58cSKevin Wolf     }
1383797ac58cSKevin Wolf 
1384797ac58cSKevin Wolf     gettimeofday(&ctx->t1, NULL);
13854c7b7e9bSMax Reitz     block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size,
13864c7b7e9bSMax Reitz                      BLOCK_ACCT_READ);
13877b3f9712SEric Blake     blk_aio_preadv(blk, ctx->offset, &ctx->qiov, 0, aio_read_done, ctx);
1388797ac58cSKevin Wolf     return 0;
1389797ac58cSKevin Wolf }
1390797ac58cSKevin Wolf 
1391797ac58cSKevin Wolf static void aio_write_help(void)
1392797ac58cSKevin Wolf {
1393797ac58cSKevin Wolf     printf(
1394797ac58cSKevin Wolf "\n"
1395797ac58cSKevin Wolf " asynchronously writes a range of bytes from the given offset source\n"
1396797ac58cSKevin Wolf " from multiple buffers\n"
1397797ac58cSKevin Wolf "\n"
1398797ac58cSKevin Wolf " Example:\n"
1399797ac58cSKevin Wolf " 'aio_write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n"
1400797ac58cSKevin Wolf "\n"
1401797ac58cSKevin Wolf " Writes into a segment of the currently open file, using a buffer\n"
1402797ac58cSKevin Wolf " filled with a set pattern (0xcdcdcdcd).\n"
1403797ac58cSKevin Wolf " The write is performed asynchronously and the aio_flush command must be\n"
1404797ac58cSKevin Wolf " used to ensure all outstanding aio requests have been completed.\n"
1405797ac58cSKevin Wolf " -P, -- use different pattern to fill file\n"
1406797ac58cSKevin Wolf " -C, -- report statistics in a machine parsable format\n"
1407770e0e0eSEric Blake " -f, -- use Force Unit Access semantics\n"
140837546ff2SEric Blake " -i, -- treat request as invalid, for exercising stats\n"
1409797ac58cSKevin Wolf " -q, -- quiet mode, do not show I/O statistics\n"
1410c2e001ccSEric Blake " -u, -- with -z, allow unmapping\n"
1411d004bd52SEric Blake " -z, -- write zeroes using blk_aio_pwrite_zeroes\n"
1412797ac58cSKevin Wolf "\n");
1413797ac58cSKevin Wolf }
1414797ac58cSKevin Wolf 
14154c7b7e9bSMax Reitz static int aio_write_f(BlockBackend *blk, int argc, char **argv);
1416797ac58cSKevin Wolf 
1417797ac58cSKevin Wolf static const cmdinfo_t aio_write_cmd = {
1418797ac58cSKevin Wolf     .name       = "aio_write",
1419797ac58cSKevin Wolf     .cfunc      = aio_write_f,
1420*887354bdSKevin Wolf     .perm       = BLK_PERM_WRITE,
1421797ac58cSKevin Wolf     .argmin     = 2,
1422797ac58cSKevin Wolf     .argmax     = -1,
142337546ff2SEric Blake     .args       = "[-Cfiquz] [-P pattern] off len [len..]",
1424797ac58cSKevin Wolf     .oneline    = "asynchronously writes a number of bytes",
1425797ac58cSKevin Wolf     .help       = aio_write_help,
1426797ac58cSKevin Wolf };
1427797ac58cSKevin Wolf 
14284c7b7e9bSMax Reitz static int aio_write_f(BlockBackend *blk, int argc, char **argv)
1429797ac58cSKevin Wolf {
1430797ac58cSKevin Wolf     int nr_iov, c;
1431797ac58cSKevin Wolf     int pattern = 0xcd;
1432797ac58cSKevin Wolf     struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
1433770e0e0eSEric Blake     int flags = 0;
1434797ac58cSKevin Wolf 
14354c7b7e9bSMax Reitz     ctx->blk = blk;
143637546ff2SEric Blake     while ((c = getopt(argc, argv, "CfiqP:uz")) != -1) {
1437797ac58cSKevin Wolf         switch (c) {
1438797ac58cSKevin Wolf         case 'C':
1439dc38852aSEric Blake             ctx->Cflag = true;
1440797ac58cSKevin Wolf             break;
1441770e0e0eSEric Blake         case 'f':
1442770e0e0eSEric Blake             flags |= BDRV_REQ_FUA;
1443770e0e0eSEric Blake             break;
1444797ac58cSKevin Wolf         case 'q':
1445dc38852aSEric Blake             ctx->qflag = true;
1446797ac58cSKevin Wolf             break;
1447c2e001ccSEric Blake         case 'u':
1448c2e001ccSEric Blake             flags |= BDRV_REQ_MAY_UNMAP;
1449c2e001ccSEric Blake             break;
1450797ac58cSKevin Wolf         case 'P':
1451797ac58cSKevin Wolf             pattern = parse_pattern(optarg);
1452797ac58cSKevin Wolf             if (pattern < 0) {
1453797ac58cSKevin Wolf                 g_free(ctx);
1454797ac58cSKevin Wolf                 return 0;
1455797ac58cSKevin Wolf             }
1456797ac58cSKevin Wolf             break;
145737546ff2SEric Blake         case 'i':
145837546ff2SEric Blake             printf("injecting invalid write request\n");
145937546ff2SEric Blake             block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_WRITE);
146037546ff2SEric Blake             g_free(ctx);
146137546ff2SEric Blake             return 0;
14625ceb7765SKevin Wolf         case 'z':
1463dc38852aSEric Blake             ctx->zflag = true;
14645ceb7765SKevin Wolf             break;
1465797ac58cSKevin Wolf         default:
1466797ac58cSKevin Wolf             g_free(ctx);
1467c2cdf5c5SKevin Wolf             return qemuio_command_usage(&aio_write_cmd);
1468797ac58cSKevin Wolf         }
1469797ac58cSKevin Wolf     }
1470797ac58cSKevin Wolf 
1471797ac58cSKevin Wolf     if (optind > argc - 2) {
1472797ac58cSKevin Wolf         g_free(ctx);
1473c2cdf5c5SKevin Wolf         return qemuio_command_usage(&aio_write_cmd);
1474797ac58cSKevin Wolf     }
1475797ac58cSKevin Wolf 
14765ceb7765SKevin Wolf     if (ctx->zflag && optind != argc - 2) {
14775ceb7765SKevin Wolf         printf("-z supports only a single length parameter\n");
14785ceb7765SKevin Wolf         g_free(ctx);
14795ceb7765SKevin Wolf         return 0;
14805ceb7765SKevin Wolf     }
14815ceb7765SKevin Wolf 
1482c2e001ccSEric Blake     if ((flags & BDRV_REQ_MAY_UNMAP) && !ctx->zflag) {
1483c2e001ccSEric Blake         printf("-u requires -z to be specified\n");
14844ca1d340SEric Blake         g_free(ctx);
1485c2e001ccSEric Blake         return 0;
1486c2e001ccSEric Blake     }
1487c2e001ccSEric Blake 
14885ceb7765SKevin Wolf     if (ctx->zflag && ctx->Pflag) {
14895ceb7765SKevin Wolf         printf("-z and -P cannot be specified at the same time\n");
14905ceb7765SKevin Wolf         g_free(ctx);
14915ceb7765SKevin Wolf         return 0;
14925ceb7765SKevin Wolf     }
14935ceb7765SKevin Wolf 
1494797ac58cSKevin Wolf     ctx->offset = cvtnum(argv[optind]);
1495797ac58cSKevin Wolf     if (ctx->offset < 0) {
1496a9ecfa00SJohn Snow         print_cvtnum_err(ctx->offset, argv[optind]);
1497797ac58cSKevin Wolf         g_free(ctx);
1498797ac58cSKevin Wolf         return 0;
1499797ac58cSKevin Wolf     }
1500797ac58cSKevin Wolf     optind++;
1501797ac58cSKevin Wolf 
15025ceb7765SKevin Wolf     if (ctx->zflag) {
15035ceb7765SKevin Wolf         int64_t count = cvtnum(argv[optind]);
15045ceb7765SKevin Wolf         if (count < 0) {
15055ceb7765SKevin Wolf             print_cvtnum_err(count, argv[optind]);
15060e01b76eSKevin Wolf             g_free(ctx);
15075ceb7765SKevin Wolf             return 0;
15085ceb7765SKevin Wolf         }
15095ceb7765SKevin Wolf 
15105ceb7765SKevin Wolf         ctx->qiov.size = count;
1511d004bd52SEric Blake         blk_aio_pwrite_zeroes(blk, ctx->offset, count, flags, aio_write_done,
1512770e0e0eSEric Blake                               ctx);
15135ceb7765SKevin Wolf     } else {
1514797ac58cSKevin Wolf         nr_iov = argc - optind;
15155ceb7765SKevin Wolf         ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov,
15165ceb7765SKevin Wolf                                 pattern);
1517797ac58cSKevin Wolf         if (ctx->buf == NULL) {
1518556c2b60SAlberto Garcia             block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_WRITE);
1519797ac58cSKevin Wolf             g_free(ctx);
1520797ac58cSKevin Wolf             return 0;
1521797ac58cSKevin Wolf         }
1522797ac58cSKevin Wolf 
1523797ac58cSKevin Wolf         gettimeofday(&ctx->t1, NULL);
15244c7b7e9bSMax Reitz         block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size,
15254c7b7e9bSMax Reitz                          BLOCK_ACCT_WRITE);
15265ceb7765SKevin Wolf 
1527770e0e0eSEric Blake         blk_aio_pwritev(blk, ctx->offset, &ctx->qiov, flags, aio_write_done,
1528770e0e0eSEric Blake                         ctx);
15295ceb7765SKevin Wolf     }
1530797ac58cSKevin Wolf     return 0;
1531797ac58cSKevin Wolf }
1532797ac58cSKevin Wolf 
15334c7b7e9bSMax Reitz static int aio_flush_f(BlockBackend *blk, int argc, char **argv)
1534797ac58cSKevin Wolf {
1535556c2b60SAlberto Garcia     BlockAcctCookie cookie;
1536556c2b60SAlberto Garcia     block_acct_start(blk_get_stats(blk), &cookie, 0, BLOCK_ACCT_FLUSH);
15374c7b7e9bSMax Reitz     blk_drain_all();
1538556c2b60SAlberto Garcia     block_acct_done(blk_get_stats(blk), &cookie);
1539797ac58cSKevin Wolf     return 0;
1540797ac58cSKevin Wolf }
1541797ac58cSKevin Wolf 
1542797ac58cSKevin Wolf static const cmdinfo_t aio_flush_cmd = {
1543797ac58cSKevin Wolf     .name       = "aio_flush",
1544797ac58cSKevin Wolf     .cfunc      = aio_flush_f,
1545797ac58cSKevin Wolf     .oneline    = "completes all outstanding aio requests"
1546797ac58cSKevin Wolf };
1547797ac58cSKevin Wolf 
15484c7b7e9bSMax Reitz static int flush_f(BlockBackend *blk, int argc, char **argv)
1549797ac58cSKevin Wolf {
15504c7b7e9bSMax Reitz     blk_flush(blk);
1551797ac58cSKevin Wolf     return 0;
1552797ac58cSKevin Wolf }
1553797ac58cSKevin Wolf 
1554797ac58cSKevin Wolf static const cmdinfo_t flush_cmd = {
1555797ac58cSKevin Wolf     .name       = "flush",
1556797ac58cSKevin Wolf     .altname    = "f",
1557797ac58cSKevin Wolf     .cfunc      = flush_f,
1558797ac58cSKevin Wolf     .oneline    = "flush all in-core file state to disk",
1559797ac58cSKevin Wolf };
1560797ac58cSKevin Wolf 
15614c7b7e9bSMax Reitz static int truncate_f(BlockBackend *blk, int argc, char **argv)
1562797ac58cSKevin Wolf {
1563797ac58cSKevin Wolf     int64_t offset;
1564797ac58cSKevin Wolf     int ret;
1565797ac58cSKevin Wolf 
1566797ac58cSKevin Wolf     offset = cvtnum(argv[1]);
1567797ac58cSKevin Wolf     if (offset < 0) {
1568a9ecfa00SJohn Snow         print_cvtnum_err(offset, argv[1]);
1569797ac58cSKevin Wolf         return 0;
1570797ac58cSKevin Wolf     }
1571797ac58cSKevin Wolf 
15724c7b7e9bSMax Reitz     ret = blk_truncate(blk, offset);
1573797ac58cSKevin Wolf     if (ret < 0) {
1574797ac58cSKevin Wolf         printf("truncate: %s\n", strerror(-ret));
1575797ac58cSKevin Wolf         return 0;
1576797ac58cSKevin Wolf     }
1577797ac58cSKevin Wolf 
1578797ac58cSKevin Wolf     return 0;
1579797ac58cSKevin Wolf }
1580797ac58cSKevin Wolf 
1581797ac58cSKevin Wolf static const cmdinfo_t truncate_cmd = {
1582797ac58cSKevin Wolf     .name       = "truncate",
1583797ac58cSKevin Wolf     .altname    = "t",
1584797ac58cSKevin Wolf     .cfunc      = truncate_f,
1585*887354bdSKevin Wolf     .perm       = BLK_PERM_WRITE | BLK_PERM_RESIZE,
1586797ac58cSKevin Wolf     .argmin     = 1,
1587797ac58cSKevin Wolf     .argmax     = 1,
1588797ac58cSKevin Wolf     .args       = "off",
1589797ac58cSKevin Wolf     .oneline    = "truncates the current file at the given offset",
1590797ac58cSKevin Wolf };
1591797ac58cSKevin Wolf 
15924c7b7e9bSMax Reitz static int length_f(BlockBackend *blk, int argc, char **argv)
1593797ac58cSKevin Wolf {
1594797ac58cSKevin Wolf     int64_t size;
1595797ac58cSKevin Wolf     char s1[64];
1596797ac58cSKevin Wolf 
15974c7b7e9bSMax Reitz     size = blk_getlength(blk);
1598797ac58cSKevin Wolf     if (size < 0) {
1599797ac58cSKevin Wolf         printf("getlength: %s\n", strerror(-size));
1600797ac58cSKevin Wolf         return 0;
1601797ac58cSKevin Wolf     }
1602797ac58cSKevin Wolf 
1603797ac58cSKevin Wolf     cvtstr(size, s1, sizeof(s1));
1604797ac58cSKevin Wolf     printf("%s\n", s1);
1605797ac58cSKevin Wolf     return 0;
1606797ac58cSKevin Wolf }
1607797ac58cSKevin Wolf 
1608797ac58cSKevin Wolf 
1609797ac58cSKevin Wolf static const cmdinfo_t length_cmd = {
1610797ac58cSKevin Wolf     .name   = "length",
1611797ac58cSKevin Wolf     .altname    = "l",
1612797ac58cSKevin Wolf     .cfunc      = length_f,
1613797ac58cSKevin Wolf     .oneline    = "gets the length of the current file",
1614797ac58cSKevin Wolf };
1615797ac58cSKevin Wolf 
1616797ac58cSKevin Wolf 
16174c7b7e9bSMax Reitz static int info_f(BlockBackend *blk, int argc, char **argv)
1618797ac58cSKevin Wolf {
16194c7b7e9bSMax Reitz     BlockDriverState *bs = blk_bs(blk);
1620797ac58cSKevin Wolf     BlockDriverInfo bdi;
1621a8d8ecb7SMax Reitz     ImageInfoSpecific *spec_info;
1622797ac58cSKevin Wolf     char s1[64], s2[64];
1623797ac58cSKevin Wolf     int ret;
1624797ac58cSKevin Wolf 
1625797ac58cSKevin Wolf     if (bs->drv && bs->drv->format_name) {
1626797ac58cSKevin Wolf         printf("format name: %s\n", bs->drv->format_name);
1627797ac58cSKevin Wolf     }
1628797ac58cSKevin Wolf     if (bs->drv && bs->drv->protocol_name) {
1629797ac58cSKevin Wolf         printf("format name: %s\n", bs->drv->protocol_name);
1630797ac58cSKevin Wolf     }
1631797ac58cSKevin Wolf 
1632797ac58cSKevin Wolf     ret = bdrv_get_info(bs, &bdi);
1633797ac58cSKevin Wolf     if (ret) {
1634797ac58cSKevin Wolf         return 0;
1635797ac58cSKevin Wolf     }
1636797ac58cSKevin Wolf 
1637797ac58cSKevin Wolf     cvtstr(bdi.cluster_size, s1, sizeof(s1));
1638797ac58cSKevin Wolf     cvtstr(bdi.vm_state_offset, s2, sizeof(s2));
1639797ac58cSKevin Wolf 
1640797ac58cSKevin Wolf     printf("cluster size: %s\n", s1);
1641797ac58cSKevin Wolf     printf("vm state offset: %s\n", s2);
1642797ac58cSKevin Wolf 
1643a8d8ecb7SMax Reitz     spec_info = bdrv_get_specific_info(bs);
1644a8d8ecb7SMax Reitz     if (spec_info) {
1645a8d8ecb7SMax Reitz         printf("Format specific information:\n");
1646a8d8ecb7SMax Reitz         bdrv_image_info_specific_dump(fprintf, stdout, spec_info);
1647a8d8ecb7SMax Reitz         qapi_free_ImageInfoSpecific(spec_info);
1648a8d8ecb7SMax Reitz     }
1649a8d8ecb7SMax Reitz 
1650797ac58cSKevin Wolf     return 0;
1651797ac58cSKevin Wolf }
1652797ac58cSKevin Wolf 
1653797ac58cSKevin Wolf 
1654797ac58cSKevin Wolf 
1655797ac58cSKevin Wolf static const cmdinfo_t info_cmd = {
1656797ac58cSKevin Wolf     .name       = "info",
1657797ac58cSKevin Wolf     .altname    = "i",
1658797ac58cSKevin Wolf     .cfunc      = info_f,
1659797ac58cSKevin Wolf     .oneline    = "prints information about the current file",
1660797ac58cSKevin Wolf };
1661797ac58cSKevin Wolf 
1662797ac58cSKevin Wolf static void discard_help(void)
1663797ac58cSKevin Wolf {
1664797ac58cSKevin Wolf     printf(
1665797ac58cSKevin Wolf "\n"
1666797ac58cSKevin Wolf " discards a range of bytes from the given offset\n"
1667797ac58cSKevin Wolf "\n"
1668797ac58cSKevin Wolf " Example:\n"
1669797ac58cSKevin Wolf " 'discard 512 1k' - discards 1 kilobyte from 512 bytes into the file\n"
1670797ac58cSKevin Wolf "\n"
1671797ac58cSKevin Wolf " Discards a segment of the currently open file.\n"
1672797ac58cSKevin Wolf " -C, -- report statistics in a machine parsable format\n"
1673797ac58cSKevin Wolf " -q, -- quiet mode, do not show I/O statistics\n"
1674797ac58cSKevin Wolf "\n");
1675797ac58cSKevin Wolf }
1676797ac58cSKevin Wolf 
16774c7b7e9bSMax Reitz static int discard_f(BlockBackend *blk, int argc, char **argv);
1678797ac58cSKevin Wolf 
1679797ac58cSKevin Wolf static const cmdinfo_t discard_cmd = {
1680797ac58cSKevin Wolf     .name       = "discard",
1681797ac58cSKevin Wolf     .altname    = "d",
1682797ac58cSKevin Wolf     .cfunc      = discard_f,
1683*887354bdSKevin Wolf     .perm       = BLK_PERM_WRITE,
1684797ac58cSKevin Wolf     .argmin     = 2,
1685797ac58cSKevin Wolf     .argmax     = -1,
1686797ac58cSKevin Wolf     .args       = "[-Cq] off len",
1687797ac58cSKevin Wolf     .oneline    = "discards a number of bytes at a specified offset",
1688797ac58cSKevin Wolf     .help       = discard_help,
1689797ac58cSKevin Wolf };
1690797ac58cSKevin Wolf 
16914c7b7e9bSMax Reitz static int discard_f(BlockBackend *blk, int argc, char **argv)
1692797ac58cSKevin Wolf {
1693797ac58cSKevin Wolf     struct timeval t1, t2;
1694dc38852aSEric Blake     bool Cflag = false, qflag = false;
1695797ac58cSKevin Wolf     int c, ret;
16969b0beaf3SJohn Snow     int64_t offset, count;
1697797ac58cSKevin Wolf 
1698b062ad86SEric Blake     while ((c = getopt(argc, argv, "Cq")) != -1) {
1699797ac58cSKevin Wolf         switch (c) {
1700797ac58cSKevin Wolf         case 'C':
1701dc38852aSEric Blake             Cflag = true;
1702797ac58cSKevin Wolf             break;
1703797ac58cSKevin Wolf         case 'q':
1704dc38852aSEric Blake             qflag = true;
1705797ac58cSKevin Wolf             break;
1706797ac58cSKevin Wolf         default:
1707c2cdf5c5SKevin Wolf             return qemuio_command_usage(&discard_cmd);
1708797ac58cSKevin Wolf         }
1709797ac58cSKevin Wolf     }
1710797ac58cSKevin Wolf 
1711797ac58cSKevin Wolf     if (optind != argc - 2) {
1712c2cdf5c5SKevin Wolf         return qemuio_command_usage(&discard_cmd);
1713797ac58cSKevin Wolf     }
1714797ac58cSKevin Wolf 
1715797ac58cSKevin Wolf     offset = cvtnum(argv[optind]);
1716797ac58cSKevin Wolf     if (offset < 0) {
1717a9ecfa00SJohn Snow         print_cvtnum_err(offset, argv[optind]);
1718797ac58cSKevin Wolf         return 0;
1719797ac58cSKevin Wolf     }
1720797ac58cSKevin Wolf 
1721797ac58cSKevin Wolf     optind++;
1722797ac58cSKevin Wolf     count = cvtnum(argv[optind]);
1723797ac58cSKevin Wolf     if (count < 0) {
1724a9ecfa00SJohn Snow         print_cvtnum_err(count, argv[optind]);
1725797ac58cSKevin Wolf         return 0;
1726a3674679SMax Reitz     } else if (count >> BDRV_SECTOR_BITS > BDRV_REQUEST_MAX_SECTORS) {
17279b0beaf3SJohn Snow         printf("length cannot exceed %"PRIu64", given %s\n",
1728a3674679SMax Reitz                (uint64_t)BDRV_REQUEST_MAX_SECTORS << BDRV_SECTOR_BITS,
17299b0beaf3SJohn Snow                argv[optind]);
17309b0beaf3SJohn Snow         return 0;
1731797ac58cSKevin Wolf     }
1732797ac58cSKevin Wolf 
1733797ac58cSKevin Wolf     gettimeofday(&t1, NULL);
17341c6c4bb7SEric Blake     ret = blk_pdiscard(blk, offset, count);
1735797ac58cSKevin Wolf     gettimeofday(&t2, NULL);
1736797ac58cSKevin Wolf 
1737797ac58cSKevin Wolf     if (ret < 0) {
1738797ac58cSKevin Wolf         printf("discard failed: %s\n", strerror(-ret));
1739797ac58cSKevin Wolf         goto out;
1740797ac58cSKevin Wolf     }
1741797ac58cSKevin Wolf 
1742797ac58cSKevin Wolf     /* Finally, report back -- -C gives a parsable format */
1743797ac58cSKevin Wolf     if (!qflag) {
1744797ac58cSKevin Wolf         t2 = tsub(t2, t1);
1745797ac58cSKevin Wolf         print_report("discard", &t2, offset, count, count, 1, Cflag);
1746797ac58cSKevin Wolf     }
1747797ac58cSKevin Wolf 
1748797ac58cSKevin Wolf out:
1749797ac58cSKevin Wolf     return 0;
1750797ac58cSKevin Wolf }
1751797ac58cSKevin Wolf 
17524c7b7e9bSMax Reitz static int alloc_f(BlockBackend *blk, int argc, char **argv)
1753797ac58cSKevin Wolf {
17544c7b7e9bSMax Reitz     BlockDriverState *bs = blk_bs(blk);
17559b0beaf3SJohn Snow     int64_t offset, sector_num, nb_sectors, remaining;
1756797ac58cSKevin Wolf     char s1[64];
17579b0beaf3SJohn Snow     int num, ret;
17589b0beaf3SJohn Snow     int64_t sum_alloc;
1759797ac58cSKevin Wolf 
1760797ac58cSKevin Wolf     offset = cvtnum(argv[1]);
1761797ac58cSKevin Wolf     if (offset < 0) {
1762a9ecfa00SJohn Snow         print_cvtnum_err(offset, argv[1]);
1763797ac58cSKevin Wolf         return 0;
1764797ac58cSKevin Wolf     } else if (offset & 0x1ff) {
1765797ac58cSKevin Wolf         printf("offset %" PRId64 " is not sector aligned\n",
1766797ac58cSKevin Wolf                offset);
1767797ac58cSKevin Wolf         return 0;
1768797ac58cSKevin Wolf     }
1769797ac58cSKevin Wolf 
1770797ac58cSKevin Wolf     if (argc == 3) {
1771797ac58cSKevin Wolf         nb_sectors = cvtnum(argv[2]);
1772797ac58cSKevin Wolf         if (nb_sectors < 0) {
1773a9ecfa00SJohn Snow             print_cvtnum_err(nb_sectors, argv[2]);
1774797ac58cSKevin Wolf             return 0;
17759b0beaf3SJohn Snow         } else if (nb_sectors > INT_MAX) {
17769b0beaf3SJohn Snow             printf("length argument cannot exceed %d, given %s\n",
17779b0beaf3SJohn Snow                    INT_MAX, argv[2]);
17789b0beaf3SJohn Snow             return 0;
1779797ac58cSKevin Wolf         }
1780797ac58cSKevin Wolf     } else {
1781797ac58cSKevin Wolf         nb_sectors = 1;
1782797ac58cSKevin Wolf     }
1783797ac58cSKevin Wolf 
1784797ac58cSKevin Wolf     remaining = nb_sectors;
1785797ac58cSKevin Wolf     sum_alloc = 0;
1786797ac58cSKevin Wolf     sector_num = offset >> 9;
1787797ac58cSKevin Wolf     while (remaining) {
1788797ac58cSKevin Wolf         ret = bdrv_is_allocated(bs, sector_num, remaining, &num);
1789d663640cSPaolo Bonzini         if (ret < 0) {
1790d663640cSPaolo Bonzini             printf("is_allocated failed: %s\n", strerror(-ret));
1791d663640cSPaolo Bonzini             return 0;
1792d663640cSPaolo Bonzini         }
1793797ac58cSKevin Wolf         sector_num += num;
1794797ac58cSKevin Wolf         remaining -= num;
1795797ac58cSKevin Wolf         if (ret) {
1796797ac58cSKevin Wolf             sum_alloc += num;
1797797ac58cSKevin Wolf         }
1798797ac58cSKevin Wolf         if (num == 0) {
1799797ac58cSKevin Wolf             nb_sectors -= remaining;
1800797ac58cSKevin Wolf             remaining = 0;
1801797ac58cSKevin Wolf         }
1802797ac58cSKevin Wolf     }
1803797ac58cSKevin Wolf 
1804797ac58cSKevin Wolf     cvtstr(offset, s1, sizeof(s1));
1805797ac58cSKevin Wolf 
18069b0beaf3SJohn Snow     printf("%"PRId64"/%"PRId64" sectors allocated at offset %s\n",
1807797ac58cSKevin Wolf            sum_alloc, nb_sectors, s1);
1808797ac58cSKevin Wolf     return 0;
1809797ac58cSKevin Wolf }
1810797ac58cSKevin Wolf 
1811797ac58cSKevin Wolf static const cmdinfo_t alloc_cmd = {
1812797ac58cSKevin Wolf     .name       = "alloc",
1813797ac58cSKevin Wolf     .altname    = "a",
1814797ac58cSKevin Wolf     .argmin     = 1,
1815797ac58cSKevin Wolf     .argmax     = 2,
1816797ac58cSKevin Wolf     .cfunc      = alloc_f,
1817797ac58cSKevin Wolf     .args       = "off [sectors]",
1818797ac58cSKevin Wolf     .oneline    = "checks if a sector is present in the file",
1819797ac58cSKevin Wolf };
1820797ac58cSKevin Wolf 
1821797ac58cSKevin Wolf 
1822797ac58cSKevin Wolf static int map_is_allocated(BlockDriverState *bs, int64_t sector_num,
1823797ac58cSKevin Wolf                             int64_t nb_sectors, int64_t *pnum)
1824797ac58cSKevin Wolf {
1825797ac58cSKevin Wolf     int num, num_checked;
1826797ac58cSKevin Wolf     int ret, firstret;
1827797ac58cSKevin Wolf 
1828797ac58cSKevin Wolf     num_checked = MIN(nb_sectors, INT_MAX);
1829797ac58cSKevin Wolf     ret = bdrv_is_allocated(bs, sector_num, num_checked, &num);
1830797ac58cSKevin Wolf     if (ret < 0) {
1831797ac58cSKevin Wolf         return ret;
1832797ac58cSKevin Wolf     }
1833797ac58cSKevin Wolf 
1834797ac58cSKevin Wolf     firstret = ret;
1835797ac58cSKevin Wolf     *pnum = num;
1836797ac58cSKevin Wolf 
1837797ac58cSKevin Wolf     while (nb_sectors > 0 && ret == firstret) {
1838797ac58cSKevin Wolf         sector_num += num;
1839797ac58cSKevin Wolf         nb_sectors -= num;
1840797ac58cSKevin Wolf 
1841797ac58cSKevin Wolf         num_checked = MIN(nb_sectors, INT_MAX);
1842797ac58cSKevin Wolf         ret = bdrv_is_allocated(bs, sector_num, num_checked, &num);
18434b25bbc4SMax Reitz         if (ret == firstret && num) {
1844797ac58cSKevin Wolf             *pnum += num;
1845797ac58cSKevin Wolf         } else {
1846797ac58cSKevin Wolf             break;
1847797ac58cSKevin Wolf         }
1848797ac58cSKevin Wolf     }
1849797ac58cSKevin Wolf 
1850797ac58cSKevin Wolf     return firstret;
1851797ac58cSKevin Wolf }
1852797ac58cSKevin Wolf 
18534c7b7e9bSMax Reitz static int map_f(BlockBackend *blk, int argc, char **argv)
1854797ac58cSKevin Wolf {
1855797ac58cSKevin Wolf     int64_t offset;
18564c7b7e9bSMax Reitz     int64_t nb_sectors, total_sectors;
1857797ac58cSKevin Wolf     char s1[64];
1858797ac58cSKevin Wolf     int64_t num;
1859797ac58cSKevin Wolf     int ret;
1860797ac58cSKevin Wolf     const char *retstr;
1861797ac58cSKevin Wolf 
1862797ac58cSKevin Wolf     offset = 0;
18634c7b7e9bSMax Reitz     total_sectors = blk_nb_sectors(blk);
18644c7b7e9bSMax Reitz     if (total_sectors < 0) {
18654c7b7e9bSMax Reitz         error_report("Failed to query image length: %s",
18664c7b7e9bSMax Reitz                      strerror(-total_sectors));
18674c7b7e9bSMax Reitz         return 0;
18684c7b7e9bSMax Reitz     }
18694c7b7e9bSMax Reitz 
18704c7b7e9bSMax Reitz     nb_sectors = total_sectors;
1871797ac58cSKevin Wolf 
1872797ac58cSKevin Wolf     do {
18734c7b7e9bSMax Reitz         ret = map_is_allocated(blk_bs(blk), offset, nb_sectors, &num);
1874797ac58cSKevin Wolf         if (ret < 0) {
1875797ac58cSKevin Wolf             error_report("Failed to get allocation status: %s", strerror(-ret));
1876797ac58cSKevin Wolf             return 0;
18774b25bbc4SMax Reitz         } else if (!num) {
18784b25bbc4SMax Reitz             error_report("Unexpected end of image");
18794b25bbc4SMax Reitz             return 0;
1880797ac58cSKevin Wolf         }
1881797ac58cSKevin Wolf 
1882797ac58cSKevin Wolf         retstr = ret ? "    allocated" : "not allocated";
1883797ac58cSKevin Wolf         cvtstr(offset << 9ULL, s1, sizeof(s1));
1884797ac58cSKevin Wolf         printf("[% 24" PRId64 "] % 8" PRId64 "/% 8" PRId64 " sectors %s "
1885797ac58cSKevin Wolf                "at offset %s (%d)\n",
1886797ac58cSKevin Wolf                offset << 9ULL, num, nb_sectors, retstr, s1, ret);
1887797ac58cSKevin Wolf 
1888797ac58cSKevin Wolf         offset += num;
1889797ac58cSKevin Wolf         nb_sectors -= num;
18904c7b7e9bSMax Reitz     } while (offset < total_sectors);
1891797ac58cSKevin Wolf 
1892797ac58cSKevin Wolf     return 0;
1893797ac58cSKevin Wolf }
1894797ac58cSKevin Wolf 
1895797ac58cSKevin Wolf static const cmdinfo_t map_cmd = {
1896797ac58cSKevin Wolf        .name           = "map",
1897797ac58cSKevin Wolf        .argmin         = 0,
1898797ac58cSKevin Wolf        .argmax         = 0,
1899797ac58cSKevin Wolf        .cfunc          = map_f,
1900797ac58cSKevin Wolf        .args           = "",
1901797ac58cSKevin Wolf        .oneline        = "prints the allocated areas of a file",
1902797ac58cSKevin Wolf };
1903797ac58cSKevin Wolf 
19045bbd2e59SKevin Wolf static void reopen_help(void)
19055bbd2e59SKevin Wolf {
19065bbd2e59SKevin Wolf     printf(
19075bbd2e59SKevin Wolf "\n"
19085bbd2e59SKevin Wolf " Changes the open options of an already opened image\n"
19095bbd2e59SKevin Wolf "\n"
19105bbd2e59SKevin Wolf " Example:\n"
19115bbd2e59SKevin Wolf " 'reopen -o lazy-refcounts=on' - activates lazy refcount writeback on a qcow2 image\n"
19125bbd2e59SKevin Wolf "\n"
19135bbd2e59SKevin Wolf " -r, -- Reopen the image read-only\n"
19145bbd2e59SKevin Wolf " -c, -- Change the cache mode to the given value\n"
19155bbd2e59SKevin Wolf " -o, -- Changes block driver options (cf. 'open' command)\n"
19165bbd2e59SKevin Wolf "\n");
19175bbd2e59SKevin Wolf }
19185bbd2e59SKevin Wolf 
19195bbd2e59SKevin Wolf static int reopen_f(BlockBackend *blk, int argc, char **argv);
19205bbd2e59SKevin Wolf 
19215bbd2e59SKevin Wolf static QemuOptsList reopen_opts = {
19225bbd2e59SKevin Wolf     .name = "reopen",
19235bbd2e59SKevin Wolf     .merge_lists = true,
19245bbd2e59SKevin Wolf     .head = QTAILQ_HEAD_INITIALIZER(reopen_opts.head),
19255bbd2e59SKevin Wolf     .desc = {
19265bbd2e59SKevin Wolf         /* no elements => accept any params */
19275bbd2e59SKevin Wolf         { /* end of list */ }
19285bbd2e59SKevin Wolf     },
19295bbd2e59SKevin Wolf };
19305bbd2e59SKevin Wolf 
19315bbd2e59SKevin Wolf static const cmdinfo_t reopen_cmd = {
19325bbd2e59SKevin Wolf        .name           = "reopen",
19335bbd2e59SKevin Wolf        .argmin         = 0,
19345bbd2e59SKevin Wolf        .argmax         = -1,
19355bbd2e59SKevin Wolf        .cfunc          = reopen_f,
19365bbd2e59SKevin Wolf        .args           = "[-r] [-c cache] [-o options]",
19375bbd2e59SKevin Wolf        .oneline        = "reopens an image with new options",
19385bbd2e59SKevin Wolf        .help           = reopen_help,
19395bbd2e59SKevin Wolf };
19405bbd2e59SKevin Wolf 
19415bbd2e59SKevin Wolf static int reopen_f(BlockBackend *blk, int argc, char **argv)
19425bbd2e59SKevin Wolf {
19435bbd2e59SKevin Wolf     BlockDriverState *bs = blk_bs(blk);
19445bbd2e59SKevin Wolf     QemuOpts *qopts;
19455bbd2e59SKevin Wolf     QDict *opts;
19465bbd2e59SKevin Wolf     int c;
19475bbd2e59SKevin Wolf     int flags = bs->open_flags;
194819dbecdcSKevin Wolf     bool writethrough = !blk_enable_write_cache(blk);
19495bbd2e59SKevin Wolf 
19505bbd2e59SKevin Wolf     BlockReopenQueue *brq;
19515bbd2e59SKevin Wolf     Error *local_err = NULL;
19525bbd2e59SKevin Wolf 
19535bbd2e59SKevin Wolf     while ((c = getopt(argc, argv, "c:o:r")) != -1) {
19545bbd2e59SKevin Wolf         switch (c) {
19555bbd2e59SKevin Wolf         case 'c':
195619dbecdcSKevin Wolf             if (bdrv_parse_cache_mode(optarg, &flags, &writethrough) < 0) {
19575bbd2e59SKevin Wolf                 error_report("Invalid cache option: %s", optarg);
19585bbd2e59SKevin Wolf                 return 0;
19595bbd2e59SKevin Wolf             }
19605bbd2e59SKevin Wolf             break;
19615bbd2e59SKevin Wolf         case 'o':
19625bbd2e59SKevin Wolf             if (!qemu_opts_parse_noisily(&reopen_opts, optarg, 0)) {
19635bbd2e59SKevin Wolf                 qemu_opts_reset(&reopen_opts);
19645bbd2e59SKevin Wolf                 return 0;
19655bbd2e59SKevin Wolf             }
19665bbd2e59SKevin Wolf             break;
19675bbd2e59SKevin Wolf         case 'r':
19685bbd2e59SKevin Wolf             flags &= ~BDRV_O_RDWR;
19695bbd2e59SKevin Wolf             break;
19705bbd2e59SKevin Wolf         default:
19715bbd2e59SKevin Wolf             qemu_opts_reset(&reopen_opts);
19725bbd2e59SKevin Wolf             return qemuio_command_usage(&reopen_cmd);
19735bbd2e59SKevin Wolf         }
19745bbd2e59SKevin Wolf     }
19755bbd2e59SKevin Wolf 
19765bbd2e59SKevin Wolf     if (optind != argc) {
19775bbd2e59SKevin Wolf         qemu_opts_reset(&reopen_opts);
19785bbd2e59SKevin Wolf         return qemuio_command_usage(&reopen_cmd);
19795bbd2e59SKevin Wolf     }
19805bbd2e59SKevin Wolf 
198119dbecdcSKevin Wolf     if (writethrough != blk_enable_write_cache(blk) &&
198219dbecdcSKevin Wolf         blk_get_attached_dev(blk))
198319dbecdcSKevin Wolf     {
198419dbecdcSKevin Wolf         error_report("Cannot change cache.writeback: Device attached");
198519dbecdcSKevin Wolf         qemu_opts_reset(&reopen_opts);
198619dbecdcSKevin Wolf         return 0;
198719dbecdcSKevin Wolf     }
198819dbecdcSKevin Wolf 
19895bbd2e59SKevin Wolf     qopts = qemu_opts_find(&reopen_opts, NULL);
19905bbd2e59SKevin Wolf     opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : NULL;
19915bbd2e59SKevin Wolf     qemu_opts_reset(&reopen_opts);
19925bbd2e59SKevin Wolf 
19935bbd2e59SKevin Wolf     brq = bdrv_reopen_queue(NULL, bs, opts, flags);
1994720150f3SPaolo Bonzini     bdrv_reopen_multiple(bdrv_get_aio_context(bs), brq, &local_err);
19955bbd2e59SKevin Wolf     if (local_err) {
19965bbd2e59SKevin Wolf         error_report_err(local_err);
199719dbecdcSKevin Wolf     } else {
199819dbecdcSKevin Wolf         blk_set_enable_write_cache(blk, !writethrough);
19995bbd2e59SKevin Wolf     }
20005bbd2e59SKevin Wolf 
20015bbd2e59SKevin Wolf     return 0;
20025bbd2e59SKevin Wolf }
20035bbd2e59SKevin Wolf 
20044c7b7e9bSMax Reitz static int break_f(BlockBackend *blk, int argc, char **argv)
2005797ac58cSKevin Wolf {
2006797ac58cSKevin Wolf     int ret;
2007797ac58cSKevin Wolf 
20084c7b7e9bSMax Reitz     ret = bdrv_debug_breakpoint(blk_bs(blk), argv[1], argv[2]);
2009797ac58cSKevin Wolf     if (ret < 0) {
2010797ac58cSKevin Wolf         printf("Could not set breakpoint: %s\n", strerror(-ret));
2011797ac58cSKevin Wolf     }
2012797ac58cSKevin Wolf 
2013797ac58cSKevin Wolf     return 0;
2014797ac58cSKevin Wolf }
2015797ac58cSKevin Wolf 
20164c7b7e9bSMax Reitz static int remove_break_f(BlockBackend *blk, int argc, char **argv)
20174cc70e93SFam Zheng {
20184cc70e93SFam Zheng     int ret;
20194cc70e93SFam Zheng 
20204c7b7e9bSMax Reitz     ret = bdrv_debug_remove_breakpoint(blk_bs(blk), argv[1]);
20214cc70e93SFam Zheng     if (ret < 0) {
20224cc70e93SFam Zheng         printf("Could not remove breakpoint %s: %s\n", argv[1], strerror(-ret));
20234cc70e93SFam Zheng     }
20244cc70e93SFam Zheng 
20254cc70e93SFam Zheng     return 0;
20264cc70e93SFam Zheng }
20274cc70e93SFam Zheng 
2028797ac58cSKevin Wolf static const cmdinfo_t break_cmd = {
2029797ac58cSKevin Wolf        .name           = "break",
2030797ac58cSKevin Wolf        .argmin         = 2,
2031797ac58cSKevin Wolf        .argmax         = 2,
2032797ac58cSKevin Wolf        .cfunc          = break_f,
2033797ac58cSKevin Wolf        .args           = "event tag",
2034797ac58cSKevin Wolf        .oneline        = "sets a breakpoint on event and tags the stopped "
2035797ac58cSKevin Wolf                          "request as tag",
2036797ac58cSKevin Wolf };
2037797ac58cSKevin Wolf 
20384cc70e93SFam Zheng static const cmdinfo_t remove_break_cmd = {
20394cc70e93SFam Zheng        .name           = "remove_break",
20404cc70e93SFam Zheng        .argmin         = 1,
20414cc70e93SFam Zheng        .argmax         = 1,
20424cc70e93SFam Zheng        .cfunc          = remove_break_f,
20434cc70e93SFam Zheng        .args           = "tag",
20444cc70e93SFam Zheng        .oneline        = "remove a breakpoint by tag",
20454cc70e93SFam Zheng };
20464cc70e93SFam Zheng 
20474c7b7e9bSMax Reitz static int resume_f(BlockBackend *blk, int argc, char **argv)
2048797ac58cSKevin Wolf {
2049797ac58cSKevin Wolf     int ret;
2050797ac58cSKevin Wolf 
20514c7b7e9bSMax Reitz     ret = bdrv_debug_resume(blk_bs(blk), argv[1]);
2052797ac58cSKevin Wolf     if (ret < 0) {
2053797ac58cSKevin Wolf         printf("Could not resume request: %s\n", strerror(-ret));
2054797ac58cSKevin Wolf     }
2055797ac58cSKevin Wolf 
2056797ac58cSKevin Wolf     return 0;
2057797ac58cSKevin Wolf }
2058797ac58cSKevin Wolf 
2059797ac58cSKevin Wolf static const cmdinfo_t resume_cmd = {
2060797ac58cSKevin Wolf        .name           = "resume",
2061797ac58cSKevin Wolf        .argmin         = 1,
2062797ac58cSKevin Wolf        .argmax         = 1,
2063797ac58cSKevin Wolf        .cfunc          = resume_f,
2064797ac58cSKevin Wolf        .args           = "tag",
2065797ac58cSKevin Wolf        .oneline        = "resumes the request tagged as tag",
2066797ac58cSKevin Wolf };
2067797ac58cSKevin Wolf 
20684c7b7e9bSMax Reitz static int wait_break_f(BlockBackend *blk, int argc, char **argv)
2069797ac58cSKevin Wolf {
20704c7b7e9bSMax Reitz     while (!bdrv_debug_is_suspended(blk_bs(blk), argv[1])) {
20714c7b7e9bSMax Reitz         aio_poll(blk_get_aio_context(blk), true);
2072797ac58cSKevin Wolf     }
2073797ac58cSKevin Wolf 
2074797ac58cSKevin Wolf     return 0;
2075797ac58cSKevin Wolf }
2076797ac58cSKevin Wolf 
2077797ac58cSKevin Wolf static const cmdinfo_t wait_break_cmd = {
2078797ac58cSKevin Wolf        .name           = "wait_break",
2079797ac58cSKevin Wolf        .argmin         = 1,
2080797ac58cSKevin Wolf        .argmax         = 1,
2081797ac58cSKevin Wolf        .cfunc          = wait_break_f,
2082797ac58cSKevin Wolf        .args           = "tag",
2083797ac58cSKevin Wolf        .oneline        = "waits for the suspension of a request",
2084797ac58cSKevin Wolf };
2085797ac58cSKevin Wolf 
20864c7b7e9bSMax Reitz static int abort_f(BlockBackend *blk, int argc, char **argv)
2087797ac58cSKevin Wolf {
2088797ac58cSKevin Wolf     abort();
2089797ac58cSKevin Wolf }
2090797ac58cSKevin Wolf 
2091797ac58cSKevin Wolf static const cmdinfo_t abort_cmd = {
2092797ac58cSKevin Wolf        .name           = "abort",
2093797ac58cSKevin Wolf        .cfunc          = abort_f,
2094797ac58cSKevin Wolf        .flags          = CMD_NOFILE_OK,
2095797ac58cSKevin Wolf        .oneline        = "simulate a program crash using abort(3)",
2096797ac58cSKevin Wolf };
2097797ac58cSKevin Wolf 
20980e82dc7bSMax Reitz static void sigraise_help(void)
20990e82dc7bSMax Reitz {
21000e82dc7bSMax Reitz     printf(
21010e82dc7bSMax Reitz "\n"
21020e82dc7bSMax Reitz " raises the given signal\n"
21030e82dc7bSMax Reitz "\n"
21040e82dc7bSMax Reitz " Example:\n"
21050e82dc7bSMax Reitz " 'sigraise %i' - raises SIGTERM\n"
21060e82dc7bSMax Reitz "\n"
21070e82dc7bSMax Reitz " Invokes raise(signal), where \"signal\" is the mandatory integer argument\n"
21080e82dc7bSMax Reitz " given to sigraise.\n"
21090e82dc7bSMax Reitz "\n", SIGTERM);
21100e82dc7bSMax Reitz }
21110e82dc7bSMax Reitz 
21124c7b7e9bSMax Reitz static int sigraise_f(BlockBackend *blk, int argc, char **argv);
21130e82dc7bSMax Reitz 
21140e82dc7bSMax Reitz static const cmdinfo_t sigraise_cmd = {
21150e82dc7bSMax Reitz     .name       = "sigraise",
21160e82dc7bSMax Reitz     .cfunc      = sigraise_f,
21170e82dc7bSMax Reitz     .argmin     = 1,
21180e82dc7bSMax Reitz     .argmax     = 1,
21190e82dc7bSMax Reitz     .flags      = CMD_NOFILE_OK,
21200e82dc7bSMax Reitz     .args       = "signal",
21210e82dc7bSMax Reitz     .oneline    = "raises a signal",
21220e82dc7bSMax Reitz     .help       = sigraise_help,
21230e82dc7bSMax Reitz };
21240e82dc7bSMax Reitz 
21254c7b7e9bSMax Reitz static int sigraise_f(BlockBackend *blk, int argc, char **argv)
21260e82dc7bSMax Reitz {
21279b0beaf3SJohn Snow     int64_t sig = cvtnum(argv[1]);
21280e82dc7bSMax Reitz     if (sig < 0) {
2129a9ecfa00SJohn Snow         print_cvtnum_err(sig, argv[1]);
21300e82dc7bSMax Reitz         return 0;
21319b0beaf3SJohn Snow     } else if (sig > NSIG) {
21329b0beaf3SJohn Snow         printf("signal argument '%s' is too large to be a valid signal\n",
21339b0beaf3SJohn Snow                argv[1]);
21349b0beaf3SJohn Snow         return 0;
21350e82dc7bSMax Reitz     }
21360e82dc7bSMax Reitz 
21370e82dc7bSMax Reitz     /* Using raise() to kill this process does not necessarily flush all open
21380e82dc7bSMax Reitz      * streams. At least stdout and stderr (although the latter should be
21390e82dc7bSMax Reitz      * non-buffered anyway) should be flushed, though. */
21400e82dc7bSMax Reitz     fflush(stdout);
21410e82dc7bSMax Reitz     fflush(stderr);
21420e82dc7bSMax Reitz 
21430e82dc7bSMax Reitz     raise(sig);
21440e82dc7bSMax Reitz     return 0;
21450e82dc7bSMax Reitz }
21460e82dc7bSMax Reitz 
2147cd33d02aSKevin Wolf static void sleep_cb(void *opaque)
2148cd33d02aSKevin Wolf {
2149cd33d02aSKevin Wolf     bool *expired = opaque;
2150cd33d02aSKevin Wolf     *expired = true;
2151cd33d02aSKevin Wolf }
2152cd33d02aSKevin Wolf 
21534c7b7e9bSMax Reitz static int sleep_f(BlockBackend *blk, int argc, char **argv)
2154cd33d02aSKevin Wolf {
2155cd33d02aSKevin Wolf     char *endptr;
2156cd33d02aSKevin Wolf     long ms;
2157cd33d02aSKevin Wolf     struct QEMUTimer *timer;
2158cd33d02aSKevin Wolf     bool expired = false;
2159cd33d02aSKevin Wolf 
2160cd33d02aSKevin Wolf     ms = strtol(argv[1], &endptr, 0);
2161cd33d02aSKevin Wolf     if (ms < 0 || *endptr != '\0') {
2162cd33d02aSKevin Wolf         printf("%s is not a valid number\n", argv[1]);
2163cd33d02aSKevin Wolf         return 0;
2164cd33d02aSKevin Wolf     }
2165cd33d02aSKevin Wolf 
2166cd33d02aSKevin Wolf     timer = timer_new_ns(QEMU_CLOCK_HOST, sleep_cb, &expired);
2167cd33d02aSKevin Wolf     timer_mod(timer, qemu_clock_get_ns(QEMU_CLOCK_HOST) + SCALE_MS * ms);
2168cd33d02aSKevin Wolf 
2169cd33d02aSKevin Wolf     while (!expired) {
2170cd33d02aSKevin Wolf         main_loop_wait(false);
2171cd33d02aSKevin Wolf     }
2172cd33d02aSKevin Wolf 
2173cd33d02aSKevin Wolf     timer_free(timer);
2174cd33d02aSKevin Wolf 
2175cd33d02aSKevin Wolf     return 0;
2176cd33d02aSKevin Wolf }
2177cd33d02aSKevin Wolf 
2178cd33d02aSKevin Wolf static const cmdinfo_t sleep_cmd = {
2179cd33d02aSKevin Wolf        .name           = "sleep",
2180cd33d02aSKevin Wolf        .argmin         = 1,
2181cd33d02aSKevin Wolf        .argmax         = 1,
2182cd33d02aSKevin Wolf        .cfunc          = sleep_f,
2183cd33d02aSKevin Wolf        .flags          = CMD_NOFILE_OK,
2184cd33d02aSKevin Wolf        .oneline        = "waits for the given value in milliseconds",
2185cd33d02aSKevin Wolf };
2186cd33d02aSKevin Wolf 
2187f18a834aSKevin Wolf static void help_oneline(const char *cmd, const cmdinfo_t *ct)
2188f18a834aSKevin Wolf {
2189f18a834aSKevin Wolf     if (cmd) {
2190f18a834aSKevin Wolf         printf("%s ", cmd);
2191f18a834aSKevin Wolf     } else {
2192f18a834aSKevin Wolf         printf("%s ", ct->name);
2193f18a834aSKevin Wolf         if (ct->altname) {
2194f18a834aSKevin Wolf             printf("(or %s) ", ct->altname);
2195f18a834aSKevin Wolf         }
2196f18a834aSKevin Wolf     }
2197f18a834aSKevin Wolf 
2198f18a834aSKevin Wolf     if (ct->args) {
2199f18a834aSKevin Wolf         printf("%s ", ct->args);
2200f18a834aSKevin Wolf     }
2201f18a834aSKevin Wolf     printf("-- %s\n", ct->oneline);
2202f18a834aSKevin Wolf }
2203f18a834aSKevin Wolf 
2204f18a834aSKevin Wolf static void help_onecmd(const char *cmd, const cmdinfo_t *ct)
2205f18a834aSKevin Wolf {
2206f18a834aSKevin Wolf     help_oneline(cmd, ct);
2207f18a834aSKevin Wolf     if (ct->help) {
2208f18a834aSKevin Wolf         ct->help();
2209f18a834aSKevin Wolf     }
2210f18a834aSKevin Wolf }
2211f18a834aSKevin Wolf 
2212f18a834aSKevin Wolf static void help_all(void)
2213f18a834aSKevin Wolf {
2214f18a834aSKevin Wolf     const cmdinfo_t *ct;
2215f18a834aSKevin Wolf 
2216f18a834aSKevin Wolf     for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) {
2217f18a834aSKevin Wolf         help_oneline(ct->name, ct);
2218f18a834aSKevin Wolf     }
2219f18a834aSKevin Wolf     printf("\nUse 'help commandname' for extended help.\n");
2220f18a834aSKevin Wolf }
2221f18a834aSKevin Wolf 
22224c7b7e9bSMax Reitz static int help_f(BlockBackend *blk, int argc, char **argv)
2223f18a834aSKevin Wolf {
2224f18a834aSKevin Wolf     const cmdinfo_t *ct;
2225f18a834aSKevin Wolf 
2226f18a834aSKevin Wolf     if (argc == 1) {
2227f18a834aSKevin Wolf         help_all();
2228f18a834aSKevin Wolf         return 0;
2229f18a834aSKevin Wolf     }
2230f18a834aSKevin Wolf 
2231f18a834aSKevin Wolf     ct = find_command(argv[1]);
2232f18a834aSKevin Wolf     if (ct == NULL) {
2233f18a834aSKevin Wolf         printf("command %s not found\n", argv[1]);
2234f18a834aSKevin Wolf         return 0;
2235f18a834aSKevin Wolf     }
2236f18a834aSKevin Wolf 
2237f18a834aSKevin Wolf     help_onecmd(argv[1], ct);
2238f18a834aSKevin Wolf     return 0;
2239f18a834aSKevin Wolf }
2240f18a834aSKevin Wolf 
2241f18a834aSKevin Wolf static const cmdinfo_t help_cmd = {
2242f18a834aSKevin Wolf     .name       = "help",
2243f18a834aSKevin Wolf     .altname    = "?",
2244f18a834aSKevin Wolf     .cfunc      = help_f,
2245f18a834aSKevin Wolf     .argmin     = 0,
2246f18a834aSKevin Wolf     .argmax     = 1,
2247f18a834aSKevin Wolf     .flags      = CMD_FLAG_GLOBAL,
2248f18a834aSKevin Wolf     .args       = "[command]",
2249f18a834aSKevin Wolf     .oneline    = "help for one or all commands",
2250f18a834aSKevin Wolf };
2251f18a834aSKevin Wolf 
22524c7b7e9bSMax Reitz bool qemuio_command(BlockBackend *blk, const char *cmd)
2253dd583296SKevin Wolf {
225415afd94aSPaolo Bonzini     AioContext *ctx;
2255dd583296SKevin Wolf     char *input;
2256dd583296SKevin Wolf     const cmdinfo_t *ct;
2257dd583296SKevin Wolf     char **v;
2258dd583296SKevin Wolf     int c;
2259dd583296SKevin Wolf     bool done = false;
2260dd583296SKevin Wolf 
2261dd583296SKevin Wolf     input = g_strdup(cmd);
2262dd583296SKevin Wolf     v = breakline(input, &c);
2263dd583296SKevin Wolf     if (c) {
2264dd583296SKevin Wolf         ct = find_command(v[0]);
2265dd583296SKevin Wolf         if (ct) {
226615afd94aSPaolo Bonzini             ctx = blk ? blk_get_aio_context(blk) : qemu_get_aio_context();
226715afd94aSPaolo Bonzini             aio_context_acquire(ctx);
22684c7b7e9bSMax Reitz             done = command(blk, ct, c, v);
226915afd94aSPaolo Bonzini             aio_context_release(ctx);
2270dd583296SKevin Wolf         } else {
2271dd583296SKevin Wolf             fprintf(stderr, "command \"%s\" not found\n", v[0]);
2272dd583296SKevin Wolf         }
2273dd583296SKevin Wolf     }
2274dd583296SKevin Wolf     g_free(input);
2275dd583296SKevin Wolf     g_free(v);
2276dd583296SKevin Wolf 
2277dd583296SKevin Wolf     return done;
2278dd583296SKevin Wolf }
2279dd583296SKevin Wolf 
2280797ac58cSKevin Wolf static void __attribute((constructor)) init_qemuio_commands(void)
2281797ac58cSKevin Wolf {
2282797ac58cSKevin Wolf     /* initialize commands */
2283c2cdf5c5SKevin Wolf     qemuio_add_command(&help_cmd);
2284c2cdf5c5SKevin Wolf     qemuio_add_command(&read_cmd);
2285c2cdf5c5SKevin Wolf     qemuio_add_command(&readv_cmd);
2286c2cdf5c5SKevin Wolf     qemuio_add_command(&write_cmd);
2287c2cdf5c5SKevin Wolf     qemuio_add_command(&writev_cmd);
2288c2cdf5c5SKevin Wolf     qemuio_add_command(&aio_read_cmd);
2289c2cdf5c5SKevin Wolf     qemuio_add_command(&aio_write_cmd);
2290c2cdf5c5SKevin Wolf     qemuio_add_command(&aio_flush_cmd);
2291c2cdf5c5SKevin Wolf     qemuio_add_command(&flush_cmd);
2292c2cdf5c5SKevin Wolf     qemuio_add_command(&truncate_cmd);
2293c2cdf5c5SKevin Wolf     qemuio_add_command(&length_cmd);
2294c2cdf5c5SKevin Wolf     qemuio_add_command(&info_cmd);
2295c2cdf5c5SKevin Wolf     qemuio_add_command(&discard_cmd);
2296c2cdf5c5SKevin Wolf     qemuio_add_command(&alloc_cmd);
2297c2cdf5c5SKevin Wolf     qemuio_add_command(&map_cmd);
22985bbd2e59SKevin Wolf     qemuio_add_command(&reopen_cmd);
2299c2cdf5c5SKevin Wolf     qemuio_add_command(&break_cmd);
23004cc70e93SFam Zheng     qemuio_add_command(&remove_break_cmd);
2301c2cdf5c5SKevin Wolf     qemuio_add_command(&resume_cmd);
2302c2cdf5c5SKevin Wolf     qemuio_add_command(&wait_break_cmd);
2303c2cdf5c5SKevin Wolf     qemuio_add_command(&abort_cmd);
2304cd33d02aSKevin Wolf     qemuio_add_command(&sleep_cmd);
23050e82dc7bSMax Reitz     qemuio_add_command(&sigraise_cmd);
2306797ac58cSKevin Wolf }
2307