blob: 2f0d8ac25a469326ff92d0f572c9329249c1ac7b [file] [log] [blame]
Kevin Wolf797ac582013-06-05 14:19:31 +02001/*
2 * Command line utility to exercise the QEMU I/O path.
3 *
Eric Blake093ea232016-05-07 21:16:43 -06004 * Copyright (C) 2009-2016 Red Hat, Inc.
Kevin Wolf797ac582013-06-05 14:19:31 +02005 * Copyright (c) 2003-2005 Silicon Graphics, Inc.
6 *
7 * This work is licensed under the terms of the GNU GPL, version 2 or later.
8 * See the COPYING file in the top-level directory.
9 */
10
Peter Maydell80c71a22016-01-18 18:01:42 +000011#include "qemu/osdep.h"
Markus Armbrusterda34e652016-03-14 09:01:28 +010012#include "qapi/error.h"
Alberto Garciadc900c32018-11-12 16:00:42 +020013#include "qapi/qmp/qdict.h"
Kevin Wolf3d219942013-06-05 14:19:39 +020014#include "qemu-io.h"
Max Reitz4c7b7e92015-02-05 13:58:22 -050015#include "sysemu/block-backend.h"
16#include "block/block.h"
17#include "block/block_int.h" /* for info_f() */
Max Reitza8d8ecb2013-10-09 10:46:17 +020018#include "block/qapi.h"
Markus Armbrusterd49b6832015-03-17 18:29:20 +010019#include "qemu/error-report.h"
Alex Bligh6a1751b2013-08-21 16:02:47 +010020#include "qemu/main-loop.h"
Markus Armbruster922a01a2018-02-01 12:18:46 +010021#include "qemu/option.h"
Kevin Wolfcd33d022014-01-15 15:39:10 +010022#include "qemu/timer.h"
Veronia Bahaaf348b6d2016-03-20 19:16:19 +020023#include "qemu/cutils.h"
Peter Maydell5df022c2022-02-26 18:07:23 +000024#include "qemu/memalign.h"
Kevin Wolf797ac582013-06-05 14:19:31 +020025
26#define CMD_NOFILE_OK 0x01
27
Stefan Weilf9883882014-03-05 22:23:00 +010028bool qemuio_misalign;
Kevin Wolf797ac582013-06-05 14:19:31 +020029
Kevin Wolfc2cdf5c2013-06-05 14:19:36 +020030static cmdinfo_t *cmdtab;
31static int ncmds;
32
33static int compare_cmdname(const void *a, const void *b)
34{
35 return strcmp(((const cmdinfo_t *)a)->name,
36 ((const cmdinfo_t *)b)->name);
37}
38
39void qemuio_add_command(const cmdinfo_t *ci)
40{
Peter Maydell6aabeb52017-03-31 14:38:49 +010041 /* ci->perm assumes a file is open, but the GLOBAL and NOFILE_OK
42 * flags allow it not to be, so that combination is invalid.
43 * Catch it now rather than letting it manifest as a crash if a
44 * particular set of command line options are used.
45 */
46 assert(ci->perm == 0 ||
47 (ci->flags & (CMD_FLAG_GLOBAL | CMD_NOFILE_OK)) == 0);
Markus Armbruster02c4f262014-08-19 10:31:09 +020048 cmdtab = g_renew(cmdinfo_t, cmdtab, ++ncmds);
Kevin Wolfc2cdf5c2013-06-05 14:19:36 +020049 cmdtab[ncmds - 1] = *ci;
50 qsort(cmdtab, ncmds, sizeof(*cmdtab), compare_cmdname);
51}
52
Max Reitzb444d0e2018-05-09 21:42:58 +020053void qemuio_command_usage(const cmdinfo_t *ci)
Kevin Wolfc2cdf5c2013-06-05 14:19:36 +020054{
55 printf("%s %s -- %s\n", ci->name, ci->args, ci->oneline);
Kevin Wolfc2cdf5c2013-06-05 14:19:36 +020056}
57
Max Reitz4c7b7e92015-02-05 13:58:22 -050058static int init_check_command(BlockBackend *blk, const cmdinfo_t *ct)
Kevin Wolfc2cdf5c2013-06-05 14:19:36 +020059{
60 if (ct->flags & CMD_FLAG_GLOBAL) {
61 return 1;
62 }
Max Reitz4c7b7e92015-02-05 13:58:22 -050063 if (!(ct->flags & CMD_NOFILE_OK) && !blk) {
Kevin Wolfc2cdf5c2013-06-05 14:19:36 +020064 fprintf(stderr, "no file open, try 'help open'\n");
65 return 0;
66 }
67 return 1;
68}
69
Max Reitzb32d7a32018-05-09 21:42:59 +020070static int command(BlockBackend *blk, const cmdinfo_t *ct, int argc,
71 char **argv)
Kevin Wolfc2cdf5c2013-06-05 14:19:36 +020072{
73 char *cmd = argv[0];
74
Max Reitz4c7b7e92015-02-05 13:58:22 -050075 if (!init_check_command(blk, ct)) {
Max Reitzb32d7a32018-05-09 21:42:59 +020076 return -EINVAL;
Kevin Wolfc2cdf5c2013-06-05 14:19:36 +020077 }
78
79 if (argc - 1 < ct->argmin || (ct->argmax != -1 && argc - 1 > ct->argmax)) {
80 if (ct->argmax == -1) {
81 fprintf(stderr,
82 "bad argument count %d to %s, expected at least %d arguments\n",
83 argc-1, cmd, ct->argmin);
84 } else if (ct->argmin == ct->argmax) {
85 fprintf(stderr,
86 "bad argument count %d to %s, expected %d arguments\n",
87 argc-1, cmd, ct->argmin);
88 } else {
89 fprintf(stderr,
90 "bad argument count %d to %s, expected between %d and %d arguments\n",
91 argc-1, cmd, ct->argmin, ct->argmax);
92 }
Max Reitzb32d7a32018-05-09 21:42:59 +020093 return -EINVAL;
Kevin Wolfc2cdf5c2013-06-05 14:19:36 +020094 }
Kevin Wolf887354b2017-02-10 16:24:56 +010095
Vladimir Sementsov-Ogievskiy8eaf1012021-05-19 12:05:32 +030096 /*
97 * Request additional permissions if necessary for this command. The caller
Kevin Wolf887354b2017-02-10 16:24:56 +010098 * is responsible for restoring the original permissions afterwards if this
Vladimir Sementsov-Ogievskiy8eaf1012021-05-19 12:05:32 +030099 * is what it wants.
100 *
101 * Coverity thinks that blk may be NULL in the following if condition. It's
102 * not so: in init_check_command() we fail if blk is NULL for command with
103 * both CMD_FLAG_GLOBAL and CMD_NOFILE_OK flags unset. And in
104 * qemuio_add_command() we assert that command with non-zero .perm field
105 * doesn't set this flags. So, the following assertion is to silence
106 * Coverity:
107 */
108 assert(blk || !ct->perm);
Kevin Wolf887354b2017-02-10 16:24:56 +0100109 if (ct->perm && blk_is_available(blk)) {
110 uint64_t orig_perm, orig_shared_perm;
111 blk_get_perm(blk, &orig_perm, &orig_shared_perm);
112
113 if (ct->perm & ~orig_perm) {
114 uint64_t new_perm;
115 Error *local_err = NULL;
116 int ret;
117
118 new_perm = orig_perm | ct->perm;
119
120 ret = blk_set_perm(blk, new_perm, orig_shared_perm, &local_err);
121 if (ret < 0) {
122 error_report_err(local_err);
Max Reitzb32d7a32018-05-09 21:42:59 +0200123 return ret;
Kevin Wolf887354b2017-02-10 16:24:56 +0100124 }
125 }
126 }
127
Richard W.M. Jonesd339d762019-01-18 10:11:14 +0000128 qemu_reset_optind();
Max Reitzb32d7a32018-05-09 21:42:59 +0200129 return ct->cfunc(blk, argc, argv);
Kevin Wolfc2cdf5c2013-06-05 14:19:36 +0200130}
131
132static const cmdinfo_t *find_command(const char *cmd)
133{
134 cmdinfo_t *ct;
135
136 for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) {
137 if (strcmp(ct->name, cmd) == 0 ||
138 (ct->altname && strcmp(ct->altname, cmd) == 0))
139 {
140 return (const cmdinfo_t *)ct;
141 }
142 }
143 return NULL;
144}
145
Stefan Hajnoczi46940202013-11-14 11:54:18 +0100146/* Invoke fn() for commands with a matching prefix */
147void qemuio_complete_command(const char *input,
148 void (*fn)(const char *cmd, void *opaque),
149 void *opaque)
150{
151 cmdinfo_t *ct;
152 size_t input_len = strlen(input);
153
154 for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) {
155 if (strncmp(input, ct->name, input_len) == 0) {
156 fn(ct->name, opaque);
157 }
158 }
159}
160
Kevin Wolfc2cdf5c2013-06-05 14:19:36 +0200161static char **breakline(char *input, int *count)
162{
163 int c = 0;
164 char *p;
Markus Armbruster5839e532014-08-19 10:31:08 +0200165 char **rval = g_new0(char *, 1);
Kevin Wolfc2cdf5c2013-06-05 14:19:36 +0200166
167 while (rval && (p = qemu_strsep(&input, " ")) != NULL) {
168 if (!*p) {
169 continue;
170 }
171 c++;
Markus Armbruster08193dd2014-08-19 10:31:10 +0200172 rval = g_renew(char *, rval, (c + 1));
Kevin Wolfc2cdf5c2013-06-05 14:19:36 +0200173 rval[c - 1] = p;
174 rval[c] = NULL;
175 }
176 *count = c;
177 return rval;
178}
179
Kevin Wolf797ac582013-06-05 14:19:31 +0200180static int64_t cvtnum(const char *s)
181{
Markus Armbrusterf17fd4f2017-02-21 21:14:06 +0100182 int err;
Markus Armbrusterf46bfdb2017-02-21 21:14:07 +0100183 uint64_t value;
John Snowef5a7882015-11-05 18:53:03 -0500184
Markus Armbrusterf17fd4f2017-02-21 21:14:06 +0100185 err = qemu_strtosz(s, NULL, &value);
186 if (err < 0) {
187 return err;
188 }
Markus Armbrusterf46bfdb2017-02-21 21:14:07 +0100189 if (value > INT64_MAX) {
190 return -ERANGE;
191 }
Markus Armbrusterf17fd4f2017-02-21 21:14:06 +0100192 return value;
Kevin Wolf797ac582013-06-05 14:19:31 +0200193}
194
John Snowa9ecfa02015-11-05 18:53:04 -0500195static void print_cvtnum_err(int64_t rc, const char *arg)
196{
197 switch (rc) {
198 case -EINVAL:
199 printf("Parsing error: non-numeric argument,"
200 " or extraneous/unrecognized suffix -- %s\n", arg);
201 break;
202 case -ERANGE:
203 printf("Parsing error: argument too large -- %s\n", arg);
204 break;
205 default:
206 printf("Parsing error: %s\n", arg);
207 }
208}
209
Kevin Wolf0b613882013-06-05 14:19:38 +0200210#define EXABYTES(x) ((long long)(x) << 60)
211#define PETABYTES(x) ((long long)(x) << 50)
212#define TERABYTES(x) ((long long)(x) << 40)
213#define GIGABYTES(x) ((long long)(x) << 30)
214#define MEGABYTES(x) ((long long)(x) << 20)
215#define KILOBYTES(x) ((long long)(x) << 10)
216
217#define TO_EXABYTES(x) ((x) / EXABYTES(1))
218#define TO_PETABYTES(x) ((x) / PETABYTES(1))
219#define TO_TERABYTES(x) ((x) / TERABYTES(1))
220#define TO_GIGABYTES(x) ((x) / GIGABYTES(1))
221#define TO_MEGABYTES(x) ((x) / MEGABYTES(1))
222#define TO_KILOBYTES(x) ((x) / KILOBYTES(1))
223
224static void cvtstr(double value, char *str, size_t size)
225{
226 char *trim;
227 const char *suffix;
228
229 if (value >= EXABYTES(1)) {
230 suffix = " EiB";
231 snprintf(str, size - 4, "%.3f", TO_EXABYTES(value));
232 } else if (value >= PETABYTES(1)) {
233 suffix = " PiB";
234 snprintf(str, size - 4, "%.3f", TO_PETABYTES(value));
235 } else if (value >= TERABYTES(1)) {
236 suffix = " TiB";
237 snprintf(str, size - 4, "%.3f", TO_TERABYTES(value));
238 } else if (value >= GIGABYTES(1)) {
239 suffix = " GiB";
240 snprintf(str, size - 4, "%.3f", TO_GIGABYTES(value));
241 } else if (value >= MEGABYTES(1)) {
242 suffix = " MiB";
243 snprintf(str, size - 4, "%.3f", TO_MEGABYTES(value));
244 } else if (value >= KILOBYTES(1)) {
245 suffix = " KiB";
246 snprintf(str, size - 4, "%.3f", TO_KILOBYTES(value));
247 } else {
248 suffix = " bytes";
249 snprintf(str, size - 6, "%f", value);
250 }
251
252 trim = strstr(str, ".000");
253 if (trim) {
254 strcpy(trim, suffix);
255 } else {
256 strcat(str, suffix);
257 }
258}
259
260
261
Alex Bennée50290c02019-05-29 17:16:32 +0100262static struct timespec tsub(struct timespec t1, struct timespec t2)
Kevin Wolf0b613882013-06-05 14:19:38 +0200263{
Alex Bennée50290c02019-05-29 17:16:32 +0100264 t1.tv_nsec -= t2.tv_nsec;
265 if (t1.tv_nsec < 0) {
266 t1.tv_nsec += NANOSECONDS_PER_SECOND;
Kevin Wolf0b613882013-06-05 14:19:38 +0200267 t1.tv_sec--;
268 }
269 t1.tv_sec -= t2.tv_sec;
270 return t1;
271}
272
Alex Bennée50290c02019-05-29 17:16:32 +0100273static double tdiv(double value, struct timespec tv)
Kevin Wolf0b613882013-06-05 14:19:38 +0200274{
Alex Bennée50290c02019-05-29 17:16:32 +0100275 double seconds = tv.tv_sec + (tv.tv_nsec / 1e9);
276 return value / seconds;
Kevin Wolf0b613882013-06-05 14:19:38 +0200277}
278
279#define HOURS(sec) ((sec) / (60 * 60))
280#define MINUTES(sec) (((sec) % (60 * 60)) / 60)
281#define SECONDS(sec) ((sec) % 60)
282
283enum {
284 DEFAULT_TIME = 0x0,
285 TERSE_FIXED_TIME = 0x1,
286 VERBOSE_FIXED_TIME = 0x2,
287};
288
Alex Bennée50290c02019-05-29 17:16:32 +0100289static void timestr(struct timespec *tv, char *ts, size_t size, int format)
Kevin Wolf0b613882013-06-05 14:19:38 +0200290{
Alex Bennée50290c02019-05-29 17:16:32 +0100291 double frac_sec = tv->tv_nsec / 1e9;
Kevin Wolf0b613882013-06-05 14:19:38 +0200292
293 if (format & TERSE_FIXED_TIME) {
294 if (!HOURS(tv->tv_sec)) {
Alex Bennée50290c02019-05-29 17:16:32 +0100295 snprintf(ts, size, "%u:%05.2f",
296 (unsigned int) MINUTES(tv->tv_sec),
297 SECONDS(tv->tv_sec) + frac_sec);
Kevin Wolf0b613882013-06-05 14:19:38 +0200298 return;
299 }
300 format |= VERBOSE_FIXED_TIME; /* fallback if hours needed */
301 }
302
303 if ((format & VERBOSE_FIXED_TIME) || tv->tv_sec) {
Alex Bennée50290c02019-05-29 17:16:32 +0100304 snprintf(ts, size, "%u:%02u:%05.2f",
Kevin Wolf0b613882013-06-05 14:19:38 +0200305 (unsigned int) HOURS(tv->tv_sec),
306 (unsigned int) MINUTES(tv->tv_sec),
Alex Bennée50290c02019-05-29 17:16:32 +0100307 SECONDS(tv->tv_sec) + frac_sec);
Kevin Wolf0b613882013-06-05 14:19:38 +0200308 } else {
Alex Bennée50290c02019-05-29 17:16:32 +0100309 snprintf(ts, size, "%05.2f sec", frac_sec);
Kevin Wolf0b613882013-06-05 14:19:38 +0200310 }
311}
312
Kevin Wolf797ac582013-06-05 14:19:31 +0200313/*
314 * Parse the pattern argument to various sub-commands.
315 *
316 * Because the pattern is used as an argument to memset it must evaluate
317 * to an unsigned integer that fits into a single byte.
318 */
319static int parse_pattern(const char *arg)
320{
321 char *endptr = NULL;
322 long pattern;
323
324 pattern = strtol(arg, &endptr, 0);
325 if (pattern < 0 || pattern > UCHAR_MAX || *endptr != '\0') {
326 printf("%s is not a valid pattern byte\n", arg);
327 return -1;
328 }
329
330 return pattern;
331}
332
333/*
334 * Memory allocation helpers.
335 *
336 * Make sure memory is aligned by default, or purposefully misaligned if
337 * that is specified on the command line.
338 */
339
340#define MISALIGN_OFFSET 16
Max Reitz4c7b7e92015-02-05 13:58:22 -0500341static void *qemu_io_alloc(BlockBackend *blk, size_t len, int pattern)
Kevin Wolf797ac582013-06-05 14:19:31 +0200342{
343 void *buf;
344
345 if (qemuio_misalign) {
346 len += MISALIGN_OFFSET;
347 }
Max Reitz4c7b7e92015-02-05 13:58:22 -0500348 buf = blk_blockalign(blk, len);
Kevin Wolf797ac582013-06-05 14:19:31 +0200349 memset(buf, pattern, len);
350 if (qemuio_misalign) {
351 buf += MISALIGN_OFFSET;
352 }
353 return buf;
354}
355
356static void qemu_io_free(void *p)
357{
358 if (qemuio_misalign) {
359 p -= MISALIGN_OFFSET;
360 }
361 qemu_vfree(p);
362}
363
Denis Plotnikov4d731512019-08-20 19:46:16 +0300364/*
365 * qemu_io_alloc_from_file()
366 *
367 * Allocates the buffer and populates it with the content of the given file
368 * up to @len bytes. If the file length is less than @len, then the buffer
369 * is populated with the file content cyclically.
370 *
371 * @blk - the block backend where the buffer content is going to be written to
372 * @len - the buffer length
373 * @file_name - the file to read the content from
374 *
375 * Returns: the buffer pointer on success
376 * NULL on error
377 */
378static void *qemu_io_alloc_from_file(BlockBackend *blk, size_t len,
379 const char *file_name)
380{
381 char *buf, *buf_origin;
382 FILE *f = fopen(file_name, "r");
383 int pattern_len;
384
385 if (!f) {
386 perror(file_name);
387 return NULL;
388 }
389
390 if (qemuio_misalign) {
391 len += MISALIGN_OFFSET;
392 }
393
394 buf_origin = buf = blk_blockalign(blk, len);
395
396 if (qemuio_misalign) {
397 buf_origin += MISALIGN_OFFSET;
398 buf += MISALIGN_OFFSET;
399 len -= MISALIGN_OFFSET;
400 }
401
402 pattern_len = fread(buf_origin, 1, len, f);
403
404 if (ferror(f)) {
405 perror(file_name);
406 goto error;
407 }
408
409 if (pattern_len == 0) {
410 fprintf(stderr, "%s: file is empty\n", file_name);
411 goto error;
412 }
413
414 fclose(f);
Kevin Wolfc8e68b42019-09-10 09:03:06 +0200415 f = NULL;
Denis Plotnikov4d731512019-08-20 19:46:16 +0300416
417 if (len > pattern_len) {
418 len -= pattern_len;
419 buf += pattern_len;
420
421 while (len > 0) {
422 size_t len_to_copy = MIN(pattern_len, len);
423
424 memcpy(buf, buf_origin, len_to_copy);
425
426 len -= len_to_copy;
427 buf += len_to_copy;
428 }
429 }
430
431 return buf_origin;
432
433error:
434 qemu_io_free(buf_origin);
Kevin Wolfc8e68b42019-09-10 09:03:06 +0200435 if (f) {
436 fclose(f);
437 }
Denis Plotnikov4d731512019-08-20 19:46:16 +0300438 return NULL;
439}
440
John Snow9b0beaf2015-11-05 18:53:02 -0500441static void dump_buffer(const void *buffer, int64_t offset, int64_t len)
Kevin Wolf797ac582013-06-05 14:19:31 +0200442{
John Snow9b0beaf2015-11-05 18:53:02 -0500443 uint64_t i;
444 int j;
Kevin Wolf797ac582013-06-05 14:19:31 +0200445 const uint8_t *p;
446
447 for (i = 0, p = buffer; i < len; i += 16) {
448 const uint8_t *s = p;
449
450 printf("%08" PRIx64 ": ", offset + i);
451 for (j = 0; j < 16 && i + j < len; j++, p++) {
452 printf("%02x ", *p);
453 }
454 printf(" ");
455 for (j = 0; j < 16 && i + j < len; j++, s++) {
456 if (isalnum(*s)) {
457 printf("%c", *s);
458 } else {
459 printf(".");
460 }
461 }
462 printf("\n");
463 }
464}
465
Alex Bennée50290c02019-05-29 17:16:32 +0100466static void print_report(const char *op, struct timespec *t, int64_t offset,
Eric Blakedc388522016-05-07 21:16:42 -0600467 int64_t count, int64_t total, int cnt, bool Cflag)
Kevin Wolf797ac582013-06-05 14:19:31 +0200468{
469 char s1[64], s2[64], ts[64];
470
471 timestr(t, ts, sizeof(ts), Cflag ? VERBOSE_FIXED_TIME : 0);
472 if (!Cflag) {
473 cvtstr((double)total, s1, sizeof(s1));
474 cvtstr(tdiv((double)total, *t), s2, sizeof(s2));
John Snow9b0beaf2015-11-05 18:53:02 -0500475 printf("%s %"PRId64"/%"PRId64" bytes at offset %" PRId64 "\n",
Kevin Wolf797ac582013-06-05 14:19:31 +0200476 op, total, count, offset);
477 printf("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n",
478 s1, cnt, ts, s2, tdiv((double)cnt, *t));
479 } else {/* bytes,ops,time,bytes/sec,ops/sec */
John Snow9b0beaf2015-11-05 18:53:02 -0500480 printf("%"PRId64",%d,%s,%.3f,%.3f\n",
Kevin Wolf797ac582013-06-05 14:19:31 +0200481 total, cnt, ts,
482 tdiv((double)total, *t),
483 tdiv((double)cnt, *t));
484 }
485}
486
487/*
488 * Parse multiple length statements for vectored I/O, and construct an I/O
489 * vector matching it.
490 */
491static void *
Max Reitz4c7b7e92015-02-05 13:58:22 -0500492create_iovec(BlockBackend *blk, QEMUIOVector *qiov, char **argv, int nr_iov,
Kevin Wolf797ac582013-06-05 14:19:31 +0200493 int pattern)
494{
495 size_t *sizes = g_new0(size_t, nr_iov);
496 size_t count = 0;
497 void *buf = NULL;
498 void *p;
499 int i;
500
501 for (i = 0; i < nr_iov; i++) {
502 char *arg = argv[i];
503 int64_t len;
504
505 len = cvtnum(arg);
506 if (len < 0) {
John Snowa9ecfa02015-11-05 18:53:04 -0500507 print_cvtnum_err(len, arg);
Kevin Wolf797ac582013-06-05 14:19:31 +0200508 goto fail;
509 }
510
Alberto Garcia3026c462017-01-31 18:09:54 +0200511 if (len > BDRV_REQUEST_MAX_BYTES) {
512 printf("Argument '%s' exceeds maximum size %" PRIu64 "\n", arg,
513 (uint64_t)BDRV_REQUEST_MAX_BYTES);
514 goto fail;
515 }
516
517 if (count > BDRV_REQUEST_MAX_BYTES - len) {
518 printf("The total number of bytes exceed the maximum size %" PRIu64
519 "\n", (uint64_t)BDRV_REQUEST_MAX_BYTES);
Kevin Wolf797ac582013-06-05 14:19:31 +0200520 goto fail;
521 }
522
Kevin Wolf797ac582013-06-05 14:19:31 +0200523 sizes[i] = len;
524 count += len;
525 }
526
527 qemu_iovec_init(qiov, nr_iov);
528
Max Reitz4c7b7e92015-02-05 13:58:22 -0500529 buf = p = qemu_io_alloc(blk, count, pattern);
Kevin Wolf797ac582013-06-05 14:19:31 +0200530
531 for (i = 0; i < nr_iov; i++) {
532 qemu_iovec_add(qiov, p, sizes[i]);
533 p += sizes[i];
534 }
535
536fail:
537 g_free(sizes);
538 return buf;
539}
540
John Snow9b0beaf2015-11-05 18:53:02 -0500541static int do_pread(BlockBackend *blk, char *buf, int64_t offset,
Manos Pitsidianakisf5a5ca72017-06-09 13:18:08 +0300542 int64_t bytes, int64_t *total)
Kevin Wolf797ac582013-06-05 14:19:31 +0200543{
Manos Pitsidianakisf5a5ca72017-06-09 13:18:08 +0300544 if (bytes > INT_MAX) {
John Snow9b0beaf2015-11-05 18:53:02 -0500545 return -ERANGE;
546 }
547
Manos Pitsidianakisf5a5ca72017-06-09 13:18:08 +0300548 *total = blk_pread(blk, offset, (uint8_t *)buf, bytes);
Kevin Wolf797ac582013-06-05 14:19:31 +0200549 if (*total < 0) {
550 return *total;
551 }
552 return 1;
553}
554
John Snow9b0beaf2015-11-05 18:53:02 -0500555static int do_pwrite(BlockBackend *blk, char *buf, int64_t offset,
Manos Pitsidianakisf5a5ca72017-06-09 13:18:08 +0300556 int64_t bytes, int flags, int64_t *total)
Kevin Wolf797ac582013-06-05 14:19:31 +0200557{
Manos Pitsidianakisf5a5ca72017-06-09 13:18:08 +0300558 if (bytes > INT_MAX) {
John Snow9b0beaf2015-11-05 18:53:02 -0500559 return -ERANGE;
560 }
561
Manos Pitsidianakisf5a5ca72017-06-09 13:18:08 +0300562 *total = blk_pwrite(blk, offset, (uint8_t *)buf, bytes, flags);
Kevin Wolf797ac582013-06-05 14:19:31 +0200563 if (*total < 0) {
564 return *total;
565 }
566 return 1;
567}
568
569typedef struct {
Max Reitz4c7b7e92015-02-05 13:58:22 -0500570 BlockBackend *blk;
Kevin Wolf797ac582013-06-05 14:19:31 +0200571 int64_t offset;
Manos Pitsidianakisf5a5ca72017-06-09 13:18:08 +0300572 int64_t bytes;
John Snow9b0beaf2015-11-05 18:53:02 -0500573 int64_t *total;
Eric Blake770e0e02016-05-07 21:16:44 -0600574 int flags;
Kevin Wolf797ac582013-06-05 14:19:31 +0200575 int ret;
576 bool done;
577} CoWriteZeroes;
578
Eric Blaked004bd52016-05-24 16:25:20 -0600579static void coroutine_fn co_pwrite_zeroes_entry(void *opaque)
Kevin Wolf797ac582013-06-05 14:19:31 +0200580{
581 CoWriteZeroes *data = opaque;
582
Manos Pitsidianakisf5a5ca72017-06-09 13:18:08 +0300583 data->ret = blk_co_pwrite_zeroes(data->blk, data->offset, data->bytes,
Eric Blaked004bd52016-05-24 16:25:20 -0600584 data->flags);
Kevin Wolf797ac582013-06-05 14:19:31 +0200585 data->done = true;
586 if (data->ret < 0) {
587 *data->total = data->ret;
588 return;
589 }
590
Manos Pitsidianakisf5a5ca72017-06-09 13:18:08 +0300591 *data->total = data->bytes;
Kevin Wolf797ac582013-06-05 14:19:31 +0200592}
593
Eric Blaked004bd52016-05-24 16:25:20 -0600594static int do_co_pwrite_zeroes(BlockBackend *blk, int64_t offset,
Manos Pitsidianakisf5a5ca72017-06-09 13:18:08 +0300595 int64_t bytes, int flags, int64_t *total)
Kevin Wolf797ac582013-06-05 14:19:31 +0200596{
597 Coroutine *co;
598 CoWriteZeroes data = {
Max Reitz4c7b7e92015-02-05 13:58:22 -0500599 .blk = blk,
Kevin Wolf797ac582013-06-05 14:19:31 +0200600 .offset = offset,
Manos Pitsidianakisf5a5ca72017-06-09 13:18:08 +0300601 .bytes = bytes,
Kevin Wolf797ac582013-06-05 14:19:31 +0200602 .total = total,
Eric Blake770e0e02016-05-07 21:16:44 -0600603 .flags = flags,
Kevin Wolf797ac582013-06-05 14:19:31 +0200604 .done = false,
605 };
606
Paolo Bonzini0b8b8752016-07-04 19:10:01 +0200607 co = qemu_coroutine_create(co_pwrite_zeroes_entry, &data);
Fam Zheng324ec3e2017-04-10 20:16:18 +0800608 bdrv_coroutine_enter(blk_bs(blk), co);
Kevin Wolf797ac582013-06-05 14:19:31 +0200609 while (!data.done) {
Max Reitz4c7b7e92015-02-05 13:58:22 -0500610 aio_poll(blk_get_aio_context(blk), true);
Kevin Wolf797ac582013-06-05 14:19:31 +0200611 }
612 if (data.ret < 0) {
613 return data.ret;
614 } else {
615 return 1;
616 }
617}
618
Max Reitz4c7b7e92015-02-05 13:58:22 -0500619static int do_write_compressed(BlockBackend *blk, char *buf, int64_t offset,
Manos Pitsidianakisf5a5ca72017-06-09 13:18:08 +0300620 int64_t bytes, int64_t *total)
Kevin Wolf797ac582013-06-05 14:19:31 +0200621{
622 int ret;
623
Alberto Garcia41ae31e2019-05-14 16:57:35 +0300624 if (bytes > BDRV_REQUEST_MAX_BYTES) {
John Snow9b0beaf2015-11-05 18:53:02 -0500625 return -ERANGE;
626 }
627
Manos Pitsidianakisf5a5ca72017-06-09 13:18:08 +0300628 ret = blk_pwrite_compressed(blk, offset, buf, bytes);
Kevin Wolf797ac582013-06-05 14:19:31 +0200629 if (ret < 0) {
630 return ret;
631 }
Manos Pitsidianakisf5a5ca72017-06-09 13:18:08 +0300632 *total = bytes;
Kevin Wolf797ac582013-06-05 14:19:31 +0200633 return 1;
634}
635
Max Reitz4c7b7e92015-02-05 13:58:22 -0500636static int do_load_vmstate(BlockBackend *blk, char *buf, int64_t offset,
John Snow9b0beaf2015-11-05 18:53:02 -0500637 int64_t count, int64_t *total)
Kevin Wolf797ac582013-06-05 14:19:31 +0200638{
John Snow9b0beaf2015-11-05 18:53:02 -0500639 if (count > INT_MAX) {
640 return -ERANGE;
641 }
642
Max Reitz4c7b7e92015-02-05 13:58:22 -0500643 *total = blk_load_vmstate(blk, (uint8_t *)buf, offset, count);
Kevin Wolf797ac582013-06-05 14:19:31 +0200644 if (*total < 0) {
645 return *total;
646 }
647 return 1;
648}
649
Max Reitz4c7b7e92015-02-05 13:58:22 -0500650static int do_save_vmstate(BlockBackend *blk, char *buf, int64_t offset,
John Snow9b0beaf2015-11-05 18:53:02 -0500651 int64_t count, int64_t *total)
Kevin Wolf797ac582013-06-05 14:19:31 +0200652{
John Snow9b0beaf2015-11-05 18:53:02 -0500653 if (count > INT_MAX) {
654 return -ERANGE;
655 }
656
Max Reitz4c7b7e92015-02-05 13:58:22 -0500657 *total = blk_save_vmstate(blk, (uint8_t *)buf, offset, count);
Kevin Wolf797ac582013-06-05 14:19:31 +0200658 if (*total < 0) {
659 return *total;
660 }
661 return 1;
662}
663
664#define NOT_DONE 0x7fffffff
665static void aio_rw_done(void *opaque, int ret)
666{
667 *(int *)opaque = ret;
668}
669
Max Reitz4c7b7e92015-02-05 13:58:22 -0500670static int do_aio_readv(BlockBackend *blk, QEMUIOVector *qiov,
Kevin Wolf797ac582013-06-05 14:19:31 +0200671 int64_t offset, int *total)
672{
673 int async_ret = NOT_DONE;
674
Eric Blake7b3f9712016-05-06 10:26:44 -0600675 blk_aio_preadv(blk, offset, qiov, 0, aio_rw_done, &async_ret);
Kevin Wolf797ac582013-06-05 14:19:31 +0200676 while (async_ret == NOT_DONE) {
677 main_loop_wait(false);
678 }
679
680 *total = qiov->size;
681 return async_ret < 0 ? async_ret : 1;
682}
683
Max Reitz4c7b7e92015-02-05 13:58:22 -0500684static int do_aio_writev(BlockBackend *blk, QEMUIOVector *qiov,
Eric Blake770e0e02016-05-07 21:16:44 -0600685 int64_t offset, int flags, int *total)
Kevin Wolf797ac582013-06-05 14:19:31 +0200686{
687 int async_ret = NOT_DONE;
688
Eric Blake770e0e02016-05-07 21:16:44 -0600689 blk_aio_pwritev(blk, offset, qiov, flags, aio_rw_done, &async_ret);
Kevin Wolf797ac582013-06-05 14:19:31 +0200690 while (async_ret == NOT_DONE) {
691 main_loop_wait(false);
692 }
693
694 *total = qiov->size;
695 return async_ret < 0 ? async_ret : 1;
696}
697
Kevin Wolf797ac582013-06-05 14:19:31 +0200698static void read_help(void)
699{
700 printf(
701"\n"
702" reads a range of bytes from the given offset\n"
703"\n"
704" Example:\n"
705" 'read -v 512 1k' - dumps 1 kilobyte read from 512 bytes into the file\n"
706"\n"
707" Reads a segment of the currently open file, optionally dumping it to the\n"
708" standard output stream (with -v option) for subsequent inspection.\n"
709" -b, -- read from the VM state rather than the virtual disk\n"
710" -C, -- report statistics in a machine parsable format\n"
711" -l, -- length for pattern verification (only with -P)\n"
Eric Blake093ea232016-05-07 21:16:43 -0600712" -p, -- ignored for backwards compatibility\n"
Kevin Wolf797ac582013-06-05 14:19:31 +0200713" -P, -- use a pattern to verify read data\n"
714" -q, -- quiet mode, do not show I/O statistics\n"
715" -s, -- start offset for pattern verification (only with -P)\n"
716" -v, -- dump buffer to standard output\n"
717"\n");
718}
719
Max Reitzb32d7a32018-05-09 21:42:59 +0200720static int read_f(BlockBackend *blk, int argc, char **argv);
Kevin Wolf797ac582013-06-05 14:19:31 +0200721
722static const cmdinfo_t read_cmd = {
723 .name = "read",
724 .altname = "r",
725 .cfunc = read_f,
726 .argmin = 2,
727 .argmax = -1,
Eric Blake093ea232016-05-07 21:16:43 -0600728 .args = "[-abCqv] [-P pattern [-s off] [-l len]] off len",
Kevin Wolf797ac582013-06-05 14:19:31 +0200729 .oneline = "reads a number of bytes at a specified offset",
730 .help = read_help,
731};
732
Max Reitzb32d7a32018-05-09 21:42:59 +0200733static int read_f(BlockBackend *blk, int argc, char **argv)
Kevin Wolf797ac582013-06-05 14:19:31 +0200734{
Alex Bennée50290c02019-05-29 17:16:32 +0100735 struct timespec t1, t2;
Eric Blake093ea232016-05-07 21:16:43 -0600736 bool Cflag = false, qflag = false, vflag = false;
Eric Blakedc388522016-05-07 21:16:42 -0600737 bool Pflag = false, sflag = false, lflag = false, bflag = false;
Max Reitzb32d7a32018-05-09 21:42:59 +0200738 int c, cnt, ret;
Kevin Wolf797ac582013-06-05 14:19:31 +0200739 char *buf;
740 int64_t offset;
John Snow9b0beaf2015-11-05 18:53:02 -0500741 int64_t count;
Kevin Wolf797ac582013-06-05 14:19:31 +0200742 /* Some compilers get confused and warn if this is not initialized. */
John Snow9b0beaf2015-11-05 18:53:02 -0500743 int64_t total = 0;
744 int pattern = 0;
745 int64_t pattern_offset = 0, pattern_count = 0;
Kevin Wolf797ac582013-06-05 14:19:31 +0200746
Eric Blakeb062ad82015-05-12 09:10:56 -0600747 while ((c = getopt(argc, argv, "bCl:pP:qs:v")) != -1) {
Kevin Wolf797ac582013-06-05 14:19:31 +0200748 switch (c) {
749 case 'b':
Eric Blakedc388522016-05-07 21:16:42 -0600750 bflag = true;
Kevin Wolf797ac582013-06-05 14:19:31 +0200751 break;
752 case 'C':
Eric Blakedc388522016-05-07 21:16:42 -0600753 Cflag = true;
Kevin Wolf797ac582013-06-05 14:19:31 +0200754 break;
755 case 'l':
Eric Blakedc388522016-05-07 21:16:42 -0600756 lflag = true;
Kevin Wolf797ac582013-06-05 14:19:31 +0200757 pattern_count = cvtnum(optarg);
758 if (pattern_count < 0) {
John Snowa9ecfa02015-11-05 18:53:04 -0500759 print_cvtnum_err(pattern_count, optarg);
Max Reitzb32d7a32018-05-09 21:42:59 +0200760 return pattern_count;
Kevin Wolf797ac582013-06-05 14:19:31 +0200761 }
762 break;
763 case 'p':
Eric Blake093ea232016-05-07 21:16:43 -0600764 /* Ignored for backwards compatibility */
Kevin Wolf797ac582013-06-05 14:19:31 +0200765 break;
766 case 'P':
Eric Blakedc388522016-05-07 21:16:42 -0600767 Pflag = true;
Kevin Wolf797ac582013-06-05 14:19:31 +0200768 pattern = parse_pattern(optarg);
769 if (pattern < 0) {
Max Reitzb32d7a32018-05-09 21:42:59 +0200770 return -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +0200771 }
772 break;
773 case 'q':
Eric Blakedc388522016-05-07 21:16:42 -0600774 qflag = true;
Kevin Wolf797ac582013-06-05 14:19:31 +0200775 break;
776 case 's':
Eric Blakedc388522016-05-07 21:16:42 -0600777 sflag = true;
Kevin Wolf797ac582013-06-05 14:19:31 +0200778 pattern_offset = cvtnum(optarg);
779 if (pattern_offset < 0) {
John Snowa9ecfa02015-11-05 18:53:04 -0500780 print_cvtnum_err(pattern_offset, optarg);
Max Reitzb32d7a32018-05-09 21:42:59 +0200781 return pattern_offset;
Kevin Wolf797ac582013-06-05 14:19:31 +0200782 }
783 break;
784 case 'v':
Eric Blakedc388522016-05-07 21:16:42 -0600785 vflag = true;
Kevin Wolf797ac582013-06-05 14:19:31 +0200786 break;
787 default:
Max Reitzb444d0e2018-05-09 21:42:58 +0200788 qemuio_command_usage(&read_cmd);
Max Reitzb32d7a32018-05-09 21:42:59 +0200789 return -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +0200790 }
791 }
792
793 if (optind != argc - 2) {
Max Reitzb444d0e2018-05-09 21:42:58 +0200794 qemuio_command_usage(&read_cmd);
Max Reitzb32d7a32018-05-09 21:42:59 +0200795 return -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +0200796 }
797
Kevin Wolf797ac582013-06-05 14:19:31 +0200798 offset = cvtnum(argv[optind]);
799 if (offset < 0) {
John Snowa9ecfa02015-11-05 18:53:04 -0500800 print_cvtnum_err(offset, argv[optind]);
Max Reitzb32d7a32018-05-09 21:42:59 +0200801 return offset;
Kevin Wolf797ac582013-06-05 14:19:31 +0200802 }
803
804 optind++;
805 count = cvtnum(argv[optind]);
806 if (count < 0) {
John Snowa9ecfa02015-11-05 18:53:04 -0500807 print_cvtnum_err(count, argv[optind]);
Max Reitzb32d7a32018-05-09 21:42:59 +0200808 return count;
Alberto Garcia3026c462017-01-31 18:09:54 +0200809 } else if (count > BDRV_REQUEST_MAX_BYTES) {
John Snow9b0beaf2015-11-05 18:53:02 -0500810 printf("length cannot exceed %" PRIu64 ", given %s\n",
Alberto Garcia3026c462017-01-31 18:09:54 +0200811 (uint64_t)BDRV_REQUEST_MAX_BYTES, argv[optind]);
Max Reitzb32d7a32018-05-09 21:42:59 +0200812 return -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +0200813 }
814
815 if (!Pflag && (lflag || sflag)) {
Max Reitzb444d0e2018-05-09 21:42:58 +0200816 qemuio_command_usage(&read_cmd);
Max Reitzb32d7a32018-05-09 21:42:59 +0200817 return -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +0200818 }
819
820 if (!lflag) {
821 pattern_count = count - pattern_offset;
822 }
823
824 if ((pattern_count < 0) || (pattern_count + pattern_offset > count)) {
825 printf("pattern verification range exceeds end of read data\n");
Max Reitzb32d7a32018-05-09 21:42:59 +0200826 return -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +0200827 }
828
Eric Blake093ea232016-05-07 21:16:43 -0600829 if (bflag) {
Eric Blake1bce6b42017-04-29 14:14:11 -0500830 if (!QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE)) {
831 printf("%" PRId64 " is not a sector-aligned value for 'offset'\n",
Kevin Wolf797ac582013-06-05 14:19:31 +0200832 offset);
Max Reitzb32d7a32018-05-09 21:42:59 +0200833 return -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +0200834 }
Eric Blake1bce6b42017-04-29 14:14:11 -0500835 if (!QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE)) {
836 printf("%"PRId64" is not a sector-aligned value for 'count'\n",
Kevin Wolf797ac582013-06-05 14:19:31 +0200837 count);
Max Reitzb32d7a32018-05-09 21:42:59 +0200838 return -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +0200839 }
840 }
841
Max Reitz4c7b7e92015-02-05 13:58:22 -0500842 buf = qemu_io_alloc(blk, count, 0xab);
Kevin Wolf797ac582013-06-05 14:19:31 +0200843
Alex Bennée50290c02019-05-29 17:16:32 +0100844 clock_gettime(CLOCK_MONOTONIC, &t1);
Eric Blake7b3f9712016-05-06 10:26:44 -0600845 if (bflag) {
Max Reitzb32d7a32018-05-09 21:42:59 +0200846 ret = do_load_vmstate(blk, buf, offset, count, &total);
Kevin Wolf797ac582013-06-05 14:19:31 +0200847 } else {
Max Reitzb32d7a32018-05-09 21:42:59 +0200848 ret = do_pread(blk, buf, offset, count, &total);
Kevin Wolf797ac582013-06-05 14:19:31 +0200849 }
Alex Bennée50290c02019-05-29 17:16:32 +0100850 clock_gettime(CLOCK_MONOTONIC, &t2);
Kevin Wolf797ac582013-06-05 14:19:31 +0200851
Max Reitzb32d7a32018-05-09 21:42:59 +0200852 if (ret < 0) {
853 printf("read failed: %s\n", strerror(-ret));
Kevin Wolf797ac582013-06-05 14:19:31 +0200854 goto out;
855 }
Max Reitzb32d7a32018-05-09 21:42:59 +0200856 cnt = ret;
857
858 ret = 0;
Kevin Wolf797ac582013-06-05 14:19:31 +0200859
860 if (Pflag) {
861 void *cmp_buf = g_malloc(pattern_count);
862 memset(cmp_buf, pattern, pattern_count);
863 if (memcmp(buf + pattern_offset, cmp_buf, pattern_count)) {
864 printf("Pattern verification failed at offset %"
John Snow9b0beaf2015-11-05 18:53:02 -0500865 PRId64 ", %"PRId64" bytes\n",
Kevin Wolf797ac582013-06-05 14:19:31 +0200866 offset + pattern_offset, pattern_count);
Max Reitzb32d7a32018-05-09 21:42:59 +0200867 ret = -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +0200868 }
869 g_free(cmp_buf);
870 }
871
872 if (qflag) {
873 goto out;
874 }
875
876 if (vflag) {
877 dump_buffer(buf, offset, count);
878 }
879
880 /* Finally, report back -- -C gives a parsable format */
881 t2 = tsub(t2, t1);
882 print_report("read", &t2, offset, count, total, cnt, Cflag);
883
884out:
885 qemu_io_free(buf);
Max Reitzb32d7a32018-05-09 21:42:59 +0200886 return ret;
Kevin Wolf797ac582013-06-05 14:19:31 +0200887}
888
889static void readv_help(void)
890{
891 printf(
892"\n"
893" reads a range of bytes from the given offset into multiple buffers\n"
894"\n"
895" Example:\n"
896" 'readv -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n"
897"\n"
898" Reads a segment of the currently open file, optionally dumping it to the\n"
899" standard output stream (with -v option) for subsequent inspection.\n"
900" Uses multiple iovec buffers if more than one byte range is specified.\n"
901" -C, -- report statistics in a machine parsable format\n"
902" -P, -- use a pattern to verify read data\n"
903" -v, -- dump buffer to standard output\n"
904" -q, -- quiet mode, do not show I/O statistics\n"
905"\n");
906}
907
Max Reitzb32d7a32018-05-09 21:42:59 +0200908static int readv_f(BlockBackend *blk, int argc, char **argv);
Kevin Wolf797ac582013-06-05 14:19:31 +0200909
910static const cmdinfo_t readv_cmd = {
911 .name = "readv",
912 .cfunc = readv_f,
913 .argmin = 2,
914 .argmax = -1,
Eric Blake093ea232016-05-07 21:16:43 -0600915 .args = "[-Cqv] [-P pattern] off len [len..]",
Kevin Wolf797ac582013-06-05 14:19:31 +0200916 .oneline = "reads a number of bytes at a specified offset",
917 .help = readv_help,
918};
919
Max Reitzb32d7a32018-05-09 21:42:59 +0200920static int readv_f(BlockBackend *blk, int argc, char **argv)
Kevin Wolf797ac582013-06-05 14:19:31 +0200921{
Alex Bennée50290c02019-05-29 17:16:32 +0100922 struct timespec t1, t2;
Eric Blakedc388522016-05-07 21:16:42 -0600923 bool Cflag = false, qflag = false, vflag = false;
Max Reitzb32d7a32018-05-09 21:42:59 +0200924 int c, cnt, ret;
Kevin Wolf797ac582013-06-05 14:19:31 +0200925 char *buf;
926 int64_t offset;
927 /* Some compilers get confused and warn if this is not initialized. */
928 int total = 0;
929 int nr_iov;
930 QEMUIOVector qiov;
931 int pattern = 0;
Eric Blakedc388522016-05-07 21:16:42 -0600932 bool Pflag = false;
Kevin Wolf797ac582013-06-05 14:19:31 +0200933
Eric Blakeb062ad82015-05-12 09:10:56 -0600934 while ((c = getopt(argc, argv, "CP:qv")) != -1) {
Kevin Wolf797ac582013-06-05 14:19:31 +0200935 switch (c) {
936 case 'C':
Eric Blakedc388522016-05-07 21:16:42 -0600937 Cflag = true;
Kevin Wolf797ac582013-06-05 14:19:31 +0200938 break;
939 case 'P':
Eric Blakedc388522016-05-07 21:16:42 -0600940 Pflag = true;
Kevin Wolf797ac582013-06-05 14:19:31 +0200941 pattern = parse_pattern(optarg);
942 if (pattern < 0) {
Max Reitzb32d7a32018-05-09 21:42:59 +0200943 return -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +0200944 }
945 break;
946 case 'q':
Eric Blakedc388522016-05-07 21:16:42 -0600947 qflag = true;
Kevin Wolf797ac582013-06-05 14:19:31 +0200948 break;
949 case 'v':
Eric Blakedc388522016-05-07 21:16:42 -0600950 vflag = true;
Kevin Wolf797ac582013-06-05 14:19:31 +0200951 break;
952 default:
Max Reitzb444d0e2018-05-09 21:42:58 +0200953 qemuio_command_usage(&readv_cmd);
Max Reitzb32d7a32018-05-09 21:42:59 +0200954 return -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +0200955 }
956 }
957
958 if (optind > argc - 2) {
Max Reitzb444d0e2018-05-09 21:42:58 +0200959 qemuio_command_usage(&readv_cmd);
Max Reitzb32d7a32018-05-09 21:42:59 +0200960 return -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +0200961 }
962
963
964 offset = cvtnum(argv[optind]);
965 if (offset < 0) {
John Snowa9ecfa02015-11-05 18:53:04 -0500966 print_cvtnum_err(offset, argv[optind]);
Max Reitzb32d7a32018-05-09 21:42:59 +0200967 return offset;
Kevin Wolf797ac582013-06-05 14:19:31 +0200968 }
969 optind++;
970
Kevin Wolf797ac582013-06-05 14:19:31 +0200971 nr_iov = argc - optind;
Max Reitz4c7b7e92015-02-05 13:58:22 -0500972 buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, 0xab);
Kevin Wolf797ac582013-06-05 14:19:31 +0200973 if (buf == NULL) {
Max Reitzb32d7a32018-05-09 21:42:59 +0200974 return -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +0200975 }
976
Alex Bennée50290c02019-05-29 17:16:32 +0100977 clock_gettime(CLOCK_MONOTONIC, &t1);
Max Reitzb32d7a32018-05-09 21:42:59 +0200978 ret = do_aio_readv(blk, &qiov, offset, &total);
Alex Bennée50290c02019-05-29 17:16:32 +0100979 clock_gettime(CLOCK_MONOTONIC, &t2);
Kevin Wolf797ac582013-06-05 14:19:31 +0200980
Max Reitzb32d7a32018-05-09 21:42:59 +0200981 if (ret < 0) {
982 printf("readv failed: %s\n", strerror(-ret));
Kevin Wolf797ac582013-06-05 14:19:31 +0200983 goto out;
984 }
Max Reitzb32d7a32018-05-09 21:42:59 +0200985 cnt = ret;
986
987 ret = 0;
Kevin Wolf797ac582013-06-05 14:19:31 +0200988
989 if (Pflag) {
990 void *cmp_buf = g_malloc(qiov.size);
991 memset(cmp_buf, pattern, qiov.size);
992 if (memcmp(buf, cmp_buf, qiov.size)) {
993 printf("Pattern verification failed at offset %"
Stefan Weilcf67b692018-10-06 20:38:51 +0200994 PRId64 ", %zu bytes\n", offset, qiov.size);
Max Reitzb32d7a32018-05-09 21:42:59 +0200995 ret = -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +0200996 }
997 g_free(cmp_buf);
998 }
999
1000 if (qflag) {
1001 goto out;
1002 }
1003
1004 if (vflag) {
1005 dump_buffer(buf, offset, qiov.size);
1006 }
1007
1008 /* Finally, report back -- -C gives a parsable format */
1009 t2 = tsub(t2, t1);
1010 print_report("read", &t2, offset, qiov.size, total, cnt, Cflag);
1011
1012out:
1013 qemu_iovec_destroy(&qiov);
1014 qemu_io_free(buf);
Max Reitzb32d7a32018-05-09 21:42:59 +02001015 return ret;
Kevin Wolf797ac582013-06-05 14:19:31 +02001016}
1017
1018static void write_help(void)
1019{
1020 printf(
1021"\n"
1022" writes a range of bytes from the given offset\n"
1023"\n"
1024" Example:\n"
1025" 'write 512 1k' - writes 1 kilobyte at 512 bytes into the open file\n"
1026"\n"
1027" Writes into a segment of the currently open file, using a buffer\n"
1028" filled with a set pattern (0xcdcdcdcd).\n"
1029" -b, -- write to the VM state rather than the virtual disk\n"
Max Reitz4c7b7e92015-02-05 13:58:22 -05001030" -c, -- write compressed data with blk_write_compressed\n"
Eric Blake770e0e02016-05-07 21:16:44 -06001031" -f, -- use Force Unit Access semantics\n"
Kevin Wolfc6e3f522019-03-22 13:53:03 +01001032" -n, -- with -z, don't allow slow fallback\n"
Eric Blake093ea232016-05-07 21:16:43 -06001033" -p, -- ignored for backwards compatibility\n"
Kevin Wolf797ac582013-06-05 14:19:31 +02001034" -P, -- use different pattern to fill file\n"
Denis Plotnikov4d731512019-08-20 19:46:16 +03001035" -s, -- use a pattern file to fill the write buffer\n"
Kevin Wolf797ac582013-06-05 14:19:31 +02001036" -C, -- report statistics in a machine parsable format\n"
1037" -q, -- quiet mode, do not show I/O statistics\n"
Eric Blakec2e001c2016-05-07 21:16:45 -06001038" -u, -- with -z, allow unmapping\n"
Eric Blaked004bd52016-05-24 16:25:20 -06001039" -z, -- write zeroes using blk_co_pwrite_zeroes\n"
Kevin Wolf797ac582013-06-05 14:19:31 +02001040"\n");
1041}
1042
Max Reitzb32d7a32018-05-09 21:42:59 +02001043static int write_f(BlockBackend *blk, int argc, char **argv);
Kevin Wolf797ac582013-06-05 14:19:31 +02001044
1045static const cmdinfo_t write_cmd = {
1046 .name = "write",
1047 .altname = "w",
1048 .cfunc = write_f,
Kevin Wolf887354b2017-02-10 16:24:56 +01001049 .perm = BLK_PERM_WRITE,
Kevin Wolf797ac582013-06-05 14:19:31 +02001050 .argmin = 2,
1051 .argmax = -1,
Denis Plotnikov4d731512019-08-20 19:46:16 +03001052 .args = "[-bcCfnquz] [-P pattern | -s source_file] off len",
Kevin Wolf797ac582013-06-05 14:19:31 +02001053 .oneline = "writes a number of bytes at a specified offset",
1054 .help = write_help,
1055};
1056
Max Reitzb32d7a32018-05-09 21:42:59 +02001057static int write_f(BlockBackend *blk, int argc, char **argv)
Kevin Wolf797ac582013-06-05 14:19:31 +02001058{
Alex Bennée50290c02019-05-29 17:16:32 +01001059 struct timespec t1, t2;
Eric Blake093ea232016-05-07 21:16:43 -06001060 bool Cflag = false, qflag = false, bflag = false;
Denis Plotnikov4d731512019-08-20 19:46:16 +03001061 bool Pflag = false, zflag = false, cflag = false, sflag = false;
Eric Blake770e0e02016-05-07 21:16:44 -06001062 int flags = 0;
Max Reitzb32d7a32018-05-09 21:42:59 +02001063 int c, cnt, ret;
Kevin Wolf797ac582013-06-05 14:19:31 +02001064 char *buf = NULL;
1065 int64_t offset;
John Snow9b0beaf2015-11-05 18:53:02 -05001066 int64_t count;
Kevin Wolf797ac582013-06-05 14:19:31 +02001067 /* Some compilers get confused and warn if this is not initialized. */
John Snow9b0beaf2015-11-05 18:53:02 -05001068 int64_t total = 0;
Kevin Wolf797ac582013-06-05 14:19:31 +02001069 int pattern = 0xcd;
Denis Plotnikov4d731512019-08-20 19:46:16 +03001070 const char *file_name = NULL;
Kevin Wolf797ac582013-06-05 14:19:31 +02001071
Denis Plotnikov4d731512019-08-20 19:46:16 +03001072 while ((c = getopt(argc, argv, "bcCfnpP:qs:uz")) != -1) {
Kevin Wolf797ac582013-06-05 14:19:31 +02001073 switch (c) {
1074 case 'b':
Eric Blakedc388522016-05-07 21:16:42 -06001075 bflag = true;
Kevin Wolf797ac582013-06-05 14:19:31 +02001076 break;
1077 case 'c':
Eric Blakedc388522016-05-07 21:16:42 -06001078 cflag = true;
Kevin Wolf797ac582013-06-05 14:19:31 +02001079 break;
1080 case 'C':
Eric Blakedc388522016-05-07 21:16:42 -06001081 Cflag = true;
Kevin Wolf797ac582013-06-05 14:19:31 +02001082 break;
Eric Blake770e0e02016-05-07 21:16:44 -06001083 case 'f':
1084 flags |= BDRV_REQ_FUA;
1085 break;
Kevin Wolfc6e3f522019-03-22 13:53:03 +01001086 case 'n':
1087 flags |= BDRV_REQ_NO_FALLBACK;
1088 break;
Kevin Wolf797ac582013-06-05 14:19:31 +02001089 case 'p':
Eric Blake093ea232016-05-07 21:16:43 -06001090 /* Ignored for backwards compatibility */
Kevin Wolf797ac582013-06-05 14:19:31 +02001091 break;
1092 case 'P':
Eric Blakedc388522016-05-07 21:16:42 -06001093 Pflag = true;
Kevin Wolf797ac582013-06-05 14:19:31 +02001094 pattern = parse_pattern(optarg);
1095 if (pattern < 0) {
Max Reitzb32d7a32018-05-09 21:42:59 +02001096 return -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +02001097 }
1098 break;
1099 case 'q':
Eric Blakedc388522016-05-07 21:16:42 -06001100 qflag = true;
Kevin Wolf797ac582013-06-05 14:19:31 +02001101 break;
Denis Plotnikov4d731512019-08-20 19:46:16 +03001102 case 's':
1103 sflag = true;
1104 file_name = optarg;
1105 break;
Eric Blakec2e001c2016-05-07 21:16:45 -06001106 case 'u':
1107 flags |= BDRV_REQ_MAY_UNMAP;
1108 break;
Kevin Wolf797ac582013-06-05 14:19:31 +02001109 case 'z':
Eric Blakedc388522016-05-07 21:16:42 -06001110 zflag = true;
Kevin Wolf797ac582013-06-05 14:19:31 +02001111 break;
1112 default:
Max Reitzb444d0e2018-05-09 21:42:58 +02001113 qemuio_command_usage(&write_cmd);
Max Reitzb32d7a32018-05-09 21:42:59 +02001114 return -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +02001115 }
1116 }
1117
1118 if (optind != argc - 2) {
Max Reitzb444d0e2018-05-09 21:42:58 +02001119 qemuio_command_usage(&write_cmd);
Max Reitzb32d7a32018-05-09 21:42:59 +02001120 return -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +02001121 }
1122
Eric Blake093ea232016-05-07 21:16:43 -06001123 if (bflag && zflag) {
1124 printf("-b and -z cannot be specified at the same time\n");
Max Reitzb32d7a32018-05-09 21:42:59 +02001125 return -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +02001126 }
1127
Eric Blake770e0e02016-05-07 21:16:44 -06001128 if ((flags & BDRV_REQ_FUA) && (bflag || cflag)) {
1129 printf("-f and -b or -c cannot be specified at the same time\n");
Max Reitzb32d7a32018-05-09 21:42:59 +02001130 return -EINVAL;
Eric Blake770e0e02016-05-07 21:16:44 -06001131 }
1132
Kevin Wolfc6e3f522019-03-22 13:53:03 +01001133 if ((flags & BDRV_REQ_NO_FALLBACK) && !zflag) {
1134 printf("-n requires -z to be specified\n");
1135 return -EINVAL;
1136 }
1137
Eric Blakec2e001c2016-05-07 21:16:45 -06001138 if ((flags & BDRV_REQ_MAY_UNMAP) && !zflag) {
1139 printf("-u requires -z to be specified\n");
Max Reitzb32d7a32018-05-09 21:42:59 +02001140 return -EINVAL;
Eric Blakec2e001c2016-05-07 21:16:45 -06001141 }
1142
Denis Plotnikov4d731512019-08-20 19:46:16 +03001143 if (zflag + Pflag + sflag > 1) {
1144 printf("Only one of -z, -P, and -s "
1145 "can be specified at the same time\n");
Max Reitzb32d7a32018-05-09 21:42:59 +02001146 return -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +02001147 }
1148
1149 offset = cvtnum(argv[optind]);
1150 if (offset < 0) {
John Snowa9ecfa02015-11-05 18:53:04 -05001151 print_cvtnum_err(offset, argv[optind]);
Max Reitzb32d7a32018-05-09 21:42:59 +02001152 return offset;
Kevin Wolf797ac582013-06-05 14:19:31 +02001153 }
1154
1155 optind++;
1156 count = cvtnum(argv[optind]);
1157 if (count < 0) {
John Snowa9ecfa02015-11-05 18:53:04 -05001158 print_cvtnum_err(count, argv[optind]);
Max Reitzb32d7a32018-05-09 21:42:59 +02001159 return count;
Eric Blake395aecd2021-12-03 17:15:28 -06001160 } else if (count > BDRV_REQUEST_MAX_BYTES &&
1161 !(flags & BDRV_REQ_NO_FALLBACK)) {
1162 printf("length cannot exceed %" PRIu64 " without -n, given %s\n",
Alberto Garcia3026c462017-01-31 18:09:54 +02001163 (uint64_t)BDRV_REQUEST_MAX_BYTES, argv[optind]);
Max Reitzb32d7a32018-05-09 21:42:59 +02001164 return -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +02001165 }
1166
Eric Blake093ea232016-05-07 21:16:43 -06001167 if (bflag || cflag) {
Eric Blake1bce6b42017-04-29 14:14:11 -05001168 if (!QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE)) {
1169 printf("%" PRId64 " is not a sector-aligned value for 'offset'\n",
Kevin Wolf797ac582013-06-05 14:19:31 +02001170 offset);
Max Reitzb32d7a32018-05-09 21:42:59 +02001171 return -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +02001172 }
1173
Eric Blake1bce6b42017-04-29 14:14:11 -05001174 if (!QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE)) {
1175 printf("%"PRId64" is not a sector-aligned value for 'count'\n",
Kevin Wolf797ac582013-06-05 14:19:31 +02001176 count);
Max Reitzb32d7a32018-05-09 21:42:59 +02001177 return -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +02001178 }
1179 }
1180
1181 if (!zflag) {
Denis Plotnikov4d731512019-08-20 19:46:16 +03001182 if (sflag) {
1183 buf = qemu_io_alloc_from_file(blk, count, file_name);
1184 if (!buf) {
1185 return -EINVAL;
1186 }
1187 } else {
1188 buf = qemu_io_alloc(blk, count, pattern);
1189 }
Kevin Wolf797ac582013-06-05 14:19:31 +02001190 }
1191
Alex Bennée50290c02019-05-29 17:16:32 +01001192 clock_gettime(CLOCK_MONOTONIC, &t1);
Eric Blake7b3f9712016-05-06 10:26:44 -06001193 if (bflag) {
Max Reitzb32d7a32018-05-09 21:42:59 +02001194 ret = do_save_vmstate(blk, buf, offset, count, &total);
Kevin Wolf797ac582013-06-05 14:19:31 +02001195 } else if (zflag) {
Max Reitzb32d7a32018-05-09 21:42:59 +02001196 ret = do_co_pwrite_zeroes(blk, offset, count, flags, &total);
Kevin Wolf797ac582013-06-05 14:19:31 +02001197 } else if (cflag) {
Max Reitzb32d7a32018-05-09 21:42:59 +02001198 ret = do_write_compressed(blk, buf, offset, count, &total);
Kevin Wolf797ac582013-06-05 14:19:31 +02001199 } else {
Max Reitzb32d7a32018-05-09 21:42:59 +02001200 ret = do_pwrite(blk, buf, offset, count, flags, &total);
Kevin Wolf797ac582013-06-05 14:19:31 +02001201 }
Alex Bennée50290c02019-05-29 17:16:32 +01001202 clock_gettime(CLOCK_MONOTONIC, &t2);
Kevin Wolf797ac582013-06-05 14:19:31 +02001203
Max Reitzb32d7a32018-05-09 21:42:59 +02001204 if (ret < 0) {
1205 printf("write failed: %s\n", strerror(-ret));
Kevin Wolf797ac582013-06-05 14:19:31 +02001206 goto out;
1207 }
Max Reitzb32d7a32018-05-09 21:42:59 +02001208 cnt = ret;
1209
1210 ret = 0;
Kevin Wolf797ac582013-06-05 14:19:31 +02001211
1212 if (qflag) {
1213 goto out;
1214 }
1215
1216 /* Finally, report back -- -C gives a parsable format */
1217 t2 = tsub(t2, t1);
1218 print_report("wrote", &t2, offset, count, total, cnt, Cflag);
1219
1220out:
1221 if (!zflag) {
1222 qemu_io_free(buf);
1223 }
Max Reitzb32d7a32018-05-09 21:42:59 +02001224 return ret;
Kevin Wolf797ac582013-06-05 14:19:31 +02001225}
1226
1227static void
1228writev_help(void)
1229{
1230 printf(
1231"\n"
1232" writes a range of bytes from the given offset source from multiple buffers\n"
1233"\n"
1234" Example:\n"
Maria Kustova6e6507c2014-03-18 09:59:17 +04001235" 'writev 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n"
Kevin Wolf797ac582013-06-05 14:19:31 +02001236"\n"
1237" Writes into a segment of the currently open file, using a buffer\n"
1238" filled with a set pattern (0xcdcdcdcd).\n"
1239" -P, -- use different pattern to fill file\n"
1240" -C, -- report statistics in a machine parsable format\n"
Eric Blake770e0e02016-05-07 21:16:44 -06001241" -f, -- use Force Unit Access semantics\n"
Kevin Wolf797ac582013-06-05 14:19:31 +02001242" -q, -- quiet mode, do not show I/O statistics\n"
1243"\n");
1244}
1245
Max Reitzb32d7a32018-05-09 21:42:59 +02001246static int writev_f(BlockBackend *blk, int argc, char **argv);
Kevin Wolf797ac582013-06-05 14:19:31 +02001247
1248static const cmdinfo_t writev_cmd = {
1249 .name = "writev",
1250 .cfunc = writev_f,
Kevin Wolf887354b2017-02-10 16:24:56 +01001251 .perm = BLK_PERM_WRITE,
Kevin Wolf797ac582013-06-05 14:19:31 +02001252 .argmin = 2,
1253 .argmax = -1,
Eric Blake770e0e02016-05-07 21:16:44 -06001254 .args = "[-Cfq] [-P pattern] off len [len..]",
Kevin Wolf797ac582013-06-05 14:19:31 +02001255 .oneline = "writes a number of bytes at a specified offset",
1256 .help = writev_help,
1257};
1258
Max Reitzb32d7a32018-05-09 21:42:59 +02001259static int writev_f(BlockBackend *blk, int argc, char **argv)
Kevin Wolf797ac582013-06-05 14:19:31 +02001260{
Alex Bennée50290c02019-05-29 17:16:32 +01001261 struct timespec t1, t2;
Eric Blakedc388522016-05-07 21:16:42 -06001262 bool Cflag = false, qflag = false;
Eric Blake770e0e02016-05-07 21:16:44 -06001263 int flags = 0;
Max Reitzb32d7a32018-05-09 21:42:59 +02001264 int c, cnt, ret;
Kevin Wolf797ac582013-06-05 14:19:31 +02001265 char *buf;
1266 int64_t offset;
1267 /* Some compilers get confused and warn if this is not initialized. */
1268 int total = 0;
1269 int nr_iov;
1270 int pattern = 0xcd;
1271 QEMUIOVector qiov;
1272
Eric Blake4ca1d342016-05-16 10:43:01 -06001273 while ((c = getopt(argc, argv, "CfqP:")) != -1) {
Kevin Wolf797ac582013-06-05 14:19:31 +02001274 switch (c) {
1275 case 'C':
Eric Blakedc388522016-05-07 21:16:42 -06001276 Cflag = true;
Kevin Wolf797ac582013-06-05 14:19:31 +02001277 break;
Eric Blake770e0e02016-05-07 21:16:44 -06001278 case 'f':
1279 flags |= BDRV_REQ_FUA;
1280 break;
Kevin Wolf797ac582013-06-05 14:19:31 +02001281 case 'q':
Eric Blakedc388522016-05-07 21:16:42 -06001282 qflag = true;
Kevin Wolf797ac582013-06-05 14:19:31 +02001283 break;
1284 case 'P':
1285 pattern = parse_pattern(optarg);
1286 if (pattern < 0) {
Max Reitzb32d7a32018-05-09 21:42:59 +02001287 return -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +02001288 }
1289 break;
1290 default:
Max Reitzb444d0e2018-05-09 21:42:58 +02001291 qemuio_command_usage(&writev_cmd);
Max Reitzb32d7a32018-05-09 21:42:59 +02001292 return -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +02001293 }
1294 }
1295
1296 if (optind > argc - 2) {
Max Reitzb444d0e2018-05-09 21:42:58 +02001297 qemuio_command_usage(&writev_cmd);
Max Reitzb32d7a32018-05-09 21:42:59 +02001298 return -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +02001299 }
1300
1301 offset = cvtnum(argv[optind]);
1302 if (offset < 0) {
John Snowa9ecfa02015-11-05 18:53:04 -05001303 print_cvtnum_err(offset, argv[optind]);
Max Reitzb32d7a32018-05-09 21:42:59 +02001304 return offset;
Kevin Wolf797ac582013-06-05 14:19:31 +02001305 }
1306 optind++;
1307
Kevin Wolf797ac582013-06-05 14:19:31 +02001308 nr_iov = argc - optind;
Max Reitz4c7b7e92015-02-05 13:58:22 -05001309 buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, pattern);
Kevin Wolf797ac582013-06-05 14:19:31 +02001310 if (buf == NULL) {
Max Reitzb32d7a32018-05-09 21:42:59 +02001311 return -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +02001312 }
1313
Alex Bennée50290c02019-05-29 17:16:32 +01001314 clock_gettime(CLOCK_MONOTONIC, &t1);
Max Reitzb32d7a32018-05-09 21:42:59 +02001315 ret = do_aio_writev(blk, &qiov, offset, flags, &total);
Alex Bennée50290c02019-05-29 17:16:32 +01001316 clock_gettime(CLOCK_MONOTONIC, &t2);
Kevin Wolf797ac582013-06-05 14:19:31 +02001317
Max Reitzb32d7a32018-05-09 21:42:59 +02001318 if (ret < 0) {
1319 printf("writev failed: %s\n", strerror(-ret));
Kevin Wolf797ac582013-06-05 14:19:31 +02001320 goto out;
1321 }
Max Reitzb32d7a32018-05-09 21:42:59 +02001322 cnt = ret;
1323
1324 ret = 0;
Kevin Wolf797ac582013-06-05 14:19:31 +02001325
1326 if (qflag) {
1327 goto out;
1328 }
1329
1330 /* Finally, report back -- -C gives a parsable format */
1331 t2 = tsub(t2, t1);
1332 print_report("wrote", &t2, offset, qiov.size, total, cnt, Cflag);
1333out:
1334 qemu_iovec_destroy(&qiov);
1335 qemu_io_free(buf);
Max Reitzb32d7a32018-05-09 21:42:59 +02001336 return ret;
Kevin Wolf797ac582013-06-05 14:19:31 +02001337}
1338
Kevin Wolf797ac582013-06-05 14:19:31 +02001339struct aio_ctx {
Max Reitz4c7b7e92015-02-05 13:58:22 -05001340 BlockBackend *blk;
Kevin Wolf797ac582013-06-05 14:19:31 +02001341 QEMUIOVector qiov;
1342 int64_t offset;
1343 char *buf;
Eric Blakedc388522016-05-07 21:16:42 -06001344 bool qflag;
1345 bool vflag;
1346 bool Cflag;
1347 bool Pflag;
1348 bool zflag;
Fam Zhenga91f9582015-01-30 10:49:42 +08001349 BlockAcctCookie acct;
Kevin Wolf797ac582013-06-05 14:19:31 +02001350 int pattern;
Alex Bennée50290c02019-05-29 17:16:32 +01001351 struct timespec t1;
Kevin Wolf797ac582013-06-05 14:19:31 +02001352};
1353
1354static void aio_write_done(void *opaque, int ret)
1355{
1356 struct aio_ctx *ctx = opaque;
Alex Bennée50290c02019-05-29 17:16:32 +01001357 struct timespec t2;
Kevin Wolf797ac582013-06-05 14:19:31 +02001358
Alex Bennée50290c02019-05-29 17:16:32 +01001359 clock_gettime(CLOCK_MONOTONIC, &t2);
Kevin Wolf797ac582013-06-05 14:19:31 +02001360
1361
1362 if (ret < 0) {
1363 printf("aio_write failed: %s\n", strerror(-ret));
Alberto Garcia556c2b62015-10-28 17:33:08 +02001364 block_acct_failed(blk_get_stats(ctx->blk), &ctx->acct);
Kevin Wolf797ac582013-06-05 14:19:31 +02001365 goto out;
1366 }
1367
Max Reitz4c7b7e92015-02-05 13:58:22 -05001368 block_acct_done(blk_get_stats(ctx->blk), &ctx->acct);
Fam Zhenga91f9582015-01-30 10:49:42 +08001369
Kevin Wolf797ac582013-06-05 14:19:31 +02001370 if (ctx->qflag) {
1371 goto out;
1372 }
1373
1374 /* Finally, report back -- -C gives a parsable format */
1375 t2 = tsub(t2, ctx->t1);
1376 print_report("wrote", &t2, ctx->offset, ctx->qiov.size,
1377 ctx->qiov.size, 1, ctx->Cflag);
1378out:
Kevin Wolf5ceb7762016-04-13 12:39:39 +02001379 if (!ctx->zflag) {
1380 qemu_io_free(ctx->buf);
1381 qemu_iovec_destroy(&ctx->qiov);
1382 }
Kevin Wolf797ac582013-06-05 14:19:31 +02001383 g_free(ctx);
1384}
1385
1386static void aio_read_done(void *opaque, int ret)
1387{
1388 struct aio_ctx *ctx = opaque;
Alex Bennée50290c02019-05-29 17:16:32 +01001389 struct timespec t2;
Kevin Wolf797ac582013-06-05 14:19:31 +02001390
Alex Bennée50290c02019-05-29 17:16:32 +01001391 clock_gettime(CLOCK_MONOTONIC, &t2);
Kevin Wolf797ac582013-06-05 14:19:31 +02001392
1393 if (ret < 0) {
1394 printf("readv failed: %s\n", strerror(-ret));
Alberto Garcia556c2b62015-10-28 17:33:08 +02001395 block_acct_failed(blk_get_stats(ctx->blk), &ctx->acct);
Kevin Wolf797ac582013-06-05 14:19:31 +02001396 goto out;
1397 }
1398
1399 if (ctx->Pflag) {
1400 void *cmp_buf = g_malloc(ctx->qiov.size);
1401
1402 memset(cmp_buf, ctx->pattern, ctx->qiov.size);
1403 if (memcmp(ctx->buf, cmp_buf, ctx->qiov.size)) {
1404 printf("Pattern verification failed at offset %"
Stefan Weilcf67b692018-10-06 20:38:51 +02001405 PRId64 ", %zu bytes\n", ctx->offset, ctx->qiov.size);
Kevin Wolf797ac582013-06-05 14:19:31 +02001406 }
1407 g_free(cmp_buf);
1408 }
1409
Max Reitz4c7b7e92015-02-05 13:58:22 -05001410 block_acct_done(blk_get_stats(ctx->blk), &ctx->acct);
Fam Zhenga91f9582015-01-30 10:49:42 +08001411
Kevin Wolf797ac582013-06-05 14:19:31 +02001412 if (ctx->qflag) {
1413 goto out;
1414 }
1415
1416 if (ctx->vflag) {
1417 dump_buffer(ctx->buf, ctx->offset, ctx->qiov.size);
1418 }
1419
1420 /* Finally, report back -- -C gives a parsable format */
1421 t2 = tsub(t2, ctx->t1);
1422 print_report("read", &t2, ctx->offset, ctx->qiov.size,
1423 ctx->qiov.size, 1, ctx->Cflag);
1424out:
1425 qemu_io_free(ctx->buf);
1426 qemu_iovec_destroy(&ctx->qiov);
1427 g_free(ctx);
1428}
1429
1430static void aio_read_help(void)
1431{
1432 printf(
1433"\n"
1434" asynchronously reads a range of bytes from the given offset\n"
1435"\n"
1436" Example:\n"
1437" 'aio_read -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n"
1438"\n"
1439" Reads a segment of the currently open file, optionally dumping it to the\n"
1440" standard output stream (with -v option) for subsequent inspection.\n"
1441" The read is performed asynchronously and the aio_flush command must be\n"
1442" used to ensure all outstanding aio requests have been completed.\n"
Max Reitzb32d7a32018-05-09 21:42:59 +02001443" Note that due to its asynchronous nature, this command will be\n"
1444" considered successful once the request is submitted, independently\n"
1445" of potential I/O errors or pattern mismatches.\n"
Kevin Wolf797ac582013-06-05 14:19:31 +02001446" -C, -- report statistics in a machine parsable format\n"
1447" -P, -- use a pattern to verify read data\n"
Eric Blake37546ff2016-05-16 10:43:03 -06001448" -i, -- treat request as invalid, for exercising stats\n"
Kevin Wolf797ac582013-06-05 14:19:31 +02001449" -v, -- dump buffer to standard output\n"
1450" -q, -- quiet mode, do not show I/O statistics\n"
1451"\n");
1452}
1453
Max Reitzb32d7a32018-05-09 21:42:59 +02001454static int aio_read_f(BlockBackend *blk, int argc, char **argv);
Kevin Wolf797ac582013-06-05 14:19:31 +02001455
1456static const cmdinfo_t aio_read_cmd = {
1457 .name = "aio_read",
1458 .cfunc = aio_read_f,
1459 .argmin = 2,
1460 .argmax = -1,
Eric Blake37546ff2016-05-16 10:43:03 -06001461 .args = "[-Ciqv] [-P pattern] off len [len..]",
Kevin Wolf797ac582013-06-05 14:19:31 +02001462 .oneline = "asynchronously reads a number of bytes",
1463 .help = aio_read_help,
1464};
1465
Max Reitzb32d7a32018-05-09 21:42:59 +02001466static int aio_read_f(BlockBackend *blk, int argc, char **argv)
Kevin Wolf797ac582013-06-05 14:19:31 +02001467{
1468 int nr_iov, c;
1469 struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
1470
Max Reitz4c7b7e92015-02-05 13:58:22 -05001471 ctx->blk = blk;
Eric Blake37546ff2016-05-16 10:43:03 -06001472 while ((c = getopt(argc, argv, "CP:iqv")) != -1) {
Kevin Wolf797ac582013-06-05 14:19:31 +02001473 switch (c) {
1474 case 'C':
Eric Blakedc388522016-05-07 21:16:42 -06001475 ctx->Cflag = true;
Kevin Wolf797ac582013-06-05 14:19:31 +02001476 break;
1477 case 'P':
Eric Blakedc388522016-05-07 21:16:42 -06001478 ctx->Pflag = true;
Kevin Wolf797ac582013-06-05 14:19:31 +02001479 ctx->pattern = parse_pattern(optarg);
1480 if (ctx->pattern < 0) {
1481 g_free(ctx);
Max Reitzb32d7a32018-05-09 21:42:59 +02001482 return -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +02001483 }
1484 break;
Eric Blake37546ff2016-05-16 10:43:03 -06001485 case 'i':
1486 printf("injecting invalid read request\n");
1487 block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_READ);
1488 g_free(ctx);
Max Reitzb32d7a32018-05-09 21:42:59 +02001489 return 0;
Kevin Wolf797ac582013-06-05 14:19:31 +02001490 case 'q':
Eric Blakedc388522016-05-07 21:16:42 -06001491 ctx->qflag = true;
Kevin Wolf797ac582013-06-05 14:19:31 +02001492 break;
1493 case 'v':
Eric Blakedc388522016-05-07 21:16:42 -06001494 ctx->vflag = true;
Kevin Wolf797ac582013-06-05 14:19:31 +02001495 break;
1496 default:
1497 g_free(ctx);
Max Reitzb444d0e2018-05-09 21:42:58 +02001498 qemuio_command_usage(&aio_read_cmd);
Max Reitzb32d7a32018-05-09 21:42:59 +02001499 return -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +02001500 }
1501 }
1502
1503 if (optind > argc - 2) {
1504 g_free(ctx);
Max Reitzb444d0e2018-05-09 21:42:58 +02001505 qemuio_command_usage(&aio_read_cmd);
Max Reitzb32d7a32018-05-09 21:42:59 +02001506 return -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +02001507 }
1508
1509 ctx->offset = cvtnum(argv[optind]);
1510 if (ctx->offset < 0) {
Max Reitzb32d7a32018-05-09 21:42:59 +02001511 int ret = ctx->offset;
1512 print_cvtnum_err(ret, argv[optind]);
Kevin Wolf797ac582013-06-05 14:19:31 +02001513 g_free(ctx);
Max Reitzb32d7a32018-05-09 21:42:59 +02001514 return ret;
Kevin Wolf797ac582013-06-05 14:19:31 +02001515 }
1516 optind++;
1517
Kevin Wolf797ac582013-06-05 14:19:31 +02001518 nr_iov = argc - optind;
Max Reitz4c7b7e92015-02-05 13:58:22 -05001519 ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov, 0xab);
Kevin Wolf797ac582013-06-05 14:19:31 +02001520 if (ctx->buf == NULL) {
Alberto Garcia556c2b62015-10-28 17:33:08 +02001521 block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_READ);
Kevin Wolf797ac582013-06-05 14:19:31 +02001522 g_free(ctx);
Max Reitzb32d7a32018-05-09 21:42:59 +02001523 return -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +02001524 }
1525
Alex Bennée50290c02019-05-29 17:16:32 +01001526 clock_gettime(CLOCK_MONOTONIC, &ctx->t1);
Max Reitz4c7b7e92015-02-05 13:58:22 -05001527 block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size,
1528 BLOCK_ACCT_READ);
Eric Blake7b3f9712016-05-06 10:26:44 -06001529 blk_aio_preadv(blk, ctx->offset, &ctx->qiov, 0, aio_read_done, ctx);
Max Reitzb32d7a32018-05-09 21:42:59 +02001530 return 0;
Kevin Wolf797ac582013-06-05 14:19:31 +02001531}
1532
1533static void aio_write_help(void)
1534{
1535 printf(
1536"\n"
1537" asynchronously writes a range of bytes from the given offset source\n"
1538" from multiple buffers\n"
1539"\n"
1540" Example:\n"
1541" 'aio_write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n"
1542"\n"
1543" Writes into a segment of the currently open file, using a buffer\n"
1544" filled with a set pattern (0xcdcdcdcd).\n"
1545" The write is performed asynchronously and the aio_flush command must be\n"
1546" used to ensure all outstanding aio requests have been completed.\n"
Max Reitzb32d7a32018-05-09 21:42:59 +02001547" Note that due to its asynchronous nature, this command will be\n"
1548" considered successful once the request is submitted, independently\n"
1549" of potential I/O errors or pattern mismatches.\n"
Kevin Wolf797ac582013-06-05 14:19:31 +02001550" -P, -- use different pattern to fill file\n"
1551" -C, -- report statistics in a machine parsable format\n"
Eric Blake770e0e02016-05-07 21:16:44 -06001552" -f, -- use Force Unit Access semantics\n"
Eric Blake37546ff2016-05-16 10:43:03 -06001553" -i, -- treat request as invalid, for exercising stats\n"
Kevin Wolf797ac582013-06-05 14:19:31 +02001554" -q, -- quiet mode, do not show I/O statistics\n"
Eric Blakec2e001c2016-05-07 21:16:45 -06001555" -u, -- with -z, allow unmapping\n"
Eric Blaked004bd52016-05-24 16:25:20 -06001556" -z, -- write zeroes using blk_aio_pwrite_zeroes\n"
Kevin Wolf797ac582013-06-05 14:19:31 +02001557"\n");
1558}
1559
Max Reitzb32d7a32018-05-09 21:42:59 +02001560static int aio_write_f(BlockBackend *blk, int argc, char **argv);
Kevin Wolf797ac582013-06-05 14:19:31 +02001561
1562static const cmdinfo_t aio_write_cmd = {
1563 .name = "aio_write",
1564 .cfunc = aio_write_f,
Kevin Wolf887354b2017-02-10 16:24:56 +01001565 .perm = BLK_PERM_WRITE,
Kevin Wolf797ac582013-06-05 14:19:31 +02001566 .argmin = 2,
1567 .argmax = -1,
Eric Blake37546ff2016-05-16 10:43:03 -06001568 .args = "[-Cfiquz] [-P pattern] off len [len..]",
Kevin Wolf797ac582013-06-05 14:19:31 +02001569 .oneline = "asynchronously writes a number of bytes",
1570 .help = aio_write_help,
1571};
1572
Max Reitzb32d7a32018-05-09 21:42:59 +02001573static int aio_write_f(BlockBackend *blk, int argc, char **argv)
Kevin Wolf797ac582013-06-05 14:19:31 +02001574{
1575 int nr_iov, c;
1576 int pattern = 0xcd;
1577 struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
Eric Blake770e0e02016-05-07 21:16:44 -06001578 int flags = 0;
Kevin Wolf797ac582013-06-05 14:19:31 +02001579
Max Reitz4c7b7e92015-02-05 13:58:22 -05001580 ctx->blk = blk;
Eric Blake37546ff2016-05-16 10:43:03 -06001581 while ((c = getopt(argc, argv, "CfiqP:uz")) != -1) {
Kevin Wolf797ac582013-06-05 14:19:31 +02001582 switch (c) {
1583 case 'C':
Eric Blakedc388522016-05-07 21:16:42 -06001584 ctx->Cflag = true;
Kevin Wolf797ac582013-06-05 14:19:31 +02001585 break;
Eric Blake770e0e02016-05-07 21:16:44 -06001586 case 'f':
1587 flags |= BDRV_REQ_FUA;
1588 break;
Kevin Wolf797ac582013-06-05 14:19:31 +02001589 case 'q':
Eric Blakedc388522016-05-07 21:16:42 -06001590 ctx->qflag = true;
Kevin Wolf797ac582013-06-05 14:19:31 +02001591 break;
Eric Blakec2e001c2016-05-07 21:16:45 -06001592 case 'u':
1593 flags |= BDRV_REQ_MAY_UNMAP;
1594 break;
Kevin Wolf797ac582013-06-05 14:19:31 +02001595 case 'P':
1596 pattern = parse_pattern(optarg);
1597 if (pattern < 0) {
1598 g_free(ctx);
Max Reitzb32d7a32018-05-09 21:42:59 +02001599 return -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +02001600 }
1601 break;
Eric Blake37546ff2016-05-16 10:43:03 -06001602 case 'i':
1603 printf("injecting invalid write request\n");
1604 block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_WRITE);
1605 g_free(ctx);
Max Reitzb32d7a32018-05-09 21:42:59 +02001606 return 0;
Kevin Wolf5ceb7762016-04-13 12:39:39 +02001607 case 'z':
Eric Blakedc388522016-05-07 21:16:42 -06001608 ctx->zflag = true;
Kevin Wolf5ceb7762016-04-13 12:39:39 +02001609 break;
Kevin Wolf797ac582013-06-05 14:19:31 +02001610 default:
1611 g_free(ctx);
Max Reitzb444d0e2018-05-09 21:42:58 +02001612 qemuio_command_usage(&aio_write_cmd);
Max Reitzb32d7a32018-05-09 21:42:59 +02001613 return -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +02001614 }
1615 }
1616
1617 if (optind > argc - 2) {
1618 g_free(ctx);
Max Reitzb444d0e2018-05-09 21:42:58 +02001619 qemuio_command_usage(&aio_write_cmd);
Max Reitzb32d7a32018-05-09 21:42:59 +02001620 return -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +02001621 }
1622
Kevin Wolf5ceb7762016-04-13 12:39:39 +02001623 if (ctx->zflag && optind != argc - 2) {
1624 printf("-z supports only a single length parameter\n");
1625 g_free(ctx);
Max Reitzb32d7a32018-05-09 21:42:59 +02001626 return -EINVAL;
Kevin Wolf5ceb7762016-04-13 12:39:39 +02001627 }
1628
Eric Blakec2e001c2016-05-07 21:16:45 -06001629 if ((flags & BDRV_REQ_MAY_UNMAP) && !ctx->zflag) {
1630 printf("-u requires -z to be specified\n");
Eric Blake4ca1d342016-05-16 10:43:01 -06001631 g_free(ctx);
Max Reitzb32d7a32018-05-09 21:42:59 +02001632 return -EINVAL;
Eric Blakec2e001c2016-05-07 21:16:45 -06001633 }
1634
Kevin Wolf5ceb7762016-04-13 12:39:39 +02001635 if (ctx->zflag && ctx->Pflag) {
1636 printf("-z and -P cannot be specified at the same time\n");
1637 g_free(ctx);
Max Reitzb32d7a32018-05-09 21:42:59 +02001638 return -EINVAL;
Kevin Wolf5ceb7762016-04-13 12:39:39 +02001639 }
1640
Kevin Wolf797ac582013-06-05 14:19:31 +02001641 ctx->offset = cvtnum(argv[optind]);
1642 if (ctx->offset < 0) {
Max Reitzb32d7a32018-05-09 21:42:59 +02001643 int ret = ctx->offset;
1644 print_cvtnum_err(ret, argv[optind]);
Kevin Wolf797ac582013-06-05 14:19:31 +02001645 g_free(ctx);
Max Reitzb32d7a32018-05-09 21:42:59 +02001646 return ret;
Kevin Wolf797ac582013-06-05 14:19:31 +02001647 }
1648 optind++;
1649
Kevin Wolf5ceb7762016-04-13 12:39:39 +02001650 if (ctx->zflag) {
1651 int64_t count = cvtnum(argv[optind]);
1652 if (count < 0) {
1653 print_cvtnum_err(count, argv[optind]);
Kevin Wolf0e01b762016-05-09 12:03:04 +02001654 g_free(ctx);
Max Reitzb32d7a32018-05-09 21:42:59 +02001655 return count;
Kevin Wolf5ceb7762016-04-13 12:39:39 +02001656 }
Kevin Wolf797ac582013-06-05 14:19:31 +02001657
Kevin Wolf5ceb7762016-04-13 12:39:39 +02001658 ctx->qiov.size = count;
Eric Blaked004bd52016-05-24 16:25:20 -06001659 blk_aio_pwrite_zeroes(blk, ctx->offset, count, flags, aio_write_done,
1660 ctx);
Kevin Wolf5ceb7762016-04-13 12:39:39 +02001661 } else {
1662 nr_iov = argc - optind;
1663 ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov,
1664 pattern);
1665 if (ctx->buf == NULL) {
1666 block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_WRITE);
1667 g_free(ctx);
Max Reitzb32d7a32018-05-09 21:42:59 +02001668 return -EINVAL;
Kevin Wolf5ceb7762016-04-13 12:39:39 +02001669 }
1670
Alex Bennée50290c02019-05-29 17:16:32 +01001671 clock_gettime(CLOCK_MONOTONIC, &ctx->t1);
Kevin Wolf5ceb7762016-04-13 12:39:39 +02001672 block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size,
1673 BLOCK_ACCT_WRITE);
1674
Eric Blake770e0e02016-05-07 21:16:44 -06001675 blk_aio_pwritev(blk, ctx->offset, &ctx->qiov, flags, aio_write_done,
1676 ctx);
Kevin Wolf5ceb7762016-04-13 12:39:39 +02001677 }
Max Reitzb32d7a32018-05-09 21:42:59 +02001678
1679 return 0;
Kevin Wolf797ac582013-06-05 14:19:31 +02001680}
1681
Max Reitzb32d7a32018-05-09 21:42:59 +02001682static int aio_flush_f(BlockBackend *blk, int argc, char **argv)
Kevin Wolf797ac582013-06-05 14:19:31 +02001683{
Alberto Garcia556c2b62015-10-28 17:33:08 +02001684 BlockAcctCookie cookie;
1685 block_acct_start(blk_get_stats(blk), &cookie, 0, BLOCK_ACCT_FLUSH);
Max Reitz4c7b7e92015-02-05 13:58:22 -05001686 blk_drain_all();
Alberto Garcia556c2b62015-10-28 17:33:08 +02001687 block_acct_done(blk_get_stats(blk), &cookie);
Max Reitzb32d7a32018-05-09 21:42:59 +02001688 return 0;
Kevin Wolf797ac582013-06-05 14:19:31 +02001689}
1690
1691static const cmdinfo_t aio_flush_cmd = {
1692 .name = "aio_flush",
1693 .cfunc = aio_flush_f,
1694 .oneline = "completes all outstanding aio requests"
1695};
1696
Max Reitzb32d7a32018-05-09 21:42:59 +02001697static int flush_f(BlockBackend *blk, int argc, char **argv)
Kevin Wolf797ac582013-06-05 14:19:31 +02001698{
Max Reitzb32d7a32018-05-09 21:42:59 +02001699 return blk_flush(blk);
Kevin Wolf797ac582013-06-05 14:19:31 +02001700}
1701
1702static const cmdinfo_t flush_cmd = {
1703 .name = "flush",
1704 .altname = "f",
1705 .cfunc = flush_f,
1706 .oneline = "flush all in-core file state to disk",
1707};
1708
Vladimir Sementsov-Ogievskiy42ba0222020-10-21 17:58:47 +03001709static int truncate_f(BlockBackend *blk, int argc, char **argv);
1710static const cmdinfo_t truncate_cmd = {
1711 .name = "truncate",
1712 .altname = "t",
1713 .cfunc = truncate_f,
1714 .perm = BLK_PERM_WRITE | BLK_PERM_RESIZE,
1715 .argmin = 1,
1716 .argmax = 3,
1717 .args = "[-m prealloc_mode] off",
1718 .oneline = "truncates the current file at the given offset",
1719};
1720
Max Reitzb32d7a32018-05-09 21:42:59 +02001721static int truncate_f(BlockBackend *blk, int argc, char **argv)
Kevin Wolf797ac582013-06-05 14:19:31 +02001722{
Max Reitzed3d2ec2017-03-28 22:51:27 +02001723 Error *local_err = NULL;
Kevin Wolf797ac582013-06-05 14:19:31 +02001724 int64_t offset;
Vladimir Sementsov-Ogievskiy42ba0222020-10-21 17:58:47 +03001725 int c, ret;
1726 PreallocMode prealloc = PREALLOC_MODE_OFF;
Kevin Wolf797ac582013-06-05 14:19:31 +02001727
Vladimir Sementsov-Ogievskiy42ba0222020-10-21 17:58:47 +03001728 while ((c = getopt(argc, argv, "m:")) != -1) {
1729 switch (c) {
1730 case 'm':
1731 prealloc = qapi_enum_parse(&PreallocMode_lookup, optarg,
1732 PREALLOC_MODE__MAX, NULL);
1733 if (prealloc == PREALLOC_MODE__MAX) {
1734 error_report("Invalid preallocation mode '%s'", optarg);
1735 return -EINVAL;
1736 }
1737 break;
1738 default:
1739 qemuio_command_usage(&truncate_cmd);
1740 return -EINVAL;
1741 }
1742 }
1743
1744 offset = cvtnum(argv[optind]);
Kevin Wolf797ac582013-06-05 14:19:31 +02001745 if (offset < 0) {
John Snowa9ecfa02015-11-05 18:53:04 -05001746 print_cvtnum_err(offset, argv[1]);
Max Reitzb32d7a32018-05-09 21:42:59 +02001747 return offset;
Kevin Wolf797ac582013-06-05 14:19:31 +02001748 }
1749
Max Reitze8d04f92019-09-18 11:51:43 +02001750 /*
1751 * qemu-io is a debugging tool, so let us be strict here and pass
1752 * exact=true. It is better to err on the "emit more errors" side
1753 * than to be overly permissive.
1754 */
Vladimir Sementsov-Ogievskiy42ba0222020-10-21 17:58:47 +03001755 ret = blk_truncate(blk, offset, false, prealloc, 0, &local_err);
Kevin Wolf797ac582013-06-05 14:19:31 +02001756 if (ret < 0) {
Max Reitzed3d2ec2017-03-28 22:51:27 +02001757 error_report_err(local_err);
Max Reitzb32d7a32018-05-09 21:42:59 +02001758 return ret;
Kevin Wolf797ac582013-06-05 14:19:31 +02001759 }
Max Reitzb32d7a32018-05-09 21:42:59 +02001760
1761 return 0;
Kevin Wolf797ac582013-06-05 14:19:31 +02001762}
1763
Max Reitzb32d7a32018-05-09 21:42:59 +02001764static int length_f(BlockBackend *blk, int argc, char **argv)
Kevin Wolf797ac582013-06-05 14:19:31 +02001765{
1766 int64_t size;
1767 char s1[64];
1768
Max Reitz4c7b7e92015-02-05 13:58:22 -05001769 size = blk_getlength(blk);
Kevin Wolf797ac582013-06-05 14:19:31 +02001770 if (size < 0) {
1771 printf("getlength: %s\n", strerror(-size));
Max Reitzb32d7a32018-05-09 21:42:59 +02001772 return size;
Kevin Wolf797ac582013-06-05 14:19:31 +02001773 }
1774
1775 cvtstr(size, s1, sizeof(s1));
1776 printf("%s\n", s1);
Max Reitzb32d7a32018-05-09 21:42:59 +02001777 return 0;
Kevin Wolf797ac582013-06-05 14:19:31 +02001778}
1779
1780
1781static const cmdinfo_t length_cmd = {
1782 .name = "length",
1783 .altname = "l",
1784 .cfunc = length_f,
1785 .oneline = "gets the length of the current file",
1786};
1787
1788
Max Reitzb32d7a32018-05-09 21:42:59 +02001789static int info_f(BlockBackend *blk, int argc, char **argv)
Kevin Wolf797ac582013-06-05 14:19:31 +02001790{
Max Reitz4c7b7e92015-02-05 13:58:22 -05001791 BlockDriverState *bs = blk_bs(blk);
Kevin Wolf797ac582013-06-05 14:19:31 +02001792 BlockDriverInfo bdi;
Max Reitza8d8ecb2013-10-09 10:46:17 +02001793 ImageInfoSpecific *spec_info;
Andrey Shinkevich1bf6e9c2019-02-08 18:06:06 +03001794 Error *local_err = NULL;
Kevin Wolf797ac582013-06-05 14:19:31 +02001795 char s1[64], s2[64];
1796 int ret;
1797
1798 if (bs->drv && bs->drv->format_name) {
1799 printf("format name: %s\n", bs->drv->format_name);
1800 }
1801 if (bs->drv && bs->drv->protocol_name) {
1802 printf("format name: %s\n", bs->drv->protocol_name);
1803 }
1804
1805 ret = bdrv_get_info(bs, &bdi);
1806 if (ret) {
Max Reitzb32d7a32018-05-09 21:42:59 +02001807 return ret;
Kevin Wolf797ac582013-06-05 14:19:31 +02001808 }
1809
1810 cvtstr(bdi.cluster_size, s1, sizeof(s1));
1811 cvtstr(bdi.vm_state_offset, s2, sizeof(s2));
1812
1813 printf("cluster size: %s\n", s1);
1814 printf("vm state offset: %s\n", s2);
1815
Andrey Shinkevich1bf6e9c2019-02-08 18:06:06 +03001816 spec_info = bdrv_get_specific_info(bs, &local_err);
1817 if (local_err) {
1818 error_report_err(local_err);
1819 return -EIO;
1820 }
Max Reitza8d8ecb2013-10-09 10:46:17 +02001821 if (spec_info) {
1822 printf("Format specific information:\n");
Markus Armbrustere1ce7d72019-04-17 21:17:55 +02001823 bdrv_image_info_specific_dump(spec_info);
Max Reitza8d8ecb2013-10-09 10:46:17 +02001824 qapi_free_ImageInfoSpecific(spec_info);
1825 }
Max Reitzb32d7a32018-05-09 21:42:59 +02001826
1827 return 0;
Kevin Wolf797ac582013-06-05 14:19:31 +02001828}
1829
1830
1831
1832static const cmdinfo_t info_cmd = {
1833 .name = "info",
1834 .altname = "i",
1835 .cfunc = info_f,
1836 .oneline = "prints information about the current file",
1837};
1838
1839static void discard_help(void)
1840{
1841 printf(
1842"\n"
1843" discards a range of bytes from the given offset\n"
1844"\n"
1845" Example:\n"
1846" 'discard 512 1k' - discards 1 kilobyte from 512 bytes into the file\n"
1847"\n"
1848" Discards a segment of the currently open file.\n"
1849" -C, -- report statistics in a machine parsable format\n"
1850" -q, -- quiet mode, do not show I/O statistics\n"
1851"\n");
1852}
1853
Max Reitzb32d7a32018-05-09 21:42:59 +02001854static int discard_f(BlockBackend *blk, int argc, char **argv);
Kevin Wolf797ac582013-06-05 14:19:31 +02001855
1856static const cmdinfo_t discard_cmd = {
1857 .name = "discard",
1858 .altname = "d",
1859 .cfunc = discard_f,
Kevin Wolf887354b2017-02-10 16:24:56 +01001860 .perm = BLK_PERM_WRITE,
Kevin Wolf797ac582013-06-05 14:19:31 +02001861 .argmin = 2,
1862 .argmax = -1,
1863 .args = "[-Cq] off len",
1864 .oneline = "discards a number of bytes at a specified offset",
1865 .help = discard_help,
1866};
1867
Max Reitzb32d7a32018-05-09 21:42:59 +02001868static int discard_f(BlockBackend *blk, int argc, char **argv)
Kevin Wolf797ac582013-06-05 14:19:31 +02001869{
Alex Bennée50290c02019-05-29 17:16:32 +01001870 struct timespec t1, t2;
Eric Blakedc388522016-05-07 21:16:42 -06001871 bool Cflag = false, qflag = false;
Kevin Wolf797ac582013-06-05 14:19:31 +02001872 int c, ret;
Manos Pitsidianakisf5a5ca72017-06-09 13:18:08 +03001873 int64_t offset, bytes;
Kevin Wolf797ac582013-06-05 14:19:31 +02001874
Eric Blakeb062ad82015-05-12 09:10:56 -06001875 while ((c = getopt(argc, argv, "Cq")) != -1) {
Kevin Wolf797ac582013-06-05 14:19:31 +02001876 switch (c) {
1877 case 'C':
Eric Blakedc388522016-05-07 21:16:42 -06001878 Cflag = true;
Kevin Wolf797ac582013-06-05 14:19:31 +02001879 break;
1880 case 'q':
Eric Blakedc388522016-05-07 21:16:42 -06001881 qflag = true;
Kevin Wolf797ac582013-06-05 14:19:31 +02001882 break;
1883 default:
Max Reitzb444d0e2018-05-09 21:42:58 +02001884 qemuio_command_usage(&discard_cmd);
Max Reitzb32d7a32018-05-09 21:42:59 +02001885 return -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +02001886 }
1887 }
1888
1889 if (optind != argc - 2) {
Max Reitzb444d0e2018-05-09 21:42:58 +02001890 qemuio_command_usage(&discard_cmd);
Max Reitzb32d7a32018-05-09 21:42:59 +02001891 return -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +02001892 }
1893
1894 offset = cvtnum(argv[optind]);
1895 if (offset < 0) {
John Snowa9ecfa02015-11-05 18:53:04 -05001896 print_cvtnum_err(offset, argv[optind]);
Max Reitzb32d7a32018-05-09 21:42:59 +02001897 return offset;
Kevin Wolf797ac582013-06-05 14:19:31 +02001898 }
1899
1900 optind++;
Manos Pitsidianakisf5a5ca72017-06-09 13:18:08 +03001901 bytes = cvtnum(argv[optind]);
1902 if (bytes < 0) {
1903 print_cvtnum_err(bytes, argv[optind]);
Max Reitzb32d7a32018-05-09 21:42:59 +02001904 return bytes;
Alberto Garcia41ae31e2019-05-14 16:57:35 +03001905 } else if (bytes > BDRV_REQUEST_MAX_BYTES) {
John Snow9b0beaf2015-11-05 18:53:02 -05001906 printf("length cannot exceed %"PRIu64", given %s\n",
Alberto Garcia41ae31e2019-05-14 16:57:35 +03001907 (uint64_t)BDRV_REQUEST_MAX_BYTES, argv[optind]);
Max Reitzb32d7a32018-05-09 21:42:59 +02001908 return -EINVAL;
Kevin Wolf797ac582013-06-05 14:19:31 +02001909 }
1910
Alex Bennée50290c02019-05-29 17:16:32 +01001911 clock_gettime(CLOCK_MONOTONIC, &t1);
Manos Pitsidianakisf5a5ca72017-06-09 13:18:08 +03001912 ret = blk_pdiscard(blk, offset, bytes);
Alex Bennée50290c02019-05-29 17:16:32 +01001913 clock_gettime(CLOCK_MONOTONIC, &t2);
Kevin Wolf797ac582013-06-05 14:19:31 +02001914
1915 if (ret < 0) {
1916 printf("discard failed: %s\n", strerror(-ret));
Max Reitzb32d7a32018-05-09 21:42:59 +02001917 return ret;
Kevin Wolf797ac582013-06-05 14:19:31 +02001918 }
1919
1920 /* Finally, report back -- -C gives a parsable format */
1921 if (!qflag) {
1922 t2 = tsub(t2, t1);
Manos Pitsidianakisf5a5ca72017-06-09 13:18:08 +03001923 print_report("discard", &t2, offset, bytes, bytes, 1, Cflag);
Kevin Wolf797ac582013-06-05 14:19:31 +02001924 }
Max Reitzb32d7a32018-05-09 21:42:59 +02001925
1926 return 0;
Kevin Wolf797ac582013-06-05 14:19:31 +02001927}
1928
Max Reitzb32d7a32018-05-09 21:42:59 +02001929static int alloc_f(BlockBackend *blk, int argc, char **argv)
Kevin Wolf797ac582013-06-05 14:19:31 +02001930{
Max Reitz4c7b7e92015-02-05 13:58:22 -05001931 BlockDriverState *bs = blk_bs(blk);
Eric Blaked6a644b2017-07-07 07:44:57 -05001932 int64_t offset, start, remaining, count;
Kevin Wolf797ac582013-06-05 14:19:31 +02001933 char s1[64];
Eric Blaked6a644b2017-07-07 07:44:57 -05001934 int ret;
1935 int64_t num, sum_alloc;
Kevin Wolf797ac582013-06-05 14:19:31 +02001936
Eric Blaked6a644b2017-07-07 07:44:57 -05001937 start = offset = cvtnum(argv[1]);
Kevin Wolf797ac582013-06-05 14:19:31 +02001938 if (offset < 0) {
John Snowa9ecfa02015-11-05 18:53:04 -05001939 print_cvtnum_err(offset, argv[1]);
Max Reitzb32d7a32018-05-09 21:42:59 +02001940 return offset;
Kevin Wolf797ac582013-06-05 14:19:31 +02001941 }
1942
1943 if (argc == 3) {
Eric Blake4401fdc2017-04-29 14:14:12 -05001944 count = cvtnum(argv[2]);
1945 if (count < 0) {
1946 print_cvtnum_err(count, argv[2]);
Max Reitzb32d7a32018-05-09 21:42:59 +02001947 return count;
Kevin Wolf797ac582013-06-05 14:19:31 +02001948 }
1949 } else {
Eric Blake4401fdc2017-04-29 14:14:12 -05001950 count = BDRV_SECTOR_SIZE;
Kevin Wolf797ac582013-06-05 14:19:31 +02001951 }
1952
Eric Blaked6a644b2017-07-07 07:44:57 -05001953 remaining = count;
Kevin Wolf797ac582013-06-05 14:19:31 +02001954 sum_alloc = 0;
Kevin Wolf797ac582013-06-05 14:19:31 +02001955 while (remaining) {
Eric Blaked6a644b2017-07-07 07:44:57 -05001956 ret = bdrv_is_allocated(bs, offset, remaining, &num);
Paolo Bonzinid6636402013-09-04 19:00:25 +02001957 if (ret < 0) {
1958 printf("is_allocated failed: %s\n", strerror(-ret));
Max Reitzb32d7a32018-05-09 21:42:59 +02001959 return ret;
Paolo Bonzinid6636402013-09-04 19:00:25 +02001960 }
Eric Blaked6a644b2017-07-07 07:44:57 -05001961 offset += num;
Kevin Wolf797ac582013-06-05 14:19:31 +02001962 remaining -= num;
1963 if (ret) {
1964 sum_alloc += num;
1965 }
1966 if (num == 0) {
Eric Blaked6a644b2017-07-07 07:44:57 -05001967 count -= remaining;
Kevin Wolf797ac582013-06-05 14:19:31 +02001968 remaining = 0;
1969 }
1970 }
1971
Eric Blaked6a644b2017-07-07 07:44:57 -05001972 cvtstr(start, s1, sizeof(s1));
Kevin Wolf797ac582013-06-05 14:19:31 +02001973
Eric Blake4401fdc2017-04-29 14:14:12 -05001974 printf("%"PRId64"/%"PRId64" bytes allocated at offset %s\n",
Eric Blaked6a644b2017-07-07 07:44:57 -05001975 sum_alloc, count, s1);
Max Reitzb32d7a32018-05-09 21:42:59 +02001976 return 0;
Kevin Wolf797ac582013-06-05 14:19:31 +02001977}
1978
1979static const cmdinfo_t alloc_cmd = {
1980 .name = "alloc",
1981 .altname = "a",
1982 .argmin = 1,
1983 .argmax = 2,
1984 .cfunc = alloc_f,
Eric Blake4401fdc2017-04-29 14:14:12 -05001985 .args = "offset [count]",
1986 .oneline = "checks if offset is allocated in the file",
Kevin Wolf797ac582013-06-05 14:19:31 +02001987};
1988
1989
Eric Blaked6a644b2017-07-07 07:44:57 -05001990static int map_is_allocated(BlockDriverState *bs, int64_t offset,
1991 int64_t bytes, int64_t *pnum)
Kevin Wolf797ac582013-06-05 14:19:31 +02001992{
Eric Blaked6a644b2017-07-07 07:44:57 -05001993 int64_t num;
Kevin Wolf797ac582013-06-05 14:19:31 +02001994 int ret, firstret;
1995
Eric Blake087f2fb2021-12-03 17:15:27 -06001996 ret = bdrv_is_allocated(bs, offset, bytes, &num);
Kevin Wolf797ac582013-06-05 14:19:31 +02001997 if (ret < 0) {
1998 return ret;
1999 }
2000
2001 firstret = ret;
2002 *pnum = num;
2003
Eric Blaked6a644b2017-07-07 07:44:57 -05002004 while (bytes > 0 && ret == firstret) {
2005 offset += num;
2006 bytes -= num;
Kevin Wolf797ac582013-06-05 14:19:31 +02002007
Eric Blake087f2fb2021-12-03 17:15:27 -06002008 ret = bdrv_is_allocated(bs, offset, bytes, &num);
Max Reitz4b25bbc2014-10-22 17:00:16 +02002009 if (ret == firstret && num) {
Kevin Wolf797ac582013-06-05 14:19:31 +02002010 *pnum += num;
2011 } else {
2012 break;
2013 }
2014 }
2015
2016 return firstret;
2017}
2018
Max Reitzb32d7a32018-05-09 21:42:59 +02002019static int map_f(BlockBackend *blk, int argc, char **argv)
Kevin Wolf797ac582013-06-05 14:19:31 +02002020{
Eric Blaked6a644b2017-07-07 07:44:57 -05002021 int64_t offset, bytes;
Eric Blake6f3c90a2017-04-29 14:14:13 -05002022 char s1[64], s2[64];
Kevin Wolf797ac582013-06-05 14:19:31 +02002023 int64_t num;
2024 int ret;
2025 const char *retstr;
2026
2027 offset = 0;
Eric Blaked6a644b2017-07-07 07:44:57 -05002028 bytes = blk_getlength(blk);
2029 if (bytes < 0) {
2030 error_report("Failed to query image length: %s", strerror(-bytes));
Max Reitzb32d7a32018-05-09 21:42:59 +02002031 return bytes;
Max Reitz4c7b7e92015-02-05 13:58:22 -05002032 }
2033
Eric Blaked6a644b2017-07-07 07:44:57 -05002034 while (bytes) {
2035 ret = map_is_allocated(blk_bs(blk), offset, bytes, &num);
Kevin Wolf797ac582013-06-05 14:19:31 +02002036 if (ret < 0) {
2037 error_report("Failed to get allocation status: %s", strerror(-ret));
Max Reitzb32d7a32018-05-09 21:42:59 +02002038 return ret;
Max Reitz4b25bbc2014-10-22 17:00:16 +02002039 } else if (!num) {
2040 error_report("Unexpected end of image");
Max Reitzb32d7a32018-05-09 21:42:59 +02002041 return -EIO;
Kevin Wolf797ac582013-06-05 14:19:31 +02002042 }
2043
2044 retstr = ret ? " allocated" : "not allocated";
Eric Blaked6a644b2017-07-07 07:44:57 -05002045 cvtstr(num, s1, sizeof(s1));
2046 cvtstr(offset, s2, sizeof(s2));
Eric Blake6f3c90a2017-04-29 14:14:13 -05002047 printf("%s (0x%" PRIx64 ") bytes %s at offset %s (0x%" PRIx64 ")\n",
Eric Blaked6a644b2017-07-07 07:44:57 -05002048 s1, num, retstr, s2, offset);
Kevin Wolf797ac582013-06-05 14:19:31 +02002049
2050 offset += num;
Eric Blaked6a644b2017-07-07 07:44:57 -05002051 bytes -= num;
2052 }
Max Reitzb32d7a32018-05-09 21:42:59 +02002053
2054 return 0;
Kevin Wolf797ac582013-06-05 14:19:31 +02002055}
2056
2057static const cmdinfo_t map_cmd = {
2058 .name = "map",
2059 .argmin = 0,
2060 .argmax = 0,
2061 .cfunc = map_f,
2062 .args = "",
2063 .oneline = "prints the allocated areas of a file",
2064};
2065
Kevin Wolf5bbd2e52014-12-08 17:37:28 +01002066static void reopen_help(void)
2067{
2068 printf(
2069"\n"
2070" Changes the open options of an already opened image\n"
2071"\n"
2072" Example:\n"
2073" 'reopen -o lazy-refcounts=on' - activates lazy refcount writeback on a qcow2 image\n"
2074"\n"
2075" -r, -- Reopen the image read-only\n"
Kevin Wolfea922032017-08-03 17:03:00 +02002076" -w, -- Reopen the image read-write\n"
Kevin Wolf5bbd2e52014-12-08 17:37:28 +01002077" -c, -- Change the cache mode to the given value\n"
2078" -o, -- Changes block driver options (cf. 'open' command)\n"
2079"\n");
2080}
2081
Max Reitzb32d7a32018-05-09 21:42:59 +02002082static int reopen_f(BlockBackend *blk, int argc, char **argv);
Kevin Wolf5bbd2e52014-12-08 17:37:28 +01002083
2084static QemuOptsList reopen_opts = {
2085 .name = "reopen",
2086 .merge_lists = true,
2087 .head = QTAILQ_HEAD_INITIALIZER(reopen_opts.head),
2088 .desc = {
2089 /* no elements => accept any params */
2090 { /* end of list */ }
2091 },
2092};
2093
2094static const cmdinfo_t reopen_cmd = {
2095 .name = "reopen",
2096 .argmin = 0,
2097 .argmax = -1,
2098 .cfunc = reopen_f,
Kevin Wolfea922032017-08-03 17:03:00 +02002099 .args = "[(-r|-w)] [-c cache] [-o options]",
Kevin Wolf5bbd2e52014-12-08 17:37:28 +01002100 .oneline = "reopens an image with new options",
2101 .help = reopen_help,
2102};
2103
Max Reitzb32d7a32018-05-09 21:42:59 +02002104static int reopen_f(BlockBackend *blk, int argc, char **argv)
Kevin Wolf5bbd2e52014-12-08 17:37:28 +01002105{
2106 BlockDriverState *bs = blk_bs(blk);
2107 QemuOpts *qopts;
2108 QDict *opts;
2109 int c;
2110 int flags = bs->open_flags;
Kevin Wolf19dbecd2016-03-18 15:36:31 +01002111 bool writethrough = !blk_enable_write_cache(blk);
Kevin Wolfea922032017-08-03 17:03:00 +02002112 bool has_rw_option = false;
Alberto Garciadc900c32018-11-12 16:00:42 +02002113 bool has_cache_option = false;
Kevin Wolf5bbd2e52014-12-08 17:37:28 +01002114 Error *local_err = NULL;
2115
Kevin Wolfea922032017-08-03 17:03:00 +02002116 while ((c = getopt(argc, argv, "c:o:rw")) != -1) {
Kevin Wolf5bbd2e52014-12-08 17:37:28 +01002117 switch (c) {
2118 case 'c':
Kevin Wolf19dbecd2016-03-18 15:36:31 +01002119 if (bdrv_parse_cache_mode(optarg, &flags, &writethrough) < 0) {
Kevin Wolf5bbd2e52014-12-08 17:37:28 +01002120 error_report("Invalid cache option: %s", optarg);
Max Reitzb32d7a32018-05-09 21:42:59 +02002121 return -EINVAL;
Kevin Wolf5bbd2e52014-12-08 17:37:28 +01002122 }
Alberto Garciadc900c32018-11-12 16:00:42 +02002123 has_cache_option = true;
Kevin Wolf5bbd2e52014-12-08 17:37:28 +01002124 break;
2125 case 'o':
2126 if (!qemu_opts_parse_noisily(&reopen_opts, optarg, 0)) {
2127 qemu_opts_reset(&reopen_opts);
Max Reitzb32d7a32018-05-09 21:42:59 +02002128 return -EINVAL;
Kevin Wolf5bbd2e52014-12-08 17:37:28 +01002129 }
2130 break;
2131 case 'r':
Kevin Wolfea922032017-08-03 17:03:00 +02002132 if (has_rw_option) {
2133 error_report("Only one -r/-w option may be given");
Max Reitzb32d7a32018-05-09 21:42:59 +02002134 return -EINVAL;
Kevin Wolfea922032017-08-03 17:03:00 +02002135 }
Kevin Wolf5bbd2e52014-12-08 17:37:28 +01002136 flags &= ~BDRV_O_RDWR;
Kevin Wolfea922032017-08-03 17:03:00 +02002137 has_rw_option = true;
2138 break;
2139 case 'w':
2140 if (has_rw_option) {
2141 error_report("Only one -r/-w option may be given");
Max Reitzb32d7a32018-05-09 21:42:59 +02002142 return -EINVAL;
Kevin Wolfea922032017-08-03 17:03:00 +02002143 }
2144 flags |= BDRV_O_RDWR;
2145 has_rw_option = true;
Kevin Wolf5bbd2e52014-12-08 17:37:28 +01002146 break;
2147 default:
2148 qemu_opts_reset(&reopen_opts);
Max Reitzb444d0e2018-05-09 21:42:58 +02002149 qemuio_command_usage(&reopen_cmd);
Max Reitzb32d7a32018-05-09 21:42:59 +02002150 return -EINVAL;
Kevin Wolf5bbd2e52014-12-08 17:37:28 +01002151 }
2152 }
2153
2154 if (optind != argc) {
2155 qemu_opts_reset(&reopen_opts);
Max Reitzb444d0e2018-05-09 21:42:58 +02002156 qemuio_command_usage(&reopen_cmd);
Max Reitzb32d7a32018-05-09 21:42:59 +02002157 return -EINVAL;
Kevin Wolf5bbd2e52014-12-08 17:37:28 +01002158 }
2159
Alberto Garciaa8003ec2018-09-06 12:37:01 +03002160 if (!writethrough != blk_enable_write_cache(blk) &&
Kevin Wolf19dbecd2016-03-18 15:36:31 +01002161 blk_get_attached_dev(blk))
2162 {
2163 error_report("Cannot change cache.writeback: Device attached");
2164 qemu_opts_reset(&reopen_opts);
Max Reitzb32d7a32018-05-09 21:42:59 +02002165 return -EBUSY;
Kevin Wolf19dbecd2016-03-18 15:36:31 +01002166 }
2167
Kevin Wolff3adefb2017-09-22 14:50:12 +02002168 if (!(flags & BDRV_O_RDWR)) {
2169 uint64_t orig_perm, orig_shared_perm;
2170
2171 bdrv_drain(bs);
2172
2173 blk_get_perm(blk, &orig_perm, &orig_shared_perm);
2174 blk_set_perm(blk,
2175 orig_perm & ~(BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED),
2176 orig_shared_perm,
2177 &error_abort);
2178 }
2179
Kevin Wolf5bbd2e52014-12-08 17:37:28 +01002180 qopts = qemu_opts_find(&reopen_opts, NULL);
Alberto Garciadc900c32018-11-12 16:00:42 +02002181 opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : qdict_new();
Kevin Wolf5bbd2e52014-12-08 17:37:28 +01002182 qemu_opts_reset(&reopen_opts);
2183
Alberto Garciadc900c32018-11-12 16:00:42 +02002184 if (qdict_haskey(opts, BDRV_OPT_READ_ONLY)) {
2185 if (has_rw_option) {
2186 error_report("Cannot set both -r/-w and '" BDRV_OPT_READ_ONLY "'");
2187 qobject_unref(opts);
2188 return -EINVAL;
2189 }
2190 } else {
2191 qdict_put_bool(opts, BDRV_OPT_READ_ONLY, !(flags & BDRV_O_RDWR));
2192 }
2193
2194 if (qdict_haskey(opts, BDRV_OPT_CACHE_DIRECT) ||
2195 qdict_haskey(opts, BDRV_OPT_CACHE_NO_FLUSH)) {
2196 if (has_cache_option) {
2197 error_report("Cannot set both -c and the cache options");
2198 qobject_unref(opts);
2199 return -EINVAL;
2200 }
2201 } else {
2202 qdict_put_bool(opts, BDRV_OPT_CACHE_DIRECT, flags & BDRV_O_NOCACHE);
2203 qdict_put_bool(opts, BDRV_OPT_CACHE_NO_FLUSH, flags & BDRV_O_NO_FLUSH);
2204 }
2205
Kevin Wolf6cf42ca2021-07-08 13:47:06 +02002206 bdrv_reopen(bs, opts, true, &local_err);
Kevin Wolf1a63a902017-12-06 20:24:44 +01002207
Kevin Wolf5bbd2e52014-12-08 17:37:28 +01002208 if (local_err) {
2209 error_report_err(local_err);
Max Reitzb32d7a32018-05-09 21:42:59 +02002210 return -EINVAL;
Kevin Wolf5bbd2e52014-12-08 17:37:28 +01002211 }
Max Reitzb32d7a32018-05-09 21:42:59 +02002212
2213 blk_set_enable_write_cache(blk, !writethrough);
2214 return 0;
Kevin Wolf5bbd2e52014-12-08 17:37:28 +01002215}
2216
Max Reitzb32d7a32018-05-09 21:42:59 +02002217static int break_f(BlockBackend *blk, int argc, char **argv)
Kevin Wolf797ac582013-06-05 14:19:31 +02002218{
2219 int ret;
2220
Max Reitz4c7b7e92015-02-05 13:58:22 -05002221 ret = bdrv_debug_breakpoint(blk_bs(blk), argv[1], argv[2]);
Kevin Wolf797ac582013-06-05 14:19:31 +02002222 if (ret < 0) {
2223 printf("Could not set breakpoint: %s\n", strerror(-ret));
Max Reitzb32d7a32018-05-09 21:42:59 +02002224 return ret;
Kevin Wolf797ac582013-06-05 14:19:31 +02002225 }
Max Reitzb32d7a32018-05-09 21:42:59 +02002226
2227 return 0;
Kevin Wolf797ac582013-06-05 14:19:31 +02002228}
2229
Max Reitzb32d7a32018-05-09 21:42:59 +02002230static int remove_break_f(BlockBackend *blk, int argc, char **argv)
Fam Zheng4cc70e92013-11-20 10:01:54 +08002231{
2232 int ret;
2233
Max Reitz4c7b7e92015-02-05 13:58:22 -05002234 ret = bdrv_debug_remove_breakpoint(blk_bs(blk), argv[1]);
Fam Zheng4cc70e92013-11-20 10:01:54 +08002235 if (ret < 0) {
2236 printf("Could not remove breakpoint %s: %s\n", argv[1], strerror(-ret));
Max Reitzb32d7a32018-05-09 21:42:59 +02002237 return ret;
Fam Zheng4cc70e92013-11-20 10:01:54 +08002238 }
Max Reitzb32d7a32018-05-09 21:42:59 +02002239
2240 return 0;
Fam Zheng4cc70e92013-11-20 10:01:54 +08002241}
2242
Kevin Wolf797ac582013-06-05 14:19:31 +02002243static const cmdinfo_t break_cmd = {
2244 .name = "break",
2245 .argmin = 2,
2246 .argmax = 2,
2247 .cfunc = break_f,
2248 .args = "event tag",
2249 .oneline = "sets a breakpoint on event and tags the stopped "
2250 "request as tag",
2251};
2252
Fam Zheng4cc70e92013-11-20 10:01:54 +08002253static const cmdinfo_t remove_break_cmd = {
2254 .name = "remove_break",
2255 .argmin = 1,
2256 .argmax = 1,
2257 .cfunc = remove_break_f,
2258 .args = "tag",
2259 .oneline = "remove a breakpoint by tag",
2260};
2261
Max Reitzb32d7a32018-05-09 21:42:59 +02002262static int resume_f(BlockBackend *blk, int argc, char **argv)
Kevin Wolf797ac582013-06-05 14:19:31 +02002263{
2264 int ret;
2265
Max Reitz4c7b7e92015-02-05 13:58:22 -05002266 ret = bdrv_debug_resume(blk_bs(blk), argv[1]);
Kevin Wolf797ac582013-06-05 14:19:31 +02002267 if (ret < 0) {
2268 printf("Could not resume request: %s\n", strerror(-ret));
Max Reitzb32d7a32018-05-09 21:42:59 +02002269 return ret;
Kevin Wolf797ac582013-06-05 14:19:31 +02002270 }
Max Reitzb32d7a32018-05-09 21:42:59 +02002271
2272 return 0;
Kevin Wolf797ac582013-06-05 14:19:31 +02002273}
2274
2275static const cmdinfo_t resume_cmd = {
2276 .name = "resume",
2277 .argmin = 1,
2278 .argmax = 1,
2279 .cfunc = resume_f,
2280 .args = "tag",
2281 .oneline = "resumes the request tagged as tag",
2282};
2283
Max Reitzb32d7a32018-05-09 21:42:59 +02002284static int wait_break_f(BlockBackend *blk, int argc, char **argv)
Kevin Wolf797ac582013-06-05 14:19:31 +02002285{
Max Reitz4c7b7e92015-02-05 13:58:22 -05002286 while (!bdrv_debug_is_suspended(blk_bs(blk), argv[1])) {
2287 aio_poll(blk_get_aio_context(blk), true);
Kevin Wolf797ac582013-06-05 14:19:31 +02002288 }
Max Reitzb32d7a32018-05-09 21:42:59 +02002289 return 0;
Kevin Wolf797ac582013-06-05 14:19:31 +02002290}
2291
2292static const cmdinfo_t wait_break_cmd = {
2293 .name = "wait_break",
2294 .argmin = 1,
2295 .argmax = 1,
2296 .cfunc = wait_break_f,
2297 .args = "tag",
2298 .oneline = "waits for the suspension of a request",
2299};
2300
Max Reitzb32d7a32018-05-09 21:42:59 +02002301static int abort_f(BlockBackend *blk, int argc, char **argv)
Kevin Wolf797ac582013-06-05 14:19:31 +02002302{
2303 abort();
2304}
2305
2306static const cmdinfo_t abort_cmd = {
2307 .name = "abort",
2308 .cfunc = abort_f,
2309 .flags = CMD_NOFILE_OK,
2310 .oneline = "simulate a program crash using abort(3)",
2311};
2312
Max Reitz0e82dc72014-12-08 10:48:10 +01002313static void sigraise_help(void)
2314{
2315 printf(
2316"\n"
2317" raises the given signal\n"
2318"\n"
2319" Example:\n"
2320" 'sigraise %i' - raises SIGTERM\n"
2321"\n"
2322" Invokes raise(signal), where \"signal\" is the mandatory integer argument\n"
2323" given to sigraise.\n"
2324"\n", SIGTERM);
2325}
2326
Max Reitzb32d7a32018-05-09 21:42:59 +02002327static int sigraise_f(BlockBackend *blk, int argc, char **argv);
Max Reitz0e82dc72014-12-08 10:48:10 +01002328
2329static const cmdinfo_t sigraise_cmd = {
2330 .name = "sigraise",
2331 .cfunc = sigraise_f,
2332 .argmin = 1,
2333 .argmax = 1,
2334 .flags = CMD_NOFILE_OK,
2335 .args = "signal",
2336 .oneline = "raises a signal",
2337 .help = sigraise_help,
2338};
2339
Max Reitzb32d7a32018-05-09 21:42:59 +02002340static int sigraise_f(BlockBackend *blk, int argc, char **argv)
Max Reitz0e82dc72014-12-08 10:48:10 +01002341{
John Snow9b0beaf2015-11-05 18:53:02 -05002342 int64_t sig = cvtnum(argv[1]);
Max Reitz0e82dc72014-12-08 10:48:10 +01002343 if (sig < 0) {
John Snowa9ecfa02015-11-05 18:53:04 -05002344 print_cvtnum_err(sig, argv[1]);
Max Reitzb32d7a32018-05-09 21:42:59 +02002345 return sig;
John Snow9b0beaf2015-11-05 18:53:02 -05002346 } else if (sig > NSIG) {
2347 printf("signal argument '%s' is too large to be a valid signal\n",
2348 argv[1]);
Max Reitzb32d7a32018-05-09 21:42:59 +02002349 return -EINVAL;
Max Reitz0e82dc72014-12-08 10:48:10 +01002350 }
2351
2352 /* Using raise() to kill this process does not necessarily flush all open
2353 * streams. At least stdout and stderr (although the latter should be
2354 * non-buffered anyway) should be flushed, though. */
2355 fflush(stdout);
2356 fflush(stderr);
2357
2358 raise(sig);
Max Reitzb32d7a32018-05-09 21:42:59 +02002359
2360 return 0;
Max Reitz0e82dc72014-12-08 10:48:10 +01002361}
2362
Kevin Wolfcd33d022014-01-15 15:39:10 +01002363static void sleep_cb(void *opaque)
2364{
2365 bool *expired = opaque;
2366 *expired = true;
2367}
2368
Max Reitzb32d7a32018-05-09 21:42:59 +02002369static int sleep_f(BlockBackend *blk, int argc, char **argv)
Kevin Wolfcd33d022014-01-15 15:39:10 +01002370{
2371 char *endptr;
2372 long ms;
2373 struct QEMUTimer *timer;
2374 bool expired = false;
2375
2376 ms = strtol(argv[1], &endptr, 0);
2377 if (ms < 0 || *endptr != '\0') {
2378 printf("%s is not a valid number\n", argv[1]);
Max Reitzb32d7a32018-05-09 21:42:59 +02002379 return -EINVAL;
Kevin Wolfcd33d022014-01-15 15:39:10 +01002380 }
2381
2382 timer = timer_new_ns(QEMU_CLOCK_HOST, sleep_cb, &expired);
2383 timer_mod(timer, qemu_clock_get_ns(QEMU_CLOCK_HOST) + SCALE_MS * ms);
2384
2385 while (!expired) {
2386 main_loop_wait(false);
2387 }
2388
2389 timer_free(timer);
Max Reitzb32d7a32018-05-09 21:42:59 +02002390 return 0;
Kevin Wolfcd33d022014-01-15 15:39:10 +01002391}
2392
2393static const cmdinfo_t sleep_cmd = {
2394 .name = "sleep",
2395 .argmin = 1,
2396 .argmax = 1,
2397 .cfunc = sleep_f,
2398 .flags = CMD_NOFILE_OK,
2399 .oneline = "waits for the given value in milliseconds",
2400};
2401
Kevin Wolff18a8342013-06-05 14:19:33 +02002402static void help_oneline(const char *cmd, const cmdinfo_t *ct)
2403{
Dr. David Alan Gilbertda16f4b2020-08-24 11:29:14 +01002404 printf("%s ", cmd);
Kevin Wolff18a8342013-06-05 14:19:33 +02002405
2406 if (ct->args) {
2407 printf("%s ", ct->args);
2408 }
2409 printf("-- %s\n", ct->oneline);
2410}
2411
2412static void help_onecmd(const char *cmd, const cmdinfo_t *ct)
2413{
2414 help_oneline(cmd, ct);
2415 if (ct->help) {
2416 ct->help();
2417 }
2418}
2419
2420static void help_all(void)
2421{
2422 const cmdinfo_t *ct;
2423
2424 for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) {
2425 help_oneline(ct->name, ct);
2426 }
2427 printf("\nUse 'help commandname' for extended help.\n");
2428}
2429
Max Reitzb32d7a32018-05-09 21:42:59 +02002430static int help_f(BlockBackend *blk, int argc, char **argv)
Kevin Wolff18a8342013-06-05 14:19:33 +02002431{
2432 const cmdinfo_t *ct;
2433
Dr. David Alan Gilbertda16f4b2020-08-24 11:29:14 +01002434 if (argc < 2) {
Kevin Wolff18a8342013-06-05 14:19:33 +02002435 help_all();
Max Reitzb32d7a32018-05-09 21:42:59 +02002436 return 0;
Kevin Wolff18a8342013-06-05 14:19:33 +02002437 }
2438
2439 ct = find_command(argv[1]);
2440 if (ct == NULL) {
2441 printf("command %s not found\n", argv[1]);
Max Reitzb32d7a32018-05-09 21:42:59 +02002442 return -EINVAL;
Kevin Wolff18a8342013-06-05 14:19:33 +02002443 }
2444
2445 help_onecmd(argv[1], ct);
Max Reitzb32d7a32018-05-09 21:42:59 +02002446 return 0;
Kevin Wolff18a8342013-06-05 14:19:33 +02002447}
2448
2449static const cmdinfo_t help_cmd = {
2450 .name = "help",
2451 .altname = "?",
2452 .cfunc = help_f,
2453 .argmin = 0,
2454 .argmax = 1,
2455 .flags = CMD_FLAG_GLOBAL,
2456 .args = "[command]",
2457 .oneline = "help for one or all commands",
2458};
2459
Vladimir Sementsov-Ogievskiy78632a3d2021-04-23 16:42:33 +03002460/*
2461 * Called with aio context of blk acquired. Or with qemu_get_aio_context()
2462 * context acquired if blk is NULL.
2463 */
Max Reitzb32d7a32018-05-09 21:42:59 +02002464int qemuio_command(BlockBackend *blk, const char *cmd)
Kevin Wolfdd583292013-06-05 14:19:32 +02002465{
2466 char *input;
2467 const cmdinfo_t *ct;
2468 char **v;
2469 int c;
Max Reitzb32d7a32018-05-09 21:42:59 +02002470 int ret = 0;
Kevin Wolfdd583292013-06-05 14:19:32 +02002471
2472 input = g_strdup(cmd);
2473 v = breakline(input, &c);
2474 if (c) {
2475 ct = find_command(v[0]);
2476 if (ct) {
Max Reitzb32d7a32018-05-09 21:42:59 +02002477 ret = command(blk, ct, c, v);
Kevin Wolfdd583292013-06-05 14:19:32 +02002478 } else {
2479 fprintf(stderr, "command \"%s\" not found\n", v[0]);
Max Reitzb32d7a32018-05-09 21:42:59 +02002480 ret = -EINVAL;
Kevin Wolfdd583292013-06-05 14:19:32 +02002481 }
2482 }
2483 g_free(input);
2484 g_free(v);
Max Reitzb32d7a32018-05-09 21:42:59 +02002485
2486 return ret;
Kevin Wolfdd583292013-06-05 14:19:32 +02002487}
2488
Kevin Wolf797ac582013-06-05 14:19:31 +02002489static void __attribute((constructor)) init_qemuio_commands(void)
2490{
2491 /* initialize commands */
Kevin Wolfc2cdf5c2013-06-05 14:19:36 +02002492 qemuio_add_command(&help_cmd);
2493 qemuio_add_command(&read_cmd);
2494 qemuio_add_command(&readv_cmd);
2495 qemuio_add_command(&write_cmd);
2496 qemuio_add_command(&writev_cmd);
Kevin Wolfc2cdf5c2013-06-05 14:19:36 +02002497 qemuio_add_command(&aio_read_cmd);
2498 qemuio_add_command(&aio_write_cmd);
2499 qemuio_add_command(&aio_flush_cmd);
2500 qemuio_add_command(&flush_cmd);
2501 qemuio_add_command(&truncate_cmd);
2502 qemuio_add_command(&length_cmd);
2503 qemuio_add_command(&info_cmd);
2504 qemuio_add_command(&discard_cmd);
2505 qemuio_add_command(&alloc_cmd);
2506 qemuio_add_command(&map_cmd);
Kevin Wolf5bbd2e52014-12-08 17:37:28 +01002507 qemuio_add_command(&reopen_cmd);
Kevin Wolfc2cdf5c2013-06-05 14:19:36 +02002508 qemuio_add_command(&break_cmd);
Fam Zheng4cc70e92013-11-20 10:01:54 +08002509 qemuio_add_command(&remove_break_cmd);
Kevin Wolfc2cdf5c2013-06-05 14:19:36 +02002510 qemuio_add_command(&resume_cmd);
2511 qemuio_add_command(&wait_break_cmd);
2512 qemuio_add_command(&abort_cmd);
Kevin Wolfcd33d022014-01-15 15:39:10 +01002513 qemuio_add_command(&sleep_cmd);
Max Reitz0e82dc72014-12-08 10:48:10 +01002514 qemuio_add_command(&sigraise_cmd);
Kevin Wolf797ac582013-06-05 14:19:31 +02002515}