xref: /qemu/qemu-io-cmds.c (revision 3574499a)
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"
13dc900c35SAlberto Garcia #include "qapi/qmp/qdict.h"
143d21994fSKevin Wolf #include "qemu-io.h"
154c7b7e9bSMax Reitz #include "sysemu/block-backend.h"
164c7b7e9bSMax Reitz #include "block/block.h"
174c7b7e9bSMax Reitz #include "block/block_int.h" /* for info_f() */
18a8d8ecb7SMax Reitz #include "block/qapi.h"
19d49b6836SMarkus Armbruster #include "qemu/error-report.h"
206a1751b7SAlex Bligh #include "qemu/main-loop.h"
21922a01a0SMarkus Armbruster #include "qemu/option.h"
22cd33d02aSKevin Wolf #include "qemu/timer.h"
23f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
245df022cfSPeter Maydell #include "qemu/memalign.h"
25797ac58cSKevin Wolf 
26797ac58cSKevin Wolf #define CMD_NOFILE_OK   0x01
27797ac58cSKevin Wolf 
28f9883880SStefan Weil bool qemuio_misalign;
29797ac58cSKevin Wolf 
30c2cdf5c5SKevin Wolf static cmdinfo_t *cmdtab;
31c2cdf5c5SKevin Wolf static int ncmds;
32c2cdf5c5SKevin Wolf 
compare_cmdname(const void * a,const void * b)33c2cdf5c5SKevin Wolf static int compare_cmdname(const void *a, const void *b)
34c2cdf5c5SKevin Wolf {
35c2cdf5c5SKevin Wolf     return strcmp(((const cmdinfo_t *)a)->name,
36c2cdf5c5SKevin Wolf                   ((const cmdinfo_t *)b)->name);
37c2cdf5c5SKevin Wolf }
38c2cdf5c5SKevin Wolf 
qemuio_add_command(const cmdinfo_t * ci)39c2cdf5c5SKevin Wolf void qemuio_add_command(const cmdinfo_t *ci)
40c2cdf5c5SKevin Wolf {
416aabeb58SPeter Maydell     /* ci->perm assumes a file is open, but the GLOBAL and NOFILE_OK
426aabeb58SPeter Maydell      * flags allow it not to be, so that combination is invalid.
436aabeb58SPeter Maydell      * Catch it now rather than letting it manifest as a crash if a
446aabeb58SPeter Maydell      * particular set of command line options are used.
456aabeb58SPeter Maydell      */
466aabeb58SPeter Maydell     assert(ci->perm == 0 ||
476aabeb58SPeter Maydell            (ci->flags & (CMD_FLAG_GLOBAL | CMD_NOFILE_OK)) == 0);
4802c4f26bSMarkus Armbruster     cmdtab = g_renew(cmdinfo_t, cmdtab, ++ncmds);
49c2cdf5c5SKevin Wolf     cmdtab[ncmds - 1] = *ci;
50c2cdf5c5SKevin Wolf     qsort(cmdtab, ncmds, sizeof(*cmdtab), compare_cmdname);
51c2cdf5c5SKevin Wolf }
52c2cdf5c5SKevin Wolf 
qemuio_command_usage(const cmdinfo_t * ci)53b444d0e9SMax Reitz void qemuio_command_usage(const cmdinfo_t *ci)
54c2cdf5c5SKevin Wolf {
55c2cdf5c5SKevin Wolf     printf("%s %s -- %s\n", ci->name, ci->args, ci->oneline);
56c2cdf5c5SKevin Wolf }
57c2cdf5c5SKevin Wolf 
init_check_command(BlockBackend * blk,const cmdinfo_t * ct)584c7b7e9bSMax Reitz static int init_check_command(BlockBackend *blk, const cmdinfo_t *ct)
59c2cdf5c5SKevin Wolf {
60c2cdf5c5SKevin Wolf     if (ct->flags & CMD_FLAG_GLOBAL) {
61c2cdf5c5SKevin Wolf         return 1;
62c2cdf5c5SKevin Wolf     }
634c7b7e9bSMax Reitz     if (!(ct->flags & CMD_NOFILE_OK) && !blk) {
64c2cdf5c5SKevin Wolf         fprintf(stderr, "no file open, try 'help open'\n");
65c2cdf5c5SKevin Wolf         return 0;
66c2cdf5c5SKevin Wolf     }
67c2cdf5c5SKevin Wolf     return 1;
68c2cdf5c5SKevin Wolf }
69c2cdf5c5SKevin Wolf 
command(BlockBackend * blk,const cmdinfo_t * ct,int argc,char ** argv)70b32d7a39SMax Reitz static int command(BlockBackend *blk, const cmdinfo_t *ct, int argc,
713d21994fSKevin Wolf                    char **argv)
72c2cdf5c5SKevin Wolf {
73c2cdf5c5SKevin Wolf     char *cmd = argv[0];
74c2cdf5c5SKevin Wolf 
754c7b7e9bSMax Reitz     if (!init_check_command(blk, ct)) {
76b32d7a39SMax Reitz         return -EINVAL;
77c2cdf5c5SKevin Wolf     }
78c2cdf5c5SKevin Wolf 
79c2cdf5c5SKevin Wolf     if (argc - 1 < ct->argmin || (ct->argmax != -1 && argc - 1 > ct->argmax)) {
80c2cdf5c5SKevin Wolf         if (ct->argmax == -1) {
81c2cdf5c5SKevin Wolf             fprintf(stderr,
82c2cdf5c5SKevin Wolf                     "bad argument count %d to %s, expected at least %d arguments\n",
83c2cdf5c5SKevin Wolf                     argc-1, cmd, ct->argmin);
84c2cdf5c5SKevin Wolf         } else if (ct->argmin == ct->argmax) {
85c2cdf5c5SKevin Wolf             fprintf(stderr,
86c2cdf5c5SKevin Wolf                     "bad argument count %d to %s, expected %d arguments\n",
87c2cdf5c5SKevin Wolf                     argc-1, cmd, ct->argmin);
88c2cdf5c5SKevin Wolf         } else {
89c2cdf5c5SKevin Wolf             fprintf(stderr,
90c2cdf5c5SKevin Wolf                     "bad argument count %d to %s, expected between %d and %d arguments\n",
91c2cdf5c5SKevin Wolf                     argc-1, cmd, ct->argmin, ct->argmax);
92c2cdf5c5SKevin Wolf         }
93b32d7a39SMax Reitz         return -EINVAL;
94c2cdf5c5SKevin Wolf     }
95887354bdSKevin Wolf 
968eaf1018SVladimir Sementsov-Ogievskiy     /*
978eaf1018SVladimir Sementsov-Ogievskiy      * Request additional permissions if necessary for this command. The caller
98887354bdSKevin Wolf      * is responsible for restoring the original permissions afterwards if this
998eaf1018SVladimir Sementsov-Ogievskiy      * is what it wants.
1008eaf1018SVladimir Sementsov-Ogievskiy      *
1018eaf1018SVladimir Sementsov-Ogievskiy      * Coverity thinks that blk may be NULL in the following if condition. It's
1028eaf1018SVladimir Sementsov-Ogievskiy      * not so: in init_check_command() we fail if blk is NULL for command with
1038eaf1018SVladimir Sementsov-Ogievskiy      * both CMD_FLAG_GLOBAL and CMD_NOFILE_OK flags unset. And in
1048eaf1018SVladimir Sementsov-Ogievskiy      * qemuio_add_command() we assert that command with non-zero .perm field
1058eaf1018SVladimir Sementsov-Ogievskiy      * doesn't set this flags. So, the following assertion is to silence
1068eaf1018SVladimir Sementsov-Ogievskiy      * Coverity:
1078eaf1018SVladimir Sementsov-Ogievskiy      */
1088eaf1018SVladimir Sementsov-Ogievskiy     assert(blk || !ct->perm);
109887354bdSKevin Wolf     if (ct->perm && blk_is_available(blk)) {
110887354bdSKevin Wolf         uint64_t orig_perm, orig_shared_perm;
111887354bdSKevin Wolf         blk_get_perm(blk, &orig_perm, &orig_shared_perm);
112887354bdSKevin Wolf 
113887354bdSKevin Wolf         if (ct->perm & ~orig_perm) {
114887354bdSKevin Wolf             uint64_t new_perm;
115887354bdSKevin Wolf             Error *local_err = NULL;
116887354bdSKevin Wolf             int ret;
117887354bdSKevin Wolf 
118887354bdSKevin Wolf             new_perm = orig_perm | ct->perm;
119887354bdSKevin Wolf 
120887354bdSKevin Wolf             ret = blk_set_perm(blk, new_perm, orig_shared_perm, &local_err);
121887354bdSKevin Wolf             if (ret < 0) {
122887354bdSKevin Wolf                 error_report_err(local_err);
123b32d7a39SMax Reitz                 return ret;
124887354bdSKevin Wolf             }
125887354bdSKevin Wolf         }
126887354bdSKevin Wolf     }
127887354bdSKevin Wolf 
128d339d766SRichard W.M. Jones     qemu_reset_optind();
129b32d7a39SMax Reitz     return ct->cfunc(blk, argc, argv);
130c2cdf5c5SKevin Wolf }
131c2cdf5c5SKevin Wolf 
find_command(const char * cmd)132c2cdf5c5SKevin Wolf static const cmdinfo_t *find_command(const char *cmd)
133c2cdf5c5SKevin Wolf {
134c2cdf5c5SKevin Wolf     cmdinfo_t *ct;
135c2cdf5c5SKevin Wolf 
136c2cdf5c5SKevin Wolf     for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) {
137c2cdf5c5SKevin Wolf         if (strcmp(ct->name, cmd) == 0 ||
138c2cdf5c5SKevin Wolf             (ct->altname && strcmp(ct->altname, cmd) == 0))
139c2cdf5c5SKevin Wolf         {
140c2cdf5c5SKevin Wolf             return (const cmdinfo_t *)ct;
141c2cdf5c5SKevin Wolf         }
142c2cdf5c5SKevin Wolf     }
143c2cdf5c5SKevin Wolf     return NULL;
144c2cdf5c5SKevin Wolf }
145c2cdf5c5SKevin Wolf 
1464694020dSStefan Hajnoczi /* Invoke fn() for commands with a matching prefix */
qemuio_complete_command(const char * input,void (* fn)(const char * cmd,void * opaque),void * opaque)1474694020dSStefan Hajnoczi void qemuio_complete_command(const char *input,
1484694020dSStefan Hajnoczi                              void (*fn)(const char *cmd, void *opaque),
1494694020dSStefan Hajnoczi                              void *opaque)
1504694020dSStefan Hajnoczi {
1514694020dSStefan Hajnoczi     cmdinfo_t *ct;
1524694020dSStefan Hajnoczi     size_t input_len = strlen(input);
1534694020dSStefan Hajnoczi 
1544694020dSStefan Hajnoczi     for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) {
1554694020dSStefan Hajnoczi         if (strncmp(input, ct->name, input_len) == 0) {
1564694020dSStefan Hajnoczi             fn(ct->name, opaque);
1574694020dSStefan Hajnoczi         }
1584694020dSStefan Hajnoczi     }
1594694020dSStefan Hajnoczi }
1604694020dSStefan Hajnoczi 
breakline(char * input,int * count)161c2cdf5c5SKevin Wolf static char **breakline(char *input, int *count)
162c2cdf5c5SKevin Wolf {
163c2cdf5c5SKevin Wolf     int c = 0;
164c2cdf5c5SKevin Wolf     char *p;
1655839e53bSMarkus Armbruster     char **rval = g_new0(char *, 1);
166c2cdf5c5SKevin Wolf 
167c2cdf5c5SKevin Wolf     while (rval && (p = qemu_strsep(&input, " ")) != NULL) {
168c2cdf5c5SKevin Wolf         if (!*p) {
169c2cdf5c5SKevin Wolf             continue;
170c2cdf5c5SKevin Wolf         }
171c2cdf5c5SKevin Wolf         c++;
17208193dd5SMarkus Armbruster         rval = g_renew(char *, rval, (c + 1));
173c2cdf5c5SKevin Wolf         rval[c - 1] = p;
174c2cdf5c5SKevin Wolf         rval[c] = NULL;
175c2cdf5c5SKevin Wolf     }
176c2cdf5c5SKevin Wolf     *count = c;
177c2cdf5c5SKevin Wolf     return rval;
178c2cdf5c5SKevin Wolf }
179c2cdf5c5SKevin Wolf 
cvtnum(const char * s)180797ac58cSKevin Wolf static int64_t cvtnum(const char *s)
181797ac58cSKevin Wolf {
182f17fd4fdSMarkus Armbruster     int err;
183f46bfdbfSMarkus Armbruster     uint64_t value;
184ef5a7885SJohn Snow 
185f17fd4fdSMarkus Armbruster     err = qemu_strtosz(s, NULL, &value);
186f17fd4fdSMarkus Armbruster     if (err < 0) {
187f17fd4fdSMarkus Armbruster         return err;
188f17fd4fdSMarkus Armbruster     }
189f46bfdbfSMarkus Armbruster     if (value > INT64_MAX) {
190f46bfdbfSMarkus Armbruster         return -ERANGE;
191f46bfdbfSMarkus Armbruster     }
192f17fd4fdSMarkus Armbruster     return value;
193797ac58cSKevin Wolf }
194797ac58cSKevin Wolf 
print_cvtnum_err(int64_t rc,const char * arg)195a9ecfa00SJohn Snow static void print_cvtnum_err(int64_t rc, const char *arg)
196a9ecfa00SJohn Snow {
197a9ecfa00SJohn Snow     switch (rc) {
198a9ecfa00SJohn Snow     case -EINVAL:
199a9ecfa00SJohn Snow         printf("Parsing error: non-numeric argument,"
200a9ecfa00SJohn Snow                " or extraneous/unrecognized suffix -- %s\n", arg);
201a9ecfa00SJohn Snow         break;
202a9ecfa00SJohn Snow     case -ERANGE:
203a9ecfa00SJohn Snow         printf("Parsing error: argument too large -- %s\n", arg);
204a9ecfa00SJohn Snow         break;
205a9ecfa00SJohn Snow     default:
206a9ecfa00SJohn Snow         printf("Parsing error: %s\n", arg);
207a9ecfa00SJohn Snow     }
208a9ecfa00SJohn Snow }
209a9ecfa00SJohn Snow 
2100b613881SKevin Wolf #define EXABYTES(x)     ((long long)(x) << 60)
2110b613881SKevin Wolf #define PETABYTES(x)    ((long long)(x) << 50)
2120b613881SKevin Wolf #define TERABYTES(x)    ((long long)(x) << 40)
2130b613881SKevin Wolf #define GIGABYTES(x)    ((long long)(x) << 30)
2140b613881SKevin Wolf #define MEGABYTES(x)    ((long long)(x) << 20)
2150b613881SKevin Wolf #define KILOBYTES(x)    ((long long)(x) << 10)
2160b613881SKevin Wolf 
2170b613881SKevin Wolf #define TO_EXABYTES(x)  ((x) / EXABYTES(1))
2180b613881SKevin Wolf #define TO_PETABYTES(x) ((x) / PETABYTES(1))
2190b613881SKevin Wolf #define TO_TERABYTES(x) ((x) / TERABYTES(1))
2200b613881SKevin Wolf #define TO_GIGABYTES(x) ((x) / GIGABYTES(1))
2210b613881SKevin Wolf #define TO_MEGABYTES(x) ((x) / MEGABYTES(1))
2220b613881SKevin Wolf #define TO_KILOBYTES(x) ((x) / KILOBYTES(1))
2230b613881SKevin Wolf 
cvtstr(double value,char * str,size_t size)2240b613881SKevin Wolf static void cvtstr(double value, char *str, size_t size)
2250b613881SKevin Wolf {
2260b613881SKevin Wolf     char *trim;
2270b613881SKevin Wolf     const char *suffix;
2280b613881SKevin Wolf 
2290b613881SKevin Wolf     if (value >= EXABYTES(1)) {
2300b613881SKevin Wolf         suffix = " EiB";
2310b613881SKevin Wolf         snprintf(str, size - 4, "%.3f", TO_EXABYTES(value));
2320b613881SKevin Wolf     } else if (value >= PETABYTES(1)) {
2330b613881SKevin Wolf         suffix = " PiB";
2340b613881SKevin Wolf         snprintf(str, size - 4, "%.3f", TO_PETABYTES(value));
2350b613881SKevin Wolf     } else if (value >= TERABYTES(1)) {
2360b613881SKevin Wolf         suffix = " TiB";
2370b613881SKevin Wolf         snprintf(str, size - 4, "%.3f", TO_TERABYTES(value));
2380b613881SKevin Wolf     } else if (value >= GIGABYTES(1)) {
2390b613881SKevin Wolf         suffix = " GiB";
2400b613881SKevin Wolf         snprintf(str, size - 4, "%.3f", TO_GIGABYTES(value));
2410b613881SKevin Wolf     } else if (value >= MEGABYTES(1)) {
2420b613881SKevin Wolf         suffix = " MiB";
2430b613881SKevin Wolf         snprintf(str, size - 4, "%.3f", TO_MEGABYTES(value));
2440b613881SKevin Wolf     } else if (value >= KILOBYTES(1)) {
2450b613881SKevin Wolf         suffix = " KiB";
2460b613881SKevin Wolf         snprintf(str, size - 4, "%.3f", TO_KILOBYTES(value));
2470b613881SKevin Wolf     } else {
2480b613881SKevin Wolf         suffix = " bytes";
2490b613881SKevin Wolf         snprintf(str, size - 6, "%f", value);
2500b613881SKevin Wolf     }
2510b613881SKevin Wolf 
2520b613881SKevin Wolf     trim = strstr(str, ".000");
2530b613881SKevin Wolf     if (trim) {
2540b613881SKevin Wolf         strcpy(trim, suffix);
2550b613881SKevin Wolf     } else {
2560b613881SKevin Wolf         strcat(str, suffix);
2570b613881SKevin Wolf     }
2580b613881SKevin Wolf }
2590b613881SKevin Wolf 
2600b613881SKevin Wolf 
2610b613881SKevin Wolf 
tsub(struct timespec t1,struct timespec t2)26250290c00SAlex Bennée static struct timespec tsub(struct timespec t1, struct timespec t2)
2630b613881SKevin Wolf {
26450290c00SAlex Bennée     t1.tv_nsec -= t2.tv_nsec;
26550290c00SAlex Bennée     if (t1.tv_nsec < 0) {
26650290c00SAlex Bennée         t1.tv_nsec += NANOSECONDS_PER_SECOND;
2670b613881SKevin Wolf         t1.tv_sec--;
2680b613881SKevin Wolf     }
2690b613881SKevin Wolf     t1.tv_sec -= t2.tv_sec;
2700b613881SKevin Wolf     return t1;
2710b613881SKevin Wolf }
2720b613881SKevin Wolf 
tdiv(double value,struct timespec tv)27350290c00SAlex Bennée static double tdiv(double value, struct timespec tv)
2740b613881SKevin Wolf {
27550290c00SAlex Bennée     double seconds = tv.tv_sec + (tv.tv_nsec / 1e9);
27650290c00SAlex Bennée     return value / seconds;
2770b613881SKevin Wolf }
2780b613881SKevin Wolf 
2790b613881SKevin Wolf #define HOURS(sec)      ((sec) / (60 * 60))
2800b613881SKevin Wolf #define MINUTES(sec)    (((sec) % (60 * 60)) / 60)
2810b613881SKevin Wolf #define SECONDS(sec)    ((sec) % 60)
2820b613881SKevin Wolf 
2830b613881SKevin Wolf enum {
2840b613881SKevin Wolf     DEFAULT_TIME        = 0x0,
2850b613881SKevin Wolf     TERSE_FIXED_TIME    = 0x1,
2860b613881SKevin Wolf     VERBOSE_FIXED_TIME  = 0x2,
2870b613881SKevin Wolf };
2880b613881SKevin Wolf 
timestr(struct timespec * tv,char * ts,size_t size,int format)28950290c00SAlex Bennée static void timestr(struct timespec *tv, char *ts, size_t size, int format)
2900b613881SKevin Wolf {
29150290c00SAlex Bennée     double frac_sec = tv->tv_nsec / 1e9;
2920b613881SKevin Wolf 
2930b613881SKevin Wolf     if (format & TERSE_FIXED_TIME) {
2940b613881SKevin Wolf         if (!HOURS(tv->tv_sec)) {
29550290c00SAlex Bennée             snprintf(ts, size, "%u:%05.2f",
2960b613881SKevin Wolf                      (unsigned int) MINUTES(tv->tv_sec),
29750290c00SAlex Bennée                      SECONDS(tv->tv_sec) + frac_sec);
2980b613881SKevin Wolf             return;
2990b613881SKevin Wolf         }
3000b613881SKevin Wolf         format |= VERBOSE_FIXED_TIME; /* fallback if hours needed */
3010b613881SKevin Wolf     }
3020b613881SKevin Wolf 
3030b613881SKevin Wolf     if ((format & VERBOSE_FIXED_TIME) || tv->tv_sec) {
30450290c00SAlex Bennée         snprintf(ts, size, "%u:%02u:%05.2f",
3050b613881SKevin Wolf                 (unsigned int) HOURS(tv->tv_sec),
3060b613881SKevin Wolf                 (unsigned int) MINUTES(tv->tv_sec),
30750290c00SAlex Bennée                  SECONDS(tv->tv_sec) + frac_sec);
3080b613881SKevin Wolf     } else {
30950290c00SAlex Bennée         snprintf(ts, size, "%05.2f sec", frac_sec);
3100b613881SKevin Wolf     }
3110b613881SKevin Wolf }
3120b613881SKevin Wolf 
313797ac58cSKevin Wolf /*
314797ac58cSKevin Wolf  * Parse the pattern argument to various sub-commands.
315797ac58cSKevin Wolf  *
316797ac58cSKevin Wolf  * Because the pattern is used as an argument to memset it must evaluate
317797ac58cSKevin Wolf  * to an unsigned integer that fits into a single byte.
318797ac58cSKevin Wolf  */
parse_pattern(const char * arg)319797ac58cSKevin Wolf static int parse_pattern(const char *arg)
320797ac58cSKevin Wolf {
321797ac58cSKevin Wolf     char *endptr = NULL;
322797ac58cSKevin Wolf     long pattern;
323797ac58cSKevin Wolf 
324797ac58cSKevin Wolf     pattern = strtol(arg, &endptr, 0);
325797ac58cSKevin Wolf     if (pattern < 0 || pattern > UCHAR_MAX || *endptr != '\0') {
326797ac58cSKevin Wolf         printf("%s is not a valid pattern byte\n", arg);
327797ac58cSKevin Wolf         return -1;
328797ac58cSKevin Wolf     }
329797ac58cSKevin Wolf 
330797ac58cSKevin Wolf     return pattern;
331797ac58cSKevin Wolf }
332797ac58cSKevin Wolf 
333797ac58cSKevin Wolf /*
334797ac58cSKevin Wolf  * Memory allocation helpers.
335797ac58cSKevin Wolf  *
336797ac58cSKevin Wolf  * Make sure memory is aligned by default, or purposefully misaligned if
337797ac58cSKevin Wolf  * that is specified on the command line.
338797ac58cSKevin Wolf  */
339797ac58cSKevin Wolf 
340797ac58cSKevin Wolf #define MISALIGN_OFFSET     16
qemu_io_alloc(BlockBackend * blk,size_t len,int pattern,bool register_buf)34100e2a04cSStefan Hajnoczi static void *qemu_io_alloc(BlockBackend *blk, size_t len, int pattern,
34200e2a04cSStefan Hajnoczi                            bool register_buf)
343797ac58cSKevin Wolf {
344797ac58cSKevin Wolf     void *buf;
345797ac58cSKevin Wolf 
346797ac58cSKevin Wolf     if (qemuio_misalign) {
347797ac58cSKevin Wolf         len += MISALIGN_OFFSET;
348797ac58cSKevin Wolf     }
3494c7b7e9bSMax Reitz     buf = blk_blockalign(blk, len);
350797ac58cSKevin Wolf     memset(buf, pattern, len);
35100e2a04cSStefan Hajnoczi     if (register_buf) {
35200e2a04cSStefan Hajnoczi         blk_register_buf(blk, buf, len, &error_abort);
35300e2a04cSStefan Hajnoczi     }
354797ac58cSKevin Wolf     if (qemuio_misalign) {
355797ac58cSKevin Wolf         buf += MISALIGN_OFFSET;
356797ac58cSKevin Wolf     }
357797ac58cSKevin Wolf     return buf;
358797ac58cSKevin Wolf }
359797ac58cSKevin Wolf 
qemu_io_free(BlockBackend * blk,void * p,size_t len,bool unregister_buf)36000e2a04cSStefan Hajnoczi static void qemu_io_free(BlockBackend *blk, void *p, size_t len,
36100e2a04cSStefan Hajnoczi                          bool unregister_buf)
362797ac58cSKevin Wolf {
363797ac58cSKevin Wolf     if (qemuio_misalign) {
364797ac58cSKevin Wolf         p -= MISALIGN_OFFSET;
36500e2a04cSStefan Hajnoczi         len += MISALIGN_OFFSET;
36600e2a04cSStefan Hajnoczi     }
36700e2a04cSStefan Hajnoczi     if (unregister_buf) {
36800e2a04cSStefan Hajnoczi         blk_unregister_buf(blk, p, len);
369797ac58cSKevin Wolf     }
370797ac58cSKevin Wolf     qemu_vfree(p);
371797ac58cSKevin Wolf }
372797ac58cSKevin Wolf 
3734d731510SDenis Plotnikov /*
3744d731510SDenis Plotnikov  * qemu_io_alloc_from_file()
3754d731510SDenis Plotnikov  *
3764d731510SDenis Plotnikov  * Allocates the buffer and populates it with the content of the given file
3774d731510SDenis Plotnikov  * up to @len bytes. If the file length is less than @len, then the buffer
3784d731510SDenis Plotnikov  * is populated with the file content cyclically.
3794d731510SDenis Plotnikov  *
3804d731510SDenis Plotnikov  * @blk - the block backend where the buffer content is going to be written to
3814d731510SDenis Plotnikov  * @len - the buffer length
3824d731510SDenis Plotnikov  * @file_name - the file to read the content from
38300e2a04cSStefan Hajnoczi  * @register_buf - call blk_register_buf()
3844d731510SDenis Plotnikov  *
3854d731510SDenis Plotnikov  * Returns: the buffer pointer on success
3864d731510SDenis Plotnikov  *          NULL on error
3874d731510SDenis Plotnikov  */
qemu_io_alloc_from_file(BlockBackend * blk,size_t len,const char * file_name,bool register_buf)3884d731510SDenis Plotnikov static void *qemu_io_alloc_from_file(BlockBackend *blk, size_t len,
38900e2a04cSStefan Hajnoczi                                      const char *file_name, bool register_buf)
3904d731510SDenis Plotnikov {
39100e2a04cSStefan Hajnoczi     size_t alloc_len = len + (qemuio_misalign ? MISALIGN_OFFSET : 0);
39200e2a04cSStefan Hajnoczi     char *alloc_buf, *buf, *end;
3934d731510SDenis Plotnikov     FILE *f = fopen(file_name, "r");
3944d731510SDenis Plotnikov     int pattern_len;
3954d731510SDenis Plotnikov 
3964d731510SDenis Plotnikov     if (!f) {
3974d731510SDenis Plotnikov         perror(file_name);
3984d731510SDenis Plotnikov         return NULL;
3994d731510SDenis Plotnikov     }
4004d731510SDenis Plotnikov 
40100e2a04cSStefan Hajnoczi     alloc_buf = buf = blk_blockalign(blk, alloc_len);
4024d731510SDenis Plotnikov 
4034d731510SDenis Plotnikov     if (qemuio_misalign) {
4044d731510SDenis Plotnikov         buf += MISALIGN_OFFSET;
4054d731510SDenis Plotnikov     }
4064d731510SDenis Plotnikov 
40700e2a04cSStefan Hajnoczi     pattern_len = fread(buf, 1, len, f);
4084d731510SDenis Plotnikov 
4094d731510SDenis Plotnikov     if (ferror(f)) {
4104d731510SDenis Plotnikov         perror(file_name);
4114d731510SDenis Plotnikov         goto error;
4124d731510SDenis Plotnikov     }
4134d731510SDenis Plotnikov 
4144d731510SDenis Plotnikov     if (pattern_len == 0) {
4154d731510SDenis Plotnikov         fprintf(stderr, "%s: file is empty\n", file_name);
4164d731510SDenis Plotnikov         goto error;
4174d731510SDenis Plotnikov     }
4184d731510SDenis Plotnikov 
4194d731510SDenis Plotnikov     fclose(f);
420c8e68b43SKevin Wolf     f = NULL;
4214d731510SDenis Plotnikov 
42200e2a04cSStefan Hajnoczi     if (register_buf) {
42300e2a04cSStefan Hajnoczi         blk_register_buf(blk, alloc_buf, alloc_len, &error_abort);
4244d731510SDenis Plotnikov     }
4254d731510SDenis Plotnikov 
42600e2a04cSStefan Hajnoczi     end = buf + len;
42700e2a04cSStefan Hajnoczi     for (char *p = buf + pattern_len; p < end; p += pattern_len) {
42800e2a04cSStefan Hajnoczi         memcpy(p, buf, MIN(pattern_len, end - p));
42900e2a04cSStefan Hajnoczi     }
43000e2a04cSStefan Hajnoczi 
43100e2a04cSStefan Hajnoczi     return buf;
4324d731510SDenis Plotnikov 
4334d731510SDenis Plotnikov error:
43400e2a04cSStefan Hajnoczi     /*
43500e2a04cSStefan Hajnoczi      * This code path is only taken before blk_register_buf() is called, so
43600e2a04cSStefan Hajnoczi      * hardcode the qemu_io_free() unregister_buf argument to false.
43700e2a04cSStefan Hajnoczi      */
43800e2a04cSStefan Hajnoczi     qemu_io_free(blk, alloc_buf, alloc_len, false);
439c8e68b43SKevin Wolf     if (f) {
440c8e68b43SKevin Wolf         fclose(f);
441c8e68b43SKevin Wolf     }
4424d731510SDenis Plotnikov     return NULL;
4434d731510SDenis Plotnikov }
4444d731510SDenis Plotnikov 
dump_buffer(const void * buffer,int64_t offset,int64_t len)4459b0beaf3SJohn Snow static void dump_buffer(const void *buffer, int64_t offset, int64_t len)
446797ac58cSKevin Wolf {
4479b0beaf3SJohn Snow     uint64_t i;
4489b0beaf3SJohn Snow     int j;
449797ac58cSKevin Wolf     const uint8_t *p;
450797ac58cSKevin Wolf 
451797ac58cSKevin Wolf     for (i = 0, p = buffer; i < len; i += 16) {
452797ac58cSKevin Wolf         const uint8_t *s = p;
453797ac58cSKevin Wolf 
454797ac58cSKevin Wolf         printf("%08" PRIx64 ":  ", offset + i);
455797ac58cSKevin Wolf         for (j = 0; j < 16 && i + j < len; j++, p++) {
456797ac58cSKevin Wolf             printf("%02x ", *p);
457797ac58cSKevin Wolf         }
458797ac58cSKevin Wolf         printf(" ");
459797ac58cSKevin Wolf         for (j = 0; j < 16 && i + j < len; j++, s++) {
460797ac58cSKevin Wolf             if (isalnum(*s)) {
461797ac58cSKevin Wolf                 printf("%c", *s);
462797ac58cSKevin Wolf             } else {
463797ac58cSKevin Wolf                 printf(".");
464797ac58cSKevin Wolf             }
465797ac58cSKevin Wolf         }
466797ac58cSKevin Wolf         printf("\n");
467797ac58cSKevin Wolf     }
468797ac58cSKevin Wolf }
469797ac58cSKevin Wolf 
print_report(const char * op,struct timespec * t,int64_t offset,int64_t count,int64_t total,int cnt,bool Cflag)47050290c00SAlex Bennée static void print_report(const char *op, struct timespec *t, int64_t offset,
471dc38852aSEric Blake                          int64_t count, int64_t total, int cnt, bool Cflag)
472797ac58cSKevin Wolf {
473797ac58cSKevin Wolf     char s1[64], s2[64], ts[64];
474797ac58cSKevin Wolf 
475797ac58cSKevin Wolf     timestr(t, ts, sizeof(ts), Cflag ? VERBOSE_FIXED_TIME : 0);
476797ac58cSKevin Wolf     if (!Cflag) {
477797ac58cSKevin Wolf         cvtstr((double)total, s1, sizeof(s1));
478797ac58cSKevin Wolf         cvtstr(tdiv((double)total, *t), s2, sizeof(s2));
4799b0beaf3SJohn Snow         printf("%s %"PRId64"/%"PRId64" bytes at offset %" PRId64 "\n",
480797ac58cSKevin Wolf                op, total, count, offset);
481797ac58cSKevin Wolf         printf("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n",
482797ac58cSKevin Wolf                s1, cnt, ts, s2, tdiv((double)cnt, *t));
483797ac58cSKevin Wolf     } else {/* bytes,ops,time,bytes/sec,ops/sec */
4849b0beaf3SJohn Snow         printf("%"PRId64",%d,%s,%.3f,%.3f\n",
485797ac58cSKevin Wolf             total, cnt, ts,
486797ac58cSKevin Wolf             tdiv((double)total, *t),
487797ac58cSKevin Wolf             tdiv((double)cnt, *t));
488797ac58cSKevin Wolf     }
489797ac58cSKevin Wolf }
490797ac58cSKevin Wolf 
491797ac58cSKevin Wolf /*
492797ac58cSKevin Wolf  * Parse multiple length statements for vectored I/O, and construct an I/O
493797ac58cSKevin Wolf  * vector matching it.
494797ac58cSKevin Wolf  */
495797ac58cSKevin Wolf static void *
create_iovec(BlockBackend * blk,QEMUIOVector * qiov,char ** argv,int nr_iov,int pattern,bool register_buf)4964c7b7e9bSMax Reitz create_iovec(BlockBackend *blk, QEMUIOVector *qiov, char **argv, int nr_iov,
49700e2a04cSStefan Hajnoczi              int pattern, bool register_buf)
498797ac58cSKevin Wolf {
499797ac58cSKevin Wolf     size_t *sizes = g_new0(size_t, nr_iov);
500797ac58cSKevin Wolf     size_t count = 0;
501797ac58cSKevin Wolf     void *buf = NULL;
502797ac58cSKevin Wolf     void *p;
503797ac58cSKevin Wolf     int i;
504797ac58cSKevin Wolf 
505797ac58cSKevin Wolf     for (i = 0; i < nr_iov; i++) {
506797ac58cSKevin Wolf         char *arg = argv[i];
507797ac58cSKevin Wolf         int64_t len;
508797ac58cSKevin Wolf 
509797ac58cSKevin Wolf         len = cvtnum(arg);
510797ac58cSKevin Wolf         if (len < 0) {
511a9ecfa00SJohn Snow             print_cvtnum_err(len, arg);
512797ac58cSKevin Wolf             goto fail;
513797ac58cSKevin Wolf         }
514797ac58cSKevin Wolf 
5153026c468SAlberto Garcia         if (len > BDRV_REQUEST_MAX_BYTES) {
5163026c468SAlberto Garcia             printf("Argument '%s' exceeds maximum size %" PRIu64 "\n", arg,
5173026c468SAlberto Garcia                    (uint64_t)BDRV_REQUEST_MAX_BYTES);
5183026c468SAlberto Garcia             goto fail;
5193026c468SAlberto Garcia         }
5203026c468SAlberto Garcia 
5213026c468SAlberto Garcia         if (count > BDRV_REQUEST_MAX_BYTES - len) {
5223026c468SAlberto Garcia             printf("The total number of bytes exceed the maximum size %" PRIu64
5233026c468SAlberto Garcia                    "\n", (uint64_t)BDRV_REQUEST_MAX_BYTES);
524797ac58cSKevin Wolf             goto fail;
525797ac58cSKevin Wolf         }
526797ac58cSKevin Wolf 
527797ac58cSKevin Wolf         sizes[i] = len;
528797ac58cSKevin Wolf         count += len;
529797ac58cSKevin Wolf     }
530797ac58cSKevin Wolf 
531797ac58cSKevin Wolf     qemu_iovec_init(qiov, nr_iov);
532797ac58cSKevin Wolf 
53300e2a04cSStefan Hajnoczi     buf = p = qemu_io_alloc(blk, count, pattern, register_buf);
534797ac58cSKevin Wolf 
535797ac58cSKevin Wolf     for (i = 0; i < nr_iov; i++) {
536797ac58cSKevin Wolf         qemu_iovec_add(qiov, p, sizes[i]);
537797ac58cSKevin Wolf         p += sizes[i];
538797ac58cSKevin Wolf     }
539797ac58cSKevin Wolf 
540797ac58cSKevin Wolf fail:
541797ac58cSKevin Wolf     g_free(sizes);
542797ac58cSKevin Wolf     return buf;
543797ac58cSKevin Wolf }
544797ac58cSKevin Wolf 
do_pread(BlockBackend * blk,char * buf,int64_t offset,int64_t bytes,BdrvRequestFlags flags,int64_t * total)5459b0beaf3SJohn Snow static int do_pread(BlockBackend *blk, char *buf, int64_t offset,
54600e2a04cSStefan Hajnoczi                     int64_t bytes, BdrvRequestFlags flags, int64_t *total)
547797ac58cSKevin Wolf {
548bf5b16faSAlberto Faria     int ret;
549bf5b16faSAlberto Faria 
550f5a5ca79SManos Pitsidianakis     if (bytes > INT_MAX) {
5519b0beaf3SJohn Snow         return -ERANGE;
5529b0beaf3SJohn Snow     }
5539b0beaf3SJohn Snow 
55400e2a04cSStefan Hajnoczi     ret = blk_pread(blk, offset, bytes, (uint8_t *)buf, flags);
555bf5b16faSAlberto Faria     if (ret < 0) {
556bf5b16faSAlberto Faria         return ret;
557797ac58cSKevin Wolf     }
558bf5b16faSAlberto Faria     *total = bytes;
559797ac58cSKevin Wolf     return 1;
560797ac58cSKevin Wolf }
561797ac58cSKevin Wolf 
do_pwrite(BlockBackend * blk,char * buf,int64_t offset,int64_t bytes,BdrvRequestFlags flags,int64_t * total)5629b0beaf3SJohn Snow static int do_pwrite(BlockBackend *blk, char *buf, int64_t offset,
5631321e008SStefan Hajnoczi                      int64_t bytes, BdrvRequestFlags flags, int64_t *total)
564797ac58cSKevin Wolf {
565bf5b16faSAlberto Faria     int ret;
566bf5b16faSAlberto Faria 
567f5a5ca79SManos Pitsidianakis     if (bytes > INT_MAX) {
5689b0beaf3SJohn Snow         return -ERANGE;
5699b0beaf3SJohn Snow     }
5709b0beaf3SJohn Snow 
571a9262f55SAlberto Faria     ret = blk_pwrite(blk, offset, bytes, (uint8_t *)buf, flags);
572bf5b16faSAlberto Faria     if (ret < 0) {
573bf5b16faSAlberto Faria         return ret;
574797ac58cSKevin Wolf     }
575bf5b16faSAlberto Faria     *total = bytes;
576797ac58cSKevin Wolf     return 1;
577797ac58cSKevin Wolf }
578797ac58cSKevin Wolf 
do_pwrite_zeroes(BlockBackend * blk,int64_t offset,int64_t bytes,BdrvRequestFlags flags,int64_t * total)579264dcbb2SPaolo Bonzini static int do_pwrite_zeroes(BlockBackend *blk, int64_t offset,
5801321e008SStefan Hajnoczi                                int64_t bytes, BdrvRequestFlags flags,
5811321e008SStefan Hajnoczi                                int64_t *total)
582797ac58cSKevin Wolf {
583264dcbb2SPaolo Bonzini     int ret = blk_pwrite_zeroes(blk, offset, bytes,
584264dcbb2SPaolo Bonzini                                 flags | BDRV_REQ_ZERO_WRITE);
585797ac58cSKevin Wolf 
586264dcbb2SPaolo Bonzini     if (ret < 0) {
587264dcbb2SPaolo Bonzini         return ret;
588797ac58cSKevin Wolf     }
589264dcbb2SPaolo Bonzini     *total = bytes;
590797ac58cSKevin Wolf     return 1;
591797ac58cSKevin Wolf }
592797ac58cSKevin Wolf 
do_write_compressed(BlockBackend * blk,char * buf,int64_t offset,int64_t bytes,int64_t * total)5934c7b7e9bSMax Reitz static int do_write_compressed(BlockBackend *blk, char *buf, int64_t offset,
594f5a5ca79SManos Pitsidianakis                                int64_t bytes, int64_t *total)
595797ac58cSKevin Wolf {
596797ac58cSKevin Wolf     int ret;
597797ac58cSKevin Wolf 
59841ae31e3SAlberto Garcia     if (bytes > BDRV_REQUEST_MAX_BYTES) {
5999b0beaf3SJohn Snow         return -ERANGE;
6009b0beaf3SJohn Snow     }
6019b0beaf3SJohn Snow 
6020cadf2c8SAlberto Faria     ret = blk_pwrite_compressed(blk, offset, bytes, buf);
603797ac58cSKevin Wolf     if (ret < 0) {
604797ac58cSKevin Wolf         return ret;
605797ac58cSKevin Wolf     }
606f5a5ca79SManos Pitsidianakis     *total = bytes;
607797ac58cSKevin Wolf     return 1;
608797ac58cSKevin Wolf }
609797ac58cSKevin Wolf 
do_load_vmstate(BlockBackend * blk,char * buf,int64_t offset,int64_t count,int64_t * total)6104c7b7e9bSMax Reitz static int do_load_vmstate(BlockBackend *blk, char *buf, int64_t offset,
6119b0beaf3SJohn Snow                            int64_t count, int64_t *total)
612797ac58cSKevin Wolf {
6139b0beaf3SJohn Snow     if (count > INT_MAX) {
6149b0beaf3SJohn Snow         return -ERANGE;
6159b0beaf3SJohn Snow     }
6169b0beaf3SJohn Snow 
6174c7b7e9bSMax Reitz     *total = blk_load_vmstate(blk, (uint8_t *)buf, offset, count);
618797ac58cSKevin Wolf     if (*total < 0) {
619797ac58cSKevin Wolf         return *total;
620797ac58cSKevin Wolf     }
621797ac58cSKevin Wolf     return 1;
622797ac58cSKevin Wolf }
623797ac58cSKevin Wolf 
do_save_vmstate(BlockBackend * blk,char * buf,int64_t offset,int64_t count,int64_t * total)6244c7b7e9bSMax Reitz static int do_save_vmstate(BlockBackend *blk, char *buf, int64_t offset,
6259b0beaf3SJohn Snow                            int64_t count, int64_t *total)
626797ac58cSKevin Wolf {
6279b0beaf3SJohn Snow     if (count > INT_MAX) {
6289b0beaf3SJohn Snow         return -ERANGE;
6299b0beaf3SJohn Snow     }
6309b0beaf3SJohn Snow 
6314c7b7e9bSMax Reitz     *total = blk_save_vmstate(blk, (uint8_t *)buf, offset, count);
632797ac58cSKevin Wolf     if (*total < 0) {
633797ac58cSKevin Wolf         return *total;
634797ac58cSKevin Wolf     }
635797ac58cSKevin Wolf     return 1;
636797ac58cSKevin Wolf }
637797ac58cSKevin Wolf 
638797ac58cSKevin Wolf #define NOT_DONE 0x7fffffff
aio_rw_done(void * opaque,int ret)639797ac58cSKevin Wolf static void aio_rw_done(void *opaque, int ret)
640797ac58cSKevin Wolf {
641797ac58cSKevin Wolf     *(int *)opaque = ret;
642797ac58cSKevin Wolf }
643797ac58cSKevin Wolf 
do_aio_readv(BlockBackend * blk,QEMUIOVector * qiov,int64_t offset,BdrvRequestFlags flags,int * total)6444c7b7e9bSMax Reitz static int do_aio_readv(BlockBackend *blk, QEMUIOVector *qiov,
64500e2a04cSStefan Hajnoczi                         int64_t offset, BdrvRequestFlags flags, int *total)
646797ac58cSKevin Wolf {
647797ac58cSKevin Wolf     int async_ret = NOT_DONE;
648797ac58cSKevin Wolf 
64900e2a04cSStefan Hajnoczi     blk_aio_preadv(blk, offset, qiov, flags, aio_rw_done, &async_ret);
650797ac58cSKevin Wolf     while (async_ret == NOT_DONE) {
651797ac58cSKevin Wolf         main_loop_wait(false);
652797ac58cSKevin Wolf     }
653797ac58cSKevin Wolf 
654797ac58cSKevin Wolf     *total = qiov->size;
655797ac58cSKevin Wolf     return async_ret < 0 ? async_ret : 1;
656797ac58cSKevin Wolf }
657797ac58cSKevin Wolf 
do_aio_writev(BlockBackend * blk,QEMUIOVector * qiov,int64_t offset,BdrvRequestFlags flags,int * total)6584c7b7e9bSMax Reitz static int do_aio_writev(BlockBackend *blk, QEMUIOVector *qiov,
6591321e008SStefan Hajnoczi                          int64_t offset, BdrvRequestFlags flags, int *total)
660797ac58cSKevin Wolf {
661797ac58cSKevin Wolf     int async_ret = NOT_DONE;
662797ac58cSKevin Wolf 
663770e0e0eSEric Blake     blk_aio_pwritev(blk, offset, qiov, flags, aio_rw_done, &async_ret);
664797ac58cSKevin Wolf     while (async_ret == NOT_DONE) {
665797ac58cSKevin Wolf         main_loop_wait(false);
666797ac58cSKevin Wolf     }
667797ac58cSKevin Wolf 
668797ac58cSKevin Wolf     *total = qiov->size;
669797ac58cSKevin Wolf     return async_ret < 0 ? async_ret : 1;
670797ac58cSKevin Wolf }
671797ac58cSKevin Wolf 
read_help(void)672797ac58cSKevin Wolf static void read_help(void)
673797ac58cSKevin Wolf {
674797ac58cSKevin Wolf     printf(
675797ac58cSKevin Wolf "\n"
676797ac58cSKevin Wolf " reads a range of bytes from the given offset\n"
677797ac58cSKevin Wolf "\n"
678797ac58cSKevin Wolf " Example:\n"
679797ac58cSKevin Wolf " 'read -v 512 1k' - dumps 1 kilobyte read from 512 bytes into the file\n"
680797ac58cSKevin Wolf "\n"
681797ac58cSKevin Wolf " Reads a segment of the currently open file, optionally dumping it to the\n"
682797ac58cSKevin Wolf " standard output stream (with -v option) for subsequent inspection.\n"
683797ac58cSKevin Wolf " -b, -- read from the VM state rather than the virtual disk\n"
684797ac58cSKevin Wolf " -C, -- report statistics in a machine parsable format\n"
685797ac58cSKevin Wolf " -l, -- length for pattern verification (only with -P)\n"
686093ea232SEric Blake " -p, -- ignored for backwards compatibility\n"
687797ac58cSKevin Wolf " -P, -- use a pattern to verify read data\n"
688797ac58cSKevin Wolf " -q, -- quiet mode, do not show I/O statistics\n"
68900e2a04cSStefan Hajnoczi " -r, -- register I/O buffer\n"
690797ac58cSKevin Wolf " -s, -- start offset for pattern verification (only with -P)\n"
691797ac58cSKevin Wolf " -v, -- dump buffer to standard output\n"
692797ac58cSKevin Wolf "\n");
693797ac58cSKevin Wolf }
694797ac58cSKevin Wolf 
695b32d7a39SMax Reitz static int read_f(BlockBackend *blk, int argc, char **argv);
696797ac58cSKevin Wolf 
697797ac58cSKevin Wolf static const cmdinfo_t read_cmd = {
698797ac58cSKevin Wolf     .name       = "read",
699797ac58cSKevin Wolf     .altname    = "r",
700797ac58cSKevin Wolf     .cfunc      = read_f,
701797ac58cSKevin Wolf     .argmin     = 2,
702797ac58cSKevin Wolf     .argmax     = -1,
70300e2a04cSStefan Hajnoczi     .args       = "[-abCqrv] [-P pattern [-s off] [-l len]] off len",
704797ac58cSKevin Wolf     .oneline    = "reads a number of bytes at a specified offset",
705797ac58cSKevin Wolf     .help       = read_help,
706797ac58cSKevin Wolf };
707797ac58cSKevin Wolf 
read_f(BlockBackend * blk,int argc,char ** argv)708b32d7a39SMax Reitz static int read_f(BlockBackend *blk, int argc, char **argv)
709797ac58cSKevin Wolf {
71050290c00SAlex Bennée     struct timespec t1, t2;
711093ea232SEric Blake     bool Cflag = false, qflag = false, vflag = false;
712dc38852aSEric Blake     bool Pflag = false, sflag = false, lflag = false, bflag = false;
713b32d7a39SMax Reitz     int c, cnt, ret;
714797ac58cSKevin Wolf     char *buf;
715797ac58cSKevin Wolf     int64_t offset;
7169b0beaf3SJohn Snow     int64_t count;
717797ac58cSKevin Wolf     /* Some compilers get confused and warn if this is not initialized.  */
7189b0beaf3SJohn Snow     int64_t total = 0;
7199b0beaf3SJohn Snow     int pattern = 0;
7209b0beaf3SJohn Snow     int64_t pattern_offset = 0, pattern_count = 0;
72100e2a04cSStefan Hajnoczi     BdrvRequestFlags flags = 0;
722797ac58cSKevin Wolf 
72300e2a04cSStefan Hajnoczi     while ((c = getopt(argc, argv, "bCl:pP:qrs:v")) != -1) {
724797ac58cSKevin Wolf         switch (c) {
725797ac58cSKevin Wolf         case 'b':
726dc38852aSEric Blake             bflag = true;
727797ac58cSKevin Wolf             break;
728797ac58cSKevin Wolf         case 'C':
729dc38852aSEric Blake             Cflag = true;
730797ac58cSKevin Wolf             break;
731797ac58cSKevin Wolf         case 'l':
732dc38852aSEric Blake             lflag = true;
733797ac58cSKevin Wolf             pattern_count = cvtnum(optarg);
734797ac58cSKevin Wolf             if (pattern_count < 0) {
735a9ecfa00SJohn Snow                 print_cvtnum_err(pattern_count, optarg);
736b32d7a39SMax Reitz                 return pattern_count;
737797ac58cSKevin Wolf             }
738797ac58cSKevin Wolf             break;
739797ac58cSKevin Wolf         case 'p':
740093ea232SEric Blake             /* Ignored for backwards compatibility */
741797ac58cSKevin Wolf             break;
742797ac58cSKevin Wolf         case 'P':
743dc38852aSEric Blake             Pflag = true;
744797ac58cSKevin Wolf             pattern = parse_pattern(optarg);
745797ac58cSKevin Wolf             if (pattern < 0) {
746b32d7a39SMax Reitz                 return -EINVAL;
747797ac58cSKevin Wolf             }
748797ac58cSKevin Wolf             break;
749797ac58cSKevin Wolf         case 'q':
750dc38852aSEric Blake             qflag = true;
751797ac58cSKevin Wolf             break;
75200e2a04cSStefan Hajnoczi         case 'r':
75300e2a04cSStefan Hajnoczi             flags |= BDRV_REQ_REGISTERED_BUF;
75400e2a04cSStefan Hajnoczi             break;
755797ac58cSKevin Wolf         case 's':
756dc38852aSEric Blake             sflag = true;
757797ac58cSKevin Wolf             pattern_offset = cvtnum(optarg);
758797ac58cSKevin Wolf             if (pattern_offset < 0) {
759a9ecfa00SJohn Snow                 print_cvtnum_err(pattern_offset, optarg);
760b32d7a39SMax Reitz                 return pattern_offset;
761797ac58cSKevin Wolf             }
762797ac58cSKevin Wolf             break;
763797ac58cSKevin Wolf         case 'v':
764dc38852aSEric Blake             vflag = true;
765797ac58cSKevin Wolf             break;
766797ac58cSKevin Wolf         default:
767b444d0e9SMax Reitz             qemuio_command_usage(&read_cmd);
768b32d7a39SMax Reitz             return -EINVAL;
769797ac58cSKevin Wolf         }
770797ac58cSKevin Wolf     }
771797ac58cSKevin Wolf 
772797ac58cSKevin Wolf     if (optind != argc - 2) {
773b444d0e9SMax Reitz         qemuio_command_usage(&read_cmd);
774b32d7a39SMax Reitz         return -EINVAL;
775797ac58cSKevin Wolf     }
776797ac58cSKevin Wolf 
777797ac58cSKevin Wolf     offset = cvtnum(argv[optind]);
778797ac58cSKevin Wolf     if (offset < 0) {
779a9ecfa00SJohn Snow         print_cvtnum_err(offset, argv[optind]);
780b32d7a39SMax Reitz         return offset;
781797ac58cSKevin Wolf     }
782797ac58cSKevin Wolf 
783797ac58cSKevin Wolf     optind++;
784797ac58cSKevin Wolf     count = cvtnum(argv[optind]);
785797ac58cSKevin Wolf     if (count < 0) {
786a9ecfa00SJohn Snow         print_cvtnum_err(count, argv[optind]);
787b32d7a39SMax Reitz         return count;
7883026c468SAlberto Garcia     } else if (count > BDRV_REQUEST_MAX_BYTES) {
7899b0beaf3SJohn Snow         printf("length cannot exceed %" PRIu64 ", given %s\n",
7903026c468SAlberto Garcia                (uint64_t)BDRV_REQUEST_MAX_BYTES, argv[optind]);
791b32d7a39SMax Reitz         return -EINVAL;
792797ac58cSKevin Wolf     }
793797ac58cSKevin Wolf 
794797ac58cSKevin Wolf     if (!Pflag && (lflag || sflag)) {
795b444d0e9SMax Reitz         qemuio_command_usage(&read_cmd);
796b32d7a39SMax Reitz         return -EINVAL;
797797ac58cSKevin Wolf     }
798797ac58cSKevin Wolf 
799797ac58cSKevin Wolf     if (!lflag) {
800797ac58cSKevin Wolf         pattern_count = count - pattern_offset;
801797ac58cSKevin Wolf     }
802797ac58cSKevin Wolf 
803797ac58cSKevin Wolf     if ((pattern_count < 0) || (pattern_count + pattern_offset > count))  {
804797ac58cSKevin Wolf         printf("pattern verification range exceeds end of read data\n");
805b32d7a39SMax Reitz         return -EINVAL;
806797ac58cSKevin Wolf     }
807797ac58cSKevin Wolf 
808093ea232SEric Blake     if (bflag) {
8091bce6b4cSEric Blake         if (!QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE)) {
8101bce6b4cSEric Blake             printf("%" PRId64 " is not a sector-aligned value for 'offset'\n",
811797ac58cSKevin Wolf                    offset);
812b32d7a39SMax Reitz             return -EINVAL;
813797ac58cSKevin Wolf         }
8141bce6b4cSEric Blake         if (!QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE)) {
8151bce6b4cSEric Blake             printf("%"PRId64" is not a sector-aligned value for 'count'\n",
816797ac58cSKevin Wolf                    count);
817b32d7a39SMax Reitz             return -EINVAL;
818797ac58cSKevin Wolf         }
81900e2a04cSStefan Hajnoczi         if (flags & BDRV_REQ_REGISTERED_BUF) {
82000e2a04cSStefan Hajnoczi             printf("I/O buffer registration is not supported when reading "
82100e2a04cSStefan Hajnoczi                     "from vmstate\n");
82200e2a04cSStefan Hajnoczi             return -EINVAL;
82300e2a04cSStefan Hajnoczi         }
824797ac58cSKevin Wolf     }
825797ac58cSKevin Wolf 
82600e2a04cSStefan Hajnoczi     buf = qemu_io_alloc(blk, count, 0xab, flags & BDRV_REQ_REGISTERED_BUF);
827797ac58cSKevin Wolf 
82850290c00SAlex Bennée     clock_gettime(CLOCK_MONOTONIC, &t1);
8297b3f9712SEric Blake     if (bflag) {
830b32d7a39SMax Reitz         ret = do_load_vmstate(blk, buf, offset, count, &total);
831797ac58cSKevin Wolf     } else {
83200e2a04cSStefan Hajnoczi         ret = do_pread(blk, buf, offset, count, flags, &total);
833797ac58cSKevin Wolf     }
83450290c00SAlex Bennée     clock_gettime(CLOCK_MONOTONIC, &t2);
835797ac58cSKevin Wolf 
836b32d7a39SMax Reitz     if (ret < 0) {
837b32d7a39SMax Reitz         printf("read failed: %s\n", strerror(-ret));
838797ac58cSKevin Wolf         goto out;
839797ac58cSKevin Wolf     }
840b32d7a39SMax Reitz     cnt = ret;
841b32d7a39SMax Reitz 
842b32d7a39SMax Reitz     ret = 0;
843797ac58cSKevin Wolf 
844797ac58cSKevin Wolf     if (Pflag) {
845797ac58cSKevin Wolf         void *cmp_buf = g_malloc(pattern_count);
846797ac58cSKevin Wolf         memset(cmp_buf, pattern, pattern_count);
847797ac58cSKevin Wolf         if (memcmp(buf + pattern_offset, cmp_buf, pattern_count)) {
848797ac58cSKevin Wolf             printf("Pattern verification failed at offset %"
8499b0beaf3SJohn Snow                    PRId64 ", %"PRId64" bytes\n",
850797ac58cSKevin Wolf                    offset + pattern_offset, pattern_count);
851b32d7a39SMax Reitz             ret = -EINVAL;
852797ac58cSKevin Wolf         }
853797ac58cSKevin Wolf         g_free(cmp_buf);
854797ac58cSKevin Wolf     }
855797ac58cSKevin Wolf 
856797ac58cSKevin Wolf     if (qflag) {
857797ac58cSKevin Wolf         goto out;
858797ac58cSKevin Wolf     }
859797ac58cSKevin Wolf 
860797ac58cSKevin Wolf     if (vflag) {
861797ac58cSKevin Wolf         dump_buffer(buf, offset, count);
862797ac58cSKevin Wolf     }
863797ac58cSKevin Wolf 
864797ac58cSKevin Wolf     /* Finally, report back -- -C gives a parsable format */
865797ac58cSKevin Wolf     t2 = tsub(t2, t1);
866797ac58cSKevin Wolf     print_report("read", &t2, offset, count, total, cnt, Cflag);
867797ac58cSKevin Wolf 
868797ac58cSKevin Wolf out:
86900e2a04cSStefan Hajnoczi     qemu_io_free(blk, buf, count, flags & BDRV_REQ_REGISTERED_BUF);
870b32d7a39SMax Reitz     return ret;
871797ac58cSKevin Wolf }
872797ac58cSKevin Wolf 
readv_help(void)873797ac58cSKevin Wolf static void readv_help(void)
874797ac58cSKevin Wolf {
875797ac58cSKevin Wolf     printf(
876797ac58cSKevin Wolf "\n"
877797ac58cSKevin Wolf " reads a range of bytes from the given offset into multiple buffers\n"
878797ac58cSKevin Wolf "\n"
879797ac58cSKevin Wolf " Example:\n"
880797ac58cSKevin Wolf " 'readv -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n"
881797ac58cSKevin Wolf "\n"
882797ac58cSKevin Wolf " Reads a segment of the currently open file, optionally dumping it to the\n"
883797ac58cSKevin Wolf " standard output stream (with -v option) for subsequent inspection.\n"
884797ac58cSKevin Wolf " Uses multiple iovec buffers if more than one byte range is specified.\n"
885797ac58cSKevin Wolf " -C, -- report statistics in a machine parsable format\n"
886797ac58cSKevin Wolf " -P, -- use a pattern to verify read data\n"
887797ac58cSKevin Wolf " -q, -- quiet mode, do not show I/O statistics\n"
88800e2a04cSStefan Hajnoczi " -r, -- register I/O buffer\n"
88900e2a04cSStefan Hajnoczi " -v, -- dump buffer to standard output\n"
890797ac58cSKevin Wolf "\n");
891797ac58cSKevin Wolf }
892797ac58cSKevin Wolf 
893b32d7a39SMax Reitz static int readv_f(BlockBackend *blk, int argc, char **argv);
894797ac58cSKevin Wolf 
895797ac58cSKevin Wolf static const cmdinfo_t readv_cmd = {
896797ac58cSKevin Wolf     .name       = "readv",
897797ac58cSKevin Wolf     .cfunc      = readv_f,
898797ac58cSKevin Wolf     .argmin     = 2,
899797ac58cSKevin Wolf     .argmax     = -1,
90000e2a04cSStefan Hajnoczi     .args       = "[-Cqrv] [-P pattern] off len [len..]",
901797ac58cSKevin Wolf     .oneline    = "reads a number of bytes at a specified offset",
902797ac58cSKevin Wolf     .help       = readv_help,
903797ac58cSKevin Wolf };
904797ac58cSKevin Wolf 
readv_f(BlockBackend * blk,int argc,char ** argv)905b32d7a39SMax Reitz static int readv_f(BlockBackend *blk, int argc, char **argv)
906797ac58cSKevin Wolf {
90750290c00SAlex Bennée     struct timespec t1, t2;
908dc38852aSEric Blake     bool Cflag = false, qflag = false, vflag = false;
909b32d7a39SMax Reitz     int c, cnt, ret;
910797ac58cSKevin Wolf     char *buf;
911797ac58cSKevin Wolf     int64_t offset;
912797ac58cSKevin Wolf     /* Some compilers get confused and warn if this is not initialized.  */
913797ac58cSKevin Wolf     int total = 0;
914797ac58cSKevin Wolf     int nr_iov;
915797ac58cSKevin Wolf     QEMUIOVector qiov;
916797ac58cSKevin Wolf     int pattern = 0;
917dc38852aSEric Blake     bool Pflag = false;
91800e2a04cSStefan Hajnoczi     BdrvRequestFlags flags = 0;
919797ac58cSKevin Wolf 
92000e2a04cSStefan Hajnoczi     while ((c = getopt(argc, argv, "CP:qrv")) != -1) {
921797ac58cSKevin Wolf         switch (c) {
922797ac58cSKevin Wolf         case 'C':
923dc38852aSEric Blake             Cflag = true;
924797ac58cSKevin Wolf             break;
925797ac58cSKevin Wolf         case 'P':
926dc38852aSEric Blake             Pflag = true;
927797ac58cSKevin Wolf             pattern = parse_pattern(optarg);
928797ac58cSKevin Wolf             if (pattern < 0) {
929b32d7a39SMax Reitz                 return -EINVAL;
930797ac58cSKevin Wolf             }
931797ac58cSKevin Wolf             break;
932797ac58cSKevin Wolf         case 'q':
933dc38852aSEric Blake             qflag = true;
934797ac58cSKevin Wolf             break;
93500e2a04cSStefan Hajnoczi         case 'r':
93600e2a04cSStefan Hajnoczi             flags |= BDRV_REQ_REGISTERED_BUF;
93700e2a04cSStefan Hajnoczi             break;
938797ac58cSKevin Wolf         case 'v':
939dc38852aSEric Blake             vflag = true;
940797ac58cSKevin Wolf             break;
941797ac58cSKevin Wolf         default:
942b444d0e9SMax Reitz             qemuio_command_usage(&readv_cmd);
943b32d7a39SMax Reitz             return -EINVAL;
944797ac58cSKevin Wolf         }
945797ac58cSKevin Wolf     }
946797ac58cSKevin Wolf 
947797ac58cSKevin Wolf     if (optind > argc - 2) {
948b444d0e9SMax Reitz         qemuio_command_usage(&readv_cmd);
949b32d7a39SMax Reitz         return -EINVAL;
950797ac58cSKevin Wolf     }
951797ac58cSKevin Wolf 
952797ac58cSKevin Wolf 
953797ac58cSKevin Wolf     offset = cvtnum(argv[optind]);
954797ac58cSKevin Wolf     if (offset < 0) {
955a9ecfa00SJohn Snow         print_cvtnum_err(offset, argv[optind]);
956b32d7a39SMax Reitz         return offset;
957797ac58cSKevin Wolf     }
958797ac58cSKevin Wolf     optind++;
959797ac58cSKevin Wolf 
960797ac58cSKevin Wolf     nr_iov = argc - optind;
96100e2a04cSStefan Hajnoczi     buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, 0xab,
96200e2a04cSStefan Hajnoczi                        flags & BDRV_REQ_REGISTERED_BUF);
963797ac58cSKevin Wolf     if (buf == NULL) {
964b32d7a39SMax Reitz         return -EINVAL;
965797ac58cSKevin Wolf     }
966797ac58cSKevin Wolf 
96750290c00SAlex Bennée     clock_gettime(CLOCK_MONOTONIC, &t1);
96800e2a04cSStefan Hajnoczi     ret = do_aio_readv(blk, &qiov, offset, flags, &total);
96950290c00SAlex Bennée     clock_gettime(CLOCK_MONOTONIC, &t2);
970797ac58cSKevin Wolf 
971b32d7a39SMax Reitz     if (ret < 0) {
972b32d7a39SMax Reitz         printf("readv failed: %s\n", strerror(-ret));
973797ac58cSKevin Wolf         goto out;
974797ac58cSKevin Wolf     }
975b32d7a39SMax Reitz     cnt = ret;
976b32d7a39SMax Reitz 
977b32d7a39SMax Reitz     ret = 0;
978797ac58cSKevin Wolf 
979797ac58cSKevin Wolf     if (Pflag) {
980797ac58cSKevin Wolf         void *cmp_buf = g_malloc(qiov.size);
981797ac58cSKevin Wolf         memset(cmp_buf, pattern, qiov.size);
982797ac58cSKevin Wolf         if (memcmp(buf, cmp_buf, qiov.size)) {
983797ac58cSKevin Wolf             printf("Pattern verification failed at offset %"
984cf67b692SStefan Weil                    PRId64 ", %zu bytes\n", offset, qiov.size);
985b32d7a39SMax Reitz             ret = -EINVAL;
986797ac58cSKevin Wolf         }
987797ac58cSKevin Wolf         g_free(cmp_buf);
988797ac58cSKevin Wolf     }
989797ac58cSKevin Wolf 
990797ac58cSKevin Wolf     if (qflag) {
991797ac58cSKevin Wolf         goto out;
992797ac58cSKevin Wolf     }
993797ac58cSKevin Wolf 
994797ac58cSKevin Wolf     if (vflag) {
995797ac58cSKevin Wolf         dump_buffer(buf, offset, qiov.size);
996797ac58cSKevin Wolf     }
997797ac58cSKevin Wolf 
998797ac58cSKevin Wolf     /* Finally, report back -- -C gives a parsable format */
999797ac58cSKevin Wolf     t2 = tsub(t2, t1);
1000797ac58cSKevin Wolf     print_report("read", &t2, offset, qiov.size, total, cnt, Cflag);
1001797ac58cSKevin Wolf 
1002797ac58cSKevin Wolf out:
100300e2a04cSStefan Hajnoczi     qemu_io_free(blk, buf, qiov.size, flags & BDRV_REQ_REGISTERED_BUF);
1004797ac58cSKevin Wolf     qemu_iovec_destroy(&qiov);
1005b32d7a39SMax Reitz     return ret;
1006797ac58cSKevin Wolf }
1007797ac58cSKevin Wolf 
write_help(void)1008797ac58cSKevin Wolf static void write_help(void)
1009797ac58cSKevin Wolf {
1010797ac58cSKevin Wolf     printf(
1011797ac58cSKevin Wolf "\n"
1012797ac58cSKevin Wolf " writes a range of bytes from the given offset\n"
1013797ac58cSKevin Wolf "\n"
1014797ac58cSKevin Wolf " Example:\n"
1015797ac58cSKevin Wolf " 'write 512 1k' - writes 1 kilobyte at 512 bytes into the open file\n"
1016797ac58cSKevin Wolf "\n"
1017797ac58cSKevin Wolf " Writes into a segment of the currently open file, using a buffer\n"
1018797ac58cSKevin Wolf " filled with a set pattern (0xcdcdcdcd).\n"
1019797ac58cSKevin Wolf " -b, -- write to the VM state rather than the virtual disk\n"
10204c7b7e9bSMax Reitz " -c, -- write compressed data with blk_write_compressed\n"
102100e2a04cSStefan Hajnoczi " -C, -- report statistics in a machine parsable format\n"
1022770e0e0eSEric Blake " -f, -- use Force Unit Access semantics\n"
1023c6e3f520SKevin Wolf " -n, -- with -z, don't allow slow fallback\n"
1024093ea232SEric Blake " -p, -- ignored for backwards compatibility\n"
1025797ac58cSKevin Wolf " -P, -- use different pattern to fill file\n"
1026797ac58cSKevin Wolf " -q, -- quiet mode, do not show I/O statistics\n"
102700e2a04cSStefan Hajnoczi " -r, -- register I/O buffer\n"
102800e2a04cSStefan Hajnoczi " -s, -- use a pattern file to fill the write buffer\n"
1029c2e001ccSEric Blake " -u, -- with -z, allow unmapping\n"
1030264dcbb2SPaolo Bonzini " -z, -- write zeroes using blk_pwrite_zeroes\n"
1031797ac58cSKevin Wolf "\n");
1032797ac58cSKevin Wolf }
1033797ac58cSKevin Wolf 
1034b32d7a39SMax Reitz static int write_f(BlockBackend *blk, int argc, char **argv);
1035797ac58cSKevin Wolf 
1036797ac58cSKevin Wolf static const cmdinfo_t write_cmd = {
1037797ac58cSKevin Wolf     .name       = "write",
1038797ac58cSKevin Wolf     .altname    = "w",
1039797ac58cSKevin Wolf     .cfunc      = write_f,
1040887354bdSKevin Wolf     .perm       = BLK_PERM_WRITE,
1041797ac58cSKevin Wolf     .argmin     = 2,
1042797ac58cSKevin Wolf     .argmax     = -1,
104300e2a04cSStefan Hajnoczi     .args       = "[-bcCfnqruz] [-P pattern | -s source_file] off len",
1044797ac58cSKevin Wolf     .oneline    = "writes a number of bytes at a specified offset",
1045797ac58cSKevin Wolf     .help       = write_help,
1046797ac58cSKevin Wolf };
1047797ac58cSKevin Wolf 
write_f(BlockBackend * blk,int argc,char ** argv)1048b32d7a39SMax Reitz static int write_f(BlockBackend *blk, int argc, char **argv)
1049797ac58cSKevin Wolf {
105050290c00SAlex Bennée     struct timespec t1, t2;
1051093ea232SEric Blake     bool Cflag = false, qflag = false, bflag = false;
10524d731510SDenis Plotnikov     bool Pflag = false, zflag = false, cflag = false, sflag = false;
10531321e008SStefan Hajnoczi     BdrvRequestFlags flags = 0;
1054b32d7a39SMax Reitz     int c, cnt, ret;
1055797ac58cSKevin Wolf     char *buf = NULL;
1056797ac58cSKevin Wolf     int64_t offset;
10579b0beaf3SJohn Snow     int64_t count;
1058797ac58cSKevin Wolf     /* Some compilers get confused and warn if this is not initialized.  */
10599b0beaf3SJohn Snow     int64_t total = 0;
1060797ac58cSKevin Wolf     int pattern = 0xcd;
10614d731510SDenis Plotnikov     const char *file_name = NULL;
1062797ac58cSKevin Wolf 
106300e2a04cSStefan Hajnoczi     while ((c = getopt(argc, argv, "bcCfnpP:qrs:uz")) != -1) {
1064797ac58cSKevin Wolf         switch (c) {
1065797ac58cSKevin Wolf         case 'b':
1066dc38852aSEric Blake             bflag = true;
1067797ac58cSKevin Wolf             break;
1068797ac58cSKevin Wolf         case 'c':
1069dc38852aSEric Blake             cflag = true;
1070797ac58cSKevin Wolf             break;
1071797ac58cSKevin Wolf         case 'C':
1072dc38852aSEric Blake             Cflag = true;
1073797ac58cSKevin Wolf             break;
1074770e0e0eSEric Blake         case 'f':
1075770e0e0eSEric Blake             flags |= BDRV_REQ_FUA;
1076770e0e0eSEric Blake             break;
1077c6e3f520SKevin Wolf         case 'n':
1078c6e3f520SKevin Wolf             flags |= BDRV_REQ_NO_FALLBACK;
1079c6e3f520SKevin Wolf             break;
1080797ac58cSKevin Wolf         case 'p':
1081093ea232SEric Blake             /* Ignored for backwards compatibility */
1082797ac58cSKevin Wolf             break;
1083797ac58cSKevin Wolf         case 'P':
1084dc38852aSEric Blake             Pflag = true;
1085797ac58cSKevin Wolf             pattern = parse_pattern(optarg);
1086797ac58cSKevin Wolf             if (pattern < 0) {
1087b32d7a39SMax Reitz                 return -EINVAL;
1088797ac58cSKevin Wolf             }
1089797ac58cSKevin Wolf             break;
1090797ac58cSKevin Wolf         case 'q':
1091dc38852aSEric Blake             qflag = true;
1092797ac58cSKevin Wolf             break;
109300e2a04cSStefan Hajnoczi         case 'r':
109400e2a04cSStefan Hajnoczi             flags |= BDRV_REQ_REGISTERED_BUF;
109500e2a04cSStefan Hajnoczi             break;
10964d731510SDenis Plotnikov         case 's':
10974d731510SDenis Plotnikov             sflag = true;
10984d731510SDenis Plotnikov             file_name = optarg;
10994d731510SDenis Plotnikov             break;
1100c2e001ccSEric Blake         case 'u':
1101c2e001ccSEric Blake             flags |= BDRV_REQ_MAY_UNMAP;
1102c2e001ccSEric Blake             break;
1103797ac58cSKevin Wolf         case 'z':
1104dc38852aSEric Blake             zflag = true;
1105797ac58cSKevin Wolf             break;
1106797ac58cSKevin Wolf         default:
1107b444d0e9SMax Reitz             qemuio_command_usage(&write_cmd);
1108b32d7a39SMax Reitz             return -EINVAL;
1109797ac58cSKevin Wolf         }
1110797ac58cSKevin Wolf     }
1111797ac58cSKevin Wolf 
1112797ac58cSKevin Wolf     if (optind != argc - 2) {
1113b444d0e9SMax Reitz         qemuio_command_usage(&write_cmd);
1114b32d7a39SMax Reitz         return -EINVAL;
1115797ac58cSKevin Wolf     }
1116797ac58cSKevin Wolf 
1117093ea232SEric Blake     if (bflag && zflag) {
1118093ea232SEric Blake         printf("-b and -z cannot be specified at the same time\n");
1119b32d7a39SMax Reitz         return -EINVAL;
1120797ac58cSKevin Wolf     }
1121797ac58cSKevin Wolf 
1122770e0e0eSEric Blake     if ((flags & BDRV_REQ_FUA) && (bflag || cflag)) {
1123770e0e0eSEric Blake         printf("-f and -b or -c cannot be specified at the same time\n");
1124b32d7a39SMax Reitz         return -EINVAL;
1125770e0e0eSEric Blake     }
1126770e0e0eSEric Blake 
1127c6e3f520SKevin Wolf     if ((flags & BDRV_REQ_NO_FALLBACK) && !zflag) {
1128c6e3f520SKevin Wolf         printf("-n requires -z to be specified\n");
1129c6e3f520SKevin Wolf         return -EINVAL;
1130c6e3f520SKevin Wolf     }
1131c6e3f520SKevin Wolf 
1132c2e001ccSEric Blake     if ((flags & BDRV_REQ_MAY_UNMAP) && !zflag) {
1133c2e001ccSEric Blake         printf("-u requires -z to be specified\n");
1134b32d7a39SMax Reitz         return -EINVAL;
1135c2e001ccSEric Blake     }
1136c2e001ccSEric Blake 
11374d731510SDenis Plotnikov     if (zflag + Pflag + sflag > 1) {
11384d731510SDenis Plotnikov         printf("Only one of -z, -P, and -s "
11394d731510SDenis Plotnikov                "can be specified at the same time\n");
1140b32d7a39SMax Reitz         return -EINVAL;
1141797ac58cSKevin Wolf     }
1142797ac58cSKevin Wolf 
1143797ac58cSKevin Wolf     offset = cvtnum(argv[optind]);
1144797ac58cSKevin Wolf     if (offset < 0) {
1145a9ecfa00SJohn Snow         print_cvtnum_err(offset, argv[optind]);
1146b32d7a39SMax Reitz         return offset;
1147797ac58cSKevin Wolf     }
1148797ac58cSKevin Wolf 
1149797ac58cSKevin Wolf     optind++;
1150797ac58cSKevin Wolf     count = cvtnum(argv[optind]);
1151797ac58cSKevin Wolf     if (count < 0) {
1152a9ecfa00SJohn Snow         print_cvtnum_err(count, argv[optind]);
1153b32d7a39SMax Reitz         return count;
1154395aecd0SEric Blake     } else if (count > BDRV_REQUEST_MAX_BYTES &&
1155395aecd0SEric Blake                !(flags & BDRV_REQ_NO_FALLBACK)) {
1156395aecd0SEric Blake         printf("length cannot exceed %" PRIu64 " without -n, given %s\n",
11573026c468SAlberto Garcia                (uint64_t)BDRV_REQUEST_MAX_BYTES, argv[optind]);
1158b32d7a39SMax Reitz         return -EINVAL;
1159797ac58cSKevin Wolf     }
1160797ac58cSKevin Wolf 
1161093ea232SEric Blake     if (bflag || cflag) {
11621bce6b4cSEric Blake         if (!QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE)) {
11631bce6b4cSEric Blake             printf("%" PRId64 " is not a sector-aligned value for 'offset'\n",
1164797ac58cSKevin Wolf                    offset);
1165b32d7a39SMax Reitz             return -EINVAL;
1166797ac58cSKevin Wolf         }
1167797ac58cSKevin Wolf 
11681bce6b4cSEric Blake         if (!QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE)) {
11691bce6b4cSEric Blake             printf("%"PRId64" is not a sector-aligned value for 'count'\n",
1170797ac58cSKevin Wolf                    count);
1171b32d7a39SMax Reitz             return -EINVAL;
1172797ac58cSKevin Wolf         }
1173797ac58cSKevin Wolf     }
1174797ac58cSKevin Wolf 
117500e2a04cSStefan Hajnoczi     if (zflag) {
117600e2a04cSStefan Hajnoczi         if (flags & BDRV_REQ_REGISTERED_BUF) {
117700e2a04cSStefan Hajnoczi             printf("cannot combine zero write with registered I/O buffer\n");
117800e2a04cSStefan Hajnoczi             return -EINVAL;
117900e2a04cSStefan Hajnoczi         }
118000e2a04cSStefan Hajnoczi     } else {
11814d731510SDenis Plotnikov         if (sflag) {
118200e2a04cSStefan Hajnoczi             buf = qemu_io_alloc_from_file(blk, count, file_name,
118300e2a04cSStefan Hajnoczi                                           flags & BDRV_REQ_REGISTERED_BUF);
11844d731510SDenis Plotnikov             if (!buf) {
11854d731510SDenis Plotnikov                 return -EINVAL;
11864d731510SDenis Plotnikov             }
11874d731510SDenis Plotnikov         } else {
118800e2a04cSStefan Hajnoczi             buf = qemu_io_alloc(blk, count, pattern,
118900e2a04cSStefan Hajnoczi                                 flags & BDRV_REQ_REGISTERED_BUF);
1190797ac58cSKevin Wolf         }
11914d731510SDenis Plotnikov     }
1192797ac58cSKevin Wolf 
119350290c00SAlex Bennée     clock_gettime(CLOCK_MONOTONIC, &t1);
11947b3f9712SEric Blake     if (bflag) {
1195b32d7a39SMax Reitz         ret = do_save_vmstate(blk, buf, offset, count, &total);
1196797ac58cSKevin Wolf     } else if (zflag) {
1197264dcbb2SPaolo Bonzini         ret = do_pwrite_zeroes(blk, offset, count, flags, &total);
1198797ac58cSKevin Wolf     } else if (cflag) {
1199b32d7a39SMax Reitz         ret = do_write_compressed(blk, buf, offset, count, &total);
1200797ac58cSKevin Wolf     } else {
1201b32d7a39SMax Reitz         ret = do_pwrite(blk, buf, offset, count, flags, &total);
1202797ac58cSKevin Wolf     }
120350290c00SAlex Bennée     clock_gettime(CLOCK_MONOTONIC, &t2);
1204797ac58cSKevin Wolf 
1205b32d7a39SMax Reitz     if (ret < 0) {
1206b32d7a39SMax Reitz         printf("write failed: %s\n", strerror(-ret));
1207797ac58cSKevin Wolf         goto out;
1208797ac58cSKevin Wolf     }
1209b32d7a39SMax Reitz     cnt = ret;
1210b32d7a39SMax Reitz 
1211b32d7a39SMax Reitz     ret = 0;
1212797ac58cSKevin Wolf 
1213797ac58cSKevin Wolf     if (qflag) {
1214797ac58cSKevin Wolf         goto out;
1215797ac58cSKevin Wolf     }
1216797ac58cSKevin Wolf 
1217797ac58cSKevin Wolf     /* Finally, report back -- -C gives a parsable format */
1218797ac58cSKevin Wolf     t2 = tsub(t2, t1);
1219797ac58cSKevin Wolf     print_report("wrote", &t2, offset, count, total, cnt, Cflag);
1220797ac58cSKevin Wolf 
1221797ac58cSKevin Wolf out:
1222797ac58cSKevin Wolf     if (!zflag) {
122300e2a04cSStefan Hajnoczi         qemu_io_free(blk, buf, count, flags & BDRV_REQ_REGISTERED_BUF);
1224797ac58cSKevin Wolf     }
1225b32d7a39SMax Reitz     return ret;
1226797ac58cSKevin Wolf }
1227797ac58cSKevin Wolf 
1228797ac58cSKevin Wolf static void
writev_help(void)1229797ac58cSKevin Wolf writev_help(void)
1230797ac58cSKevin Wolf {
1231797ac58cSKevin Wolf     printf(
1232797ac58cSKevin Wolf "\n"
1233797ac58cSKevin Wolf " writes a range of bytes from the given offset source from multiple buffers\n"
1234797ac58cSKevin Wolf "\n"
1235797ac58cSKevin Wolf " Example:\n"
12366e6507c0SMaria Kustova " 'writev 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n"
1237797ac58cSKevin Wolf "\n"
1238797ac58cSKevin Wolf " Writes into a segment of the currently open file, using a buffer\n"
1239797ac58cSKevin Wolf " filled with a set pattern (0xcdcdcdcd).\n"
1240797ac58cSKevin Wolf " -C, -- report statistics in a machine parsable format\n"
1241770e0e0eSEric Blake " -f, -- use Force Unit Access semantics\n"
124200e2a04cSStefan Hajnoczi " -P, -- use different pattern to fill file\n"
1243797ac58cSKevin Wolf " -q, -- quiet mode, do not show I/O statistics\n"
124400e2a04cSStefan Hajnoczi " -r, -- register I/O buffer\n"
1245797ac58cSKevin Wolf "\n");
1246797ac58cSKevin Wolf }
1247797ac58cSKevin Wolf 
1248b32d7a39SMax Reitz static int writev_f(BlockBackend *blk, int argc, char **argv);
1249797ac58cSKevin Wolf 
1250797ac58cSKevin Wolf static const cmdinfo_t writev_cmd = {
1251797ac58cSKevin Wolf     .name       = "writev",
1252797ac58cSKevin Wolf     .cfunc      = writev_f,
1253887354bdSKevin Wolf     .perm       = BLK_PERM_WRITE,
1254797ac58cSKevin Wolf     .argmin     = 2,
1255797ac58cSKevin Wolf     .argmax     = -1,
125600e2a04cSStefan Hajnoczi     .args       = "[-Cfqr] [-P pattern] off len [len..]",
1257797ac58cSKevin Wolf     .oneline    = "writes a number of bytes at a specified offset",
1258797ac58cSKevin Wolf     .help       = writev_help,
1259797ac58cSKevin Wolf };
1260797ac58cSKevin Wolf 
writev_f(BlockBackend * blk,int argc,char ** argv)1261b32d7a39SMax Reitz static int writev_f(BlockBackend *blk, int argc, char **argv)
1262797ac58cSKevin Wolf {
126350290c00SAlex Bennée     struct timespec t1, t2;
1264dc38852aSEric Blake     bool Cflag = false, qflag = false;
12651321e008SStefan Hajnoczi     BdrvRequestFlags flags = 0;
1266b32d7a39SMax Reitz     int c, cnt, ret;
1267797ac58cSKevin Wolf     char *buf;
1268797ac58cSKevin Wolf     int64_t offset;
1269797ac58cSKevin Wolf     /* Some compilers get confused and warn if this is not initialized.  */
1270797ac58cSKevin Wolf     int total = 0;
1271797ac58cSKevin Wolf     int nr_iov;
1272797ac58cSKevin Wolf     int pattern = 0xcd;
1273797ac58cSKevin Wolf     QEMUIOVector qiov;
1274797ac58cSKevin Wolf 
127500e2a04cSStefan Hajnoczi     while ((c = getopt(argc, argv, "CfP:qr")) != -1) {
1276797ac58cSKevin Wolf         switch (c) {
1277797ac58cSKevin Wolf         case 'C':
1278dc38852aSEric Blake             Cflag = true;
1279797ac58cSKevin Wolf             break;
1280770e0e0eSEric Blake         case 'f':
1281770e0e0eSEric Blake             flags |= BDRV_REQ_FUA;
1282770e0e0eSEric Blake             break;
1283797ac58cSKevin Wolf         case 'q':
1284dc38852aSEric Blake             qflag = true;
1285797ac58cSKevin Wolf             break;
128600e2a04cSStefan Hajnoczi         case 'r':
128700e2a04cSStefan Hajnoczi             flags |= BDRV_REQ_REGISTERED_BUF;
128800e2a04cSStefan Hajnoczi             break;
1289797ac58cSKevin Wolf         case 'P':
1290797ac58cSKevin Wolf             pattern = parse_pattern(optarg);
1291797ac58cSKevin Wolf             if (pattern < 0) {
1292b32d7a39SMax Reitz                 return -EINVAL;
1293797ac58cSKevin Wolf             }
1294797ac58cSKevin Wolf             break;
1295797ac58cSKevin Wolf         default:
1296b444d0e9SMax Reitz             qemuio_command_usage(&writev_cmd);
1297b32d7a39SMax Reitz             return -EINVAL;
1298797ac58cSKevin Wolf         }
1299797ac58cSKevin Wolf     }
1300797ac58cSKevin Wolf 
1301797ac58cSKevin Wolf     if (optind > argc - 2) {
1302b444d0e9SMax Reitz         qemuio_command_usage(&writev_cmd);
1303b32d7a39SMax Reitz         return -EINVAL;
1304797ac58cSKevin Wolf     }
1305797ac58cSKevin Wolf 
1306797ac58cSKevin Wolf     offset = cvtnum(argv[optind]);
1307797ac58cSKevin Wolf     if (offset < 0) {
1308a9ecfa00SJohn Snow         print_cvtnum_err(offset, argv[optind]);
1309b32d7a39SMax Reitz         return offset;
1310797ac58cSKevin Wolf     }
1311797ac58cSKevin Wolf     optind++;
1312797ac58cSKevin Wolf 
1313797ac58cSKevin Wolf     nr_iov = argc - optind;
131400e2a04cSStefan Hajnoczi     buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, pattern,
131500e2a04cSStefan Hajnoczi                        flags & BDRV_REQ_REGISTERED_BUF);
1316797ac58cSKevin Wolf     if (buf == NULL) {
1317b32d7a39SMax Reitz         return -EINVAL;
1318797ac58cSKevin Wolf     }
1319797ac58cSKevin Wolf 
132050290c00SAlex Bennée     clock_gettime(CLOCK_MONOTONIC, &t1);
1321b32d7a39SMax Reitz     ret = do_aio_writev(blk, &qiov, offset, flags, &total);
132250290c00SAlex Bennée     clock_gettime(CLOCK_MONOTONIC, &t2);
1323797ac58cSKevin Wolf 
1324b32d7a39SMax Reitz     if (ret < 0) {
1325b32d7a39SMax Reitz         printf("writev failed: %s\n", strerror(-ret));
1326797ac58cSKevin Wolf         goto out;
1327797ac58cSKevin Wolf     }
1328b32d7a39SMax Reitz     cnt = ret;
1329b32d7a39SMax Reitz 
1330b32d7a39SMax Reitz     ret = 0;
1331797ac58cSKevin Wolf 
1332797ac58cSKevin Wolf     if (qflag) {
1333797ac58cSKevin Wolf         goto out;
1334797ac58cSKevin Wolf     }
1335797ac58cSKevin Wolf 
1336797ac58cSKevin Wolf     /* Finally, report back -- -C gives a parsable format */
1337797ac58cSKevin Wolf     t2 = tsub(t2, t1);
1338797ac58cSKevin Wolf     print_report("wrote", &t2, offset, qiov.size, total, cnt, Cflag);
1339797ac58cSKevin Wolf out:
134000e2a04cSStefan Hajnoczi     qemu_io_free(blk, buf, qiov.size, flags & BDRV_REQ_REGISTERED_BUF);
1341797ac58cSKevin Wolf     qemu_iovec_destroy(&qiov);
1342b32d7a39SMax Reitz     return ret;
1343797ac58cSKevin Wolf }
1344797ac58cSKevin Wolf 
1345797ac58cSKevin Wolf struct aio_ctx {
13464c7b7e9bSMax Reitz     BlockBackend *blk;
1347797ac58cSKevin Wolf     QEMUIOVector qiov;
1348797ac58cSKevin Wolf     int64_t offset;
1349797ac58cSKevin Wolf     char *buf;
1350dc38852aSEric Blake     bool qflag;
1351dc38852aSEric Blake     bool vflag;
1352dc38852aSEric Blake     bool Cflag;
1353dc38852aSEric Blake     bool Pflag;
1354dc38852aSEric Blake     bool zflag;
1355a91f9584SFam Zheng     BlockAcctCookie acct;
1356797ac58cSKevin Wolf     int pattern;
135700e2a04cSStefan Hajnoczi     BdrvRequestFlags flags;
135850290c00SAlex Bennée     struct timespec t1;
1359797ac58cSKevin Wolf };
1360797ac58cSKevin Wolf 
aio_write_done(void * opaque,int ret)1361797ac58cSKevin Wolf static void aio_write_done(void *opaque, int ret)
1362797ac58cSKevin Wolf {
1363797ac58cSKevin Wolf     struct aio_ctx *ctx = opaque;
136450290c00SAlex Bennée     struct timespec t2;
1365797ac58cSKevin Wolf 
136650290c00SAlex Bennée     clock_gettime(CLOCK_MONOTONIC, &t2);
1367797ac58cSKevin Wolf 
1368797ac58cSKevin Wolf 
1369797ac58cSKevin Wolf     if (ret < 0) {
1370797ac58cSKevin Wolf         printf("aio_write failed: %s\n", strerror(-ret));
1371556c2b60SAlberto Garcia         block_acct_failed(blk_get_stats(ctx->blk), &ctx->acct);
1372797ac58cSKevin Wolf         goto out;
1373797ac58cSKevin Wolf     }
1374797ac58cSKevin Wolf 
13754c7b7e9bSMax Reitz     block_acct_done(blk_get_stats(ctx->blk), &ctx->acct);
1376a91f9584SFam Zheng 
1377797ac58cSKevin Wolf     if (ctx->qflag) {
1378797ac58cSKevin Wolf         goto out;
1379797ac58cSKevin Wolf     }
1380797ac58cSKevin Wolf 
1381797ac58cSKevin Wolf     /* Finally, report back -- -C gives a parsable format */
1382797ac58cSKevin Wolf     t2 = tsub(t2, ctx->t1);
1383797ac58cSKevin Wolf     print_report("wrote", &t2, ctx->offset, ctx->qiov.size,
1384797ac58cSKevin Wolf                  ctx->qiov.size, 1, ctx->Cflag);
1385797ac58cSKevin Wolf out:
13865ceb7765SKevin Wolf     if (!ctx->zflag) {
138700e2a04cSStefan Hajnoczi         qemu_io_free(ctx->blk, ctx->buf, ctx->qiov.size,
138800e2a04cSStefan Hajnoczi                      ctx->flags & BDRV_REQ_REGISTERED_BUF);
1389797ac58cSKevin Wolf         qemu_iovec_destroy(&ctx->qiov);
13905ceb7765SKevin Wolf     }
1391797ac58cSKevin Wolf     g_free(ctx);
1392797ac58cSKevin Wolf }
1393797ac58cSKevin Wolf 
aio_read_done(void * opaque,int ret)1394797ac58cSKevin Wolf static void aio_read_done(void *opaque, int ret)
1395797ac58cSKevin Wolf {
1396797ac58cSKevin Wolf     struct aio_ctx *ctx = opaque;
139750290c00SAlex Bennée     struct timespec t2;
1398797ac58cSKevin Wolf 
139950290c00SAlex Bennée     clock_gettime(CLOCK_MONOTONIC, &t2);
1400797ac58cSKevin Wolf 
1401797ac58cSKevin Wolf     if (ret < 0) {
1402797ac58cSKevin Wolf         printf("readv failed: %s\n", strerror(-ret));
1403556c2b60SAlberto Garcia         block_acct_failed(blk_get_stats(ctx->blk), &ctx->acct);
1404797ac58cSKevin Wolf         goto out;
1405797ac58cSKevin Wolf     }
1406797ac58cSKevin Wolf 
1407797ac58cSKevin Wolf     if (ctx->Pflag) {
1408797ac58cSKevin Wolf         void *cmp_buf = g_malloc(ctx->qiov.size);
1409797ac58cSKevin Wolf 
1410797ac58cSKevin Wolf         memset(cmp_buf, ctx->pattern, ctx->qiov.size);
1411797ac58cSKevin Wolf         if (memcmp(ctx->buf, cmp_buf, ctx->qiov.size)) {
1412797ac58cSKevin Wolf             printf("Pattern verification failed at offset %"
1413cf67b692SStefan Weil                    PRId64 ", %zu bytes\n", ctx->offset, ctx->qiov.size);
1414797ac58cSKevin Wolf         }
1415797ac58cSKevin Wolf         g_free(cmp_buf);
1416797ac58cSKevin Wolf     }
1417797ac58cSKevin Wolf 
14184c7b7e9bSMax Reitz     block_acct_done(blk_get_stats(ctx->blk), &ctx->acct);
1419a91f9584SFam Zheng 
1420797ac58cSKevin Wolf     if (ctx->qflag) {
1421797ac58cSKevin Wolf         goto out;
1422797ac58cSKevin Wolf     }
1423797ac58cSKevin Wolf 
1424797ac58cSKevin Wolf     if (ctx->vflag) {
1425797ac58cSKevin Wolf         dump_buffer(ctx->buf, ctx->offset, ctx->qiov.size);
1426797ac58cSKevin Wolf     }
1427797ac58cSKevin Wolf 
1428797ac58cSKevin Wolf     /* Finally, report back -- -C gives a parsable format */
1429797ac58cSKevin Wolf     t2 = tsub(t2, ctx->t1);
1430797ac58cSKevin Wolf     print_report("read", &t2, ctx->offset, ctx->qiov.size,
1431797ac58cSKevin Wolf                  ctx->qiov.size, 1, ctx->Cflag);
1432797ac58cSKevin Wolf out:
143300e2a04cSStefan Hajnoczi     qemu_io_free(ctx->blk, ctx->buf, ctx->qiov.size,
143400e2a04cSStefan Hajnoczi                  ctx->flags & BDRV_REQ_REGISTERED_BUF);
1435797ac58cSKevin Wolf     qemu_iovec_destroy(&ctx->qiov);
1436797ac58cSKevin Wolf     g_free(ctx);
1437797ac58cSKevin Wolf }
1438797ac58cSKevin Wolf 
aio_read_help(void)1439797ac58cSKevin Wolf static void aio_read_help(void)
1440797ac58cSKevin Wolf {
1441797ac58cSKevin Wolf     printf(
1442797ac58cSKevin Wolf "\n"
1443797ac58cSKevin Wolf " asynchronously reads a range of bytes from the given offset\n"
1444797ac58cSKevin Wolf "\n"
1445797ac58cSKevin Wolf " Example:\n"
1446797ac58cSKevin Wolf " 'aio_read -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n"
1447797ac58cSKevin Wolf "\n"
1448797ac58cSKevin Wolf " Reads a segment of the currently open file, optionally dumping it to the\n"
1449797ac58cSKevin Wolf " standard output stream (with -v option) for subsequent inspection.\n"
1450797ac58cSKevin Wolf " The read is performed asynchronously and the aio_flush command must be\n"
1451797ac58cSKevin Wolf " used to ensure all outstanding aio requests have been completed.\n"
1452b32d7a39SMax Reitz " Note that due to its asynchronous nature, this command will be\n"
1453b32d7a39SMax Reitz " considered successful once the request is submitted, independently\n"
1454b32d7a39SMax Reitz " of potential I/O errors or pattern mismatches.\n"
1455797ac58cSKevin Wolf " -C, -- report statistics in a machine parsable format\n"
145637546ff2SEric Blake " -i, -- treat request as invalid, for exercising stats\n"
145700e2a04cSStefan Hajnoczi " -P, -- use a pattern to verify read data\n"
1458797ac58cSKevin Wolf " -q, -- quiet mode, do not show I/O statistics\n"
145900e2a04cSStefan Hajnoczi " -r, -- register I/O buffer\n"
146000e2a04cSStefan Hajnoczi " -v, -- dump buffer to standard output\n"
1461797ac58cSKevin Wolf "\n");
1462797ac58cSKevin Wolf }
1463797ac58cSKevin Wolf 
1464b32d7a39SMax Reitz static int aio_read_f(BlockBackend *blk, int argc, char **argv);
1465797ac58cSKevin Wolf 
1466797ac58cSKevin Wolf static const cmdinfo_t aio_read_cmd = {
1467797ac58cSKevin Wolf     .name       = "aio_read",
1468797ac58cSKevin Wolf     .cfunc      = aio_read_f,
1469797ac58cSKevin Wolf     .argmin     = 2,
1470797ac58cSKevin Wolf     .argmax     = -1,
147100e2a04cSStefan Hajnoczi     .args       = "[-Ciqrv] [-P pattern] off len [len..]",
1472797ac58cSKevin Wolf     .oneline    = "asynchronously reads a number of bytes",
1473797ac58cSKevin Wolf     .help       = aio_read_help,
1474797ac58cSKevin Wolf };
1475797ac58cSKevin Wolf 
aio_read_f(BlockBackend * blk,int argc,char ** argv)1476b32d7a39SMax Reitz static int aio_read_f(BlockBackend *blk, int argc, char **argv)
1477797ac58cSKevin Wolf {
1478797ac58cSKevin Wolf     int nr_iov, c;
1479797ac58cSKevin Wolf     struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
1480797ac58cSKevin Wolf 
14814c7b7e9bSMax Reitz     ctx->blk = blk;
148200e2a04cSStefan Hajnoczi     while ((c = getopt(argc, argv, "CiP:qrv")) != -1) {
1483797ac58cSKevin Wolf         switch (c) {
1484797ac58cSKevin Wolf         case 'C':
1485dc38852aSEric Blake             ctx->Cflag = true;
1486797ac58cSKevin Wolf             break;
1487797ac58cSKevin Wolf         case 'P':
1488dc38852aSEric Blake             ctx->Pflag = true;
1489797ac58cSKevin Wolf             ctx->pattern = parse_pattern(optarg);
1490797ac58cSKevin Wolf             if (ctx->pattern < 0) {
1491797ac58cSKevin Wolf                 g_free(ctx);
1492b32d7a39SMax Reitz                 return -EINVAL;
1493797ac58cSKevin Wolf             }
1494797ac58cSKevin Wolf             break;
149537546ff2SEric Blake         case 'i':
149637546ff2SEric Blake             printf("injecting invalid read request\n");
149737546ff2SEric Blake             block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_READ);
149837546ff2SEric Blake             g_free(ctx);
1499b32d7a39SMax Reitz             return 0;
1500797ac58cSKevin Wolf         case 'q':
1501dc38852aSEric Blake             ctx->qflag = true;
1502797ac58cSKevin Wolf             break;
150300e2a04cSStefan Hajnoczi         case 'r':
150400e2a04cSStefan Hajnoczi             ctx->flags |= BDRV_REQ_REGISTERED_BUF;
150500e2a04cSStefan Hajnoczi             break;
1506797ac58cSKevin Wolf         case 'v':
1507dc38852aSEric Blake             ctx->vflag = true;
1508797ac58cSKevin Wolf             break;
1509797ac58cSKevin Wolf         default:
1510797ac58cSKevin Wolf             g_free(ctx);
1511b444d0e9SMax Reitz             qemuio_command_usage(&aio_read_cmd);
1512b32d7a39SMax Reitz             return -EINVAL;
1513797ac58cSKevin Wolf         }
1514797ac58cSKevin Wolf     }
1515797ac58cSKevin Wolf 
1516797ac58cSKevin Wolf     if (optind > argc - 2) {
1517797ac58cSKevin Wolf         g_free(ctx);
1518b444d0e9SMax Reitz         qemuio_command_usage(&aio_read_cmd);
1519b32d7a39SMax Reitz         return -EINVAL;
1520797ac58cSKevin Wolf     }
1521797ac58cSKevin Wolf 
1522797ac58cSKevin Wolf     ctx->offset = cvtnum(argv[optind]);
1523797ac58cSKevin Wolf     if (ctx->offset < 0) {
1524b32d7a39SMax Reitz         int ret = ctx->offset;
1525b32d7a39SMax Reitz         print_cvtnum_err(ret, argv[optind]);
1526797ac58cSKevin Wolf         g_free(ctx);
1527b32d7a39SMax Reitz         return ret;
1528797ac58cSKevin Wolf     }
1529797ac58cSKevin Wolf     optind++;
1530797ac58cSKevin Wolf 
1531797ac58cSKevin Wolf     nr_iov = argc - optind;
153200e2a04cSStefan Hajnoczi     ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov, 0xab,
153300e2a04cSStefan Hajnoczi                             ctx->flags & BDRV_REQ_REGISTERED_BUF);
1534797ac58cSKevin Wolf     if (ctx->buf == NULL) {
1535556c2b60SAlberto Garcia         block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_READ);
1536797ac58cSKevin Wolf         g_free(ctx);
1537b32d7a39SMax Reitz         return -EINVAL;
1538797ac58cSKevin Wolf     }
1539797ac58cSKevin Wolf 
154050290c00SAlex Bennée     clock_gettime(CLOCK_MONOTONIC, &ctx->t1);
15414c7b7e9bSMax Reitz     block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size,
15424c7b7e9bSMax Reitz                      BLOCK_ACCT_READ);
154300e2a04cSStefan Hajnoczi     blk_aio_preadv(blk, ctx->offset, &ctx->qiov, ctx->flags, aio_read_done,
154400e2a04cSStefan Hajnoczi                    ctx);
1545b32d7a39SMax Reitz     return 0;
1546797ac58cSKevin Wolf }
1547797ac58cSKevin Wolf 
aio_write_help(void)1548797ac58cSKevin Wolf static void aio_write_help(void)
1549797ac58cSKevin Wolf {
1550797ac58cSKevin Wolf     printf(
1551797ac58cSKevin Wolf "\n"
1552797ac58cSKevin Wolf " asynchronously writes a range of bytes from the given offset source\n"
1553797ac58cSKevin Wolf " from multiple buffers\n"
1554797ac58cSKevin Wolf "\n"
1555797ac58cSKevin Wolf " Example:\n"
1556797ac58cSKevin Wolf " 'aio_write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n"
1557797ac58cSKevin Wolf "\n"
1558797ac58cSKevin Wolf " Writes into a segment of the currently open file, using a buffer\n"
1559797ac58cSKevin Wolf " filled with a set pattern (0xcdcdcdcd).\n"
1560797ac58cSKevin Wolf " The write is performed asynchronously and the aio_flush command must be\n"
1561797ac58cSKevin Wolf " used to ensure all outstanding aio requests have been completed.\n"
1562b32d7a39SMax Reitz " Note that due to its asynchronous nature, this command will be\n"
1563b32d7a39SMax Reitz " considered successful once the request is submitted, independently\n"
1564b32d7a39SMax Reitz " of potential I/O errors or pattern mismatches.\n"
1565797ac58cSKevin Wolf " -C, -- report statistics in a machine parsable format\n"
1566770e0e0eSEric Blake " -f, -- use Force Unit Access semantics\n"
156737546ff2SEric Blake " -i, -- treat request as invalid, for exercising stats\n"
156800e2a04cSStefan Hajnoczi " -P, -- use different pattern to fill file\n"
1569797ac58cSKevin Wolf " -q, -- quiet mode, do not show I/O statistics\n"
157000e2a04cSStefan Hajnoczi " -r, -- register I/O buffer\n"
1571c2e001ccSEric Blake " -u, -- with -z, allow unmapping\n"
1572d004bd52SEric Blake " -z, -- write zeroes using blk_aio_pwrite_zeroes\n"
1573797ac58cSKevin Wolf "\n");
1574797ac58cSKevin Wolf }
1575797ac58cSKevin Wolf 
1576b32d7a39SMax Reitz static int aio_write_f(BlockBackend *blk, int argc, char **argv);
1577797ac58cSKevin Wolf 
1578797ac58cSKevin Wolf static const cmdinfo_t aio_write_cmd = {
1579797ac58cSKevin Wolf     .name       = "aio_write",
1580797ac58cSKevin Wolf     .cfunc      = aio_write_f,
1581887354bdSKevin Wolf     .perm       = BLK_PERM_WRITE,
1582797ac58cSKevin Wolf     .argmin     = 2,
1583797ac58cSKevin Wolf     .argmax     = -1,
158400e2a04cSStefan Hajnoczi     .args       = "[-Cfiqruz] [-P pattern] off len [len..]",
1585797ac58cSKevin Wolf     .oneline    = "asynchronously writes a number of bytes",
1586797ac58cSKevin Wolf     .help       = aio_write_help,
1587797ac58cSKevin Wolf };
1588797ac58cSKevin Wolf 
aio_write_f(BlockBackend * blk,int argc,char ** argv)1589b32d7a39SMax Reitz static int aio_write_f(BlockBackend *blk, int argc, char **argv)
1590797ac58cSKevin Wolf {
1591797ac58cSKevin Wolf     int nr_iov, c;
1592797ac58cSKevin Wolf     int pattern = 0xcd;
1593797ac58cSKevin Wolf     struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
1594797ac58cSKevin Wolf 
15954c7b7e9bSMax Reitz     ctx->blk = blk;
159600e2a04cSStefan Hajnoczi     while ((c = getopt(argc, argv, "CfiP:qruz")) != -1) {
1597797ac58cSKevin Wolf         switch (c) {
1598797ac58cSKevin Wolf         case 'C':
1599dc38852aSEric Blake             ctx->Cflag = true;
1600797ac58cSKevin Wolf             break;
1601770e0e0eSEric Blake         case 'f':
160200e2a04cSStefan Hajnoczi             ctx->flags |= BDRV_REQ_FUA;
1603770e0e0eSEric Blake             break;
1604797ac58cSKevin Wolf         case 'q':
1605dc38852aSEric Blake             ctx->qflag = true;
1606797ac58cSKevin Wolf             break;
160700e2a04cSStefan Hajnoczi         case 'r':
160800e2a04cSStefan Hajnoczi             ctx->flags |= BDRV_REQ_REGISTERED_BUF;
160900e2a04cSStefan Hajnoczi             break;
1610c2e001ccSEric Blake         case 'u':
161100e2a04cSStefan Hajnoczi             ctx->flags |= BDRV_REQ_MAY_UNMAP;
1612c2e001ccSEric Blake             break;
1613797ac58cSKevin Wolf         case 'P':
1614797ac58cSKevin Wolf             pattern = parse_pattern(optarg);
1615797ac58cSKevin Wolf             if (pattern < 0) {
1616797ac58cSKevin Wolf                 g_free(ctx);
1617b32d7a39SMax Reitz                 return -EINVAL;
1618797ac58cSKevin Wolf             }
1619797ac58cSKevin Wolf             break;
162037546ff2SEric Blake         case 'i':
162137546ff2SEric Blake             printf("injecting invalid write request\n");
162237546ff2SEric Blake             block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_WRITE);
162337546ff2SEric Blake             g_free(ctx);
1624b32d7a39SMax Reitz             return 0;
16255ceb7765SKevin Wolf         case 'z':
1626dc38852aSEric Blake             ctx->zflag = true;
16275ceb7765SKevin Wolf             break;
1628797ac58cSKevin Wolf         default:
1629797ac58cSKevin Wolf             g_free(ctx);
1630b444d0e9SMax Reitz             qemuio_command_usage(&aio_write_cmd);
1631b32d7a39SMax Reitz             return -EINVAL;
1632797ac58cSKevin Wolf         }
1633797ac58cSKevin Wolf     }
1634797ac58cSKevin Wolf 
1635797ac58cSKevin Wolf     if (optind > argc - 2) {
1636797ac58cSKevin Wolf         g_free(ctx);
1637b444d0e9SMax Reitz         qemuio_command_usage(&aio_write_cmd);
1638b32d7a39SMax Reitz         return -EINVAL;
1639797ac58cSKevin Wolf     }
1640797ac58cSKevin Wolf 
16415ceb7765SKevin Wolf     if (ctx->zflag && optind != argc - 2) {
16425ceb7765SKevin Wolf         printf("-z supports only a single length parameter\n");
16435ceb7765SKevin Wolf         g_free(ctx);
1644b32d7a39SMax Reitz         return -EINVAL;
16455ceb7765SKevin Wolf     }
16465ceb7765SKevin Wolf 
164700e2a04cSStefan Hajnoczi     if ((ctx->flags & BDRV_REQ_MAY_UNMAP) && !ctx->zflag) {
1648c2e001ccSEric Blake         printf("-u requires -z to be specified\n");
16494ca1d340SEric Blake         g_free(ctx);
1650b32d7a39SMax Reitz         return -EINVAL;
1651c2e001ccSEric Blake     }
1652c2e001ccSEric Blake 
16535ceb7765SKevin Wolf     if (ctx->zflag && ctx->Pflag) {
16545ceb7765SKevin Wolf         printf("-z and -P cannot be specified at the same time\n");
16555ceb7765SKevin Wolf         g_free(ctx);
1656b32d7a39SMax Reitz         return -EINVAL;
16575ceb7765SKevin Wolf     }
16585ceb7765SKevin Wolf 
165900e2a04cSStefan Hajnoczi     if (ctx->zflag && (ctx->flags & BDRV_REQ_REGISTERED_BUF)) {
166000e2a04cSStefan Hajnoczi         printf("cannot combine zero write with registered I/O buffer\n");
166100e2a04cSStefan Hajnoczi         g_free(ctx);
166200e2a04cSStefan Hajnoczi         return -EINVAL;
166300e2a04cSStefan Hajnoczi     }
166400e2a04cSStefan Hajnoczi 
1665797ac58cSKevin Wolf     ctx->offset = cvtnum(argv[optind]);
1666797ac58cSKevin Wolf     if (ctx->offset < 0) {
1667b32d7a39SMax Reitz         int ret = ctx->offset;
1668b32d7a39SMax Reitz         print_cvtnum_err(ret, argv[optind]);
1669797ac58cSKevin Wolf         g_free(ctx);
1670b32d7a39SMax Reitz         return ret;
1671797ac58cSKevin Wolf     }
1672797ac58cSKevin Wolf     optind++;
1673797ac58cSKevin Wolf 
16745ceb7765SKevin Wolf     if (ctx->zflag) {
16755ceb7765SKevin Wolf         int64_t count = cvtnum(argv[optind]);
16765ceb7765SKevin Wolf         if (count < 0) {
16775ceb7765SKevin Wolf             print_cvtnum_err(count, argv[optind]);
16780e01b76eSKevin Wolf             g_free(ctx);
1679b32d7a39SMax Reitz             return count;
16805ceb7765SKevin Wolf         }
16815ceb7765SKevin Wolf 
16825ceb7765SKevin Wolf         ctx->qiov.size = count;
168300e2a04cSStefan Hajnoczi         blk_aio_pwrite_zeroes(blk, ctx->offset, count, ctx->flags,
168400e2a04cSStefan Hajnoczi                               aio_write_done, ctx);
16855ceb7765SKevin Wolf     } else {
1686797ac58cSKevin Wolf         nr_iov = argc - optind;
16875ceb7765SKevin Wolf         ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov,
168800e2a04cSStefan Hajnoczi                                 pattern, ctx->flags & BDRV_REQ_REGISTERED_BUF);
1689797ac58cSKevin Wolf         if (ctx->buf == NULL) {
1690556c2b60SAlberto Garcia             block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_WRITE);
1691797ac58cSKevin Wolf             g_free(ctx);
1692b32d7a39SMax Reitz             return -EINVAL;
1693797ac58cSKevin Wolf         }
1694797ac58cSKevin Wolf 
169550290c00SAlex Bennée         clock_gettime(CLOCK_MONOTONIC, &ctx->t1);
16964c7b7e9bSMax Reitz         block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size,
16974c7b7e9bSMax Reitz                          BLOCK_ACCT_WRITE);
16985ceb7765SKevin Wolf 
169900e2a04cSStefan Hajnoczi         blk_aio_pwritev(blk, ctx->offset, &ctx->qiov, ctx->flags,
170000e2a04cSStefan Hajnoczi                         aio_write_done, ctx);
17015ceb7765SKevin Wolf     }
1702b32d7a39SMax Reitz 
1703b32d7a39SMax Reitz     return 0;
1704797ac58cSKevin Wolf }
1705797ac58cSKevin Wolf 
aio_flush_f(BlockBackend * blk,int argc,char ** argv)1706b32d7a39SMax Reitz static int aio_flush_f(BlockBackend *blk, int argc, char **argv)
1707797ac58cSKevin Wolf {
1708556c2b60SAlberto Garcia     BlockAcctCookie cookie;
1709556c2b60SAlberto Garcia     block_acct_start(blk_get_stats(blk), &cookie, 0, BLOCK_ACCT_FLUSH);
17104c7b7e9bSMax Reitz     blk_drain_all();
1711556c2b60SAlberto Garcia     block_acct_done(blk_get_stats(blk), &cookie);
1712b32d7a39SMax Reitz     return 0;
1713797ac58cSKevin Wolf }
1714797ac58cSKevin Wolf 
1715797ac58cSKevin Wolf static const cmdinfo_t aio_flush_cmd = {
1716797ac58cSKevin Wolf     .name       = "aio_flush",
1717797ac58cSKevin Wolf     .cfunc      = aio_flush_f,
1718797ac58cSKevin Wolf     .oneline    = "completes all outstanding aio requests"
1719797ac58cSKevin Wolf };
1720797ac58cSKevin Wolf 
flush_f(BlockBackend * blk,int argc,char ** argv)1721b32d7a39SMax Reitz static int flush_f(BlockBackend *blk, int argc, char **argv)
1722797ac58cSKevin Wolf {
1723b32d7a39SMax Reitz     return blk_flush(blk);
1724797ac58cSKevin Wolf }
1725797ac58cSKevin Wolf 
1726797ac58cSKevin Wolf static const cmdinfo_t flush_cmd = {
1727797ac58cSKevin Wolf     .name       = "flush",
1728797ac58cSKevin Wolf     .altname    = "f",
1729797ac58cSKevin Wolf     .cfunc      = flush_f,
1730797ac58cSKevin Wolf     .oneline    = "flush all in-core file state to disk",
1731797ac58cSKevin Wolf };
1732797ac58cSKevin Wolf 
tosector(int64_t bytes)17336d43eaa3SSam Li static inline int64_t tosector(int64_t bytes)
17346d43eaa3SSam Li {
17356d43eaa3SSam Li     return bytes >> BDRV_SECTOR_BITS;
17366d43eaa3SSam Li }
17376d43eaa3SSam Li 
zone_report_f(BlockBackend * blk,int argc,char ** argv)17386d43eaa3SSam Li static int zone_report_f(BlockBackend *blk, int argc, char **argv)
17396d43eaa3SSam Li {
17406d43eaa3SSam Li     int ret;
17416d43eaa3SSam Li     int64_t offset;
17426d43eaa3SSam Li     unsigned int nr_zones;
17436d43eaa3SSam Li 
17446d43eaa3SSam Li     ++optind;
17456d43eaa3SSam Li     offset = cvtnum(argv[optind]);
17466d43eaa3SSam Li     ++optind;
17476d43eaa3SSam Li     nr_zones = cvtnum(argv[optind]);
17486d43eaa3SSam Li 
17496d43eaa3SSam Li     g_autofree BlockZoneDescriptor *zones = NULL;
17506d43eaa3SSam Li     zones = g_new(BlockZoneDescriptor, nr_zones);
17516d43eaa3SSam Li     ret = blk_zone_report(blk, offset, &nr_zones, zones);
17526d43eaa3SSam Li     if (ret < 0) {
17536d43eaa3SSam Li         printf("zone report failed: %s\n", strerror(-ret));
17546d43eaa3SSam Li     } else {
17556d43eaa3SSam Li         for (int i = 0; i < nr_zones; ++i) {
17566d43eaa3SSam Li             printf("start: 0x%" PRIx64 ", len 0x%" PRIx64 ", "
17576d43eaa3SSam Li                    "cap"" 0x%" PRIx64 ", wptr 0x%" PRIx64 ", "
17586d43eaa3SSam Li                    "zcond:%u, [type: %u]\n",
17596d43eaa3SSam Li                     tosector(zones[i].start), tosector(zones[i].length),
17606d43eaa3SSam Li                     tosector(zones[i].cap), tosector(zones[i].wp),
17616d43eaa3SSam Li                     zones[i].state, zones[i].type);
17626d43eaa3SSam Li         }
17636d43eaa3SSam Li     }
17646d43eaa3SSam Li     return ret;
17656d43eaa3SSam Li }
17666d43eaa3SSam Li 
17676d43eaa3SSam Li static const cmdinfo_t zone_report_cmd = {
17686d43eaa3SSam Li     .name = "zone_report",
17696d43eaa3SSam Li     .altname = "zrp",
17706d43eaa3SSam Li     .cfunc = zone_report_f,
17716d43eaa3SSam Li     .argmin = 2,
17726d43eaa3SSam Li     .argmax = 2,
17736d43eaa3SSam Li     .args = "offset number",
17746d43eaa3SSam Li     .oneline = "report zone information",
17756d43eaa3SSam Li };
17766d43eaa3SSam Li 
zone_open_f(BlockBackend * blk,int argc,char ** argv)17776d43eaa3SSam Li static int zone_open_f(BlockBackend *blk, int argc, char **argv)
17786d43eaa3SSam Li {
17796d43eaa3SSam Li     int ret;
17806d43eaa3SSam Li     int64_t offset, len;
17816d43eaa3SSam Li     ++optind;
17826d43eaa3SSam Li     offset = cvtnum(argv[optind]);
17836d43eaa3SSam Li     ++optind;
17846d43eaa3SSam Li     len = cvtnum(argv[optind]);
17856d43eaa3SSam Li     ret = blk_zone_mgmt(blk, BLK_ZO_OPEN, offset, len);
17866d43eaa3SSam Li     if (ret < 0) {
17876d43eaa3SSam Li         printf("zone open failed: %s\n", strerror(-ret));
17886d43eaa3SSam Li     }
17896d43eaa3SSam Li     return ret;
17906d43eaa3SSam Li }
17916d43eaa3SSam Li 
17926d43eaa3SSam Li static const cmdinfo_t zone_open_cmd = {
17936d43eaa3SSam Li     .name = "zone_open",
17946d43eaa3SSam Li     .altname = "zo",
17956d43eaa3SSam Li     .cfunc = zone_open_f,
17966d43eaa3SSam Li     .argmin = 2,
17976d43eaa3SSam Li     .argmax = 2,
17986d43eaa3SSam Li     .args = "offset len",
17996d43eaa3SSam Li     .oneline = "explicit open a range of zones in zone block device",
18006d43eaa3SSam Li };
18016d43eaa3SSam Li 
zone_close_f(BlockBackend * blk,int argc,char ** argv)18026d43eaa3SSam Li static int zone_close_f(BlockBackend *blk, int argc, char **argv)
18036d43eaa3SSam Li {
18046d43eaa3SSam Li     int ret;
18056d43eaa3SSam Li     int64_t offset, len;
18066d43eaa3SSam Li     ++optind;
18076d43eaa3SSam Li     offset = cvtnum(argv[optind]);
18086d43eaa3SSam Li     ++optind;
18096d43eaa3SSam Li     len = cvtnum(argv[optind]);
18106d43eaa3SSam Li     ret = blk_zone_mgmt(blk, BLK_ZO_CLOSE, offset, len);
18116d43eaa3SSam Li     if (ret < 0) {
18126d43eaa3SSam Li         printf("zone close failed: %s\n", strerror(-ret));
18136d43eaa3SSam Li     }
18146d43eaa3SSam Li     return ret;
18156d43eaa3SSam Li }
18166d43eaa3SSam Li 
18176d43eaa3SSam Li static const cmdinfo_t zone_close_cmd = {
18186d43eaa3SSam Li     .name = "zone_close",
18196d43eaa3SSam Li     .altname = "zc",
18206d43eaa3SSam Li     .cfunc = zone_close_f,
18216d43eaa3SSam Li     .argmin = 2,
18226d43eaa3SSam Li     .argmax = 2,
18236d43eaa3SSam Li     .args = "offset len",
18246d43eaa3SSam Li     .oneline = "close a range of zones in zone block device",
18256d43eaa3SSam Li };
18266d43eaa3SSam Li 
zone_finish_f(BlockBackend * blk,int argc,char ** argv)18276d43eaa3SSam Li static int zone_finish_f(BlockBackend *blk, int argc, char **argv)
18286d43eaa3SSam Li {
18296d43eaa3SSam Li     int ret;
18306d43eaa3SSam Li     int64_t offset, len;
18316d43eaa3SSam Li     ++optind;
18326d43eaa3SSam Li     offset = cvtnum(argv[optind]);
18336d43eaa3SSam Li     ++optind;
18346d43eaa3SSam Li     len = cvtnum(argv[optind]);
18356d43eaa3SSam Li     ret = blk_zone_mgmt(blk, BLK_ZO_FINISH, offset, len);
18366d43eaa3SSam Li     if (ret < 0) {
18376d43eaa3SSam Li         printf("zone finish failed: %s\n", strerror(-ret));
18386d43eaa3SSam Li     }
18396d43eaa3SSam Li     return ret;
18406d43eaa3SSam Li }
18416d43eaa3SSam Li 
18426d43eaa3SSam Li static const cmdinfo_t zone_finish_cmd = {
18436d43eaa3SSam Li     .name = "zone_finish",
18446d43eaa3SSam Li     .altname = "zf",
18456d43eaa3SSam Li     .cfunc = zone_finish_f,
18466d43eaa3SSam Li     .argmin = 2,
18476d43eaa3SSam Li     .argmax = 2,
18486d43eaa3SSam Li     .args = "offset len",
18496d43eaa3SSam Li     .oneline = "finish a range of zones in zone block device",
18506d43eaa3SSam Li };
18516d43eaa3SSam Li 
zone_reset_f(BlockBackend * blk,int argc,char ** argv)18526d43eaa3SSam Li static int zone_reset_f(BlockBackend *blk, int argc, char **argv)
18536d43eaa3SSam Li {
18546d43eaa3SSam Li     int ret;
18556d43eaa3SSam Li     int64_t offset, len;
18566d43eaa3SSam Li     ++optind;
18576d43eaa3SSam Li     offset = cvtnum(argv[optind]);
18586d43eaa3SSam Li     ++optind;
18596d43eaa3SSam Li     len = cvtnum(argv[optind]);
18606d43eaa3SSam Li     ret = blk_zone_mgmt(blk, BLK_ZO_RESET, offset, len);
18616d43eaa3SSam Li     if (ret < 0) {
18626d43eaa3SSam Li         printf("zone reset failed: %s\n", strerror(-ret));
18636d43eaa3SSam Li     }
18646d43eaa3SSam Li     return ret;
18656d43eaa3SSam Li }
18666d43eaa3SSam Li 
18676d43eaa3SSam Li static const cmdinfo_t zone_reset_cmd = {
18686d43eaa3SSam Li     .name = "zone_reset",
18696d43eaa3SSam Li     .altname = "zrs",
18706d43eaa3SSam Li     .cfunc = zone_reset_f,
18716d43eaa3SSam Li     .argmin = 2,
18726d43eaa3SSam Li     .argmax = 2,
18736d43eaa3SSam Li     .args = "offset len",
18746d43eaa3SSam Li     .oneline = "reset a zone write pointer in zone block device",
18756d43eaa3SSam Li };
18766d43eaa3SSam Li 
do_aio_zone_append(BlockBackend * blk,QEMUIOVector * qiov,int64_t * offset,int flags,int * total)1877fe4fe70dSSam Li static int do_aio_zone_append(BlockBackend *blk, QEMUIOVector *qiov,
1878fe4fe70dSSam Li                               int64_t *offset, int flags, int *total)
1879fe4fe70dSSam Li {
1880fe4fe70dSSam Li     int async_ret = NOT_DONE;
1881fe4fe70dSSam Li 
1882fe4fe70dSSam Li     blk_aio_zone_append(blk, offset, qiov, flags, aio_rw_done, &async_ret);
1883fe4fe70dSSam Li     while (async_ret == NOT_DONE) {
1884fe4fe70dSSam Li         main_loop_wait(false);
1885fe4fe70dSSam Li     }
1886fe4fe70dSSam Li 
1887fe4fe70dSSam Li     *total = qiov->size;
1888fe4fe70dSSam Li     return async_ret < 0 ? async_ret : 1;
1889fe4fe70dSSam Li }
1890fe4fe70dSSam Li 
zone_append_f(BlockBackend * blk,int argc,char ** argv)1891fe4fe70dSSam Li static int zone_append_f(BlockBackend *blk, int argc, char **argv)
1892fe4fe70dSSam Li {
1893fe4fe70dSSam Li     int ret;
1894fe4fe70dSSam Li     bool pflag = false;
1895fe4fe70dSSam Li     int flags = 0;
1896fe4fe70dSSam Li     int total = 0;
1897fe4fe70dSSam Li     int64_t offset;
1898fe4fe70dSSam Li     char *buf;
1899fe4fe70dSSam Li     int c, nr_iov;
1900fe4fe70dSSam Li     int pattern = 0xcd;
1901fe4fe70dSSam Li     QEMUIOVector qiov;
1902fe4fe70dSSam Li 
1903fe4fe70dSSam Li     if (optind > argc - 3) {
1904fe4fe70dSSam Li         return -EINVAL;
1905fe4fe70dSSam Li     }
1906fe4fe70dSSam Li 
1907fe4fe70dSSam Li     if ((c = getopt(argc, argv, "p")) != -1) {
1908fe4fe70dSSam Li         pflag = true;
1909fe4fe70dSSam Li     }
1910fe4fe70dSSam Li 
1911fe4fe70dSSam Li     offset = cvtnum(argv[optind]);
1912fe4fe70dSSam Li     if (offset < 0) {
1913fe4fe70dSSam Li         print_cvtnum_err(offset, argv[optind]);
1914fe4fe70dSSam Li         return offset;
1915fe4fe70dSSam Li     }
1916fe4fe70dSSam Li     optind++;
1917fe4fe70dSSam Li     nr_iov = argc - optind;
1918fe4fe70dSSam Li     buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, pattern,
1919fe4fe70dSSam Li                        flags & BDRV_REQ_REGISTERED_BUF);
1920fe4fe70dSSam Li     if (buf == NULL) {
1921fe4fe70dSSam Li         return -EINVAL;
1922fe4fe70dSSam Li     }
1923fe4fe70dSSam Li     ret = do_aio_zone_append(blk, &qiov, &offset, flags, &total);
1924fe4fe70dSSam Li     if (ret < 0) {
1925fe4fe70dSSam Li         printf("zone append failed: %s\n", strerror(-ret));
1926fe4fe70dSSam Li         goto out;
1927fe4fe70dSSam Li     }
1928fe4fe70dSSam Li 
1929fe4fe70dSSam Li     if (pflag) {
1930fe4fe70dSSam Li         printf("After zap done, the append sector is 0x%" PRIx64 "\n",
1931fe4fe70dSSam Li                tosector(offset));
1932fe4fe70dSSam Li     }
1933fe4fe70dSSam Li 
1934fe4fe70dSSam Li out:
1935fe4fe70dSSam Li     qemu_io_free(blk, buf, qiov.size,
1936fe4fe70dSSam Li                  flags & BDRV_REQ_REGISTERED_BUF);
1937fe4fe70dSSam Li     qemu_iovec_destroy(&qiov);
1938fe4fe70dSSam Li     return ret;
1939fe4fe70dSSam Li }
1940fe4fe70dSSam Li 
1941fe4fe70dSSam Li static const cmdinfo_t zone_append_cmd = {
1942fe4fe70dSSam Li     .name = "zone_append",
1943fe4fe70dSSam Li     .altname = "zap",
1944fe4fe70dSSam Li     .cfunc = zone_append_f,
1945fe4fe70dSSam Li     .argmin = 3,
1946fe4fe70dSSam Li     .argmax = 4,
1947fe4fe70dSSam Li     .args = "offset len [len..]",
1948fe4fe70dSSam Li     .oneline = "append write a number of bytes at a specified offset",
1949fe4fe70dSSam Li };
1950fe4fe70dSSam Li 
195142ba0225SVladimir Sementsov-Ogievskiy static int truncate_f(BlockBackend *blk, int argc, char **argv);
195242ba0225SVladimir Sementsov-Ogievskiy static const cmdinfo_t truncate_cmd = {
195342ba0225SVladimir Sementsov-Ogievskiy     .name       = "truncate",
195442ba0225SVladimir Sementsov-Ogievskiy     .altname    = "t",
195542ba0225SVladimir Sementsov-Ogievskiy     .cfunc      = truncate_f,
195642ba0225SVladimir Sementsov-Ogievskiy     .perm       = BLK_PERM_WRITE | BLK_PERM_RESIZE,
195742ba0225SVladimir Sementsov-Ogievskiy     .argmin     = 1,
195842ba0225SVladimir Sementsov-Ogievskiy     .argmax     = 3,
195942ba0225SVladimir Sementsov-Ogievskiy     .args       = "[-m prealloc_mode] off",
196042ba0225SVladimir Sementsov-Ogievskiy     .oneline    = "truncates the current file at the given offset",
196142ba0225SVladimir Sementsov-Ogievskiy };
196242ba0225SVladimir Sementsov-Ogievskiy 
truncate_f(BlockBackend * blk,int argc,char ** argv)1963b32d7a39SMax Reitz static int truncate_f(BlockBackend *blk, int argc, char **argv)
1964797ac58cSKevin Wolf {
1965ed3d2ec9SMax Reitz     Error *local_err = NULL;
1966797ac58cSKevin Wolf     int64_t offset;
196742ba0225SVladimir Sementsov-Ogievskiy     int c, ret;
196842ba0225SVladimir Sementsov-Ogievskiy     PreallocMode prealloc = PREALLOC_MODE_OFF;
1969797ac58cSKevin Wolf 
197042ba0225SVladimir Sementsov-Ogievskiy     while ((c = getopt(argc, argv, "m:")) != -1) {
197142ba0225SVladimir Sementsov-Ogievskiy         switch (c) {
197242ba0225SVladimir Sementsov-Ogievskiy         case 'm':
197342ba0225SVladimir Sementsov-Ogievskiy             prealloc = qapi_enum_parse(&PreallocMode_lookup, optarg,
197442ba0225SVladimir Sementsov-Ogievskiy                                        PREALLOC_MODE__MAX, NULL);
197542ba0225SVladimir Sementsov-Ogievskiy             if (prealloc == PREALLOC_MODE__MAX) {
197642ba0225SVladimir Sementsov-Ogievskiy                 error_report("Invalid preallocation mode '%s'", optarg);
197742ba0225SVladimir Sementsov-Ogievskiy                 return -EINVAL;
197842ba0225SVladimir Sementsov-Ogievskiy             }
197942ba0225SVladimir Sementsov-Ogievskiy             break;
198042ba0225SVladimir Sementsov-Ogievskiy         default:
198142ba0225SVladimir Sementsov-Ogievskiy             qemuio_command_usage(&truncate_cmd);
198242ba0225SVladimir Sementsov-Ogievskiy             return -EINVAL;
198342ba0225SVladimir Sementsov-Ogievskiy         }
198442ba0225SVladimir Sementsov-Ogievskiy     }
198542ba0225SVladimir Sementsov-Ogievskiy 
198642ba0225SVladimir Sementsov-Ogievskiy     offset = cvtnum(argv[optind]);
1987797ac58cSKevin Wolf     if (offset < 0) {
1988a9ecfa00SJohn Snow         print_cvtnum_err(offset, argv[1]);
1989b32d7a39SMax Reitz         return offset;
1990797ac58cSKevin Wolf     }
1991797ac58cSKevin Wolf 
1992e8d04f92SMax Reitz     /*
1993e8d04f92SMax Reitz      * qemu-io is a debugging tool, so let us be strict here and pass
1994e8d04f92SMax Reitz      * exact=true.  It is better to err on the "emit more errors" side
1995e8d04f92SMax Reitz      * than to be overly permissive.
1996e8d04f92SMax Reitz      */
199742ba0225SVladimir Sementsov-Ogievskiy     ret = blk_truncate(blk, offset, false, prealloc, 0, &local_err);
1998797ac58cSKevin Wolf     if (ret < 0) {
1999ed3d2ec9SMax Reitz         error_report_err(local_err);
2000b32d7a39SMax Reitz         return ret;
2001797ac58cSKevin Wolf     }
2002b32d7a39SMax Reitz 
2003b32d7a39SMax Reitz     return 0;
2004797ac58cSKevin Wolf }
2005797ac58cSKevin Wolf 
length_f(BlockBackend * blk,int argc,char ** argv)2006b32d7a39SMax Reitz static int length_f(BlockBackend *blk, int argc, char **argv)
2007797ac58cSKevin Wolf {
2008797ac58cSKevin Wolf     int64_t size;
2009797ac58cSKevin Wolf     char s1[64];
2010797ac58cSKevin Wolf 
20114c7b7e9bSMax Reitz     size = blk_getlength(blk);
2012797ac58cSKevin Wolf     if (size < 0) {
2013797ac58cSKevin Wolf         printf("getlength: %s\n", strerror(-size));
2014b32d7a39SMax Reitz         return size;
2015797ac58cSKevin Wolf     }
2016797ac58cSKevin Wolf 
2017797ac58cSKevin Wolf     cvtstr(size, s1, sizeof(s1));
2018797ac58cSKevin Wolf     printf("%s\n", s1);
2019b32d7a39SMax Reitz     return 0;
2020797ac58cSKevin Wolf }
2021797ac58cSKevin Wolf 
2022797ac58cSKevin Wolf 
2023797ac58cSKevin Wolf static const cmdinfo_t length_cmd = {
2024797ac58cSKevin Wolf     .name   = "length",
2025797ac58cSKevin Wolf     .altname    = "l",
2026797ac58cSKevin Wolf     .cfunc      = length_f,
2027797ac58cSKevin Wolf     .oneline    = "gets the length of the current file",
2028797ac58cSKevin Wolf };
2029797ac58cSKevin Wolf 
2030797ac58cSKevin Wolf 
info_f(BlockBackend * blk,int argc,char ** argv)2031b32d7a39SMax Reitz static int info_f(BlockBackend *blk, int argc, char **argv)
2032797ac58cSKevin Wolf {
20334c7b7e9bSMax Reitz     BlockDriverState *bs = blk_bs(blk);
2034797ac58cSKevin Wolf     BlockDriverInfo bdi;
2035a8d8ecb7SMax Reitz     ImageInfoSpecific *spec_info;
20361bf6e9caSAndrey Shinkevich     Error *local_err = NULL;
2037797ac58cSKevin Wolf     char s1[64], s2[64];
2038797ac58cSKevin Wolf     int ret;
2039797ac58cSKevin Wolf 
20403574499aSKevin Wolf     GLOBAL_STATE_CODE();
20413574499aSKevin Wolf     GRAPH_RDLOCK_GUARD_MAINLOOP();
20423574499aSKevin Wolf 
2043797ac58cSKevin Wolf     if (bs->drv && bs->drv->format_name) {
2044797ac58cSKevin Wolf         printf("format name: %s\n", bs->drv->format_name);
2045797ac58cSKevin Wolf     }
2046797ac58cSKevin Wolf     if (bs->drv && bs->drv->protocol_name) {
2047797ac58cSKevin Wolf         printf("format name: %s\n", bs->drv->protocol_name);
2048797ac58cSKevin Wolf     }
2049797ac58cSKevin Wolf 
2050797ac58cSKevin Wolf     ret = bdrv_get_info(bs, &bdi);
2051797ac58cSKevin Wolf     if (ret) {
2052b32d7a39SMax Reitz         return ret;
2053797ac58cSKevin Wolf     }
2054797ac58cSKevin Wolf 
2055797ac58cSKevin Wolf     cvtstr(bdi.cluster_size, s1, sizeof(s1));
2056797ac58cSKevin Wolf     cvtstr(bdi.vm_state_offset, s2, sizeof(s2));
2057797ac58cSKevin Wolf 
2058797ac58cSKevin Wolf     printf("cluster size: %s\n", s1);
2059797ac58cSKevin Wolf     printf("vm state offset: %s\n", s2);
2060797ac58cSKevin Wolf 
20611bf6e9caSAndrey Shinkevich     spec_info = bdrv_get_specific_info(bs, &local_err);
20621bf6e9caSAndrey Shinkevich     if (local_err) {
20631bf6e9caSAndrey Shinkevich         error_report_err(local_err);
20641bf6e9caSAndrey Shinkevich         return -EIO;
20651bf6e9caSAndrey Shinkevich     }
2066a8d8ecb7SMax Reitz     if (spec_info) {
20673716470bSHanna Reitz         bdrv_image_info_specific_dump(spec_info,
206876c9e975SHanna Reitz                                       "Format specific information:\n",
206976c9e975SHanna Reitz                                       0);
2070a8d8ecb7SMax Reitz         qapi_free_ImageInfoSpecific(spec_info);
2071a8d8ecb7SMax Reitz     }
2072b32d7a39SMax Reitz 
2073b32d7a39SMax Reitz     return 0;
2074797ac58cSKevin Wolf }
2075797ac58cSKevin Wolf 
2076797ac58cSKevin Wolf 
2077797ac58cSKevin Wolf 
2078797ac58cSKevin Wolf static const cmdinfo_t info_cmd = {
2079797ac58cSKevin Wolf     .name       = "info",
2080797ac58cSKevin Wolf     .altname    = "i",
2081797ac58cSKevin Wolf     .cfunc      = info_f,
2082797ac58cSKevin Wolf     .oneline    = "prints information about the current file",
2083797ac58cSKevin Wolf };
2084797ac58cSKevin Wolf 
discard_help(void)2085797ac58cSKevin Wolf static void discard_help(void)
2086797ac58cSKevin Wolf {
2087797ac58cSKevin Wolf     printf(
2088797ac58cSKevin Wolf "\n"
2089797ac58cSKevin Wolf " discards a range of bytes from the given offset\n"
2090797ac58cSKevin Wolf "\n"
2091797ac58cSKevin Wolf " Example:\n"
2092797ac58cSKevin Wolf " 'discard 512 1k' - discards 1 kilobyte from 512 bytes into the file\n"
2093797ac58cSKevin Wolf "\n"
2094797ac58cSKevin Wolf " Discards a segment of the currently open file.\n"
2095797ac58cSKevin Wolf " -C, -- report statistics in a machine parsable format\n"
2096797ac58cSKevin Wolf " -q, -- quiet mode, do not show I/O statistics\n"
2097797ac58cSKevin Wolf "\n");
2098797ac58cSKevin Wolf }
2099797ac58cSKevin Wolf 
2100b32d7a39SMax Reitz static int discard_f(BlockBackend *blk, int argc, char **argv);
2101797ac58cSKevin Wolf 
2102797ac58cSKevin Wolf static const cmdinfo_t discard_cmd = {
2103797ac58cSKevin Wolf     .name       = "discard",
2104797ac58cSKevin Wolf     .altname    = "d",
2105797ac58cSKevin Wolf     .cfunc      = discard_f,
2106887354bdSKevin Wolf     .perm       = BLK_PERM_WRITE,
2107797ac58cSKevin Wolf     .argmin     = 2,
2108797ac58cSKevin Wolf     .argmax     = -1,
2109797ac58cSKevin Wolf     .args       = "[-Cq] off len",
2110797ac58cSKevin Wolf     .oneline    = "discards a number of bytes at a specified offset",
2111797ac58cSKevin Wolf     .help       = discard_help,
2112797ac58cSKevin Wolf };
2113797ac58cSKevin Wolf 
discard_f(BlockBackend * blk,int argc,char ** argv)2114b32d7a39SMax Reitz static int discard_f(BlockBackend *blk, int argc, char **argv)
2115797ac58cSKevin Wolf {
211650290c00SAlex Bennée     struct timespec t1, t2;
2117dc38852aSEric Blake     bool Cflag = false, qflag = false;
2118797ac58cSKevin Wolf     int c, ret;
2119f5a5ca79SManos Pitsidianakis     int64_t offset, bytes;
2120797ac58cSKevin Wolf 
2121b062ad86SEric Blake     while ((c = getopt(argc, argv, "Cq")) != -1) {
2122797ac58cSKevin Wolf         switch (c) {
2123797ac58cSKevin Wolf         case 'C':
2124dc38852aSEric Blake             Cflag = true;
2125797ac58cSKevin Wolf             break;
2126797ac58cSKevin Wolf         case 'q':
2127dc38852aSEric Blake             qflag = true;
2128797ac58cSKevin Wolf             break;
2129797ac58cSKevin Wolf         default:
2130b444d0e9SMax Reitz             qemuio_command_usage(&discard_cmd);
2131b32d7a39SMax Reitz             return -EINVAL;
2132797ac58cSKevin Wolf         }
2133797ac58cSKevin Wolf     }
2134797ac58cSKevin Wolf 
2135797ac58cSKevin Wolf     if (optind != argc - 2) {
2136b444d0e9SMax Reitz         qemuio_command_usage(&discard_cmd);
2137b32d7a39SMax Reitz         return -EINVAL;
2138797ac58cSKevin Wolf     }
2139797ac58cSKevin Wolf 
2140797ac58cSKevin Wolf     offset = cvtnum(argv[optind]);
2141797ac58cSKevin Wolf     if (offset < 0) {
2142a9ecfa00SJohn Snow         print_cvtnum_err(offset, argv[optind]);
2143b32d7a39SMax Reitz         return offset;
2144797ac58cSKevin Wolf     }
2145797ac58cSKevin Wolf 
2146797ac58cSKevin Wolf     optind++;
2147f5a5ca79SManos Pitsidianakis     bytes = cvtnum(argv[optind]);
2148f5a5ca79SManos Pitsidianakis     if (bytes < 0) {
2149f5a5ca79SManos Pitsidianakis         print_cvtnum_err(bytes, argv[optind]);
2150b32d7a39SMax Reitz         return bytes;
215141ae31e3SAlberto Garcia     } else if (bytes > BDRV_REQUEST_MAX_BYTES) {
21529b0beaf3SJohn Snow         printf("length cannot exceed %"PRIu64", given %s\n",
215341ae31e3SAlberto Garcia                (uint64_t)BDRV_REQUEST_MAX_BYTES, argv[optind]);
2154b32d7a39SMax Reitz         return -EINVAL;
2155797ac58cSKevin Wolf     }
2156797ac58cSKevin Wolf 
215750290c00SAlex Bennée     clock_gettime(CLOCK_MONOTONIC, &t1);
2158f5a5ca79SManos Pitsidianakis     ret = blk_pdiscard(blk, offset, bytes);
215950290c00SAlex Bennée     clock_gettime(CLOCK_MONOTONIC, &t2);
2160797ac58cSKevin Wolf 
2161797ac58cSKevin Wolf     if (ret < 0) {
2162797ac58cSKevin Wolf         printf("discard failed: %s\n", strerror(-ret));
2163b32d7a39SMax Reitz         return ret;
2164797ac58cSKevin Wolf     }
2165797ac58cSKevin Wolf 
2166797ac58cSKevin Wolf     /* Finally, report back -- -C gives a parsable format */
2167797ac58cSKevin Wolf     if (!qflag) {
2168797ac58cSKevin Wolf         t2 = tsub(t2, t1);
2169f5a5ca79SManos Pitsidianakis         print_report("discard", &t2, offset, bytes, bytes, 1, Cflag);
2170797ac58cSKevin Wolf     }
2171b32d7a39SMax Reitz 
2172b32d7a39SMax Reitz     return 0;
2173797ac58cSKevin Wolf }
2174797ac58cSKevin Wolf 
alloc_f(BlockBackend * blk,int argc,char ** argv)2175b32d7a39SMax Reitz static int alloc_f(BlockBackend *blk, int argc, char **argv)
2176797ac58cSKevin Wolf {
21774c7b7e9bSMax Reitz     BlockDriverState *bs = blk_bs(blk);
2178d6a644bbSEric Blake     int64_t offset, start, remaining, count;
2179797ac58cSKevin Wolf     char s1[64];
2180d6a644bbSEric Blake     int ret;
2181d6a644bbSEric Blake     int64_t num, sum_alloc;
2182797ac58cSKevin Wolf 
2183d6a644bbSEric Blake     start = offset = cvtnum(argv[1]);
2184797ac58cSKevin Wolf     if (offset < 0) {
2185a9ecfa00SJohn Snow         print_cvtnum_err(offset, argv[1]);
2186b32d7a39SMax Reitz         return offset;
2187797ac58cSKevin Wolf     }
2188797ac58cSKevin Wolf 
2189797ac58cSKevin Wolf     if (argc == 3) {
21904401fdc7SEric Blake         count = cvtnum(argv[2]);
21914401fdc7SEric Blake         if (count < 0) {
21924401fdc7SEric Blake             print_cvtnum_err(count, argv[2]);
2193b32d7a39SMax Reitz             return count;
2194797ac58cSKevin Wolf         }
2195797ac58cSKevin Wolf     } else {
21964401fdc7SEric Blake         count = BDRV_SECTOR_SIZE;
2197797ac58cSKevin Wolf     }
2198797ac58cSKevin Wolf 
2199d6a644bbSEric Blake     remaining = count;
2200797ac58cSKevin Wolf     sum_alloc = 0;
2201797ac58cSKevin Wolf     while (remaining) {
2202d6a644bbSEric Blake         ret = bdrv_is_allocated(bs, offset, remaining, &num);
2203d663640cSPaolo Bonzini         if (ret < 0) {
2204d663640cSPaolo Bonzini             printf("is_allocated failed: %s\n", strerror(-ret));
2205b32d7a39SMax Reitz             return ret;
2206d663640cSPaolo Bonzini         }
2207d6a644bbSEric Blake         offset += num;
2208797ac58cSKevin Wolf         remaining -= num;
2209797ac58cSKevin Wolf         if (ret) {
2210797ac58cSKevin Wolf             sum_alloc += num;
2211797ac58cSKevin Wolf         }
2212797ac58cSKevin Wolf         if (num == 0) {
2213d6a644bbSEric Blake             count -= remaining;
2214797ac58cSKevin Wolf             remaining = 0;
2215797ac58cSKevin Wolf         }
2216797ac58cSKevin Wolf     }
2217797ac58cSKevin Wolf 
2218d6a644bbSEric Blake     cvtstr(start, s1, sizeof(s1));
2219797ac58cSKevin Wolf 
22204401fdc7SEric Blake     printf("%"PRId64"/%"PRId64" bytes allocated at offset %s\n",
2221d6a644bbSEric Blake            sum_alloc, count, s1);
2222b32d7a39SMax Reitz     return 0;
2223797ac58cSKevin Wolf }
2224797ac58cSKevin Wolf 
2225797ac58cSKevin Wolf static const cmdinfo_t alloc_cmd = {
2226797ac58cSKevin Wolf     .name       = "alloc",
2227797ac58cSKevin Wolf     .altname    = "a",
2228797ac58cSKevin Wolf     .argmin     = 1,
2229797ac58cSKevin Wolf     .argmax     = 2,
2230797ac58cSKevin Wolf     .cfunc      = alloc_f,
22314401fdc7SEric Blake     .args       = "offset [count]",
22324401fdc7SEric Blake     .oneline    = "checks if offset is allocated in the file",
2233797ac58cSKevin Wolf };
2234797ac58cSKevin Wolf 
2235797ac58cSKevin Wolf 
map_is_allocated(BlockDriverState * bs,int64_t offset,int64_t bytes,int64_t * pnum)2236d6a644bbSEric Blake static int map_is_allocated(BlockDriverState *bs, int64_t offset,
2237d6a644bbSEric Blake                             int64_t bytes, int64_t *pnum)
2238797ac58cSKevin Wolf {
2239d6a644bbSEric Blake     int64_t num;
2240797ac58cSKevin Wolf     int ret, firstret;
2241797ac58cSKevin Wolf 
2242087f2fb3SEric Blake     ret = bdrv_is_allocated(bs, offset, bytes, &num);
2243797ac58cSKevin Wolf     if (ret < 0) {
2244797ac58cSKevin Wolf         return ret;
2245797ac58cSKevin Wolf     }
2246797ac58cSKevin Wolf 
2247797ac58cSKevin Wolf     firstret = ret;
2248797ac58cSKevin Wolf     *pnum = num;
2249797ac58cSKevin Wolf 
2250d6a644bbSEric Blake     while (bytes > 0 && ret == firstret) {
2251d6a644bbSEric Blake         offset += num;
2252d6a644bbSEric Blake         bytes -= num;
2253797ac58cSKevin Wolf 
2254087f2fb3SEric Blake         ret = bdrv_is_allocated(bs, offset, bytes, &num);
22554b25bbc4SMax Reitz         if (ret == firstret && num) {
2256797ac58cSKevin Wolf             *pnum += num;
2257797ac58cSKevin Wolf         } else {
2258797ac58cSKevin Wolf             break;
2259797ac58cSKevin Wolf         }
2260797ac58cSKevin Wolf     }
2261797ac58cSKevin Wolf 
2262797ac58cSKevin Wolf     return firstret;
2263797ac58cSKevin Wolf }
2264797ac58cSKevin Wolf 
map_f(BlockBackend * blk,int argc,char ** argv)2265b32d7a39SMax Reitz static int map_f(BlockBackend *blk, int argc, char **argv)
2266797ac58cSKevin Wolf {
2267d6a644bbSEric Blake     int64_t offset, bytes;
22686f3c90afSEric Blake     char s1[64], s2[64];
2269797ac58cSKevin Wolf     int64_t num;
2270797ac58cSKevin Wolf     int ret;
2271797ac58cSKevin Wolf     const char *retstr;
2272797ac58cSKevin Wolf 
2273797ac58cSKevin Wolf     offset = 0;
2274d6a644bbSEric Blake     bytes = blk_getlength(blk);
2275d6a644bbSEric Blake     if (bytes < 0) {
2276d6a644bbSEric Blake         error_report("Failed to query image length: %s", strerror(-bytes));
2277b32d7a39SMax Reitz         return bytes;
22784c7b7e9bSMax Reitz     }
22794c7b7e9bSMax Reitz 
2280d6a644bbSEric Blake     while (bytes) {
2281d6a644bbSEric Blake         ret = map_is_allocated(blk_bs(blk), offset, bytes, &num);
2282797ac58cSKevin Wolf         if (ret < 0) {
2283797ac58cSKevin Wolf             error_report("Failed to get allocation status: %s", strerror(-ret));
2284b32d7a39SMax Reitz             return ret;
22854b25bbc4SMax Reitz         } else if (!num) {
22864b25bbc4SMax Reitz             error_report("Unexpected end of image");
2287b32d7a39SMax Reitz             return -EIO;
2288797ac58cSKevin Wolf         }
2289797ac58cSKevin Wolf 
2290797ac58cSKevin Wolf         retstr = ret ? "    allocated" : "not allocated";
2291d6a644bbSEric Blake         cvtstr(num, s1, sizeof(s1));
2292d6a644bbSEric Blake         cvtstr(offset, s2, sizeof(s2));
22936f3c90afSEric Blake         printf("%s (0x%" PRIx64 ") bytes %s at offset %s (0x%" PRIx64 ")\n",
2294d6a644bbSEric Blake                s1, num, retstr, s2, offset);
2295797ac58cSKevin Wolf 
2296797ac58cSKevin Wolf         offset += num;
2297d6a644bbSEric Blake         bytes -= num;
2298d6a644bbSEric Blake     }
2299b32d7a39SMax Reitz 
2300b32d7a39SMax Reitz     return 0;
2301797ac58cSKevin Wolf }
2302797ac58cSKevin Wolf 
2303797ac58cSKevin Wolf static const cmdinfo_t map_cmd = {
2304797ac58cSKevin Wolf        .name           = "map",
2305797ac58cSKevin Wolf        .argmin         = 0,
2306797ac58cSKevin Wolf        .argmax         = 0,
2307797ac58cSKevin Wolf        .cfunc          = map_f,
2308797ac58cSKevin Wolf        .args           = "",
2309797ac58cSKevin Wolf        .oneline        = "prints the allocated areas of a file",
2310797ac58cSKevin Wolf };
2311797ac58cSKevin Wolf 
reopen_help(void)23125bbd2e59SKevin Wolf static void reopen_help(void)
23135bbd2e59SKevin Wolf {
23145bbd2e59SKevin Wolf     printf(
23155bbd2e59SKevin Wolf "\n"
23165bbd2e59SKevin Wolf " Changes the open options of an already opened image\n"
23175bbd2e59SKevin Wolf "\n"
23185bbd2e59SKevin Wolf " Example:\n"
23195bbd2e59SKevin Wolf " 'reopen -o lazy-refcounts=on' - activates lazy refcount writeback on a qcow2 image\n"
23205bbd2e59SKevin Wolf "\n"
23215bbd2e59SKevin Wolf " -r, -- Reopen the image read-only\n"
2322ea92203cSKevin Wolf " -w, -- Reopen the image read-write\n"
23235bbd2e59SKevin Wolf " -c, -- Change the cache mode to the given value\n"
23245bbd2e59SKevin Wolf " -o, -- Changes block driver options (cf. 'open' command)\n"
23255bbd2e59SKevin Wolf "\n");
23265bbd2e59SKevin Wolf }
23275bbd2e59SKevin Wolf 
2328b32d7a39SMax Reitz static int reopen_f(BlockBackend *blk, int argc, char **argv);
23295bbd2e59SKevin Wolf 
23305bbd2e59SKevin Wolf static QemuOptsList reopen_opts = {
23315bbd2e59SKevin Wolf     .name = "reopen",
23325bbd2e59SKevin Wolf     .merge_lists = true,
23335bbd2e59SKevin Wolf     .head = QTAILQ_HEAD_INITIALIZER(reopen_opts.head),
23345bbd2e59SKevin Wolf     .desc = {
23355bbd2e59SKevin Wolf         /* no elements => accept any params */
23365bbd2e59SKevin Wolf         { /* end of list */ }
23375bbd2e59SKevin Wolf     },
23385bbd2e59SKevin Wolf };
23395bbd2e59SKevin Wolf 
23405bbd2e59SKevin Wolf static const cmdinfo_t reopen_cmd = {
23415bbd2e59SKevin Wolf        .name           = "reopen",
23425bbd2e59SKevin Wolf        .argmin         = 0,
23435bbd2e59SKevin Wolf        .argmax         = -1,
23445bbd2e59SKevin Wolf        .cfunc          = reopen_f,
2345ea92203cSKevin Wolf        .args           = "[(-r|-w)] [-c cache] [-o options]",
23465bbd2e59SKevin Wolf        .oneline        = "reopens an image with new options",
23475bbd2e59SKevin Wolf        .help           = reopen_help,
23485bbd2e59SKevin Wolf };
23495bbd2e59SKevin Wolf 
reopen_f(BlockBackend * blk,int argc,char ** argv)2350b32d7a39SMax Reitz static int reopen_f(BlockBackend *blk, int argc, char **argv)
23515bbd2e59SKevin Wolf {
23525bbd2e59SKevin Wolf     BlockDriverState *bs = blk_bs(blk);
23535bbd2e59SKevin Wolf     QemuOpts *qopts;
23545bbd2e59SKevin Wolf     QDict *opts;
23555bbd2e59SKevin Wolf     int c;
23565bbd2e59SKevin Wolf     int flags = bs->open_flags;
235719dbecdcSKevin Wolf     bool writethrough = !blk_enable_write_cache(blk);
2358ea92203cSKevin Wolf     bool has_rw_option = false;
2359dc900c35SAlberto Garcia     bool has_cache_option = false;
23605bbd2e59SKevin Wolf     Error *local_err = NULL;
23615bbd2e59SKevin Wolf 
2362ea92203cSKevin Wolf     while ((c = getopt(argc, argv, "c:o:rw")) != -1) {
23635bbd2e59SKevin Wolf         switch (c) {
23645bbd2e59SKevin Wolf         case 'c':
236519dbecdcSKevin Wolf             if (bdrv_parse_cache_mode(optarg, &flags, &writethrough) < 0) {
23665bbd2e59SKevin Wolf                 error_report("Invalid cache option: %s", optarg);
2367b32d7a39SMax Reitz                 return -EINVAL;
23685bbd2e59SKevin Wolf             }
2369dc900c35SAlberto Garcia             has_cache_option = true;
23705bbd2e59SKevin Wolf             break;
23715bbd2e59SKevin Wolf         case 'o':
23725bbd2e59SKevin Wolf             if (!qemu_opts_parse_noisily(&reopen_opts, optarg, 0)) {
23735bbd2e59SKevin Wolf                 qemu_opts_reset(&reopen_opts);
2374b32d7a39SMax Reitz                 return -EINVAL;
23755bbd2e59SKevin Wolf             }
23765bbd2e59SKevin Wolf             break;
23775bbd2e59SKevin Wolf         case 'r':
2378ea92203cSKevin Wolf             if (has_rw_option) {
2379ea92203cSKevin Wolf                 error_report("Only one -r/-w option may be given");
2380b32d7a39SMax Reitz                 return -EINVAL;
2381ea92203cSKevin Wolf             }
23825bbd2e59SKevin Wolf             flags &= ~BDRV_O_RDWR;
2383ea92203cSKevin Wolf             has_rw_option = true;
2384ea92203cSKevin Wolf             break;
2385ea92203cSKevin Wolf         case 'w':
2386ea92203cSKevin Wolf             if (has_rw_option) {
2387ea92203cSKevin Wolf                 error_report("Only one -r/-w option may be given");
2388b32d7a39SMax Reitz                 return -EINVAL;
2389ea92203cSKevin Wolf             }
2390ea92203cSKevin Wolf             flags |= BDRV_O_RDWR;
2391ea92203cSKevin Wolf             has_rw_option = true;
23925bbd2e59SKevin Wolf             break;
23935bbd2e59SKevin Wolf         default:
23945bbd2e59SKevin Wolf             qemu_opts_reset(&reopen_opts);
2395b444d0e9SMax Reitz             qemuio_command_usage(&reopen_cmd);
2396b32d7a39SMax Reitz             return -EINVAL;
23975bbd2e59SKevin Wolf         }
23985bbd2e59SKevin Wolf     }
23995bbd2e59SKevin Wolf 
24005bbd2e59SKevin Wolf     if (optind != argc) {
24015bbd2e59SKevin Wolf         qemu_opts_reset(&reopen_opts);
2402b444d0e9SMax Reitz         qemuio_command_usage(&reopen_cmd);
2403b32d7a39SMax Reitz         return -EINVAL;
24045bbd2e59SKevin Wolf     }
24055bbd2e59SKevin Wolf 
2406a8003ec4SAlberto Garcia     if (!writethrough != blk_enable_write_cache(blk) &&
240719dbecdcSKevin Wolf         blk_get_attached_dev(blk))
240819dbecdcSKevin Wolf     {
240919dbecdcSKevin Wolf         error_report("Cannot change cache.writeback: Device attached");
241019dbecdcSKevin Wolf         qemu_opts_reset(&reopen_opts);
2411b32d7a39SMax Reitz         return -EBUSY;
241219dbecdcSKevin Wolf     }
241319dbecdcSKevin Wolf 
2414f3adefb2SKevin Wolf     if (!(flags & BDRV_O_RDWR)) {
2415f3adefb2SKevin Wolf         uint64_t orig_perm, orig_shared_perm;
2416f3adefb2SKevin Wolf 
2417f3adefb2SKevin Wolf         bdrv_drain(bs);
2418f3adefb2SKevin Wolf 
2419f3adefb2SKevin Wolf         blk_get_perm(blk, &orig_perm, &orig_shared_perm);
2420f3adefb2SKevin Wolf         blk_set_perm(blk,
2421f3adefb2SKevin Wolf                      orig_perm & ~(BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED),
2422f3adefb2SKevin Wolf                      orig_shared_perm,
2423f3adefb2SKevin Wolf                      &error_abort);
2424f3adefb2SKevin Wolf     }
2425f3adefb2SKevin Wolf 
24265bbd2e59SKevin Wolf     qopts = qemu_opts_find(&reopen_opts, NULL);
2427dc900c35SAlberto Garcia     opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : qdict_new();
24285bbd2e59SKevin Wolf     qemu_opts_reset(&reopen_opts);
24295bbd2e59SKevin Wolf 
2430dc900c35SAlberto Garcia     if (qdict_haskey(opts, BDRV_OPT_READ_ONLY)) {
2431dc900c35SAlberto Garcia         if (has_rw_option) {
2432dc900c35SAlberto Garcia             error_report("Cannot set both -r/-w and '" BDRV_OPT_READ_ONLY "'");
2433dc900c35SAlberto Garcia             qobject_unref(opts);
2434dc900c35SAlberto Garcia             return -EINVAL;
2435dc900c35SAlberto Garcia         }
2436dc900c35SAlberto Garcia     } else {
2437dc900c35SAlberto Garcia         qdict_put_bool(opts, BDRV_OPT_READ_ONLY, !(flags & BDRV_O_RDWR));
2438dc900c35SAlberto Garcia     }
2439dc900c35SAlberto Garcia 
2440dc900c35SAlberto Garcia     if (qdict_haskey(opts, BDRV_OPT_CACHE_DIRECT) ||
2441dc900c35SAlberto Garcia         qdict_haskey(opts, BDRV_OPT_CACHE_NO_FLUSH)) {
2442dc900c35SAlberto Garcia         if (has_cache_option) {
2443dc900c35SAlberto Garcia             error_report("Cannot set both -c and the cache options");
2444dc900c35SAlberto Garcia             qobject_unref(opts);
2445dc900c35SAlberto Garcia             return -EINVAL;
2446dc900c35SAlberto Garcia         }
2447dc900c35SAlberto Garcia     } else {
2448dc900c35SAlberto Garcia         qdict_put_bool(opts, BDRV_OPT_CACHE_DIRECT, flags & BDRV_O_NOCACHE);
2449dc900c35SAlberto Garcia         qdict_put_bool(opts, BDRV_OPT_CACHE_NO_FLUSH, flags & BDRV_O_NO_FLUSH);
2450dc900c35SAlberto Garcia     }
2451dc900c35SAlberto Garcia 
24526cf42ca2SKevin Wolf     bdrv_reopen(bs, opts, true, &local_err);
24531a63a907SKevin Wolf 
24545bbd2e59SKevin Wolf     if (local_err) {
24555bbd2e59SKevin Wolf         error_report_err(local_err);
2456b32d7a39SMax Reitz         return -EINVAL;
24575bbd2e59SKevin Wolf     }
24585bbd2e59SKevin Wolf 
2459b32d7a39SMax Reitz     blk_set_enable_write_cache(blk, !writethrough);
2460b32d7a39SMax Reitz     return 0;
2461b32d7a39SMax Reitz }
2462b32d7a39SMax Reitz 
break_f(BlockBackend * blk,int argc,char ** argv)2463b32d7a39SMax Reitz static int break_f(BlockBackend *blk, int argc, char **argv)
2464797ac58cSKevin Wolf {
2465797ac58cSKevin Wolf     int ret;
2466797ac58cSKevin Wolf 
24674c7b7e9bSMax Reitz     ret = bdrv_debug_breakpoint(blk_bs(blk), argv[1], argv[2]);
2468797ac58cSKevin Wolf     if (ret < 0) {
2469797ac58cSKevin Wolf         printf("Could not set breakpoint: %s\n", strerror(-ret));
2470b32d7a39SMax Reitz         return ret;
2471797ac58cSKevin Wolf     }
2472797ac58cSKevin Wolf 
2473b32d7a39SMax Reitz     return 0;
2474b32d7a39SMax Reitz }
2475b32d7a39SMax Reitz 
remove_break_f(BlockBackend * blk,int argc,char ** argv)2476b32d7a39SMax Reitz static int remove_break_f(BlockBackend *blk, int argc, char **argv)
24774cc70e93SFam Zheng {
24784cc70e93SFam Zheng     int ret;
24794cc70e93SFam Zheng 
24804c7b7e9bSMax Reitz     ret = bdrv_debug_remove_breakpoint(blk_bs(blk), argv[1]);
24814cc70e93SFam Zheng     if (ret < 0) {
24824cc70e93SFam Zheng         printf("Could not remove breakpoint %s: %s\n", argv[1], strerror(-ret));
2483b32d7a39SMax Reitz         return ret;
24844cc70e93SFam Zheng     }
2485b32d7a39SMax Reitz 
2486b32d7a39SMax Reitz     return 0;
24874cc70e93SFam Zheng }
24884cc70e93SFam Zheng 
2489797ac58cSKevin Wolf static const cmdinfo_t break_cmd = {
2490797ac58cSKevin Wolf        .name           = "break",
2491797ac58cSKevin Wolf        .argmin         = 2,
2492797ac58cSKevin Wolf        .argmax         = 2,
2493797ac58cSKevin Wolf        .cfunc          = break_f,
2494797ac58cSKevin Wolf        .args           = "event tag",
2495797ac58cSKevin Wolf        .oneline        = "sets a breakpoint on event and tags the stopped "
2496797ac58cSKevin Wolf                          "request as tag",
2497797ac58cSKevin Wolf };
2498797ac58cSKevin Wolf 
24994cc70e93SFam Zheng static const cmdinfo_t remove_break_cmd = {
25004cc70e93SFam Zheng        .name           = "remove_break",
25014cc70e93SFam Zheng        .argmin         = 1,
25024cc70e93SFam Zheng        .argmax         = 1,
25034cc70e93SFam Zheng        .cfunc          = remove_break_f,
25044cc70e93SFam Zheng        .args           = "tag",
25054cc70e93SFam Zheng        .oneline        = "remove a breakpoint by tag",
25064cc70e93SFam Zheng };
25074cc70e93SFam Zheng 
resume_f(BlockBackend * blk,int argc,char ** argv)2508b32d7a39SMax Reitz static int resume_f(BlockBackend *blk, int argc, char **argv)
2509797ac58cSKevin Wolf {
2510797ac58cSKevin Wolf     int ret;
2511797ac58cSKevin Wolf 
25124c7b7e9bSMax Reitz     ret = bdrv_debug_resume(blk_bs(blk), argv[1]);
2513797ac58cSKevin Wolf     if (ret < 0) {
2514797ac58cSKevin Wolf         printf("Could not resume request: %s\n", strerror(-ret));
2515b32d7a39SMax Reitz         return ret;
2516797ac58cSKevin Wolf     }
2517b32d7a39SMax Reitz 
2518b32d7a39SMax Reitz     return 0;
2519797ac58cSKevin Wolf }
2520797ac58cSKevin Wolf 
2521797ac58cSKevin Wolf static const cmdinfo_t resume_cmd = {
2522797ac58cSKevin Wolf        .name           = "resume",
2523797ac58cSKevin Wolf        .argmin         = 1,
2524797ac58cSKevin Wolf        .argmax         = 1,
2525797ac58cSKevin Wolf        .cfunc          = resume_f,
2526797ac58cSKevin Wolf        .args           = "tag",
2527797ac58cSKevin Wolf        .oneline        = "resumes the request tagged as tag",
2528797ac58cSKevin Wolf };
2529797ac58cSKevin Wolf 
wait_break_f(BlockBackend * blk,int argc,char ** argv)2530b32d7a39SMax Reitz static int wait_break_f(BlockBackend *blk, int argc, char **argv)
2531797ac58cSKevin Wolf {
25324c7b7e9bSMax Reitz     while (!bdrv_debug_is_suspended(blk_bs(blk), argv[1])) {
25334c7b7e9bSMax Reitz         aio_poll(blk_get_aio_context(blk), true);
2534797ac58cSKevin Wolf     }
2535b32d7a39SMax Reitz     return 0;
2536797ac58cSKevin Wolf }
2537797ac58cSKevin Wolf 
2538797ac58cSKevin Wolf static const cmdinfo_t wait_break_cmd = {
2539797ac58cSKevin Wolf        .name           = "wait_break",
2540797ac58cSKevin Wolf        .argmin         = 1,
2541797ac58cSKevin Wolf        .argmax         = 1,
2542797ac58cSKevin Wolf        .cfunc          = wait_break_f,
2543797ac58cSKevin Wolf        .args           = "tag",
2544797ac58cSKevin Wolf        .oneline        = "waits for the suspension of a request",
2545797ac58cSKevin Wolf };
2546797ac58cSKevin Wolf 
abort_f(BlockBackend * blk,int argc,char ** argv)2547b32d7a39SMax Reitz static int abort_f(BlockBackend *blk, int argc, char **argv)
2548797ac58cSKevin Wolf {
2549797ac58cSKevin Wolf     abort();
2550797ac58cSKevin Wolf }
2551797ac58cSKevin Wolf 
2552797ac58cSKevin Wolf static const cmdinfo_t abort_cmd = {
2553797ac58cSKevin Wolf        .name           = "abort",
2554797ac58cSKevin Wolf        .cfunc          = abort_f,
2555797ac58cSKevin Wolf        .flags          = CMD_NOFILE_OK,
2556797ac58cSKevin Wolf        .oneline        = "simulate a program crash using abort(3)",
2557797ac58cSKevin Wolf };
2558797ac58cSKevin Wolf 
sigraise_help(void)25590e82dc7bSMax Reitz static void sigraise_help(void)
25600e82dc7bSMax Reitz {
25610e82dc7bSMax Reitz     printf(
25620e82dc7bSMax Reitz "\n"
25630e82dc7bSMax Reitz " raises the given signal\n"
25640e82dc7bSMax Reitz "\n"
25650e82dc7bSMax Reitz " Example:\n"
25660e82dc7bSMax Reitz " 'sigraise %i' - raises SIGTERM\n"
25670e82dc7bSMax Reitz "\n"
25680e82dc7bSMax Reitz " Invokes raise(signal), where \"signal\" is the mandatory integer argument\n"
25690e82dc7bSMax Reitz " given to sigraise.\n"
25700e82dc7bSMax Reitz "\n", SIGTERM);
25710e82dc7bSMax Reitz }
25720e82dc7bSMax Reitz 
2573b32d7a39SMax Reitz static int sigraise_f(BlockBackend *blk, int argc, char **argv);
25740e82dc7bSMax Reitz 
25750e82dc7bSMax Reitz static const cmdinfo_t sigraise_cmd = {
25760e82dc7bSMax Reitz     .name       = "sigraise",
25770e82dc7bSMax Reitz     .cfunc      = sigraise_f,
25780e82dc7bSMax Reitz     .argmin     = 1,
25790e82dc7bSMax Reitz     .argmax     = 1,
25800e82dc7bSMax Reitz     .flags      = CMD_NOFILE_OK,
25810e82dc7bSMax Reitz     .args       = "signal",
25820e82dc7bSMax Reitz     .oneline    = "raises a signal",
25830e82dc7bSMax Reitz     .help       = sigraise_help,
25840e82dc7bSMax Reitz };
25850e82dc7bSMax Reitz 
sigraise_f(BlockBackend * blk,int argc,char ** argv)2586b32d7a39SMax Reitz static int sigraise_f(BlockBackend *blk, int argc, char **argv)
25870e82dc7bSMax Reitz {
25889b0beaf3SJohn Snow     int64_t sig = cvtnum(argv[1]);
25890e82dc7bSMax Reitz     if (sig < 0) {
2590a9ecfa00SJohn Snow         print_cvtnum_err(sig, argv[1]);
2591b32d7a39SMax Reitz         return sig;
25929b0beaf3SJohn Snow     } else if (sig > NSIG) {
25939b0beaf3SJohn Snow         printf("signal argument '%s' is too large to be a valid signal\n",
25949b0beaf3SJohn Snow                argv[1]);
2595b32d7a39SMax Reitz         return -EINVAL;
25960e82dc7bSMax Reitz     }
25970e82dc7bSMax Reitz 
25980e82dc7bSMax Reitz     /* Using raise() to kill this process does not necessarily flush all open
25990e82dc7bSMax Reitz      * streams. At least stdout and stderr (although the latter should be
26000e82dc7bSMax Reitz      * non-buffered anyway) should be flushed, though. */
26010e82dc7bSMax Reitz     fflush(stdout);
26020e82dc7bSMax Reitz     fflush(stderr);
26030e82dc7bSMax Reitz 
26040e82dc7bSMax Reitz     raise(sig);
2605b32d7a39SMax Reitz 
2606b32d7a39SMax Reitz     return 0;
26070e82dc7bSMax Reitz }
26080e82dc7bSMax Reitz 
sleep_cb(void * opaque)2609cd33d02aSKevin Wolf static void sleep_cb(void *opaque)
2610cd33d02aSKevin Wolf {
2611cd33d02aSKevin Wolf     bool *expired = opaque;
2612cd33d02aSKevin Wolf     *expired = true;
2613cd33d02aSKevin Wolf }
2614cd33d02aSKevin Wolf 
sleep_f(BlockBackend * blk,int argc,char ** argv)2615b32d7a39SMax Reitz static int sleep_f(BlockBackend *blk, int argc, char **argv)
2616cd33d02aSKevin Wolf {
2617cd33d02aSKevin Wolf     char *endptr;
2618cd33d02aSKevin Wolf     long ms;
2619cd33d02aSKevin Wolf     struct QEMUTimer *timer;
2620cd33d02aSKevin Wolf     bool expired = false;
2621cd33d02aSKevin Wolf 
2622cd33d02aSKevin Wolf     ms = strtol(argv[1], &endptr, 0);
2623cd33d02aSKevin Wolf     if (ms < 0 || *endptr != '\0') {
2624cd33d02aSKevin Wolf         printf("%s is not a valid number\n", argv[1]);
2625b32d7a39SMax Reitz         return -EINVAL;
2626cd33d02aSKevin Wolf     }
2627cd33d02aSKevin Wolf 
2628cd33d02aSKevin Wolf     timer = timer_new_ns(QEMU_CLOCK_HOST, sleep_cb, &expired);
2629cd33d02aSKevin Wolf     timer_mod(timer, qemu_clock_get_ns(QEMU_CLOCK_HOST) + SCALE_MS * ms);
2630cd33d02aSKevin Wolf 
2631cd33d02aSKevin Wolf     while (!expired) {
2632cd33d02aSKevin Wolf         main_loop_wait(false);
2633cd33d02aSKevin Wolf     }
2634cd33d02aSKevin Wolf 
2635cd33d02aSKevin Wolf     timer_free(timer);
2636b32d7a39SMax Reitz     return 0;
2637cd33d02aSKevin Wolf }
2638cd33d02aSKevin Wolf 
2639cd33d02aSKevin Wolf static const cmdinfo_t sleep_cmd = {
2640cd33d02aSKevin Wolf        .name           = "sleep",
2641cd33d02aSKevin Wolf        .argmin         = 1,
2642cd33d02aSKevin Wolf        .argmax         = 1,
2643cd33d02aSKevin Wolf        .cfunc          = sleep_f,
2644cd33d02aSKevin Wolf        .flags          = CMD_NOFILE_OK,
2645cd33d02aSKevin Wolf        .oneline        = "waits for the given value in milliseconds",
2646cd33d02aSKevin Wolf };
2647cd33d02aSKevin Wolf 
help_oneline(const char * cmd,const cmdinfo_t * ct)2648f18a834aSKevin Wolf static void help_oneline(const char *cmd, const cmdinfo_t *ct)
2649f18a834aSKevin Wolf {
2650f18a834aSKevin Wolf     printf("%s ", cmd);
2651f18a834aSKevin Wolf 
2652f18a834aSKevin Wolf     if (ct->args) {
2653f18a834aSKevin Wolf         printf("%s ", ct->args);
2654f18a834aSKevin Wolf     }
2655f18a834aSKevin Wolf     printf("-- %s\n", ct->oneline);
2656f18a834aSKevin Wolf }
2657f18a834aSKevin Wolf 
help_onecmd(const char * cmd,const cmdinfo_t * ct)2658f18a834aSKevin Wolf static void help_onecmd(const char *cmd, const cmdinfo_t *ct)
2659f18a834aSKevin Wolf {
2660f18a834aSKevin Wolf     help_oneline(cmd, ct);
2661f18a834aSKevin Wolf     if (ct->help) {
2662f18a834aSKevin Wolf         ct->help();
2663f18a834aSKevin Wolf     }
2664f18a834aSKevin Wolf }
2665f18a834aSKevin Wolf 
help_all(void)2666f18a834aSKevin Wolf static void help_all(void)
2667f18a834aSKevin Wolf {
2668f18a834aSKevin Wolf     const cmdinfo_t *ct;
2669f18a834aSKevin Wolf 
2670f18a834aSKevin Wolf     for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) {
2671f18a834aSKevin Wolf         help_oneline(ct->name, ct);
2672f18a834aSKevin Wolf     }
2673f18a834aSKevin Wolf     printf("\nUse 'help commandname' for extended help.\n");
2674f18a834aSKevin Wolf }
2675f18a834aSKevin Wolf 
help_f(BlockBackend * blk,int argc,char ** argv)2676b32d7a39SMax Reitz static int help_f(BlockBackend *blk, int argc, char **argv)
2677f18a834aSKevin Wolf {
2678f18a834aSKevin Wolf     const cmdinfo_t *ct;
2679f18a834aSKevin Wolf 
2680da16f4b8SDr. David Alan Gilbert     if (argc < 2) {
2681f18a834aSKevin Wolf         help_all();
2682b32d7a39SMax Reitz         return 0;
2683f18a834aSKevin Wolf     }
2684f18a834aSKevin Wolf 
2685f18a834aSKevin Wolf     ct = find_command(argv[1]);
2686f18a834aSKevin Wolf     if (ct == NULL) {
2687f18a834aSKevin Wolf         printf("command %s not found\n", argv[1]);
2688b32d7a39SMax Reitz         return -EINVAL;
2689f18a834aSKevin Wolf     }
2690f18a834aSKevin Wolf 
2691f18a834aSKevin Wolf     help_onecmd(argv[1], ct);
2692b32d7a39SMax Reitz     return 0;
2693f18a834aSKevin Wolf }
2694f18a834aSKevin Wolf 
2695f18a834aSKevin Wolf static const cmdinfo_t help_cmd = {
2696f18a834aSKevin Wolf     .name       = "help",
2697f18a834aSKevin Wolf     .altname    = "?",
2698f18a834aSKevin Wolf     .cfunc      = help_f,
2699f18a834aSKevin Wolf     .argmin     = 0,
2700f18a834aSKevin Wolf     .argmax     = 1,
2701f18a834aSKevin Wolf     .flags      = CMD_FLAG_GLOBAL,
2702f18a834aSKevin Wolf     .args       = "[command]",
2703f18a834aSKevin Wolf     .oneline    = "help for one or all commands",
2704f18a834aSKevin Wolf };
2705f18a834aSKevin Wolf 
270678632a3dSVladimir Sementsov-Ogievskiy /*
270778632a3dSVladimir Sementsov-Ogievskiy  * Called with aio context of blk acquired. Or with qemu_get_aio_context()
270878632a3dSVladimir Sementsov-Ogievskiy  * context acquired if blk is NULL.
270978632a3dSVladimir Sementsov-Ogievskiy  */
qemuio_command(BlockBackend * blk,const char * cmd)2710b32d7a39SMax Reitz int qemuio_command(BlockBackend *blk, const char *cmd)
2711dd583296SKevin Wolf {
2712dd583296SKevin Wolf     char *input;
2713dd583296SKevin Wolf     const cmdinfo_t *ct;
2714dd583296SKevin Wolf     char **v;
2715dd583296SKevin Wolf     int c;
2716b32d7a39SMax Reitz     int ret = 0;
2717dd583296SKevin Wolf 
2718dd583296SKevin Wolf     input = g_strdup(cmd);
2719dd583296SKevin Wolf     v = breakline(input, &c);
2720dd583296SKevin Wolf     if (c) {
2721dd583296SKevin Wolf         ct = find_command(v[0]);
2722dd583296SKevin Wolf         if (ct) {
2723b32d7a39SMax Reitz             ret = command(blk, ct, c, v);
2724dd583296SKevin Wolf         } else {
2725dd583296SKevin Wolf             fprintf(stderr, "command \"%s\" not found\n", v[0]);
2726b32d7a39SMax Reitz             ret = -EINVAL;
2727dd583296SKevin Wolf         }
2728dd583296SKevin Wolf     }
2729dd583296SKevin Wolf     g_free(input);
2730dd583296SKevin Wolf     g_free(v);
2731b32d7a39SMax Reitz 
2732b32d7a39SMax Reitz     return ret;
2733dd583296SKevin Wolf }
2734dd583296SKevin Wolf 
init_qemuio_commands(void)2735797ac58cSKevin Wolf static void __attribute((constructor)) init_qemuio_commands(void)
2736797ac58cSKevin Wolf {
2737797ac58cSKevin Wolf     /* initialize commands */
2738c2cdf5c5SKevin Wolf     qemuio_add_command(&help_cmd);
2739c2cdf5c5SKevin Wolf     qemuio_add_command(&read_cmd);
2740c2cdf5c5SKevin Wolf     qemuio_add_command(&readv_cmd);
2741c2cdf5c5SKevin Wolf     qemuio_add_command(&write_cmd);
2742c2cdf5c5SKevin Wolf     qemuio_add_command(&writev_cmd);
2743c2cdf5c5SKevin Wolf     qemuio_add_command(&aio_read_cmd);
2744c2cdf5c5SKevin Wolf     qemuio_add_command(&aio_write_cmd);
2745c2cdf5c5SKevin Wolf     qemuio_add_command(&aio_flush_cmd);
2746c2cdf5c5SKevin Wolf     qemuio_add_command(&flush_cmd);
27476d43eaa3SSam Li     qemuio_add_command(&zone_report_cmd);
27486d43eaa3SSam Li     qemuio_add_command(&zone_open_cmd);
27496d43eaa3SSam Li     qemuio_add_command(&zone_close_cmd);
27506d43eaa3SSam Li     qemuio_add_command(&zone_finish_cmd);
27516d43eaa3SSam Li     qemuio_add_command(&zone_reset_cmd);
2752fe4fe70dSSam Li     qemuio_add_command(&zone_append_cmd);
2753c2cdf5c5SKevin Wolf     qemuio_add_command(&truncate_cmd);
2754c2cdf5c5SKevin Wolf     qemuio_add_command(&length_cmd);
2755c2cdf5c5SKevin Wolf     qemuio_add_command(&info_cmd);
2756c2cdf5c5SKevin Wolf     qemuio_add_command(&discard_cmd);
2757c2cdf5c5SKevin Wolf     qemuio_add_command(&alloc_cmd);
2758c2cdf5c5SKevin Wolf     qemuio_add_command(&map_cmd);
27595bbd2e59SKevin Wolf     qemuio_add_command(&reopen_cmd);
2760c2cdf5c5SKevin Wolf     qemuio_add_command(&break_cmd);
27614cc70e93SFam Zheng     qemuio_add_command(&remove_break_cmd);
2762c2cdf5c5SKevin Wolf     qemuio_add_command(&resume_cmd);
2763c2cdf5c5SKevin Wolf     qemuio_add_command(&wait_break_cmd);
2764c2cdf5c5SKevin Wolf     qemuio_add_command(&abort_cmd);
2765cd33d02aSKevin Wolf     qemuio_add_command(&sleep_cmd);
27660e82dc7bSMax Reitz     qemuio_add_command(&sigraise_cmd);
2767797ac58cSKevin Wolf }
2768