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;
1742*365911b1SStefan Hajnoczi int64_t val;
17436d43eaa3SSam Li unsigned int nr_zones;
17446d43eaa3SSam Li
17456d43eaa3SSam Li ++optind;
17466d43eaa3SSam Li offset = cvtnum(argv[optind]);
1747*365911b1SStefan Hajnoczi if (offset < 0) {
1748*365911b1SStefan Hajnoczi print_cvtnum_err(offset, argv[optind]);
1749*365911b1SStefan Hajnoczi return offset;
1750*365911b1SStefan Hajnoczi }
17516d43eaa3SSam Li ++optind;
1752*365911b1SStefan Hajnoczi val = cvtnum(argv[optind]);
1753*365911b1SStefan Hajnoczi if (val < 0) {
1754*365911b1SStefan Hajnoczi print_cvtnum_err(val, argv[optind]);
1755*365911b1SStefan Hajnoczi return val;
1756*365911b1SStefan Hajnoczi }
1757*365911b1SStefan Hajnoczi if (val > UINT_MAX) {
1758*365911b1SStefan Hajnoczi printf("Number of zones must be less than 2^32\n");
1759*365911b1SStefan Hajnoczi return -ERANGE;
1760*365911b1SStefan Hajnoczi }
1761*365911b1SStefan Hajnoczi nr_zones = val;
17626d43eaa3SSam Li
17636d43eaa3SSam Li g_autofree BlockZoneDescriptor *zones = NULL;
17646d43eaa3SSam Li zones = g_new(BlockZoneDescriptor, nr_zones);
17656d43eaa3SSam Li ret = blk_zone_report(blk, offset, &nr_zones, zones);
17666d43eaa3SSam Li if (ret < 0) {
17676d43eaa3SSam Li printf("zone report failed: %s\n", strerror(-ret));
17686d43eaa3SSam Li } else {
17696d43eaa3SSam Li for (int i = 0; i < nr_zones; ++i) {
17706d43eaa3SSam Li printf("start: 0x%" PRIx64 ", len 0x%" PRIx64 ", "
17716d43eaa3SSam Li "cap"" 0x%" PRIx64 ", wptr 0x%" PRIx64 ", "
17726d43eaa3SSam Li "zcond:%u, [type: %u]\n",
17736d43eaa3SSam Li tosector(zones[i].start), tosector(zones[i].length),
17746d43eaa3SSam Li tosector(zones[i].cap), tosector(zones[i].wp),
17756d43eaa3SSam Li zones[i].state, zones[i].type);
17766d43eaa3SSam Li }
17776d43eaa3SSam Li }
17786d43eaa3SSam Li return ret;
17796d43eaa3SSam Li }
17806d43eaa3SSam Li
17816d43eaa3SSam Li static const cmdinfo_t zone_report_cmd = {
17826d43eaa3SSam Li .name = "zone_report",
17836d43eaa3SSam Li .altname = "zrp",
17846d43eaa3SSam Li .cfunc = zone_report_f,
17856d43eaa3SSam Li .argmin = 2,
17866d43eaa3SSam Li .argmax = 2,
17876d43eaa3SSam Li .args = "offset number",
17886d43eaa3SSam Li .oneline = "report zone information",
17896d43eaa3SSam Li };
17906d43eaa3SSam Li
zone_open_f(BlockBackend * blk,int argc,char ** argv)17916d43eaa3SSam Li static int zone_open_f(BlockBackend *blk, int argc, char **argv)
17926d43eaa3SSam Li {
17936d43eaa3SSam Li int ret;
17946d43eaa3SSam Li int64_t offset, len;
17956d43eaa3SSam Li ++optind;
17966d43eaa3SSam Li offset = cvtnum(argv[optind]);
1797*365911b1SStefan Hajnoczi if (offset < 0) {
1798*365911b1SStefan Hajnoczi print_cvtnum_err(offset, argv[optind]);
1799*365911b1SStefan Hajnoczi return offset;
1800*365911b1SStefan Hajnoczi }
18016d43eaa3SSam Li ++optind;
18026d43eaa3SSam Li len = cvtnum(argv[optind]);
1803*365911b1SStefan Hajnoczi if (len < 0) {
1804*365911b1SStefan Hajnoczi print_cvtnum_err(len, argv[optind]);
1805*365911b1SStefan Hajnoczi return len;
1806*365911b1SStefan Hajnoczi }
18076d43eaa3SSam Li ret = blk_zone_mgmt(blk, BLK_ZO_OPEN, offset, len);
18086d43eaa3SSam Li if (ret < 0) {
18096d43eaa3SSam Li printf("zone open failed: %s\n", strerror(-ret));
18106d43eaa3SSam Li }
18116d43eaa3SSam Li return ret;
18126d43eaa3SSam Li }
18136d43eaa3SSam Li
18146d43eaa3SSam Li static const cmdinfo_t zone_open_cmd = {
18156d43eaa3SSam Li .name = "zone_open",
18166d43eaa3SSam Li .altname = "zo",
18176d43eaa3SSam Li .cfunc = zone_open_f,
18186d43eaa3SSam Li .argmin = 2,
18196d43eaa3SSam Li .argmax = 2,
18206d43eaa3SSam Li .args = "offset len",
18216d43eaa3SSam Li .oneline = "explicit open a range of zones in zone block device",
18226d43eaa3SSam Li };
18236d43eaa3SSam Li
zone_close_f(BlockBackend * blk,int argc,char ** argv)18246d43eaa3SSam Li static int zone_close_f(BlockBackend *blk, int argc, char **argv)
18256d43eaa3SSam Li {
18266d43eaa3SSam Li int ret;
18276d43eaa3SSam Li int64_t offset, len;
18286d43eaa3SSam Li ++optind;
18296d43eaa3SSam Li offset = cvtnum(argv[optind]);
1830*365911b1SStefan Hajnoczi if (offset < 0) {
1831*365911b1SStefan Hajnoczi print_cvtnum_err(offset, argv[optind]);
1832*365911b1SStefan Hajnoczi return offset;
1833*365911b1SStefan Hajnoczi }
18346d43eaa3SSam Li ++optind;
18356d43eaa3SSam Li len = cvtnum(argv[optind]);
1836*365911b1SStefan Hajnoczi if (len < 0) {
1837*365911b1SStefan Hajnoczi print_cvtnum_err(len, argv[optind]);
1838*365911b1SStefan Hajnoczi return len;
1839*365911b1SStefan Hajnoczi }
18406d43eaa3SSam Li ret = blk_zone_mgmt(blk, BLK_ZO_CLOSE, offset, len);
18416d43eaa3SSam Li if (ret < 0) {
18426d43eaa3SSam Li printf("zone close failed: %s\n", strerror(-ret));
18436d43eaa3SSam Li }
18446d43eaa3SSam Li return ret;
18456d43eaa3SSam Li }
18466d43eaa3SSam Li
18476d43eaa3SSam Li static const cmdinfo_t zone_close_cmd = {
18486d43eaa3SSam Li .name = "zone_close",
18496d43eaa3SSam Li .altname = "zc",
18506d43eaa3SSam Li .cfunc = zone_close_f,
18516d43eaa3SSam Li .argmin = 2,
18526d43eaa3SSam Li .argmax = 2,
18536d43eaa3SSam Li .args = "offset len",
18546d43eaa3SSam Li .oneline = "close a range of zones in zone block device",
18556d43eaa3SSam Li };
18566d43eaa3SSam Li
zone_finish_f(BlockBackend * blk,int argc,char ** argv)18576d43eaa3SSam Li static int zone_finish_f(BlockBackend *blk, int argc, char **argv)
18586d43eaa3SSam Li {
18596d43eaa3SSam Li int ret;
18606d43eaa3SSam Li int64_t offset, len;
18616d43eaa3SSam Li ++optind;
18626d43eaa3SSam Li offset = cvtnum(argv[optind]);
1863*365911b1SStefan Hajnoczi if (offset < 0) {
1864*365911b1SStefan Hajnoczi print_cvtnum_err(offset, argv[optind]);
1865*365911b1SStefan Hajnoczi return offset;
1866*365911b1SStefan Hajnoczi }
18676d43eaa3SSam Li ++optind;
18686d43eaa3SSam Li len = cvtnum(argv[optind]);
1869*365911b1SStefan Hajnoczi if (len < 0) {
1870*365911b1SStefan Hajnoczi print_cvtnum_err(len, argv[optind]);
1871*365911b1SStefan Hajnoczi return len;
1872*365911b1SStefan Hajnoczi }
18736d43eaa3SSam Li ret = blk_zone_mgmt(blk, BLK_ZO_FINISH, offset, len);
18746d43eaa3SSam Li if (ret < 0) {
18756d43eaa3SSam Li printf("zone finish failed: %s\n", strerror(-ret));
18766d43eaa3SSam Li }
18776d43eaa3SSam Li return ret;
18786d43eaa3SSam Li }
18796d43eaa3SSam Li
18806d43eaa3SSam Li static const cmdinfo_t zone_finish_cmd = {
18816d43eaa3SSam Li .name = "zone_finish",
18826d43eaa3SSam Li .altname = "zf",
18836d43eaa3SSam Li .cfunc = zone_finish_f,
18846d43eaa3SSam Li .argmin = 2,
18856d43eaa3SSam Li .argmax = 2,
18866d43eaa3SSam Li .args = "offset len",
18876d43eaa3SSam Li .oneline = "finish a range of zones in zone block device",
18886d43eaa3SSam Li };
18896d43eaa3SSam Li
zone_reset_f(BlockBackend * blk,int argc,char ** argv)18906d43eaa3SSam Li static int zone_reset_f(BlockBackend *blk, int argc, char **argv)
18916d43eaa3SSam Li {
18926d43eaa3SSam Li int ret;
18936d43eaa3SSam Li int64_t offset, len;
18946d43eaa3SSam Li ++optind;
18956d43eaa3SSam Li offset = cvtnum(argv[optind]);
1896*365911b1SStefan Hajnoczi if (offset < 0) {
1897*365911b1SStefan Hajnoczi print_cvtnum_err(offset, argv[optind]);
1898*365911b1SStefan Hajnoczi return offset;
1899*365911b1SStefan Hajnoczi }
19006d43eaa3SSam Li ++optind;
19016d43eaa3SSam Li len = cvtnum(argv[optind]);
1902*365911b1SStefan Hajnoczi if (len < 0) {
1903*365911b1SStefan Hajnoczi print_cvtnum_err(len, argv[optind]);
1904*365911b1SStefan Hajnoczi return len;
1905*365911b1SStefan Hajnoczi }
19066d43eaa3SSam Li ret = blk_zone_mgmt(blk, BLK_ZO_RESET, offset, len);
19076d43eaa3SSam Li if (ret < 0) {
19086d43eaa3SSam Li printf("zone reset failed: %s\n", strerror(-ret));
19096d43eaa3SSam Li }
19106d43eaa3SSam Li return ret;
19116d43eaa3SSam Li }
19126d43eaa3SSam Li
19136d43eaa3SSam Li static const cmdinfo_t zone_reset_cmd = {
19146d43eaa3SSam Li .name = "zone_reset",
19156d43eaa3SSam Li .altname = "zrs",
19166d43eaa3SSam Li .cfunc = zone_reset_f,
19176d43eaa3SSam Li .argmin = 2,
19186d43eaa3SSam Li .argmax = 2,
19196d43eaa3SSam Li .args = "offset len",
19206d43eaa3SSam Li .oneline = "reset a zone write pointer in zone block device",
19216d43eaa3SSam Li };
19226d43eaa3SSam Li
do_aio_zone_append(BlockBackend * blk,QEMUIOVector * qiov,int64_t * offset,int flags,int * total)1923fe4fe70dSSam Li static int do_aio_zone_append(BlockBackend *blk, QEMUIOVector *qiov,
1924fe4fe70dSSam Li int64_t *offset, int flags, int *total)
1925fe4fe70dSSam Li {
1926fe4fe70dSSam Li int async_ret = NOT_DONE;
1927fe4fe70dSSam Li
1928fe4fe70dSSam Li blk_aio_zone_append(blk, offset, qiov, flags, aio_rw_done, &async_ret);
1929fe4fe70dSSam Li while (async_ret == NOT_DONE) {
1930fe4fe70dSSam Li main_loop_wait(false);
1931fe4fe70dSSam Li }
1932fe4fe70dSSam Li
1933fe4fe70dSSam Li *total = qiov->size;
1934fe4fe70dSSam Li return async_ret < 0 ? async_ret : 1;
1935fe4fe70dSSam Li }
1936fe4fe70dSSam Li
zone_append_f(BlockBackend * blk,int argc,char ** argv)1937fe4fe70dSSam Li static int zone_append_f(BlockBackend *blk, int argc, char **argv)
1938fe4fe70dSSam Li {
1939fe4fe70dSSam Li int ret;
1940fe4fe70dSSam Li bool pflag = false;
1941fe4fe70dSSam Li int flags = 0;
1942fe4fe70dSSam Li int total = 0;
1943fe4fe70dSSam Li int64_t offset;
1944fe4fe70dSSam Li char *buf;
1945fe4fe70dSSam Li int c, nr_iov;
1946fe4fe70dSSam Li int pattern = 0xcd;
1947fe4fe70dSSam Li QEMUIOVector qiov;
1948fe4fe70dSSam Li
1949fe4fe70dSSam Li if (optind > argc - 3) {
1950fe4fe70dSSam Li return -EINVAL;
1951fe4fe70dSSam Li }
1952fe4fe70dSSam Li
1953fe4fe70dSSam Li if ((c = getopt(argc, argv, "p")) != -1) {
1954fe4fe70dSSam Li pflag = true;
1955fe4fe70dSSam Li }
1956fe4fe70dSSam Li
1957fe4fe70dSSam Li offset = cvtnum(argv[optind]);
1958fe4fe70dSSam Li if (offset < 0) {
1959fe4fe70dSSam Li print_cvtnum_err(offset, argv[optind]);
1960fe4fe70dSSam Li return offset;
1961fe4fe70dSSam Li }
1962fe4fe70dSSam Li optind++;
1963fe4fe70dSSam Li nr_iov = argc - optind;
1964fe4fe70dSSam Li buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, pattern,
1965fe4fe70dSSam Li flags & BDRV_REQ_REGISTERED_BUF);
1966fe4fe70dSSam Li if (buf == NULL) {
1967fe4fe70dSSam Li return -EINVAL;
1968fe4fe70dSSam Li }
1969fe4fe70dSSam Li ret = do_aio_zone_append(blk, &qiov, &offset, flags, &total);
1970fe4fe70dSSam Li if (ret < 0) {
1971fe4fe70dSSam Li printf("zone append failed: %s\n", strerror(-ret));
1972fe4fe70dSSam Li goto out;
1973fe4fe70dSSam Li }
1974fe4fe70dSSam Li
1975fe4fe70dSSam Li if (pflag) {
1976fe4fe70dSSam Li printf("After zap done, the append sector is 0x%" PRIx64 "\n",
1977fe4fe70dSSam Li tosector(offset));
1978fe4fe70dSSam Li }
1979fe4fe70dSSam Li
1980fe4fe70dSSam Li out:
1981fe4fe70dSSam Li qemu_io_free(blk, buf, qiov.size,
1982fe4fe70dSSam Li flags & BDRV_REQ_REGISTERED_BUF);
1983fe4fe70dSSam Li qemu_iovec_destroy(&qiov);
1984fe4fe70dSSam Li return ret;
1985fe4fe70dSSam Li }
1986fe4fe70dSSam Li
1987fe4fe70dSSam Li static const cmdinfo_t zone_append_cmd = {
1988fe4fe70dSSam Li .name = "zone_append",
1989fe4fe70dSSam Li .altname = "zap",
1990fe4fe70dSSam Li .cfunc = zone_append_f,
1991fe4fe70dSSam Li .argmin = 3,
1992fe4fe70dSSam Li .argmax = 4,
1993fe4fe70dSSam Li .args = "offset len [len..]",
1994fe4fe70dSSam Li .oneline = "append write a number of bytes at a specified offset",
1995fe4fe70dSSam Li };
1996fe4fe70dSSam Li
199742ba0225SVladimir Sementsov-Ogievskiy static int truncate_f(BlockBackend *blk, int argc, char **argv);
199842ba0225SVladimir Sementsov-Ogievskiy static const cmdinfo_t truncate_cmd = {
199942ba0225SVladimir Sementsov-Ogievskiy .name = "truncate",
200042ba0225SVladimir Sementsov-Ogievskiy .altname = "t",
200142ba0225SVladimir Sementsov-Ogievskiy .cfunc = truncate_f,
200242ba0225SVladimir Sementsov-Ogievskiy .perm = BLK_PERM_WRITE | BLK_PERM_RESIZE,
200342ba0225SVladimir Sementsov-Ogievskiy .argmin = 1,
200442ba0225SVladimir Sementsov-Ogievskiy .argmax = 3,
200542ba0225SVladimir Sementsov-Ogievskiy .args = "[-m prealloc_mode] off",
200642ba0225SVladimir Sementsov-Ogievskiy .oneline = "truncates the current file at the given offset",
200742ba0225SVladimir Sementsov-Ogievskiy };
200842ba0225SVladimir Sementsov-Ogievskiy
truncate_f(BlockBackend * blk,int argc,char ** argv)2009b32d7a39SMax Reitz static int truncate_f(BlockBackend *blk, int argc, char **argv)
2010797ac58cSKevin Wolf {
2011ed3d2ec9SMax Reitz Error *local_err = NULL;
2012797ac58cSKevin Wolf int64_t offset;
201342ba0225SVladimir Sementsov-Ogievskiy int c, ret;
201442ba0225SVladimir Sementsov-Ogievskiy PreallocMode prealloc = PREALLOC_MODE_OFF;
2015797ac58cSKevin Wolf
201642ba0225SVladimir Sementsov-Ogievskiy while ((c = getopt(argc, argv, "m:")) != -1) {
201742ba0225SVladimir Sementsov-Ogievskiy switch (c) {
201842ba0225SVladimir Sementsov-Ogievskiy case 'm':
201942ba0225SVladimir Sementsov-Ogievskiy prealloc = qapi_enum_parse(&PreallocMode_lookup, optarg,
202042ba0225SVladimir Sementsov-Ogievskiy PREALLOC_MODE__MAX, NULL);
202142ba0225SVladimir Sementsov-Ogievskiy if (prealloc == PREALLOC_MODE__MAX) {
202242ba0225SVladimir Sementsov-Ogievskiy error_report("Invalid preallocation mode '%s'", optarg);
202342ba0225SVladimir Sementsov-Ogievskiy return -EINVAL;
202442ba0225SVladimir Sementsov-Ogievskiy }
202542ba0225SVladimir Sementsov-Ogievskiy break;
202642ba0225SVladimir Sementsov-Ogievskiy default:
202742ba0225SVladimir Sementsov-Ogievskiy qemuio_command_usage(&truncate_cmd);
202842ba0225SVladimir Sementsov-Ogievskiy return -EINVAL;
202942ba0225SVladimir Sementsov-Ogievskiy }
203042ba0225SVladimir Sementsov-Ogievskiy }
203142ba0225SVladimir Sementsov-Ogievskiy
203242ba0225SVladimir Sementsov-Ogievskiy offset = cvtnum(argv[optind]);
2033797ac58cSKevin Wolf if (offset < 0) {
2034a9ecfa00SJohn Snow print_cvtnum_err(offset, argv[1]);
2035b32d7a39SMax Reitz return offset;
2036797ac58cSKevin Wolf }
2037797ac58cSKevin Wolf
2038e8d04f92SMax Reitz /*
2039e8d04f92SMax Reitz * qemu-io is a debugging tool, so let us be strict here and pass
2040e8d04f92SMax Reitz * exact=true. It is better to err on the "emit more errors" side
2041e8d04f92SMax Reitz * than to be overly permissive.
2042e8d04f92SMax Reitz */
204342ba0225SVladimir Sementsov-Ogievskiy ret = blk_truncate(blk, offset, false, prealloc, 0, &local_err);
2044797ac58cSKevin Wolf if (ret < 0) {
2045ed3d2ec9SMax Reitz error_report_err(local_err);
2046b32d7a39SMax Reitz return ret;
2047797ac58cSKevin Wolf }
2048b32d7a39SMax Reitz
2049b32d7a39SMax Reitz return 0;
2050797ac58cSKevin Wolf }
2051797ac58cSKevin Wolf
length_f(BlockBackend * blk,int argc,char ** argv)2052b32d7a39SMax Reitz static int length_f(BlockBackend *blk, int argc, char **argv)
2053797ac58cSKevin Wolf {
2054797ac58cSKevin Wolf int64_t size;
2055797ac58cSKevin Wolf char s1[64];
2056797ac58cSKevin Wolf
20574c7b7e9bSMax Reitz size = blk_getlength(blk);
2058797ac58cSKevin Wolf if (size < 0) {
2059797ac58cSKevin Wolf printf("getlength: %s\n", strerror(-size));
2060b32d7a39SMax Reitz return size;
2061797ac58cSKevin Wolf }
2062797ac58cSKevin Wolf
2063797ac58cSKevin Wolf cvtstr(size, s1, sizeof(s1));
2064797ac58cSKevin Wolf printf("%s\n", s1);
2065b32d7a39SMax Reitz return 0;
2066797ac58cSKevin Wolf }
2067797ac58cSKevin Wolf
2068797ac58cSKevin Wolf
2069797ac58cSKevin Wolf static const cmdinfo_t length_cmd = {
2070797ac58cSKevin Wolf .name = "length",
2071797ac58cSKevin Wolf .altname = "l",
2072797ac58cSKevin Wolf .cfunc = length_f,
2073797ac58cSKevin Wolf .oneline = "gets the length of the current file",
2074797ac58cSKevin Wolf };
2075797ac58cSKevin Wolf
2076797ac58cSKevin Wolf
info_f(BlockBackend * blk,int argc,char ** argv)2077b32d7a39SMax Reitz static int info_f(BlockBackend *blk, int argc, char **argv)
2078797ac58cSKevin Wolf {
20794c7b7e9bSMax Reitz BlockDriverState *bs = blk_bs(blk);
2080797ac58cSKevin Wolf BlockDriverInfo bdi;
2081a8d8ecb7SMax Reitz ImageInfoSpecific *spec_info;
20821bf6e9caSAndrey Shinkevich Error *local_err = NULL;
2083797ac58cSKevin Wolf char s1[64], s2[64];
2084797ac58cSKevin Wolf int ret;
2085797ac58cSKevin Wolf
20863574499aSKevin Wolf GLOBAL_STATE_CODE();
20873574499aSKevin Wolf GRAPH_RDLOCK_GUARD_MAINLOOP();
20883574499aSKevin Wolf
2089797ac58cSKevin Wolf if (bs->drv && bs->drv->format_name) {
2090797ac58cSKevin Wolf printf("format name: %s\n", bs->drv->format_name);
2091797ac58cSKevin Wolf }
2092797ac58cSKevin Wolf if (bs->drv && bs->drv->protocol_name) {
2093797ac58cSKevin Wolf printf("format name: %s\n", bs->drv->protocol_name);
2094797ac58cSKevin Wolf }
2095797ac58cSKevin Wolf
2096797ac58cSKevin Wolf ret = bdrv_get_info(bs, &bdi);
2097797ac58cSKevin Wolf if (ret) {
2098b32d7a39SMax Reitz return ret;
2099797ac58cSKevin Wolf }
2100797ac58cSKevin Wolf
2101797ac58cSKevin Wolf cvtstr(bdi.cluster_size, s1, sizeof(s1));
2102797ac58cSKevin Wolf cvtstr(bdi.vm_state_offset, s2, sizeof(s2));
2103797ac58cSKevin Wolf
2104797ac58cSKevin Wolf printf("cluster size: %s\n", s1);
2105797ac58cSKevin Wolf printf("vm state offset: %s\n", s2);
2106797ac58cSKevin Wolf
21071bf6e9caSAndrey Shinkevich spec_info = bdrv_get_specific_info(bs, &local_err);
21081bf6e9caSAndrey Shinkevich if (local_err) {
21091bf6e9caSAndrey Shinkevich error_report_err(local_err);
21101bf6e9caSAndrey Shinkevich return -EIO;
21111bf6e9caSAndrey Shinkevich }
2112a8d8ecb7SMax Reitz if (spec_info) {
21133716470bSHanna Reitz bdrv_image_info_specific_dump(spec_info,
211476c9e975SHanna Reitz "Format specific information:\n",
211576c9e975SHanna Reitz 0);
2116a8d8ecb7SMax Reitz qapi_free_ImageInfoSpecific(spec_info);
2117a8d8ecb7SMax Reitz }
2118b32d7a39SMax Reitz
2119b32d7a39SMax Reitz return 0;
2120797ac58cSKevin Wolf }
2121797ac58cSKevin Wolf
2122797ac58cSKevin Wolf
2123797ac58cSKevin Wolf
2124797ac58cSKevin Wolf static const cmdinfo_t info_cmd = {
2125797ac58cSKevin Wolf .name = "info",
2126797ac58cSKevin Wolf .altname = "i",
2127797ac58cSKevin Wolf .cfunc = info_f,
2128797ac58cSKevin Wolf .oneline = "prints information about the current file",
2129797ac58cSKevin Wolf };
2130797ac58cSKevin Wolf
discard_help(void)2131797ac58cSKevin Wolf static void discard_help(void)
2132797ac58cSKevin Wolf {
2133797ac58cSKevin Wolf printf(
2134797ac58cSKevin Wolf "\n"
2135797ac58cSKevin Wolf " discards a range of bytes from the given offset\n"
2136797ac58cSKevin Wolf "\n"
2137797ac58cSKevin Wolf " Example:\n"
2138797ac58cSKevin Wolf " 'discard 512 1k' - discards 1 kilobyte from 512 bytes into the file\n"
2139797ac58cSKevin Wolf "\n"
2140797ac58cSKevin Wolf " Discards a segment of the currently open file.\n"
2141797ac58cSKevin Wolf " -C, -- report statistics in a machine parsable format\n"
2142797ac58cSKevin Wolf " -q, -- quiet mode, do not show I/O statistics\n"
2143797ac58cSKevin Wolf "\n");
2144797ac58cSKevin Wolf }
2145797ac58cSKevin Wolf
2146b32d7a39SMax Reitz static int discard_f(BlockBackend *blk, int argc, char **argv);
2147797ac58cSKevin Wolf
2148797ac58cSKevin Wolf static const cmdinfo_t discard_cmd = {
2149797ac58cSKevin Wolf .name = "discard",
2150797ac58cSKevin Wolf .altname = "d",
2151797ac58cSKevin Wolf .cfunc = discard_f,
2152887354bdSKevin Wolf .perm = BLK_PERM_WRITE,
2153797ac58cSKevin Wolf .argmin = 2,
2154797ac58cSKevin Wolf .argmax = -1,
2155797ac58cSKevin Wolf .args = "[-Cq] off len",
2156797ac58cSKevin Wolf .oneline = "discards a number of bytes at a specified offset",
2157797ac58cSKevin Wolf .help = discard_help,
2158797ac58cSKevin Wolf };
2159797ac58cSKevin Wolf
discard_f(BlockBackend * blk,int argc,char ** argv)2160b32d7a39SMax Reitz static int discard_f(BlockBackend *blk, int argc, char **argv)
2161797ac58cSKevin Wolf {
216250290c00SAlex Bennée struct timespec t1, t2;
2163dc38852aSEric Blake bool Cflag = false, qflag = false;
2164797ac58cSKevin Wolf int c, ret;
2165f5a5ca79SManos Pitsidianakis int64_t offset, bytes;
2166797ac58cSKevin Wolf
2167b062ad86SEric Blake while ((c = getopt(argc, argv, "Cq")) != -1) {
2168797ac58cSKevin Wolf switch (c) {
2169797ac58cSKevin Wolf case 'C':
2170dc38852aSEric Blake Cflag = true;
2171797ac58cSKevin Wolf break;
2172797ac58cSKevin Wolf case 'q':
2173dc38852aSEric Blake qflag = true;
2174797ac58cSKevin Wolf break;
2175797ac58cSKevin Wolf default:
2176b444d0e9SMax Reitz qemuio_command_usage(&discard_cmd);
2177b32d7a39SMax Reitz return -EINVAL;
2178797ac58cSKevin Wolf }
2179797ac58cSKevin Wolf }
2180797ac58cSKevin Wolf
2181797ac58cSKevin Wolf if (optind != argc - 2) {
2182b444d0e9SMax Reitz qemuio_command_usage(&discard_cmd);
2183b32d7a39SMax Reitz return -EINVAL;
2184797ac58cSKevin Wolf }
2185797ac58cSKevin Wolf
2186797ac58cSKevin Wolf offset = cvtnum(argv[optind]);
2187797ac58cSKevin Wolf if (offset < 0) {
2188a9ecfa00SJohn Snow print_cvtnum_err(offset, argv[optind]);
2189b32d7a39SMax Reitz return offset;
2190797ac58cSKevin Wolf }
2191797ac58cSKevin Wolf
2192797ac58cSKevin Wolf optind++;
2193f5a5ca79SManos Pitsidianakis bytes = cvtnum(argv[optind]);
2194f5a5ca79SManos Pitsidianakis if (bytes < 0) {
2195f5a5ca79SManos Pitsidianakis print_cvtnum_err(bytes, argv[optind]);
2196b32d7a39SMax Reitz return bytes;
219741ae31e3SAlberto Garcia } else if (bytes > BDRV_REQUEST_MAX_BYTES) {
21989b0beaf3SJohn Snow printf("length cannot exceed %"PRIu64", given %s\n",
219941ae31e3SAlberto Garcia (uint64_t)BDRV_REQUEST_MAX_BYTES, argv[optind]);
2200b32d7a39SMax Reitz return -EINVAL;
2201797ac58cSKevin Wolf }
2202797ac58cSKevin Wolf
220350290c00SAlex Bennée clock_gettime(CLOCK_MONOTONIC, &t1);
2204f5a5ca79SManos Pitsidianakis ret = blk_pdiscard(blk, offset, bytes);
220550290c00SAlex Bennée clock_gettime(CLOCK_MONOTONIC, &t2);
2206797ac58cSKevin Wolf
2207797ac58cSKevin Wolf if (ret < 0) {
2208797ac58cSKevin Wolf printf("discard failed: %s\n", strerror(-ret));
2209b32d7a39SMax Reitz return ret;
2210797ac58cSKevin Wolf }
2211797ac58cSKevin Wolf
2212797ac58cSKevin Wolf /* Finally, report back -- -C gives a parsable format */
2213797ac58cSKevin Wolf if (!qflag) {
2214797ac58cSKevin Wolf t2 = tsub(t2, t1);
2215f5a5ca79SManos Pitsidianakis print_report("discard", &t2, offset, bytes, bytes, 1, Cflag);
2216797ac58cSKevin Wolf }
2217b32d7a39SMax Reitz
2218b32d7a39SMax Reitz return 0;
2219797ac58cSKevin Wolf }
2220797ac58cSKevin Wolf
alloc_f(BlockBackend * blk,int argc,char ** argv)2221b32d7a39SMax Reitz static int alloc_f(BlockBackend *blk, int argc, char **argv)
2222797ac58cSKevin Wolf {
22234c7b7e9bSMax Reitz BlockDriverState *bs = blk_bs(blk);
2224d6a644bbSEric Blake int64_t offset, start, remaining, count;
2225797ac58cSKevin Wolf char s1[64];
2226d6a644bbSEric Blake int ret;
2227d6a644bbSEric Blake int64_t num, sum_alloc;
2228797ac58cSKevin Wolf
2229d6a644bbSEric Blake start = offset = cvtnum(argv[1]);
2230797ac58cSKevin Wolf if (offset < 0) {
2231a9ecfa00SJohn Snow print_cvtnum_err(offset, argv[1]);
2232b32d7a39SMax Reitz return offset;
2233797ac58cSKevin Wolf }
2234797ac58cSKevin Wolf
2235797ac58cSKevin Wolf if (argc == 3) {
22364401fdc7SEric Blake count = cvtnum(argv[2]);
22374401fdc7SEric Blake if (count < 0) {
22384401fdc7SEric Blake print_cvtnum_err(count, argv[2]);
2239b32d7a39SMax Reitz return count;
2240797ac58cSKevin Wolf }
2241797ac58cSKevin Wolf } else {
22424401fdc7SEric Blake count = BDRV_SECTOR_SIZE;
2243797ac58cSKevin Wolf }
2244797ac58cSKevin Wolf
2245d6a644bbSEric Blake remaining = count;
2246797ac58cSKevin Wolf sum_alloc = 0;
2247797ac58cSKevin Wolf while (remaining) {
2248d6a644bbSEric Blake ret = bdrv_is_allocated(bs, offset, remaining, &num);
2249d663640cSPaolo Bonzini if (ret < 0) {
2250d663640cSPaolo Bonzini printf("is_allocated failed: %s\n", strerror(-ret));
2251b32d7a39SMax Reitz return ret;
2252d663640cSPaolo Bonzini }
2253d6a644bbSEric Blake offset += num;
2254797ac58cSKevin Wolf remaining -= num;
2255797ac58cSKevin Wolf if (ret) {
2256797ac58cSKevin Wolf sum_alloc += num;
2257797ac58cSKevin Wolf }
2258797ac58cSKevin Wolf if (num == 0) {
2259d6a644bbSEric Blake count -= remaining;
2260797ac58cSKevin Wolf remaining = 0;
2261797ac58cSKevin Wolf }
2262797ac58cSKevin Wolf }
2263797ac58cSKevin Wolf
2264d6a644bbSEric Blake cvtstr(start, s1, sizeof(s1));
2265797ac58cSKevin Wolf
22664401fdc7SEric Blake printf("%"PRId64"/%"PRId64" bytes allocated at offset %s\n",
2267d6a644bbSEric Blake sum_alloc, count, s1);
2268b32d7a39SMax Reitz return 0;
2269797ac58cSKevin Wolf }
2270797ac58cSKevin Wolf
2271797ac58cSKevin Wolf static const cmdinfo_t alloc_cmd = {
2272797ac58cSKevin Wolf .name = "alloc",
2273797ac58cSKevin Wolf .altname = "a",
2274797ac58cSKevin Wolf .argmin = 1,
2275797ac58cSKevin Wolf .argmax = 2,
2276797ac58cSKevin Wolf .cfunc = alloc_f,
22774401fdc7SEric Blake .args = "offset [count]",
22784401fdc7SEric Blake .oneline = "checks if offset is allocated in the file",
2279797ac58cSKevin Wolf };
2280797ac58cSKevin Wolf
2281797ac58cSKevin Wolf
map_is_allocated(BlockDriverState * bs,int64_t offset,int64_t bytes,int64_t * pnum)2282d6a644bbSEric Blake static int map_is_allocated(BlockDriverState *bs, int64_t offset,
2283d6a644bbSEric Blake int64_t bytes, int64_t *pnum)
2284797ac58cSKevin Wolf {
2285d6a644bbSEric Blake int64_t num;
2286797ac58cSKevin Wolf int ret, firstret;
2287797ac58cSKevin Wolf
2288087f2fb3SEric Blake ret = bdrv_is_allocated(bs, offset, bytes, &num);
2289797ac58cSKevin Wolf if (ret < 0) {
2290797ac58cSKevin Wolf return ret;
2291797ac58cSKevin Wolf }
2292797ac58cSKevin Wolf
2293797ac58cSKevin Wolf firstret = ret;
2294797ac58cSKevin Wolf *pnum = num;
2295797ac58cSKevin Wolf
2296d6a644bbSEric Blake while (bytes > 0 && ret == firstret) {
2297d6a644bbSEric Blake offset += num;
2298d6a644bbSEric Blake bytes -= num;
2299797ac58cSKevin Wolf
2300087f2fb3SEric Blake ret = bdrv_is_allocated(bs, offset, bytes, &num);
23014b25bbc4SMax Reitz if (ret == firstret && num) {
2302797ac58cSKevin Wolf *pnum += num;
2303797ac58cSKevin Wolf } else {
2304797ac58cSKevin Wolf break;
2305797ac58cSKevin Wolf }
2306797ac58cSKevin Wolf }
2307797ac58cSKevin Wolf
2308797ac58cSKevin Wolf return firstret;
2309797ac58cSKevin Wolf }
2310797ac58cSKevin Wolf
map_f(BlockBackend * blk,int argc,char ** argv)2311b32d7a39SMax Reitz static int map_f(BlockBackend *blk, int argc, char **argv)
2312797ac58cSKevin Wolf {
2313d6a644bbSEric Blake int64_t offset, bytes;
23146f3c90afSEric Blake char s1[64], s2[64];
2315797ac58cSKevin Wolf int64_t num;
2316797ac58cSKevin Wolf int ret;
2317797ac58cSKevin Wolf const char *retstr;
2318797ac58cSKevin Wolf
2319797ac58cSKevin Wolf offset = 0;
2320d6a644bbSEric Blake bytes = blk_getlength(blk);
2321d6a644bbSEric Blake if (bytes < 0) {
2322d6a644bbSEric Blake error_report("Failed to query image length: %s", strerror(-bytes));
2323b32d7a39SMax Reitz return bytes;
23244c7b7e9bSMax Reitz }
23254c7b7e9bSMax Reitz
2326d6a644bbSEric Blake while (bytes) {
2327d6a644bbSEric Blake ret = map_is_allocated(blk_bs(blk), offset, bytes, &num);
2328797ac58cSKevin Wolf if (ret < 0) {
2329797ac58cSKevin Wolf error_report("Failed to get allocation status: %s", strerror(-ret));
2330b32d7a39SMax Reitz return ret;
23314b25bbc4SMax Reitz } else if (!num) {
23324b25bbc4SMax Reitz error_report("Unexpected end of image");
2333b32d7a39SMax Reitz return -EIO;
2334797ac58cSKevin Wolf }
2335797ac58cSKevin Wolf
2336797ac58cSKevin Wolf retstr = ret ? " allocated" : "not allocated";
2337d6a644bbSEric Blake cvtstr(num, s1, sizeof(s1));
2338d6a644bbSEric Blake cvtstr(offset, s2, sizeof(s2));
23396f3c90afSEric Blake printf("%s (0x%" PRIx64 ") bytes %s at offset %s (0x%" PRIx64 ")\n",
2340d6a644bbSEric Blake s1, num, retstr, s2, offset);
2341797ac58cSKevin Wolf
2342797ac58cSKevin Wolf offset += num;
2343d6a644bbSEric Blake bytes -= num;
2344d6a644bbSEric Blake }
2345b32d7a39SMax Reitz
2346b32d7a39SMax Reitz return 0;
2347797ac58cSKevin Wolf }
2348797ac58cSKevin Wolf
2349797ac58cSKevin Wolf static const cmdinfo_t map_cmd = {
2350797ac58cSKevin Wolf .name = "map",
2351797ac58cSKevin Wolf .argmin = 0,
2352797ac58cSKevin Wolf .argmax = 0,
2353797ac58cSKevin Wolf .cfunc = map_f,
2354797ac58cSKevin Wolf .args = "",
2355797ac58cSKevin Wolf .oneline = "prints the allocated areas of a file",
2356797ac58cSKevin Wolf };
2357797ac58cSKevin Wolf
reopen_help(void)23585bbd2e59SKevin Wolf static void reopen_help(void)
23595bbd2e59SKevin Wolf {
23605bbd2e59SKevin Wolf printf(
23615bbd2e59SKevin Wolf "\n"
23625bbd2e59SKevin Wolf " Changes the open options of an already opened image\n"
23635bbd2e59SKevin Wolf "\n"
23645bbd2e59SKevin Wolf " Example:\n"
23655bbd2e59SKevin Wolf " 'reopen -o lazy-refcounts=on' - activates lazy refcount writeback on a qcow2 image\n"
23665bbd2e59SKevin Wolf "\n"
23675bbd2e59SKevin Wolf " -r, -- Reopen the image read-only\n"
2368ea92203cSKevin Wolf " -w, -- Reopen the image read-write\n"
23695bbd2e59SKevin Wolf " -c, -- Change the cache mode to the given value\n"
23705bbd2e59SKevin Wolf " -o, -- Changes block driver options (cf. 'open' command)\n"
23715bbd2e59SKevin Wolf "\n");
23725bbd2e59SKevin Wolf }
23735bbd2e59SKevin Wolf
2374b32d7a39SMax Reitz static int reopen_f(BlockBackend *blk, int argc, char **argv);
23755bbd2e59SKevin Wolf
23765bbd2e59SKevin Wolf static QemuOptsList reopen_opts = {
23775bbd2e59SKevin Wolf .name = "reopen",
23785bbd2e59SKevin Wolf .merge_lists = true,
23795bbd2e59SKevin Wolf .head = QTAILQ_HEAD_INITIALIZER(reopen_opts.head),
23805bbd2e59SKevin Wolf .desc = {
23815bbd2e59SKevin Wolf /* no elements => accept any params */
23825bbd2e59SKevin Wolf { /* end of list */ }
23835bbd2e59SKevin Wolf },
23845bbd2e59SKevin Wolf };
23855bbd2e59SKevin Wolf
23865bbd2e59SKevin Wolf static const cmdinfo_t reopen_cmd = {
23875bbd2e59SKevin Wolf .name = "reopen",
23885bbd2e59SKevin Wolf .argmin = 0,
23895bbd2e59SKevin Wolf .argmax = -1,
23905bbd2e59SKevin Wolf .cfunc = reopen_f,
2391ea92203cSKevin Wolf .args = "[(-r|-w)] [-c cache] [-o options]",
23925bbd2e59SKevin Wolf .oneline = "reopens an image with new options",
23935bbd2e59SKevin Wolf .help = reopen_help,
23945bbd2e59SKevin Wolf };
23955bbd2e59SKevin Wolf
reopen_f(BlockBackend * blk,int argc,char ** argv)2396b32d7a39SMax Reitz static int reopen_f(BlockBackend *blk, int argc, char **argv)
23975bbd2e59SKevin Wolf {
23985bbd2e59SKevin Wolf BlockDriverState *bs = blk_bs(blk);
23995bbd2e59SKevin Wolf QemuOpts *qopts;
24005bbd2e59SKevin Wolf QDict *opts;
24015bbd2e59SKevin Wolf int c;
24025bbd2e59SKevin Wolf int flags = bs->open_flags;
240319dbecdcSKevin Wolf bool writethrough = !blk_enable_write_cache(blk);
2404ea92203cSKevin Wolf bool has_rw_option = false;
2405dc900c35SAlberto Garcia bool has_cache_option = false;
24065bbd2e59SKevin Wolf Error *local_err = NULL;
24075bbd2e59SKevin Wolf
2408ea92203cSKevin Wolf while ((c = getopt(argc, argv, "c:o:rw")) != -1) {
24095bbd2e59SKevin Wolf switch (c) {
24105bbd2e59SKevin Wolf case 'c':
241119dbecdcSKevin Wolf if (bdrv_parse_cache_mode(optarg, &flags, &writethrough) < 0) {
24125bbd2e59SKevin Wolf error_report("Invalid cache option: %s", optarg);
2413b32d7a39SMax Reitz return -EINVAL;
24145bbd2e59SKevin Wolf }
2415dc900c35SAlberto Garcia has_cache_option = true;
24165bbd2e59SKevin Wolf break;
24175bbd2e59SKevin Wolf case 'o':
24185bbd2e59SKevin Wolf if (!qemu_opts_parse_noisily(&reopen_opts, optarg, 0)) {
24195bbd2e59SKevin Wolf qemu_opts_reset(&reopen_opts);
2420b32d7a39SMax Reitz return -EINVAL;
24215bbd2e59SKevin Wolf }
24225bbd2e59SKevin Wolf break;
24235bbd2e59SKevin Wolf case 'r':
2424ea92203cSKevin Wolf if (has_rw_option) {
2425ea92203cSKevin Wolf error_report("Only one -r/-w option may be given");
2426b32d7a39SMax Reitz return -EINVAL;
2427ea92203cSKevin Wolf }
24285bbd2e59SKevin Wolf flags &= ~BDRV_O_RDWR;
2429ea92203cSKevin Wolf has_rw_option = true;
2430ea92203cSKevin Wolf break;
2431ea92203cSKevin Wolf case 'w':
2432ea92203cSKevin Wolf if (has_rw_option) {
2433ea92203cSKevin Wolf error_report("Only one -r/-w option may be given");
2434b32d7a39SMax Reitz return -EINVAL;
2435ea92203cSKevin Wolf }
2436ea92203cSKevin Wolf flags |= BDRV_O_RDWR;
2437ea92203cSKevin Wolf has_rw_option = true;
24385bbd2e59SKevin Wolf break;
24395bbd2e59SKevin Wolf default:
24405bbd2e59SKevin Wolf qemu_opts_reset(&reopen_opts);
2441b444d0e9SMax Reitz qemuio_command_usage(&reopen_cmd);
2442b32d7a39SMax Reitz return -EINVAL;
24435bbd2e59SKevin Wolf }
24445bbd2e59SKevin Wolf }
24455bbd2e59SKevin Wolf
24465bbd2e59SKevin Wolf if (optind != argc) {
24475bbd2e59SKevin Wolf qemu_opts_reset(&reopen_opts);
2448b444d0e9SMax Reitz qemuio_command_usage(&reopen_cmd);
2449b32d7a39SMax Reitz return -EINVAL;
24505bbd2e59SKevin Wolf }
24515bbd2e59SKevin Wolf
2452a8003ec4SAlberto Garcia if (!writethrough != blk_enable_write_cache(blk) &&
245319dbecdcSKevin Wolf blk_get_attached_dev(blk))
245419dbecdcSKevin Wolf {
245519dbecdcSKevin Wolf error_report("Cannot change cache.writeback: Device attached");
245619dbecdcSKevin Wolf qemu_opts_reset(&reopen_opts);
2457b32d7a39SMax Reitz return -EBUSY;
245819dbecdcSKevin Wolf }
245919dbecdcSKevin Wolf
2460f3adefb2SKevin Wolf if (!(flags & BDRV_O_RDWR)) {
2461f3adefb2SKevin Wolf uint64_t orig_perm, orig_shared_perm;
2462f3adefb2SKevin Wolf
2463f3adefb2SKevin Wolf bdrv_drain(bs);
2464f3adefb2SKevin Wolf
2465f3adefb2SKevin Wolf blk_get_perm(blk, &orig_perm, &orig_shared_perm);
2466f3adefb2SKevin Wolf blk_set_perm(blk,
2467f3adefb2SKevin Wolf orig_perm & ~(BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED),
2468f3adefb2SKevin Wolf orig_shared_perm,
2469f3adefb2SKevin Wolf &error_abort);
2470f3adefb2SKevin Wolf }
2471f3adefb2SKevin Wolf
24725bbd2e59SKevin Wolf qopts = qemu_opts_find(&reopen_opts, NULL);
2473dc900c35SAlberto Garcia opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : qdict_new();
24745bbd2e59SKevin Wolf qemu_opts_reset(&reopen_opts);
24755bbd2e59SKevin Wolf
2476dc900c35SAlberto Garcia if (qdict_haskey(opts, BDRV_OPT_READ_ONLY)) {
2477dc900c35SAlberto Garcia if (has_rw_option) {
2478dc900c35SAlberto Garcia error_report("Cannot set both -r/-w and '" BDRV_OPT_READ_ONLY "'");
2479dc900c35SAlberto Garcia qobject_unref(opts);
2480dc900c35SAlberto Garcia return -EINVAL;
2481dc900c35SAlberto Garcia }
2482dc900c35SAlberto Garcia } else {
2483dc900c35SAlberto Garcia qdict_put_bool(opts, BDRV_OPT_READ_ONLY, !(flags & BDRV_O_RDWR));
2484dc900c35SAlberto Garcia }
2485dc900c35SAlberto Garcia
2486dc900c35SAlberto Garcia if (qdict_haskey(opts, BDRV_OPT_CACHE_DIRECT) ||
2487dc900c35SAlberto Garcia qdict_haskey(opts, BDRV_OPT_CACHE_NO_FLUSH)) {
2488dc900c35SAlberto Garcia if (has_cache_option) {
2489dc900c35SAlberto Garcia error_report("Cannot set both -c and the cache options");
2490dc900c35SAlberto Garcia qobject_unref(opts);
2491dc900c35SAlberto Garcia return -EINVAL;
2492dc900c35SAlberto Garcia }
2493dc900c35SAlberto Garcia } else {
2494dc900c35SAlberto Garcia qdict_put_bool(opts, BDRV_OPT_CACHE_DIRECT, flags & BDRV_O_NOCACHE);
2495dc900c35SAlberto Garcia qdict_put_bool(opts, BDRV_OPT_CACHE_NO_FLUSH, flags & BDRV_O_NO_FLUSH);
2496dc900c35SAlberto Garcia }
2497dc900c35SAlberto Garcia
24986cf42ca2SKevin Wolf bdrv_reopen(bs, opts, true, &local_err);
24991a63a907SKevin Wolf
25005bbd2e59SKevin Wolf if (local_err) {
25015bbd2e59SKevin Wolf error_report_err(local_err);
2502b32d7a39SMax Reitz return -EINVAL;
25035bbd2e59SKevin Wolf }
25045bbd2e59SKevin Wolf
2505b32d7a39SMax Reitz blk_set_enable_write_cache(blk, !writethrough);
2506b32d7a39SMax Reitz return 0;
2507b32d7a39SMax Reitz }
2508b32d7a39SMax Reitz
break_f(BlockBackend * blk,int argc,char ** argv)2509b32d7a39SMax Reitz static int break_f(BlockBackend *blk, int argc, char **argv)
2510797ac58cSKevin Wolf {
2511797ac58cSKevin Wolf int ret;
2512797ac58cSKevin Wolf
25134c7b7e9bSMax Reitz ret = bdrv_debug_breakpoint(blk_bs(blk), argv[1], argv[2]);
2514797ac58cSKevin Wolf if (ret < 0) {
2515797ac58cSKevin Wolf printf("Could not set breakpoint: %s\n", strerror(-ret));
2516b32d7a39SMax Reitz return ret;
2517797ac58cSKevin Wolf }
2518797ac58cSKevin Wolf
2519b32d7a39SMax Reitz return 0;
2520b32d7a39SMax Reitz }
2521b32d7a39SMax Reitz
remove_break_f(BlockBackend * blk,int argc,char ** argv)2522b32d7a39SMax Reitz static int remove_break_f(BlockBackend *blk, int argc, char **argv)
25234cc70e93SFam Zheng {
25244cc70e93SFam Zheng int ret;
25254cc70e93SFam Zheng
25264c7b7e9bSMax Reitz ret = bdrv_debug_remove_breakpoint(blk_bs(blk), argv[1]);
25274cc70e93SFam Zheng if (ret < 0) {
25284cc70e93SFam Zheng printf("Could not remove breakpoint %s: %s\n", argv[1], strerror(-ret));
2529b32d7a39SMax Reitz return ret;
25304cc70e93SFam Zheng }
2531b32d7a39SMax Reitz
2532b32d7a39SMax Reitz return 0;
25334cc70e93SFam Zheng }
25344cc70e93SFam Zheng
2535797ac58cSKevin Wolf static const cmdinfo_t break_cmd = {
2536797ac58cSKevin Wolf .name = "break",
2537797ac58cSKevin Wolf .argmin = 2,
2538797ac58cSKevin Wolf .argmax = 2,
2539797ac58cSKevin Wolf .cfunc = break_f,
2540797ac58cSKevin Wolf .args = "event tag",
2541797ac58cSKevin Wolf .oneline = "sets a breakpoint on event and tags the stopped "
2542797ac58cSKevin Wolf "request as tag",
2543797ac58cSKevin Wolf };
2544797ac58cSKevin Wolf
25454cc70e93SFam Zheng static const cmdinfo_t remove_break_cmd = {
25464cc70e93SFam Zheng .name = "remove_break",
25474cc70e93SFam Zheng .argmin = 1,
25484cc70e93SFam Zheng .argmax = 1,
25494cc70e93SFam Zheng .cfunc = remove_break_f,
25504cc70e93SFam Zheng .args = "tag",
25514cc70e93SFam Zheng .oneline = "remove a breakpoint by tag",
25524cc70e93SFam Zheng };
25534cc70e93SFam Zheng
resume_f(BlockBackend * blk,int argc,char ** argv)2554b32d7a39SMax Reitz static int resume_f(BlockBackend *blk, int argc, char **argv)
2555797ac58cSKevin Wolf {
2556797ac58cSKevin Wolf int ret;
2557797ac58cSKevin Wolf
25584c7b7e9bSMax Reitz ret = bdrv_debug_resume(blk_bs(blk), argv[1]);
2559797ac58cSKevin Wolf if (ret < 0) {
2560797ac58cSKevin Wolf printf("Could not resume request: %s\n", strerror(-ret));
2561b32d7a39SMax Reitz return ret;
2562797ac58cSKevin Wolf }
2563b32d7a39SMax Reitz
2564b32d7a39SMax Reitz return 0;
2565797ac58cSKevin Wolf }
2566797ac58cSKevin Wolf
2567797ac58cSKevin Wolf static const cmdinfo_t resume_cmd = {
2568797ac58cSKevin Wolf .name = "resume",
2569797ac58cSKevin Wolf .argmin = 1,
2570797ac58cSKevin Wolf .argmax = 1,
2571797ac58cSKevin Wolf .cfunc = resume_f,
2572797ac58cSKevin Wolf .args = "tag",
2573797ac58cSKevin Wolf .oneline = "resumes the request tagged as tag",
2574797ac58cSKevin Wolf };
2575797ac58cSKevin Wolf
wait_break_f(BlockBackend * blk,int argc,char ** argv)2576b32d7a39SMax Reitz static int wait_break_f(BlockBackend *blk, int argc, char **argv)
2577797ac58cSKevin Wolf {
25784c7b7e9bSMax Reitz while (!bdrv_debug_is_suspended(blk_bs(blk), argv[1])) {
25794c7b7e9bSMax Reitz aio_poll(blk_get_aio_context(blk), true);
2580797ac58cSKevin Wolf }
2581b32d7a39SMax Reitz return 0;
2582797ac58cSKevin Wolf }
2583797ac58cSKevin Wolf
2584797ac58cSKevin Wolf static const cmdinfo_t wait_break_cmd = {
2585797ac58cSKevin Wolf .name = "wait_break",
2586797ac58cSKevin Wolf .argmin = 1,
2587797ac58cSKevin Wolf .argmax = 1,
2588797ac58cSKevin Wolf .cfunc = wait_break_f,
2589797ac58cSKevin Wolf .args = "tag",
2590797ac58cSKevin Wolf .oneline = "waits for the suspension of a request",
2591797ac58cSKevin Wolf };
2592797ac58cSKevin Wolf
abort_f(BlockBackend * blk,int argc,char ** argv)2593b32d7a39SMax Reitz static int abort_f(BlockBackend *blk, int argc, char **argv)
2594797ac58cSKevin Wolf {
2595797ac58cSKevin Wolf abort();
2596797ac58cSKevin Wolf }
2597797ac58cSKevin Wolf
2598797ac58cSKevin Wolf static const cmdinfo_t abort_cmd = {
2599797ac58cSKevin Wolf .name = "abort",
2600797ac58cSKevin Wolf .cfunc = abort_f,
2601797ac58cSKevin Wolf .flags = CMD_NOFILE_OK,
2602797ac58cSKevin Wolf .oneline = "simulate a program crash using abort(3)",
2603797ac58cSKevin Wolf };
2604797ac58cSKevin Wolf
sigraise_help(void)26050e82dc7bSMax Reitz static void sigraise_help(void)
26060e82dc7bSMax Reitz {
26070e82dc7bSMax Reitz printf(
26080e82dc7bSMax Reitz "\n"
26090e82dc7bSMax Reitz " raises the given signal\n"
26100e82dc7bSMax Reitz "\n"
26110e82dc7bSMax Reitz " Example:\n"
26120e82dc7bSMax Reitz " 'sigraise %i' - raises SIGTERM\n"
26130e82dc7bSMax Reitz "\n"
26140e82dc7bSMax Reitz " Invokes raise(signal), where \"signal\" is the mandatory integer argument\n"
26150e82dc7bSMax Reitz " given to sigraise.\n"
26160e82dc7bSMax Reitz "\n", SIGTERM);
26170e82dc7bSMax Reitz }
26180e82dc7bSMax Reitz
2619b32d7a39SMax Reitz static int sigraise_f(BlockBackend *blk, int argc, char **argv);
26200e82dc7bSMax Reitz
26210e82dc7bSMax Reitz static const cmdinfo_t sigraise_cmd = {
26220e82dc7bSMax Reitz .name = "sigraise",
26230e82dc7bSMax Reitz .cfunc = sigraise_f,
26240e82dc7bSMax Reitz .argmin = 1,
26250e82dc7bSMax Reitz .argmax = 1,
26260e82dc7bSMax Reitz .flags = CMD_NOFILE_OK,
26270e82dc7bSMax Reitz .args = "signal",
26280e82dc7bSMax Reitz .oneline = "raises a signal",
26290e82dc7bSMax Reitz .help = sigraise_help,
26300e82dc7bSMax Reitz };
26310e82dc7bSMax Reitz
sigraise_f(BlockBackend * blk,int argc,char ** argv)2632b32d7a39SMax Reitz static int sigraise_f(BlockBackend *blk, int argc, char **argv)
26330e82dc7bSMax Reitz {
26349b0beaf3SJohn Snow int64_t sig = cvtnum(argv[1]);
26350e82dc7bSMax Reitz if (sig < 0) {
2636a9ecfa00SJohn Snow print_cvtnum_err(sig, argv[1]);
2637b32d7a39SMax Reitz return sig;
26389b0beaf3SJohn Snow } else if (sig > NSIG) {
26399b0beaf3SJohn Snow printf("signal argument '%s' is too large to be a valid signal\n",
26409b0beaf3SJohn Snow argv[1]);
2641b32d7a39SMax Reitz return -EINVAL;
26420e82dc7bSMax Reitz }
26430e82dc7bSMax Reitz
26440e82dc7bSMax Reitz /* Using raise() to kill this process does not necessarily flush all open
26450e82dc7bSMax Reitz * streams. At least stdout and stderr (although the latter should be
26460e82dc7bSMax Reitz * non-buffered anyway) should be flushed, though. */
26470e82dc7bSMax Reitz fflush(stdout);
26480e82dc7bSMax Reitz fflush(stderr);
26490e82dc7bSMax Reitz
26500e82dc7bSMax Reitz raise(sig);
2651b32d7a39SMax Reitz
2652b32d7a39SMax Reitz return 0;
26530e82dc7bSMax Reitz }
26540e82dc7bSMax Reitz
sleep_cb(void * opaque)2655cd33d02aSKevin Wolf static void sleep_cb(void *opaque)
2656cd33d02aSKevin Wolf {
2657cd33d02aSKevin Wolf bool *expired = opaque;
2658cd33d02aSKevin Wolf *expired = true;
2659cd33d02aSKevin Wolf }
2660cd33d02aSKevin Wolf
sleep_f(BlockBackend * blk,int argc,char ** argv)2661b32d7a39SMax Reitz static int sleep_f(BlockBackend *blk, int argc, char **argv)
2662cd33d02aSKevin Wolf {
2663cd33d02aSKevin Wolf char *endptr;
2664cd33d02aSKevin Wolf long ms;
2665cd33d02aSKevin Wolf struct QEMUTimer *timer;
2666cd33d02aSKevin Wolf bool expired = false;
2667cd33d02aSKevin Wolf
2668cd33d02aSKevin Wolf ms = strtol(argv[1], &endptr, 0);
2669cd33d02aSKevin Wolf if (ms < 0 || *endptr != '\0') {
2670cd33d02aSKevin Wolf printf("%s is not a valid number\n", argv[1]);
2671b32d7a39SMax Reitz return -EINVAL;
2672cd33d02aSKevin Wolf }
2673cd33d02aSKevin Wolf
2674cd33d02aSKevin Wolf timer = timer_new_ns(QEMU_CLOCK_HOST, sleep_cb, &expired);
2675cd33d02aSKevin Wolf timer_mod(timer, qemu_clock_get_ns(QEMU_CLOCK_HOST) + SCALE_MS * ms);
2676cd33d02aSKevin Wolf
2677cd33d02aSKevin Wolf while (!expired) {
2678cd33d02aSKevin Wolf main_loop_wait(false);
2679cd33d02aSKevin Wolf }
2680cd33d02aSKevin Wolf
2681cd33d02aSKevin Wolf timer_free(timer);
2682b32d7a39SMax Reitz return 0;
2683cd33d02aSKevin Wolf }
2684cd33d02aSKevin Wolf
2685cd33d02aSKevin Wolf static const cmdinfo_t sleep_cmd = {
2686cd33d02aSKevin Wolf .name = "sleep",
2687cd33d02aSKevin Wolf .argmin = 1,
2688cd33d02aSKevin Wolf .argmax = 1,
2689cd33d02aSKevin Wolf .cfunc = sleep_f,
2690cd33d02aSKevin Wolf .flags = CMD_NOFILE_OK,
2691cd33d02aSKevin Wolf .oneline = "waits for the given value in milliseconds",
2692cd33d02aSKevin Wolf };
2693cd33d02aSKevin Wolf
help_oneline(const char * cmd,const cmdinfo_t * ct)2694f18a834aSKevin Wolf static void help_oneline(const char *cmd, const cmdinfo_t *ct)
2695f18a834aSKevin Wolf {
2696f18a834aSKevin Wolf printf("%s ", cmd);
2697f18a834aSKevin Wolf
2698f18a834aSKevin Wolf if (ct->args) {
2699f18a834aSKevin Wolf printf("%s ", ct->args);
2700f18a834aSKevin Wolf }
2701f18a834aSKevin Wolf printf("-- %s\n", ct->oneline);
2702f18a834aSKevin Wolf }
2703f18a834aSKevin Wolf
help_onecmd(const char * cmd,const cmdinfo_t * ct)2704f18a834aSKevin Wolf static void help_onecmd(const char *cmd, const cmdinfo_t *ct)
2705f18a834aSKevin Wolf {
2706f18a834aSKevin Wolf help_oneline(cmd, ct);
2707f18a834aSKevin Wolf if (ct->help) {
2708f18a834aSKevin Wolf ct->help();
2709f18a834aSKevin Wolf }
2710f18a834aSKevin Wolf }
2711f18a834aSKevin Wolf
help_all(void)2712f18a834aSKevin Wolf static void help_all(void)
2713f18a834aSKevin Wolf {
2714f18a834aSKevin Wolf const cmdinfo_t *ct;
2715f18a834aSKevin Wolf
2716f18a834aSKevin Wolf for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) {
2717f18a834aSKevin Wolf help_oneline(ct->name, ct);
2718f18a834aSKevin Wolf }
2719f18a834aSKevin Wolf printf("\nUse 'help commandname' for extended help.\n");
2720f18a834aSKevin Wolf }
2721f18a834aSKevin Wolf
help_f(BlockBackend * blk,int argc,char ** argv)2722b32d7a39SMax Reitz static int help_f(BlockBackend *blk, int argc, char **argv)
2723f18a834aSKevin Wolf {
2724f18a834aSKevin Wolf const cmdinfo_t *ct;
2725f18a834aSKevin Wolf
2726da16f4b8SDr. David Alan Gilbert if (argc < 2) {
2727f18a834aSKevin Wolf help_all();
2728b32d7a39SMax Reitz return 0;
2729f18a834aSKevin Wolf }
2730f18a834aSKevin Wolf
2731f18a834aSKevin Wolf ct = find_command(argv[1]);
2732f18a834aSKevin Wolf if (ct == NULL) {
2733f18a834aSKevin Wolf printf("command %s not found\n", argv[1]);
2734b32d7a39SMax Reitz return -EINVAL;
2735f18a834aSKevin Wolf }
2736f18a834aSKevin Wolf
2737f18a834aSKevin Wolf help_onecmd(argv[1], ct);
2738b32d7a39SMax Reitz return 0;
2739f18a834aSKevin Wolf }
2740f18a834aSKevin Wolf
2741f18a834aSKevin Wolf static const cmdinfo_t help_cmd = {
2742f18a834aSKevin Wolf .name = "help",
2743f18a834aSKevin Wolf .altname = "?",
2744f18a834aSKevin Wolf .cfunc = help_f,
2745f18a834aSKevin Wolf .argmin = 0,
2746f18a834aSKevin Wolf .argmax = 1,
2747f18a834aSKevin Wolf .flags = CMD_FLAG_GLOBAL,
2748f18a834aSKevin Wolf .args = "[command]",
2749f18a834aSKevin Wolf .oneline = "help for one or all commands",
2750f18a834aSKevin Wolf };
2751f18a834aSKevin Wolf
275278632a3dSVladimir Sementsov-Ogievskiy /*
275378632a3dSVladimir Sementsov-Ogievskiy * Called with aio context of blk acquired. Or with qemu_get_aio_context()
275478632a3dSVladimir Sementsov-Ogievskiy * context acquired if blk is NULL.
275578632a3dSVladimir Sementsov-Ogievskiy */
qemuio_command(BlockBackend * blk,const char * cmd)2756b32d7a39SMax Reitz int qemuio_command(BlockBackend *blk, const char *cmd)
2757dd583296SKevin Wolf {
2758dd583296SKevin Wolf char *input;
2759dd583296SKevin Wolf const cmdinfo_t *ct;
2760dd583296SKevin Wolf char **v;
2761dd583296SKevin Wolf int c;
2762b32d7a39SMax Reitz int ret = 0;
2763dd583296SKevin Wolf
2764dd583296SKevin Wolf input = g_strdup(cmd);
2765dd583296SKevin Wolf v = breakline(input, &c);
2766dd583296SKevin Wolf if (c) {
2767dd583296SKevin Wolf ct = find_command(v[0]);
2768dd583296SKevin Wolf if (ct) {
2769b32d7a39SMax Reitz ret = command(blk, ct, c, v);
2770dd583296SKevin Wolf } else {
2771dd583296SKevin Wolf fprintf(stderr, "command \"%s\" not found\n", v[0]);
2772b32d7a39SMax Reitz ret = -EINVAL;
2773dd583296SKevin Wolf }
2774dd583296SKevin Wolf }
2775dd583296SKevin Wolf g_free(input);
2776dd583296SKevin Wolf g_free(v);
2777b32d7a39SMax Reitz
2778b32d7a39SMax Reitz return ret;
2779dd583296SKevin Wolf }
2780dd583296SKevin Wolf
init_qemuio_commands(void)2781797ac58cSKevin Wolf static void __attribute((constructor)) init_qemuio_commands(void)
2782797ac58cSKevin Wolf {
2783797ac58cSKevin Wolf /* initialize commands */
2784c2cdf5c5SKevin Wolf qemuio_add_command(&help_cmd);
2785c2cdf5c5SKevin Wolf qemuio_add_command(&read_cmd);
2786c2cdf5c5SKevin Wolf qemuio_add_command(&readv_cmd);
2787c2cdf5c5SKevin Wolf qemuio_add_command(&write_cmd);
2788c2cdf5c5SKevin Wolf qemuio_add_command(&writev_cmd);
2789c2cdf5c5SKevin Wolf qemuio_add_command(&aio_read_cmd);
2790c2cdf5c5SKevin Wolf qemuio_add_command(&aio_write_cmd);
2791c2cdf5c5SKevin Wolf qemuio_add_command(&aio_flush_cmd);
2792c2cdf5c5SKevin Wolf qemuio_add_command(&flush_cmd);
27936d43eaa3SSam Li qemuio_add_command(&zone_report_cmd);
27946d43eaa3SSam Li qemuio_add_command(&zone_open_cmd);
27956d43eaa3SSam Li qemuio_add_command(&zone_close_cmd);
27966d43eaa3SSam Li qemuio_add_command(&zone_finish_cmd);
27976d43eaa3SSam Li qemuio_add_command(&zone_reset_cmd);
2798fe4fe70dSSam Li qemuio_add_command(&zone_append_cmd);
2799c2cdf5c5SKevin Wolf qemuio_add_command(&truncate_cmd);
2800c2cdf5c5SKevin Wolf qemuio_add_command(&length_cmd);
2801c2cdf5c5SKevin Wolf qemuio_add_command(&info_cmd);
2802c2cdf5c5SKevin Wolf qemuio_add_command(&discard_cmd);
2803c2cdf5c5SKevin Wolf qemuio_add_command(&alloc_cmd);
2804c2cdf5c5SKevin Wolf qemuio_add_command(&map_cmd);
28055bbd2e59SKevin Wolf qemuio_add_command(&reopen_cmd);
2806c2cdf5c5SKevin Wolf qemuio_add_command(&break_cmd);
28074cc70e93SFam Zheng qemuio_add_command(&remove_break_cmd);
2808c2cdf5c5SKevin Wolf qemuio_add_command(&resume_cmd);
2809c2cdf5c5SKevin Wolf qemuio_add_command(&wait_break_cmd);
2810c2cdf5c5SKevin Wolf qemuio_add_command(&abort_cmd);
2811cd33d02aSKevin Wolf qemuio_add_command(&sleep_cmd);
28120e82dc7bSMax Reitz qemuio_add_command(&sigraise_cmd);
2813797ac58cSKevin Wolf }
2814