xref: /qemu/qemu-io.c (revision 1afec9138f848cfba517bd2d80167b27216b9df9)
1e3aff4f6Saliguori /*
2e3aff4f6Saliguori  * Command line utility to exercise the QEMU I/O path.
3e3aff4f6Saliguori  *
4e3aff4f6Saliguori  * Copyright (C) 2009 Red Hat, Inc.
5e3aff4f6Saliguori  * Copyright (c) 2003-2005 Silicon Graphics, Inc.
6e3aff4f6Saliguori  *
7e3aff4f6Saliguori  * This work is licensed under the terms of the GNU GPL, version 2 or later.
8e3aff4f6Saliguori  * See the COPYING file in the top-level directory.
9e3aff4f6Saliguori  */
10c32d766aSStefan Weil #include <sys/time.h>
11e3aff4f6Saliguori #include <sys/types.h>
12e3aff4f6Saliguori #include <stdarg.h>
13e3aff4f6Saliguori #include <stdio.h>
14e3aff4f6Saliguori #include <getopt.h>
15c32d766aSStefan Weil #include <libgen.h>
16e3aff4f6Saliguori 
17e3aff4f6Saliguori #include "qemu-common.h"
18e3aff4f6Saliguori #include "block_int.h"
19e3aff4f6Saliguori #include "cmd.h"
20e3aff4f6Saliguori 
21e3aff4f6Saliguori #define VERSION	"0.0.1"
22e3aff4f6Saliguori 
23e3aff4f6Saliguori #define CMD_NOFILE_OK	0x01
24e3aff4f6Saliguori 
25e3aff4f6Saliguori char *progname;
26e3aff4f6Saliguori static BlockDriverState *bs;
27e3aff4f6Saliguori 
28e3aff4f6Saliguori static int misalign;
29e3aff4f6Saliguori 
30e3aff4f6Saliguori /*
31cf070d7eSChristoph Hellwig  * Parse the pattern argument to various sub-commands.
32cf070d7eSChristoph Hellwig  *
33cf070d7eSChristoph Hellwig  * Because the pattern is used as an argument to memset it must evaluate
34cf070d7eSChristoph Hellwig  * to an unsigned integer that fits into a single byte.
35cf070d7eSChristoph Hellwig  */
36cf070d7eSChristoph Hellwig static int parse_pattern(const char *arg)
37cf070d7eSChristoph Hellwig {
38cf070d7eSChristoph Hellwig 	char *endptr = NULL;
39cf070d7eSChristoph Hellwig 	long pattern;
40cf070d7eSChristoph Hellwig 
41cf070d7eSChristoph Hellwig 	pattern = strtol(arg, &endptr, 0);
42cf070d7eSChristoph Hellwig 	if (pattern < 0 || pattern > UCHAR_MAX || *endptr != '\0') {
43cf070d7eSChristoph Hellwig 		printf("%s is not a valid pattern byte\n", arg);
44cf070d7eSChristoph Hellwig 		return -1;
45cf070d7eSChristoph Hellwig 	}
46cf070d7eSChristoph Hellwig 
47cf070d7eSChristoph Hellwig 	return pattern;
48cf070d7eSChristoph Hellwig }
49cf070d7eSChristoph Hellwig 
50cf070d7eSChristoph Hellwig /*
51e3aff4f6Saliguori  * Memory allocation helpers.
52e3aff4f6Saliguori  *
53e3aff4f6Saliguori  * Make sure memory is aligned by default, or purposefully misaligned if
54e3aff4f6Saliguori  * that is specified on the command line.
55e3aff4f6Saliguori  */
56e3aff4f6Saliguori 
57e3aff4f6Saliguori #define MISALIGN_OFFSET		16
58e3aff4f6Saliguori static void *qemu_io_alloc(size_t len, int pattern)
59e3aff4f6Saliguori {
60e3aff4f6Saliguori 	void *buf;
61e3aff4f6Saliguori 
62e3aff4f6Saliguori 	if (misalign)
63e3aff4f6Saliguori 		len += MISALIGN_OFFSET;
6472aef731SChristoph Hellwig 	buf = qemu_blockalign(bs, len);
65e3aff4f6Saliguori 	memset(buf, pattern, len);
66e3aff4f6Saliguori 	if (misalign)
67e3aff4f6Saliguori 		buf += MISALIGN_OFFSET;
68e3aff4f6Saliguori 	return buf;
69e3aff4f6Saliguori }
70e3aff4f6Saliguori 
71e3aff4f6Saliguori static void qemu_io_free(void *p)
72e3aff4f6Saliguori {
73e3aff4f6Saliguori 	if (misalign)
74e3aff4f6Saliguori 		p -= MISALIGN_OFFSET;
75e3aff4f6Saliguori 	qemu_vfree(p);
76e3aff4f6Saliguori }
77e3aff4f6Saliguori 
78e3aff4f6Saliguori static void
793abcdf49SStefan Weil dump_buffer(const void *buffer, int64_t offset, int len)
80e3aff4f6Saliguori {
81e3aff4f6Saliguori 	int i, j;
823abcdf49SStefan Weil 	const uint8_t *p;
83e3aff4f6Saliguori 
84e3aff4f6Saliguori 	for (i = 0, p = buffer; i < len; i += 16) {
853abcdf49SStefan Weil 		const uint8_t *s = p;
86e3aff4f6Saliguori 
870bfcd599SBlue Swirl                 printf("%08" PRIx64 ":  ", offset + i);
88e3aff4f6Saliguori 		for (j = 0; j < 16 && i + j < len; j++, p++)
89e3aff4f6Saliguori 			printf("%02x ", *p);
90e3aff4f6Saliguori 		printf(" ");
91e3aff4f6Saliguori 		for (j = 0; j < 16 && i + j < len; j++, s++) {
923abcdf49SStefan Weil 			if (isalnum(*s))
93e3aff4f6Saliguori 				printf("%c", *s);
94e3aff4f6Saliguori 			else
95e3aff4f6Saliguori 				printf(".");
96e3aff4f6Saliguori 		}
97e3aff4f6Saliguori 		printf("\n");
98e3aff4f6Saliguori 	}
99e3aff4f6Saliguori }
100e3aff4f6Saliguori 
101e3aff4f6Saliguori static void
102e3aff4f6Saliguori print_report(const char *op, struct timeval *t, int64_t offset,
103e3aff4f6Saliguori 		int count, int total, int cnt, int Cflag)
104e3aff4f6Saliguori {
105e3aff4f6Saliguori 	char s1[64], s2[64], ts[64];
106e3aff4f6Saliguori 
107e3aff4f6Saliguori 	timestr(t, ts, sizeof(ts), Cflag ? VERBOSE_FIXED_TIME : 0);
108e3aff4f6Saliguori 	if (!Cflag) {
109e3aff4f6Saliguori 		cvtstr((double)total, s1, sizeof(s1));
110e3aff4f6Saliguori 		cvtstr(tdiv((double)total, *t), s2, sizeof(s2));
1110bfcd599SBlue Swirl                 printf("%s %d/%d bytes at offset %" PRId64 "\n",
1120bfcd599SBlue Swirl                        op, total, count, offset);
113e3aff4f6Saliguori 		printf("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n",
114e3aff4f6Saliguori 			s1, cnt, ts, s2, tdiv((double)cnt, *t));
115e3aff4f6Saliguori 	} else {/* bytes,ops,time,bytes/sec,ops/sec */
116e3aff4f6Saliguori 		printf("%d,%d,%s,%.3f,%.3f\n",
117e3aff4f6Saliguori 			total, cnt, ts,
118e3aff4f6Saliguori 			tdiv((double)total, *t),
119e3aff4f6Saliguori 			tdiv((double)cnt, *t));
120e3aff4f6Saliguori 	}
121e3aff4f6Saliguori }
122e3aff4f6Saliguori 
123cf57298aSChristoph Hellwig /*
124cf57298aSChristoph Hellwig  * Parse multiple length statements for vectored I/O, and construct an I/O
125cf57298aSChristoph Hellwig  * vector matching it.
126cf57298aSChristoph Hellwig  */
127cf57298aSChristoph Hellwig static void *
128cf57298aSChristoph Hellwig create_iovec(QEMUIOVector *qiov, char **argv, int nr_iov, int pattern)
129cf57298aSChristoph Hellwig {
130cf57298aSChristoph Hellwig 	size_t *sizes = calloc(nr_iov, sizeof(size_t));
131cf57298aSChristoph Hellwig 	size_t count = 0;
13240a0d7c3SKevin Wolf 	void *buf = NULL;
13340a0d7c3SKevin Wolf 	void *p;
134cf57298aSChristoph Hellwig 	int i;
135cf57298aSChristoph Hellwig 
136cf57298aSChristoph Hellwig 	for (i = 0; i < nr_iov; i++) {
137cf57298aSChristoph Hellwig 		char *arg = argv[i];
138ca1d6ac6SJoel Schopp                 int64_t len;
139cf57298aSChristoph Hellwig 
140cf57298aSChristoph Hellwig 		len = cvtnum(arg);
141cf57298aSChristoph Hellwig 		if (len < 0) {
142cf57298aSChristoph Hellwig 			printf("non-numeric length argument -- %s\n", arg);
14340a0d7c3SKevin Wolf 			goto fail;
144cf57298aSChristoph Hellwig 		}
145cf57298aSChristoph Hellwig 
146cf57298aSChristoph Hellwig 		/* should be SIZE_T_MAX, but that doesn't exist */
147ca1d6ac6SJoel Schopp 		if (len > INT_MAX) {
148cf57298aSChristoph Hellwig 			printf("too large length argument -- %s\n", arg);
14940a0d7c3SKevin Wolf 			goto fail;
150cf57298aSChristoph Hellwig 		}
151cf57298aSChristoph Hellwig 
152cf57298aSChristoph Hellwig 		if (len & 0x1ff) {
1530bfcd599SBlue Swirl                         printf("length argument %" PRId64
1540bfcd599SBlue Swirl                                " is not sector aligned\n", len);
15540a0d7c3SKevin Wolf 			goto fail;
156cf57298aSChristoph Hellwig 		}
157cf57298aSChristoph Hellwig 
158cf57298aSChristoph Hellwig 		sizes[i] = len;
159cf57298aSChristoph Hellwig 		count += len;
160cf57298aSChristoph Hellwig 	}
161cf57298aSChristoph Hellwig 
162cf57298aSChristoph Hellwig 	qemu_iovec_init(qiov, nr_iov);
163cf57298aSChristoph Hellwig 
164cf57298aSChristoph Hellwig 	buf = p = qemu_io_alloc(count, pattern);
165cf57298aSChristoph Hellwig 
166cf57298aSChristoph Hellwig 	for (i = 0; i < nr_iov; i++) {
167cf57298aSChristoph Hellwig 		qemu_iovec_add(qiov, p, sizes[i]);
168cf57298aSChristoph Hellwig 		p += sizes[i];
169cf57298aSChristoph Hellwig 	}
170cf57298aSChristoph Hellwig 
17140a0d7c3SKevin Wolf fail:
172cf57298aSChristoph Hellwig 	free(sizes);
173cf57298aSChristoph Hellwig 	return buf;
174cf57298aSChristoph Hellwig }
175cf57298aSChristoph Hellwig 
176e3aff4f6Saliguori static int do_read(char *buf, int64_t offset, int count, int *total)
177e3aff4f6Saliguori {
178e3aff4f6Saliguori 	int ret;
179e3aff4f6Saliguori 
180e3aff4f6Saliguori 	ret = bdrv_read(bs, offset >> 9, (uint8_t *)buf, count >> 9);
181e3aff4f6Saliguori 	if (ret < 0)
182e3aff4f6Saliguori 		return ret;
183e3aff4f6Saliguori 	*total = count;
184e3aff4f6Saliguori 	return 1;
185e3aff4f6Saliguori }
186e3aff4f6Saliguori 
187e3aff4f6Saliguori static int do_write(char *buf, int64_t offset, int count, int *total)
188e3aff4f6Saliguori {
189e3aff4f6Saliguori 	int ret;
190e3aff4f6Saliguori 
191e3aff4f6Saliguori 	ret = bdrv_write(bs, offset >> 9, (uint8_t *)buf, count >> 9);
192e3aff4f6Saliguori 	if (ret < 0)
193e3aff4f6Saliguori 		return ret;
194e3aff4f6Saliguori 	*total = count;
195e3aff4f6Saliguori 	return 1;
196e3aff4f6Saliguori }
197e3aff4f6Saliguori 
198e3aff4f6Saliguori static int do_pread(char *buf, int64_t offset, int count, int *total)
199e3aff4f6Saliguori {
200e3aff4f6Saliguori 	*total = bdrv_pread(bs, offset, (uint8_t *)buf, count);
201e3aff4f6Saliguori 	if (*total < 0)
202e3aff4f6Saliguori 		return *total;
203e3aff4f6Saliguori 	return 1;
204e3aff4f6Saliguori }
205e3aff4f6Saliguori 
206e3aff4f6Saliguori static int do_pwrite(char *buf, int64_t offset, int count, int *total)
207e3aff4f6Saliguori {
208e3aff4f6Saliguori 	*total = bdrv_pwrite(bs, offset, (uint8_t *)buf, count);
209e3aff4f6Saliguori 	if (*total < 0)
210e3aff4f6Saliguori 		return *total;
211e3aff4f6Saliguori 	return 1;
212e3aff4f6Saliguori }
213e3aff4f6Saliguori 
214ca94dbc7SKevin Wolf static int do_load_vmstate(char *buf, int64_t offset, int count, int *total)
215ca94dbc7SKevin Wolf {
216ca94dbc7SKevin Wolf 	*total = bdrv_load_vmstate(bs, (uint8_t *)buf, offset, count);
217ca94dbc7SKevin Wolf 	if (*total < 0)
218ca94dbc7SKevin Wolf 		return *total;
219ca94dbc7SKevin Wolf 	return 1;
220ca94dbc7SKevin Wolf }
221ca94dbc7SKevin Wolf 
222ca94dbc7SKevin Wolf static int do_save_vmstate(char *buf, int64_t offset, int count, int *total)
223ca94dbc7SKevin Wolf {
224ca94dbc7SKevin Wolf 	*total = bdrv_save_vmstate(bs, (uint8_t *)buf, offset, count);
225ca94dbc7SKevin Wolf 	if (*total < 0)
226ca94dbc7SKevin Wolf 		return *total;
227ca94dbc7SKevin Wolf 	return 1;
228ca94dbc7SKevin Wolf }
229ca94dbc7SKevin Wolf 
230e3aff4f6Saliguori #define NOT_DONE 0x7fffffff
231e3aff4f6Saliguori static void aio_rw_done(void *opaque, int ret)
232e3aff4f6Saliguori {
233e3aff4f6Saliguori 	*(int *)opaque = ret;
234e3aff4f6Saliguori }
235e3aff4f6Saliguori 
236e3aff4f6Saliguori static int do_aio_readv(QEMUIOVector *qiov, int64_t offset, int *total)
237e3aff4f6Saliguori {
238e3aff4f6Saliguori 	BlockDriverAIOCB *acb;
239e3aff4f6Saliguori 	int async_ret = NOT_DONE;
240e3aff4f6Saliguori 
241e3aff4f6Saliguori 	acb = bdrv_aio_readv(bs, offset >> 9, qiov, qiov->size >> 9,
242e3aff4f6Saliguori 			     aio_rw_done, &async_ret);
243e3aff4f6Saliguori 	if (!acb)
244e3aff4f6Saliguori 		return -EIO;
245e3aff4f6Saliguori 
246e3aff4f6Saliguori 	while (async_ret == NOT_DONE)
247e3aff4f6Saliguori 		qemu_aio_wait();
248e3aff4f6Saliguori 
249e3aff4f6Saliguori 	*total = qiov->size;
250e3aff4f6Saliguori 	return async_ret < 0 ? async_ret : 1;
251e3aff4f6Saliguori }
252e3aff4f6Saliguori 
253e3aff4f6Saliguori static int do_aio_writev(QEMUIOVector *qiov, int64_t offset, int *total)
254e3aff4f6Saliguori {
255e3aff4f6Saliguori 	BlockDriverAIOCB *acb;
256e3aff4f6Saliguori 	int async_ret = NOT_DONE;
257e3aff4f6Saliguori 
258e3aff4f6Saliguori 	acb = bdrv_aio_writev(bs, offset >> 9, qiov, qiov->size >> 9,
259e3aff4f6Saliguori 			      aio_rw_done, &async_ret);
260e3aff4f6Saliguori 	if (!acb)
261e3aff4f6Saliguori 		return -EIO;
262e3aff4f6Saliguori 
263e3aff4f6Saliguori 	while (async_ret == NOT_DONE)
264e3aff4f6Saliguori 		qemu_aio_wait();
265e3aff4f6Saliguori 
2667e9bbc9fSaliguori 	*total = qiov->size;
267e3aff4f6Saliguori 	return async_ret < 0 ? async_ret : 1;
268e3aff4f6Saliguori }
269e3aff4f6Saliguori 
270776cbbbdSKevin Wolf struct multiwrite_async_ret {
271776cbbbdSKevin Wolf 	int num_done;
272776cbbbdSKevin Wolf 	int error;
273776cbbbdSKevin Wolf };
274776cbbbdSKevin Wolf 
275776cbbbdSKevin Wolf static void multiwrite_cb(void *opaque, int ret)
276776cbbbdSKevin Wolf {
277776cbbbdSKevin Wolf 	struct multiwrite_async_ret *async_ret = opaque;
278776cbbbdSKevin Wolf 
279776cbbbdSKevin Wolf 	async_ret->num_done++;
280776cbbbdSKevin Wolf 	if (ret < 0) {
281776cbbbdSKevin Wolf 		async_ret->error = ret;
282776cbbbdSKevin Wolf 	}
283776cbbbdSKevin Wolf }
284776cbbbdSKevin Wolf 
285776cbbbdSKevin Wolf static int do_aio_multiwrite(BlockRequest* reqs, int num_reqs, int *total)
286776cbbbdSKevin Wolf {
287776cbbbdSKevin Wolf 	int i, ret;
288776cbbbdSKevin Wolf 	struct multiwrite_async_ret async_ret = {
289776cbbbdSKevin Wolf 		.num_done = 0,
290776cbbbdSKevin Wolf 		.error = 0,
291776cbbbdSKevin Wolf 	};
292776cbbbdSKevin Wolf 
293776cbbbdSKevin Wolf 	*total = 0;
294776cbbbdSKevin Wolf 	for (i = 0; i < num_reqs; i++) {
295776cbbbdSKevin Wolf 		reqs[i].cb = multiwrite_cb;
296776cbbbdSKevin Wolf 		reqs[i].opaque = &async_ret;
297776cbbbdSKevin Wolf 		*total += reqs[i].qiov->size;
298776cbbbdSKevin Wolf 	}
299776cbbbdSKevin Wolf 
300776cbbbdSKevin Wolf 	ret = bdrv_aio_multiwrite(bs, reqs, num_reqs);
301776cbbbdSKevin Wolf 	if (ret < 0) {
302776cbbbdSKevin Wolf 		return ret;
303776cbbbdSKevin Wolf 	}
304776cbbbdSKevin Wolf 
305776cbbbdSKevin Wolf 	while (async_ret.num_done < num_reqs) {
306776cbbbdSKevin Wolf 		qemu_aio_wait();
307776cbbbdSKevin Wolf 	}
308776cbbbdSKevin Wolf 
309776cbbbdSKevin Wolf 	return async_ret.error < 0 ? async_ret.error : 1;
310776cbbbdSKevin Wolf }
311e3aff4f6Saliguori 
312e3aff4f6Saliguori static void
313e3aff4f6Saliguori read_help(void)
314e3aff4f6Saliguori {
315e3aff4f6Saliguori 	printf(
316e3aff4f6Saliguori "\n"
317e3aff4f6Saliguori " reads a range of bytes from the given offset\n"
318e3aff4f6Saliguori "\n"
319e3aff4f6Saliguori " Example:\n"
320e3aff4f6Saliguori " 'read -v 512 1k' - dumps 1 kilobyte read from 512 bytes into the file\n"
321e3aff4f6Saliguori "\n"
322e3aff4f6Saliguori " Reads a segment of the currently open file, optionally dumping it to the\n"
323e3aff4f6Saliguori " standard output stream (with -v option) for subsequent inspection.\n"
324ca94dbc7SKevin Wolf " -b, -- read from the VM state rather than the virtual disk\n"
325d9654a58SKevin Wolf " -C, -- report statistics in a machine parsable format\n"
326d9654a58SKevin Wolf " -l, -- length for pattern verification (only with -P)\n"
327e3aff4f6Saliguori " -p, -- use bdrv_pread to read the file\n"
328c48101aeSaliguori " -P, -- use a pattern to verify read data\n"
329095343adSKevin Wolf " -q, -- quiet mode, do not show I/O statistics\n"
330d9654a58SKevin Wolf " -s, -- start offset for pattern verification (only with -P)\n"
331d9654a58SKevin Wolf " -v, -- dump buffer to standard output\n"
332e3aff4f6Saliguori "\n");
333e3aff4f6Saliguori }
334e3aff4f6Saliguori 
33522a2bdcbSBlue Swirl static int read_f(int argc, char **argv);
33622a2bdcbSBlue Swirl 
33722a2bdcbSBlue Swirl static const cmdinfo_t read_cmd = {
33822a2bdcbSBlue Swirl 	.name		= "read",
33922a2bdcbSBlue Swirl 	.altname	= "r",
34022a2bdcbSBlue Swirl 	.cfunc		= read_f,
34122a2bdcbSBlue Swirl 	.argmin		= 2,
34222a2bdcbSBlue Swirl 	.argmax		= -1,
34322a2bdcbSBlue Swirl 	.args		= "[-abCpqv] [-P pattern [-s off] [-l len]] off len",
34422a2bdcbSBlue Swirl 	.oneline	= "reads a number of bytes at a specified offset",
34522a2bdcbSBlue Swirl 	.help		= read_help,
34622a2bdcbSBlue Swirl };
34722a2bdcbSBlue Swirl 
348e3aff4f6Saliguori static int
349e3aff4f6Saliguori read_f(int argc, char **argv)
350e3aff4f6Saliguori {
351e3aff4f6Saliguori 	struct timeval t1, t2;
352e3aff4f6Saliguori 	int Cflag = 0, pflag = 0, qflag = 0, vflag = 0;
353ca94dbc7SKevin Wolf 	int Pflag = 0, sflag = 0, lflag = 0, bflag = 0;
354e3aff4f6Saliguori 	int c, cnt;
355e3aff4f6Saliguori 	char *buf;
356e3aff4f6Saliguori 	int64_t offset;
357d4ec5228SPaul Brook 	int count;
358d4ec5228SPaul Brook         /* Some compilers get confused and warn if this is not initialized.  */
359d4ec5228SPaul Brook         int total = 0;
360d9654a58SKevin Wolf 	int pattern = 0, pattern_offset = 0, pattern_count = 0;
361e3aff4f6Saliguori 
362ca94dbc7SKevin Wolf 	while ((c = getopt(argc, argv, "bCl:pP:qs:v")) != EOF) {
363e3aff4f6Saliguori 		switch (c) {
364ca94dbc7SKevin Wolf 		case 'b':
365ca94dbc7SKevin Wolf 			bflag = 1;
366ca94dbc7SKevin Wolf 			break;
367e3aff4f6Saliguori 		case 'C':
368e3aff4f6Saliguori 			Cflag = 1;
369e3aff4f6Saliguori 			break;
370d9654a58SKevin Wolf 		case 'l':
371d9654a58SKevin Wolf 			lflag = 1;
372d9654a58SKevin Wolf 			pattern_count = cvtnum(optarg);
373d9654a58SKevin Wolf 			if (pattern_count < 0) {
374d9654a58SKevin Wolf 				printf("non-numeric length argument -- %s\n", optarg);
375d9654a58SKevin Wolf 				return 0;
376d9654a58SKevin Wolf 			}
377d9654a58SKevin Wolf 			break;
378e3aff4f6Saliguori 		case 'p':
379e3aff4f6Saliguori 			pflag = 1;
380e3aff4f6Saliguori 			break;
381c48101aeSaliguori 		case 'P':
382c48101aeSaliguori 			Pflag = 1;
383cf070d7eSChristoph Hellwig 			pattern = parse_pattern(optarg);
384cf070d7eSChristoph Hellwig 			if (pattern < 0)
385cf070d7eSChristoph Hellwig 				return 0;
386c48101aeSaliguori 			break;
387e3aff4f6Saliguori 		case 'q':
388e3aff4f6Saliguori 			qflag = 1;
389e3aff4f6Saliguori 			break;
390d9654a58SKevin Wolf 		case 's':
391d9654a58SKevin Wolf 			sflag = 1;
392d9654a58SKevin Wolf 			pattern_offset = cvtnum(optarg);
393d9654a58SKevin Wolf 			if (pattern_offset < 0) {
394d9654a58SKevin Wolf 				printf("non-numeric length argument -- %s\n", optarg);
395d9654a58SKevin Wolf 				return 0;
396d9654a58SKevin Wolf 			}
397d9654a58SKevin Wolf 			break;
398e3aff4f6Saliguori 		case 'v':
399e3aff4f6Saliguori 			vflag = 1;
400e3aff4f6Saliguori 			break;
401e3aff4f6Saliguori 		default:
402e3aff4f6Saliguori 			return command_usage(&read_cmd);
403e3aff4f6Saliguori 		}
404e3aff4f6Saliguori 	}
405e3aff4f6Saliguori 
406e3aff4f6Saliguori 	if (optind != argc - 2)
407e3aff4f6Saliguori 		return command_usage(&read_cmd);
408e3aff4f6Saliguori 
409ca94dbc7SKevin Wolf 	if (bflag && pflag) {
410ca94dbc7SKevin Wolf 		printf("-b and -p cannot be specified at the same time\n");
411ca94dbc7SKevin Wolf 		return 0;
412ca94dbc7SKevin Wolf 	}
413ca94dbc7SKevin Wolf 
414e3aff4f6Saliguori 	offset = cvtnum(argv[optind]);
415e3aff4f6Saliguori 	if (offset < 0) {
416e3aff4f6Saliguori 		printf("non-numeric length argument -- %s\n", argv[optind]);
417e3aff4f6Saliguori 		return 0;
418e3aff4f6Saliguori 	}
419e3aff4f6Saliguori 
420e3aff4f6Saliguori 	optind++;
421e3aff4f6Saliguori 	count = cvtnum(argv[optind]);
422e3aff4f6Saliguori 	if (count < 0) {
423e3aff4f6Saliguori 		printf("non-numeric length argument -- %s\n", argv[optind]);
424e3aff4f6Saliguori 		return 0;
425e3aff4f6Saliguori 	}
426e3aff4f6Saliguori 
427d9654a58SKevin Wolf     if (!Pflag && (lflag || sflag)) {
428d9654a58SKevin Wolf         return command_usage(&read_cmd);
429d9654a58SKevin Wolf     }
430d9654a58SKevin Wolf 
431d9654a58SKevin Wolf     if (!lflag) {
432d9654a58SKevin Wolf         pattern_count = count - pattern_offset;
433d9654a58SKevin Wolf     }
434d9654a58SKevin Wolf 
435d9654a58SKevin Wolf     if ((pattern_count < 0) || (pattern_count + pattern_offset > count))  {
436d9654a58SKevin Wolf         printf("pattern verfication range exceeds end of read data\n");
437d9654a58SKevin Wolf         return 0;
438d9654a58SKevin Wolf     }
439d9654a58SKevin Wolf 
440e3aff4f6Saliguori 	if (!pflag)
441e3aff4f6Saliguori 		if (offset & 0x1ff) {
4420bfcd599SBlue Swirl                         printf("offset %" PRId64 " is not sector aligned\n",
4430bfcd599SBlue Swirl                                offset);
444e3aff4f6Saliguori 			return 0;
445e3aff4f6Saliguori 
446e3aff4f6Saliguori 		if (count & 0x1ff) {
447e3aff4f6Saliguori 			printf("count %d is not sector aligned\n",
448e3aff4f6Saliguori 				count);
449e3aff4f6Saliguori 			return 0;
450e3aff4f6Saliguori 		}
451e3aff4f6Saliguori 	}
452e3aff4f6Saliguori 
453e3aff4f6Saliguori 	buf = qemu_io_alloc(count, 0xab);
454e3aff4f6Saliguori 
455e3aff4f6Saliguori 	gettimeofday(&t1, NULL);
456e3aff4f6Saliguori 	if (pflag)
457e3aff4f6Saliguori 		cnt = do_pread(buf, offset, count, &total);
458ca94dbc7SKevin Wolf 	else if (bflag)
459ca94dbc7SKevin Wolf 		cnt = do_load_vmstate(buf, offset, count, &total);
460e3aff4f6Saliguori 	else
461e3aff4f6Saliguori 		cnt = do_read(buf, offset, count, &total);
462e3aff4f6Saliguori 	gettimeofday(&t2, NULL);
463e3aff4f6Saliguori 
464e3aff4f6Saliguori 	if (cnt < 0) {
465e3aff4f6Saliguori 		printf("read failed: %s\n", strerror(-cnt));
4667d8abfcbSKevin Wolf 		goto out;
467e3aff4f6Saliguori 	}
468e3aff4f6Saliguori 
469c48101aeSaliguori 	if (Pflag) {
470d9654a58SKevin Wolf 		void* cmp_buf = malloc(pattern_count);
471d9654a58SKevin Wolf 		memset(cmp_buf, pattern, pattern_count);
472d9654a58SKevin Wolf 		if (memcmp(buf + pattern_offset, cmp_buf, pattern_count)) {
4730bfcd599SBlue Swirl 			printf("Pattern verification failed at offset %"
4740bfcd599SBlue Swirl                                PRId64 ", %d bytes\n",
4750bfcd599SBlue Swirl                                offset + pattern_offset, pattern_count);
476c48101aeSaliguori 		}
477c48101aeSaliguori 		free(cmp_buf);
478c48101aeSaliguori 	}
479c48101aeSaliguori 
480e3aff4f6Saliguori 	if (qflag)
4817d8abfcbSKevin Wolf 		goto out;
482e3aff4f6Saliguori 
483e3aff4f6Saliguori         if (vflag)
484e3aff4f6Saliguori 		dump_buffer(buf, offset, count);
485e3aff4f6Saliguori 
486e3aff4f6Saliguori 	/* Finally, report back -- -C gives a parsable format */
487e3aff4f6Saliguori 	t2 = tsub(t2, t1);
488e3aff4f6Saliguori 	print_report("read", &t2, offset, count, total, cnt, Cflag);
489e3aff4f6Saliguori 
4907d8abfcbSKevin Wolf out:
491e3aff4f6Saliguori 	qemu_io_free(buf);
492e3aff4f6Saliguori 
493e3aff4f6Saliguori 	return 0;
494e3aff4f6Saliguori }
495e3aff4f6Saliguori 
496e3aff4f6Saliguori static void
497e3aff4f6Saliguori readv_help(void)
498e3aff4f6Saliguori {
499e3aff4f6Saliguori 	printf(
500e3aff4f6Saliguori "\n"
501e3aff4f6Saliguori " reads a range of bytes from the given offset into multiple buffers\n"
502e3aff4f6Saliguori "\n"
503e3aff4f6Saliguori " Example:\n"
504e3aff4f6Saliguori " 'readv -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n"
505e3aff4f6Saliguori "\n"
506e3aff4f6Saliguori " Reads a segment of the currently open file, optionally dumping it to the\n"
507e3aff4f6Saliguori " standard output stream (with -v option) for subsequent inspection.\n"
508e3aff4f6Saliguori " Uses multiple iovec buffers if more than one byte range is specified.\n"
509e3aff4f6Saliguori " -C, -- report statistics in a machine parsable format\n"
510c48101aeSaliguori " -P, -- use a pattern to verify read data\n"
511e3aff4f6Saliguori " -v, -- dump buffer to standard output\n"
512095343adSKevin Wolf " -q, -- quiet mode, do not show I/O statistics\n"
513e3aff4f6Saliguori "\n");
514e3aff4f6Saliguori }
515e3aff4f6Saliguori 
51622a2bdcbSBlue Swirl static int readv_f(int argc, char **argv);
51722a2bdcbSBlue Swirl 
51822a2bdcbSBlue Swirl static const cmdinfo_t readv_cmd = {
51922a2bdcbSBlue Swirl 	.name		= "readv",
52022a2bdcbSBlue Swirl 	.cfunc		= readv_f,
52122a2bdcbSBlue Swirl 	.argmin		= 2,
52222a2bdcbSBlue Swirl 	.argmax		= -1,
52322a2bdcbSBlue Swirl 	.args		= "[-Cqv] [-P pattern ] off len [len..]",
52422a2bdcbSBlue Swirl 	.oneline	= "reads a number of bytes at a specified offset",
52522a2bdcbSBlue Swirl 	.help		= readv_help,
52622a2bdcbSBlue Swirl };
52722a2bdcbSBlue Swirl 
528e3aff4f6Saliguori static int
529e3aff4f6Saliguori readv_f(int argc, char **argv)
530e3aff4f6Saliguori {
531e3aff4f6Saliguori 	struct timeval t1, t2;
532e3aff4f6Saliguori 	int Cflag = 0, qflag = 0, vflag = 0;
533e3aff4f6Saliguori 	int c, cnt;
534cf57298aSChristoph Hellwig 	char *buf;
535e3aff4f6Saliguori 	int64_t offset;
5366474bd69SBlue Swirl         /* Some compilers get confused and warn if this is not initialized.  */
5376474bd69SBlue Swirl         int total = 0;
538cf57298aSChristoph Hellwig 	int nr_iov;
539e3aff4f6Saliguori 	QEMUIOVector qiov;
540c48101aeSaliguori 	int pattern = 0;
541c48101aeSaliguori 	int Pflag = 0;
542e3aff4f6Saliguori 
543c48101aeSaliguori 	while ((c = getopt(argc, argv, "CP:qv")) != EOF) {
544e3aff4f6Saliguori 		switch (c) {
545e3aff4f6Saliguori 		case 'C':
546e3aff4f6Saliguori 			Cflag = 1;
547e3aff4f6Saliguori 			break;
548c48101aeSaliguori 		case 'P':
549c48101aeSaliguori 			Pflag = 1;
550cf070d7eSChristoph Hellwig 			pattern = parse_pattern(optarg);
551cf070d7eSChristoph Hellwig 			if (pattern < 0)
552cf070d7eSChristoph Hellwig 				return 0;
553c48101aeSaliguori 			break;
554e3aff4f6Saliguori 		case 'q':
555e3aff4f6Saliguori 			qflag = 1;
556e3aff4f6Saliguori 			break;
557e3aff4f6Saliguori 		case 'v':
558e3aff4f6Saliguori 			vflag = 1;
559e3aff4f6Saliguori 			break;
560e3aff4f6Saliguori 		default:
561e3aff4f6Saliguori 			return command_usage(&readv_cmd);
562e3aff4f6Saliguori 		}
563e3aff4f6Saliguori 	}
564e3aff4f6Saliguori 
565e3aff4f6Saliguori 	if (optind > argc - 2)
566e3aff4f6Saliguori 		return command_usage(&readv_cmd);
567e3aff4f6Saliguori 
568e3aff4f6Saliguori 
569e3aff4f6Saliguori 	offset = cvtnum(argv[optind]);
570e3aff4f6Saliguori 	if (offset < 0) {
571e3aff4f6Saliguori 		printf("non-numeric length argument -- %s\n", argv[optind]);
572e3aff4f6Saliguori 		return 0;
573e3aff4f6Saliguori 	}
574e3aff4f6Saliguori 	optind++;
575e3aff4f6Saliguori 
576e3aff4f6Saliguori 	if (offset & 0x1ff) {
5770bfcd599SBlue Swirl                 printf("offset %" PRId64 " is not sector aligned\n",
5780bfcd599SBlue Swirl                        offset);
579e3aff4f6Saliguori 		return 0;
580e3aff4f6Saliguori 	}
581e3aff4f6Saliguori 
582e3aff4f6Saliguori 	nr_iov = argc - optind;
583cf57298aSChristoph Hellwig 	buf = create_iovec(&qiov, &argv[optind], nr_iov, 0xab);
584e3aff4f6Saliguori 
585e3aff4f6Saliguori 	gettimeofday(&t1, NULL);
586e3aff4f6Saliguori 	cnt = do_aio_readv(&qiov, offset, &total);
587e3aff4f6Saliguori 	gettimeofday(&t2, NULL);
588e3aff4f6Saliguori 
589e3aff4f6Saliguori 	if (cnt < 0) {
590e3aff4f6Saliguori 		printf("readv failed: %s\n", strerror(-cnt));
5917d8abfcbSKevin Wolf 		goto out;
592e3aff4f6Saliguori 	}
593e3aff4f6Saliguori 
594c48101aeSaliguori 	if (Pflag) {
595cf57298aSChristoph Hellwig 		void* cmp_buf = malloc(qiov.size);
596cf57298aSChristoph Hellwig 		memset(cmp_buf, pattern, qiov.size);
597cf57298aSChristoph Hellwig 		if (memcmp(buf, cmp_buf, qiov.size)) {
5980bfcd599SBlue Swirl 			printf("Pattern verification failed at offset %"
5990bfcd599SBlue Swirl                                PRId64 ", %zd bytes\n",
6000bfcd599SBlue Swirl                                offset, qiov.size);
601c48101aeSaliguori 		}
602c48101aeSaliguori 		free(cmp_buf);
603c48101aeSaliguori 	}
604c48101aeSaliguori 
605e3aff4f6Saliguori 	if (qflag)
6067d8abfcbSKevin Wolf 		goto out;
607e3aff4f6Saliguori 
608e3aff4f6Saliguori         if (vflag)
609e3aff4f6Saliguori 		dump_buffer(buf, offset, qiov.size);
610e3aff4f6Saliguori 
611e3aff4f6Saliguori 	/* Finally, report back -- -C gives a parsable format */
612e3aff4f6Saliguori 	t2 = tsub(t2, t1);
613e3aff4f6Saliguori 	print_report("read", &t2, offset, qiov.size, total, cnt, Cflag);
614e3aff4f6Saliguori 
6157d8abfcbSKevin Wolf out:
616e3aff4f6Saliguori 	qemu_io_free(buf);
617e3aff4f6Saliguori 	return 0;
618e3aff4f6Saliguori }
619e3aff4f6Saliguori 
620e3aff4f6Saliguori static void
621e3aff4f6Saliguori write_help(void)
622e3aff4f6Saliguori {
623e3aff4f6Saliguori 	printf(
624e3aff4f6Saliguori "\n"
625e3aff4f6Saliguori " writes a range of bytes from the given offset\n"
626e3aff4f6Saliguori "\n"
627e3aff4f6Saliguori " Example:\n"
628e3aff4f6Saliguori " 'write 512 1k' - writes 1 kilobyte at 512 bytes into the open file\n"
629e3aff4f6Saliguori "\n"
630e3aff4f6Saliguori " Writes into a segment of the currently open file, using a buffer\n"
631e3aff4f6Saliguori " filled with a set pattern (0xcdcdcdcd).\n"
632ca94dbc7SKevin Wolf " -b, -- write to the VM state rather than the virtual disk\n"
633e3aff4f6Saliguori " -p, -- use bdrv_pwrite to write the file\n"
634e3aff4f6Saliguori " -P, -- use different pattern to fill file\n"
635e3aff4f6Saliguori " -C, -- report statistics in a machine parsable format\n"
636095343adSKevin Wolf " -q, -- quiet mode, do not show I/O statistics\n"
637e3aff4f6Saliguori "\n");
638e3aff4f6Saliguori }
639e3aff4f6Saliguori 
64022a2bdcbSBlue Swirl static int write_f(int argc, char **argv);
64122a2bdcbSBlue Swirl 
64222a2bdcbSBlue Swirl static const cmdinfo_t write_cmd = {
64322a2bdcbSBlue Swirl 	.name		= "write",
64422a2bdcbSBlue Swirl 	.altname	= "w",
64522a2bdcbSBlue Swirl 	.cfunc		= write_f,
64622a2bdcbSBlue Swirl 	.argmin		= 2,
64722a2bdcbSBlue Swirl 	.argmax		= -1,
64822a2bdcbSBlue Swirl 	.args		= "[-abCpq] [-P pattern ] off len",
64922a2bdcbSBlue Swirl 	.oneline	= "writes a number of bytes at a specified offset",
65022a2bdcbSBlue Swirl 	.help		= write_help,
65122a2bdcbSBlue Swirl };
65222a2bdcbSBlue Swirl 
653e3aff4f6Saliguori static int
654e3aff4f6Saliguori write_f(int argc, char **argv)
655e3aff4f6Saliguori {
656e3aff4f6Saliguori 	struct timeval t1, t2;
657ca94dbc7SKevin Wolf 	int Cflag = 0, pflag = 0, qflag = 0, bflag = 0;
658e3aff4f6Saliguori 	int c, cnt;
659e3aff4f6Saliguori 	char *buf;
660e3aff4f6Saliguori 	int64_t offset;
661d4ec5228SPaul Brook 	int count;
662d4ec5228SPaul Brook         /* Some compilers get confused and warn if this is not initialized.  */
663d4ec5228SPaul Brook         int total = 0;
664e3aff4f6Saliguori 	int pattern = 0xcd;
665e3aff4f6Saliguori 
666ca94dbc7SKevin Wolf 	while ((c = getopt(argc, argv, "bCpP:q")) != EOF) {
667e3aff4f6Saliguori 		switch (c) {
668ca94dbc7SKevin Wolf 		case 'b':
669ca94dbc7SKevin Wolf 			bflag = 1;
670ca94dbc7SKevin Wolf 			break;
671e3aff4f6Saliguori 		case 'C':
672e3aff4f6Saliguori 			Cflag = 1;
673e3aff4f6Saliguori 			break;
674e3aff4f6Saliguori 		case 'p':
675e3aff4f6Saliguori 			pflag = 1;
676e3aff4f6Saliguori 			break;
677e3aff4f6Saliguori 		case 'P':
678cf070d7eSChristoph Hellwig 			pattern = parse_pattern(optarg);
679cf070d7eSChristoph Hellwig 			if (pattern < 0)
680cf070d7eSChristoph Hellwig 				return 0;
681e3aff4f6Saliguori 			break;
682e3aff4f6Saliguori 		case 'q':
683e3aff4f6Saliguori 			qflag = 1;
684e3aff4f6Saliguori 			break;
685e3aff4f6Saliguori 		default:
686e3aff4f6Saliguori 			return command_usage(&write_cmd);
687e3aff4f6Saliguori 		}
688e3aff4f6Saliguori 	}
689e3aff4f6Saliguori 
690e3aff4f6Saliguori 	if (optind != argc - 2)
691e3aff4f6Saliguori 		return command_usage(&write_cmd);
692e3aff4f6Saliguori 
693ca94dbc7SKevin Wolf 	if (bflag && pflag) {
694ca94dbc7SKevin Wolf 		printf("-b and -p cannot be specified at the same time\n");
695ca94dbc7SKevin Wolf 		return 0;
696ca94dbc7SKevin Wolf 	}
697ca94dbc7SKevin Wolf 
698e3aff4f6Saliguori 	offset = cvtnum(argv[optind]);
699e3aff4f6Saliguori 	if (offset < 0) {
700e3aff4f6Saliguori 		printf("non-numeric length argument -- %s\n", argv[optind]);
701e3aff4f6Saliguori 		return 0;
702e3aff4f6Saliguori 	}
703e3aff4f6Saliguori 
704e3aff4f6Saliguori 	optind++;
705e3aff4f6Saliguori 	count = cvtnum(argv[optind]);
706e3aff4f6Saliguori 	if (count < 0) {
707e3aff4f6Saliguori 		printf("non-numeric length argument -- %s\n", argv[optind]);
708e3aff4f6Saliguori 		return 0;
709e3aff4f6Saliguori 	}
710e3aff4f6Saliguori 
711e3aff4f6Saliguori 	if (!pflag) {
712e3aff4f6Saliguori 		if (offset & 0x1ff) {
7130bfcd599SBlue Swirl                         printf("offset %" PRId64 " is not sector aligned\n",
7140bfcd599SBlue Swirl                                offset);
715e3aff4f6Saliguori 			return 0;
716e3aff4f6Saliguori 		}
717e3aff4f6Saliguori 
718e3aff4f6Saliguori 		if (count & 0x1ff) {
719e3aff4f6Saliguori 			printf("count %d is not sector aligned\n",
720e3aff4f6Saliguori 				count);
721e3aff4f6Saliguori 			return 0;
722e3aff4f6Saliguori 		}
723e3aff4f6Saliguori 	}
724e3aff4f6Saliguori 
725e3aff4f6Saliguori 	buf = qemu_io_alloc(count, pattern);
726e3aff4f6Saliguori 
727e3aff4f6Saliguori 	gettimeofday(&t1, NULL);
728e3aff4f6Saliguori 	if (pflag)
729e3aff4f6Saliguori 		cnt = do_pwrite(buf, offset, count, &total);
730ca94dbc7SKevin Wolf 	else if (bflag)
731ca94dbc7SKevin Wolf 		cnt = do_save_vmstate(buf, offset, count, &total);
732e3aff4f6Saliguori 	else
733e3aff4f6Saliguori 		cnt = do_write(buf, offset, count, &total);
734e3aff4f6Saliguori 	gettimeofday(&t2, NULL);
735e3aff4f6Saliguori 
736e3aff4f6Saliguori 	if (cnt < 0) {
737e3aff4f6Saliguori 		printf("write failed: %s\n", strerror(-cnt));
7387d8abfcbSKevin Wolf 		goto out;
739e3aff4f6Saliguori 	}
740e3aff4f6Saliguori 
741e3aff4f6Saliguori 	if (qflag)
7427d8abfcbSKevin Wolf 		goto out;
743e3aff4f6Saliguori 
744e3aff4f6Saliguori 	/* Finally, report back -- -C gives a parsable format */
745e3aff4f6Saliguori 	t2 = tsub(t2, t1);
746e3aff4f6Saliguori 	print_report("wrote", &t2, offset, count, total, cnt, Cflag);
747e3aff4f6Saliguori 
7487d8abfcbSKevin Wolf out:
749e3aff4f6Saliguori 	qemu_io_free(buf);
750e3aff4f6Saliguori 
751e3aff4f6Saliguori 	return 0;
752e3aff4f6Saliguori }
753e3aff4f6Saliguori 
754e3aff4f6Saliguori static void
755e3aff4f6Saliguori writev_help(void)
756e3aff4f6Saliguori {
757e3aff4f6Saliguori 	printf(
758e3aff4f6Saliguori "\n"
759e3aff4f6Saliguori " writes a range of bytes from the given offset source from multiple buffers\n"
760e3aff4f6Saliguori "\n"
761e3aff4f6Saliguori " Example:\n"
762e3aff4f6Saliguori " 'write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n"
763e3aff4f6Saliguori "\n"
764e3aff4f6Saliguori " Writes into a segment of the currently open file, using a buffer\n"
765e3aff4f6Saliguori " filled with a set pattern (0xcdcdcdcd).\n"
766e3aff4f6Saliguori " -P, -- use different pattern to fill file\n"
767e3aff4f6Saliguori " -C, -- report statistics in a machine parsable format\n"
768095343adSKevin Wolf " -q, -- quiet mode, do not show I/O statistics\n"
769e3aff4f6Saliguori "\n");
770e3aff4f6Saliguori }
771e3aff4f6Saliguori 
77222a2bdcbSBlue Swirl static int writev_f(int argc, char **argv);
77322a2bdcbSBlue Swirl 
77422a2bdcbSBlue Swirl static const cmdinfo_t writev_cmd = {
77522a2bdcbSBlue Swirl 	.name		= "writev",
77622a2bdcbSBlue Swirl 	.cfunc		= writev_f,
77722a2bdcbSBlue Swirl 	.argmin		= 2,
77822a2bdcbSBlue Swirl 	.argmax		= -1,
77922a2bdcbSBlue Swirl 	.args		= "[-Cq] [-P pattern ] off len [len..]",
78022a2bdcbSBlue Swirl 	.oneline	= "writes a number of bytes at a specified offset",
78122a2bdcbSBlue Swirl 	.help		= writev_help,
78222a2bdcbSBlue Swirl };
78322a2bdcbSBlue Swirl 
784e3aff4f6Saliguori static int
785e3aff4f6Saliguori writev_f(int argc, char **argv)
786e3aff4f6Saliguori {
787e3aff4f6Saliguori 	struct timeval t1, t2;
788e3aff4f6Saliguori 	int Cflag = 0, qflag = 0;
789e3aff4f6Saliguori 	int c, cnt;
790cf57298aSChristoph Hellwig 	char *buf;
791e3aff4f6Saliguori 	int64_t offset;
7926474bd69SBlue Swirl         /* Some compilers get confused and warn if this is not initialized.  */
7936474bd69SBlue Swirl         int total = 0;
794cf57298aSChristoph Hellwig 	int nr_iov;
795e3aff4f6Saliguori 	int pattern = 0xcd;
796e3aff4f6Saliguori 	QEMUIOVector qiov;
797e3aff4f6Saliguori 
798e3aff4f6Saliguori 	while ((c = getopt(argc, argv, "CqP:")) != EOF) {
799e3aff4f6Saliguori 		switch (c) {
800e3aff4f6Saliguori 		case 'C':
801e3aff4f6Saliguori 			Cflag = 1;
802e3aff4f6Saliguori 			break;
803e3aff4f6Saliguori 		case 'q':
804e3aff4f6Saliguori 			qflag = 1;
805e3aff4f6Saliguori 			break;
806e3aff4f6Saliguori 		case 'P':
807cf070d7eSChristoph Hellwig 			pattern = parse_pattern(optarg);
808cf070d7eSChristoph Hellwig 			if (pattern < 0)
809cf070d7eSChristoph Hellwig 				return 0;
810e3aff4f6Saliguori 			break;
811e3aff4f6Saliguori 		default:
812e3aff4f6Saliguori 			return command_usage(&writev_cmd);
813e3aff4f6Saliguori 		}
814e3aff4f6Saliguori 	}
815e3aff4f6Saliguori 
816e3aff4f6Saliguori 	if (optind > argc - 2)
817e3aff4f6Saliguori 		return command_usage(&writev_cmd);
818e3aff4f6Saliguori 
819e3aff4f6Saliguori 	offset = cvtnum(argv[optind]);
820e3aff4f6Saliguori 	if (offset < 0) {
821e3aff4f6Saliguori 		printf("non-numeric length argument -- %s\n", argv[optind]);
822e3aff4f6Saliguori 		return 0;
823e3aff4f6Saliguori 	}
824e3aff4f6Saliguori 	optind++;
825e3aff4f6Saliguori 
826e3aff4f6Saliguori 	if (offset & 0x1ff) {
8270bfcd599SBlue Swirl                 printf("offset %" PRId64 " is not sector aligned\n",
8280bfcd599SBlue Swirl                        offset);
829e3aff4f6Saliguori 		return 0;
830e3aff4f6Saliguori 	}
831e3aff4f6Saliguori 
832e3aff4f6Saliguori 	nr_iov = argc - optind;
833cf57298aSChristoph Hellwig 	buf = create_iovec(&qiov, &argv[optind], nr_iov, pattern);
834e3aff4f6Saliguori 
835e3aff4f6Saliguori 	gettimeofday(&t1, NULL);
836e3aff4f6Saliguori 	cnt = do_aio_writev(&qiov, offset, &total);
837e3aff4f6Saliguori 	gettimeofday(&t2, NULL);
838e3aff4f6Saliguori 
839e3aff4f6Saliguori 	if (cnt < 0) {
840e3aff4f6Saliguori 		printf("writev failed: %s\n", strerror(-cnt));
8417d8abfcbSKevin Wolf 		goto out;
842e3aff4f6Saliguori 	}
843e3aff4f6Saliguori 
844e3aff4f6Saliguori 	if (qflag)
8457d8abfcbSKevin Wolf 		goto out;
846e3aff4f6Saliguori 
847e3aff4f6Saliguori 	/* Finally, report back -- -C gives a parsable format */
848e3aff4f6Saliguori 	t2 = tsub(t2, t1);
849e3aff4f6Saliguori 	print_report("wrote", &t2, offset, qiov.size, total, cnt, Cflag);
8507d8abfcbSKevin Wolf out:
851e3aff4f6Saliguori 	qemu_io_free(buf);
852e3aff4f6Saliguori 	return 0;
853e3aff4f6Saliguori }
854e3aff4f6Saliguori 
855776cbbbdSKevin Wolf static void
856776cbbbdSKevin Wolf multiwrite_help(void)
857776cbbbdSKevin Wolf {
858776cbbbdSKevin Wolf 	printf(
859776cbbbdSKevin Wolf "\n"
860776cbbbdSKevin Wolf " writes a range of bytes from the given offset source from multiple buffers,\n"
861776cbbbdSKevin Wolf " in a batch of requests that may be merged by qemu\n"
862776cbbbdSKevin Wolf "\n"
863776cbbbdSKevin Wolf " Example:\n"
864776cbbbdSKevin Wolf " 'multiwrite 512 1k 1k ; 4k 1k' \n"
865776cbbbdSKevin Wolf "  writes 2 kB at 512 bytes and 1 kB at 4 kB into the open file\n"
866776cbbbdSKevin Wolf "\n"
867776cbbbdSKevin Wolf " Writes into a segment of the currently open file, using a buffer\n"
868776cbbbdSKevin Wolf " filled with a set pattern (0xcdcdcdcd). The pattern byte is increased\n"
869776cbbbdSKevin Wolf " by one for each request contained in the multiwrite command.\n"
870776cbbbdSKevin Wolf " -P, -- use different pattern to fill file\n"
871776cbbbdSKevin Wolf " -C, -- report statistics in a machine parsable format\n"
872776cbbbdSKevin Wolf " -q, -- quiet mode, do not show I/O statistics\n"
873776cbbbdSKevin Wolf "\n");
874776cbbbdSKevin Wolf }
875776cbbbdSKevin Wolf 
876776cbbbdSKevin Wolf static int multiwrite_f(int argc, char **argv);
877776cbbbdSKevin Wolf 
878776cbbbdSKevin Wolf static const cmdinfo_t multiwrite_cmd = {
879776cbbbdSKevin Wolf 	.name		= "multiwrite",
880776cbbbdSKevin Wolf 	.cfunc		= multiwrite_f,
881776cbbbdSKevin Wolf 	.argmin		= 2,
882776cbbbdSKevin Wolf 	.argmax		= -1,
883776cbbbdSKevin Wolf 	.args		= "[-Cq] [-P pattern ] off len [len..] [; off len [len..]..]",
884776cbbbdSKevin Wolf 	.oneline	= "issues multiple write requests at once",
885776cbbbdSKevin Wolf 	.help		= multiwrite_help,
886776cbbbdSKevin Wolf };
887776cbbbdSKevin Wolf 
888776cbbbdSKevin Wolf static int
889776cbbbdSKevin Wolf multiwrite_f(int argc, char **argv)
890776cbbbdSKevin Wolf {
891776cbbbdSKevin Wolf 	struct timeval t1, t2;
892776cbbbdSKevin Wolf 	int Cflag = 0, qflag = 0;
893776cbbbdSKevin Wolf 	int c, cnt;
894776cbbbdSKevin Wolf 	char **buf;
895776cbbbdSKevin Wolf 	int64_t offset, first_offset = 0;
896776cbbbdSKevin Wolf 	/* Some compilers get confused and warn if this is not initialized.  */
897776cbbbdSKevin Wolf 	int total = 0;
898776cbbbdSKevin Wolf 	int nr_iov;
899776cbbbdSKevin Wolf 	int nr_reqs;
900776cbbbdSKevin Wolf 	int pattern = 0xcd;
901776cbbbdSKevin Wolf 	QEMUIOVector *qiovs;
902776cbbbdSKevin Wolf 	int i;
903776cbbbdSKevin Wolf 	BlockRequest *reqs;
904776cbbbdSKevin Wolf 
905776cbbbdSKevin Wolf 	while ((c = getopt(argc, argv, "CqP:")) != EOF) {
906776cbbbdSKevin Wolf 		switch (c) {
907776cbbbdSKevin Wolf 		case 'C':
908776cbbbdSKevin Wolf 			Cflag = 1;
909776cbbbdSKevin Wolf 			break;
910776cbbbdSKevin Wolf 		case 'q':
911776cbbbdSKevin Wolf 			qflag = 1;
912776cbbbdSKevin Wolf 			break;
913776cbbbdSKevin Wolf 		case 'P':
914776cbbbdSKevin Wolf 			pattern = parse_pattern(optarg);
915776cbbbdSKevin Wolf 			if (pattern < 0)
916776cbbbdSKevin Wolf 				return 0;
917776cbbbdSKevin Wolf 			break;
918776cbbbdSKevin Wolf 		default:
919776cbbbdSKevin Wolf 			return command_usage(&writev_cmd);
920776cbbbdSKevin Wolf 		}
921776cbbbdSKevin Wolf 	}
922776cbbbdSKevin Wolf 
923776cbbbdSKevin Wolf 	if (optind > argc - 2)
924776cbbbdSKevin Wolf 		return command_usage(&writev_cmd);
925776cbbbdSKevin Wolf 
926776cbbbdSKevin Wolf 	nr_reqs = 1;
927776cbbbdSKevin Wolf 	for (i = optind; i < argc; i++) {
928776cbbbdSKevin Wolf 		if (!strcmp(argv[i], ";")) {
929776cbbbdSKevin Wolf 			nr_reqs++;
930776cbbbdSKevin Wolf 		}
931776cbbbdSKevin Wolf 	}
932776cbbbdSKevin Wolf 
933776cbbbdSKevin Wolf 	reqs = qemu_malloc(nr_reqs * sizeof(*reqs));
934776cbbbdSKevin Wolf 	buf = qemu_malloc(nr_reqs * sizeof(*buf));
935776cbbbdSKevin Wolf 	qiovs = qemu_malloc(nr_reqs * sizeof(*qiovs));
936776cbbbdSKevin Wolf 
937776cbbbdSKevin Wolf 	for (i = 0; i < nr_reqs; i++) {
938776cbbbdSKevin Wolf 		int j;
939776cbbbdSKevin Wolf 
940776cbbbdSKevin Wolf 		/* Read the offset of the request */
941776cbbbdSKevin Wolf 		offset = cvtnum(argv[optind]);
942776cbbbdSKevin Wolf 		if (offset < 0) {
943776cbbbdSKevin Wolf 			printf("non-numeric offset argument -- %s\n", argv[optind]);
944776cbbbdSKevin Wolf 			return 0;
945776cbbbdSKevin Wolf 		}
946776cbbbdSKevin Wolf 		optind++;
947776cbbbdSKevin Wolf 
948776cbbbdSKevin Wolf 		if (offset & 0x1ff) {
949776cbbbdSKevin Wolf 			printf("offset %lld is not sector aligned\n",
950776cbbbdSKevin Wolf 				(long long)offset);
951776cbbbdSKevin Wolf 			return 0;
952776cbbbdSKevin Wolf 		}
953776cbbbdSKevin Wolf 
954776cbbbdSKevin Wolf         if (i == 0) {
955776cbbbdSKevin Wolf             first_offset = offset;
956776cbbbdSKevin Wolf         }
957776cbbbdSKevin Wolf 
958776cbbbdSKevin Wolf 		/* Read lengths for qiov entries */
959776cbbbdSKevin Wolf 		for (j = optind; j < argc; j++) {
960776cbbbdSKevin Wolf 			if (!strcmp(argv[j], ";")) {
961776cbbbdSKevin Wolf 				break;
962776cbbbdSKevin Wolf 			}
963776cbbbdSKevin Wolf 		}
964776cbbbdSKevin Wolf 
965776cbbbdSKevin Wolf 		nr_iov = j - optind;
966776cbbbdSKevin Wolf 
967776cbbbdSKevin Wolf 		/* Build request */
968776cbbbdSKevin Wolf 		reqs[i].qiov = &qiovs[i];
969776cbbbdSKevin Wolf 		buf[i] = create_iovec(reqs[i].qiov, &argv[optind], nr_iov, pattern);
970776cbbbdSKevin Wolf 		reqs[i].sector = offset >> 9;
971776cbbbdSKevin Wolf 		reqs[i].nb_sectors = reqs[i].qiov->size >> 9;
972776cbbbdSKevin Wolf 
973776cbbbdSKevin Wolf 		optind = j + 1;
974776cbbbdSKevin Wolf 
975776cbbbdSKevin Wolf 		offset += reqs[i].qiov->size;
976776cbbbdSKevin Wolf 		pattern++;
977776cbbbdSKevin Wolf 	}
978776cbbbdSKevin Wolf 
979776cbbbdSKevin Wolf 	gettimeofday(&t1, NULL);
980776cbbbdSKevin Wolf 	cnt = do_aio_multiwrite(reqs, nr_reqs, &total);
981776cbbbdSKevin Wolf 	gettimeofday(&t2, NULL);
982776cbbbdSKevin Wolf 
983776cbbbdSKevin Wolf 	if (cnt < 0) {
984776cbbbdSKevin Wolf 		printf("aio_multiwrite failed: %s\n", strerror(-cnt));
985776cbbbdSKevin Wolf 		goto out;
986776cbbbdSKevin Wolf 	}
987776cbbbdSKevin Wolf 
988776cbbbdSKevin Wolf 	if (qflag)
989776cbbbdSKevin Wolf 		goto out;
990776cbbbdSKevin Wolf 
991776cbbbdSKevin Wolf 	/* Finally, report back -- -C gives a parsable format */
992776cbbbdSKevin Wolf 	t2 = tsub(t2, t1);
993776cbbbdSKevin Wolf 	print_report("wrote", &t2, first_offset, total, total, cnt, Cflag);
994776cbbbdSKevin Wolf out:
995776cbbbdSKevin Wolf 	for (i = 0; i < nr_reqs; i++) {
996776cbbbdSKevin Wolf 		qemu_io_free(buf[i]);
997776cbbbdSKevin Wolf 		qemu_iovec_destroy(&qiovs[i]);
998776cbbbdSKevin Wolf 	}
999776cbbbdSKevin Wolf 	qemu_free(buf);
1000776cbbbdSKevin Wolf 	qemu_free(reqs);
1001776cbbbdSKevin Wolf 	qemu_free(qiovs);
1002776cbbbdSKevin Wolf 	return 0;
1003776cbbbdSKevin Wolf }
1004776cbbbdSKevin Wolf 
100595533d5fSChristoph Hellwig struct aio_ctx {
100695533d5fSChristoph Hellwig 	QEMUIOVector qiov;
100795533d5fSChristoph Hellwig 	int64_t offset;
100895533d5fSChristoph Hellwig 	char *buf;
100995533d5fSChristoph Hellwig 	int qflag;
101095533d5fSChristoph Hellwig 	int vflag;
101195533d5fSChristoph Hellwig 	int Cflag;
101295533d5fSChristoph Hellwig 	int Pflag;
101395533d5fSChristoph Hellwig 	int pattern;
101495533d5fSChristoph Hellwig 	struct timeval t1;
101595533d5fSChristoph Hellwig };
101695533d5fSChristoph Hellwig 
101795533d5fSChristoph Hellwig static void
101895533d5fSChristoph Hellwig aio_write_done(void *opaque, int ret)
101995533d5fSChristoph Hellwig {
102095533d5fSChristoph Hellwig 	struct aio_ctx *ctx = opaque;
102195533d5fSChristoph Hellwig 	struct timeval t2;
102295533d5fSChristoph Hellwig 
102395533d5fSChristoph Hellwig 	gettimeofday(&t2, NULL);
102495533d5fSChristoph Hellwig 
102595533d5fSChristoph Hellwig 
102695533d5fSChristoph Hellwig 	if (ret < 0) {
102795533d5fSChristoph Hellwig 		printf("aio_write failed: %s\n", strerror(-ret));
10287d8abfcbSKevin Wolf 		goto out;
102995533d5fSChristoph Hellwig 	}
103095533d5fSChristoph Hellwig 
1031230d4fa4SChristoph Hellwig 	if (ctx->qflag) {
10327d8abfcbSKevin Wolf 		goto out;
1033230d4fa4SChristoph Hellwig 	}
103495533d5fSChristoph Hellwig 
103595533d5fSChristoph Hellwig 	/* Finally, report back -- -C gives a parsable format */
103695533d5fSChristoph Hellwig 	t2 = tsub(t2, ctx->t1);
1037230d4fa4SChristoph Hellwig 	print_report("wrote", &t2, ctx->offset, ctx->qiov.size,
1038230d4fa4SChristoph Hellwig 		     ctx->qiov.size, 1, ctx->Cflag);
10397d8abfcbSKevin Wolf out:
104095533d5fSChristoph Hellwig 	qemu_io_free(ctx->buf);
104195533d5fSChristoph Hellwig 	free(ctx);
104295533d5fSChristoph Hellwig }
104395533d5fSChristoph Hellwig 
104495533d5fSChristoph Hellwig static void
104595533d5fSChristoph Hellwig aio_read_done(void *opaque, int ret)
104695533d5fSChristoph Hellwig {
104795533d5fSChristoph Hellwig 	struct aio_ctx *ctx = opaque;
104895533d5fSChristoph Hellwig 	struct timeval t2;
104995533d5fSChristoph Hellwig 
105095533d5fSChristoph Hellwig 	gettimeofday(&t2, NULL);
105195533d5fSChristoph Hellwig 
105295533d5fSChristoph Hellwig 	if (ret < 0) {
105395533d5fSChristoph Hellwig 		printf("readv failed: %s\n", strerror(-ret));
10547d8abfcbSKevin Wolf 		goto out;
105595533d5fSChristoph Hellwig 	}
105695533d5fSChristoph Hellwig 
105795533d5fSChristoph Hellwig 	if (ctx->Pflag) {
1058230d4fa4SChristoph Hellwig 		void *cmp_buf = malloc(ctx->qiov.size);
105995533d5fSChristoph Hellwig 
1060230d4fa4SChristoph Hellwig 		memset(cmp_buf, ctx->pattern, ctx->qiov.size);
1061230d4fa4SChristoph Hellwig 		if (memcmp(ctx->buf, cmp_buf, ctx->qiov.size)) {
10620bfcd599SBlue Swirl 			printf("Pattern verification failed at offset %"
10630bfcd599SBlue Swirl                                PRId64 ", %zd bytes\n",
10640bfcd599SBlue Swirl                                ctx->offset, ctx->qiov.size);
106595533d5fSChristoph Hellwig 		}
106695533d5fSChristoph Hellwig 		free(cmp_buf);
106795533d5fSChristoph Hellwig 	}
106895533d5fSChristoph Hellwig 
1069230d4fa4SChristoph Hellwig 	if (ctx->qflag) {
10707d8abfcbSKevin Wolf 		goto out;
1071230d4fa4SChristoph Hellwig 	}
107295533d5fSChristoph Hellwig 
1073230d4fa4SChristoph Hellwig 	if (ctx->vflag) {
1074230d4fa4SChristoph Hellwig 		dump_buffer(ctx->buf, ctx->offset, ctx->qiov.size);
1075230d4fa4SChristoph Hellwig 	}
107695533d5fSChristoph Hellwig 
107795533d5fSChristoph Hellwig 	/* Finally, report back -- -C gives a parsable format */
107895533d5fSChristoph Hellwig 	t2 = tsub(t2, ctx->t1);
1079230d4fa4SChristoph Hellwig 	print_report("read", &t2, ctx->offset, ctx->qiov.size,
1080230d4fa4SChristoph Hellwig 		     ctx->qiov.size, 1, ctx->Cflag);
10817d8abfcbSKevin Wolf out:
108295533d5fSChristoph Hellwig 	qemu_io_free(ctx->buf);
108395533d5fSChristoph Hellwig 	free(ctx);
108495533d5fSChristoph Hellwig }
108595533d5fSChristoph Hellwig 
108695533d5fSChristoph Hellwig static void
108795533d5fSChristoph Hellwig aio_read_help(void)
108895533d5fSChristoph Hellwig {
108995533d5fSChristoph Hellwig 	printf(
109095533d5fSChristoph Hellwig "\n"
109195533d5fSChristoph Hellwig " asynchronously reads a range of bytes from the given offset\n"
109295533d5fSChristoph Hellwig "\n"
109395533d5fSChristoph Hellwig " Example:\n"
109495533d5fSChristoph Hellwig " 'aio_read -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n"
109595533d5fSChristoph Hellwig "\n"
109695533d5fSChristoph Hellwig " Reads a segment of the currently open file, optionally dumping it to the\n"
109795533d5fSChristoph Hellwig " standard output stream (with -v option) for subsequent inspection.\n"
1098e432cef9SChristoph Hellwig " The read is performed asynchronously and the aio_flush command must be\n"
1099e432cef9SChristoph Hellwig " used to ensure all outstanding aio requests have been completed\n"
110095533d5fSChristoph Hellwig " -C, -- report statistics in a machine parsable format\n"
110195533d5fSChristoph Hellwig " -P, -- use a pattern to verify read data\n"
110295533d5fSChristoph Hellwig " -v, -- dump buffer to standard output\n"
1103095343adSKevin Wolf " -q, -- quiet mode, do not show I/O statistics\n"
110495533d5fSChristoph Hellwig "\n");
110595533d5fSChristoph Hellwig }
110695533d5fSChristoph Hellwig 
110722a2bdcbSBlue Swirl static int aio_read_f(int argc, char **argv);
110822a2bdcbSBlue Swirl 
110922a2bdcbSBlue Swirl static const cmdinfo_t aio_read_cmd = {
111022a2bdcbSBlue Swirl 	.name		= "aio_read",
111122a2bdcbSBlue Swirl 	.cfunc		= aio_read_f,
111222a2bdcbSBlue Swirl 	.argmin		= 2,
111322a2bdcbSBlue Swirl 	.argmax		= -1,
111422a2bdcbSBlue Swirl 	.args		= "[-Cqv] [-P pattern ] off len [len..]",
111522a2bdcbSBlue Swirl 	.oneline	= "asynchronously reads a number of bytes",
111622a2bdcbSBlue Swirl 	.help		= aio_read_help,
111722a2bdcbSBlue Swirl };
111822a2bdcbSBlue Swirl 
111995533d5fSChristoph Hellwig static int
112095533d5fSChristoph Hellwig aio_read_f(int argc, char **argv)
112195533d5fSChristoph Hellwig {
1122cf57298aSChristoph Hellwig 	int nr_iov, c;
112395533d5fSChristoph Hellwig 	struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx));
112495533d5fSChristoph Hellwig 	BlockDriverAIOCB *acb;
112595533d5fSChristoph Hellwig 
112695533d5fSChristoph Hellwig 	while ((c = getopt(argc, argv, "CP:qv")) != EOF) {
112795533d5fSChristoph Hellwig 		switch (c) {
112895533d5fSChristoph Hellwig 		case 'C':
112995533d5fSChristoph Hellwig 			ctx->Cflag = 1;
113095533d5fSChristoph Hellwig 			break;
113195533d5fSChristoph Hellwig 		case 'P':
113295533d5fSChristoph Hellwig 			ctx->Pflag = 1;
1133cf070d7eSChristoph Hellwig 			ctx->pattern = parse_pattern(optarg);
1134*1afec913SBlue Swirl 			if (ctx->pattern < 0) {
1135*1afec913SBlue Swirl                                 free(ctx);
1136cf070d7eSChristoph Hellwig 				return 0;
1137*1afec913SBlue Swirl                         }
113895533d5fSChristoph Hellwig 			break;
113995533d5fSChristoph Hellwig 		case 'q':
114095533d5fSChristoph Hellwig 			ctx->qflag = 1;
114195533d5fSChristoph Hellwig 			break;
114295533d5fSChristoph Hellwig 		case 'v':
114395533d5fSChristoph Hellwig 			ctx->vflag = 1;
114495533d5fSChristoph Hellwig 			break;
114595533d5fSChristoph Hellwig 		default:
11467d8abfcbSKevin Wolf 			free(ctx);
114795533d5fSChristoph Hellwig 			return command_usage(&aio_read_cmd);
114895533d5fSChristoph Hellwig 		}
114995533d5fSChristoph Hellwig 	}
115095533d5fSChristoph Hellwig 
11517d8abfcbSKevin Wolf 	if (optind > argc - 2) {
11527d8abfcbSKevin Wolf 		free(ctx);
115395533d5fSChristoph Hellwig 		return command_usage(&aio_read_cmd);
11547d8abfcbSKevin Wolf 	}
115595533d5fSChristoph Hellwig 
115695533d5fSChristoph Hellwig 	ctx->offset = cvtnum(argv[optind]);
115795533d5fSChristoph Hellwig 	if (ctx->offset < 0) {
115895533d5fSChristoph Hellwig 		printf("non-numeric length argument -- %s\n", argv[optind]);
11597d8abfcbSKevin Wolf 		free(ctx);
116095533d5fSChristoph Hellwig 		return 0;
116195533d5fSChristoph Hellwig 	}
116295533d5fSChristoph Hellwig 	optind++;
116395533d5fSChristoph Hellwig 
116495533d5fSChristoph Hellwig 	if (ctx->offset & 0x1ff) {
11650bfcd599SBlue Swirl 		printf("offset %" PRId64 " is not sector aligned\n",
11660bfcd599SBlue Swirl                        ctx->offset);
11677d8abfcbSKevin Wolf 		free(ctx);
116895533d5fSChristoph Hellwig 		return 0;
116995533d5fSChristoph Hellwig 	}
117095533d5fSChristoph Hellwig 
117195533d5fSChristoph Hellwig 	nr_iov = argc - optind;
1172cf57298aSChristoph Hellwig 	ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, 0xab);
117395533d5fSChristoph Hellwig 
117495533d5fSChristoph Hellwig 	gettimeofday(&ctx->t1, NULL);
117595533d5fSChristoph Hellwig 	acb = bdrv_aio_readv(bs, ctx->offset >> 9, &ctx->qiov,
117695533d5fSChristoph Hellwig 			      ctx->qiov.size >> 9, aio_read_done, ctx);
11777d8abfcbSKevin Wolf 	if (!acb) {
11787d8abfcbSKevin Wolf 		free(ctx->buf);
11797d8abfcbSKevin Wolf 		free(ctx);
118095533d5fSChristoph Hellwig 		return -EIO;
11817d8abfcbSKevin Wolf 	}
118295533d5fSChristoph Hellwig 
118395533d5fSChristoph Hellwig 	return 0;
118495533d5fSChristoph Hellwig }
118595533d5fSChristoph Hellwig 
118695533d5fSChristoph Hellwig static void
118795533d5fSChristoph Hellwig aio_write_help(void)
118895533d5fSChristoph Hellwig {
118995533d5fSChristoph Hellwig 	printf(
119095533d5fSChristoph Hellwig "\n"
119195533d5fSChristoph Hellwig " asynchronously writes a range of bytes from the given offset source \n"
119295533d5fSChristoph Hellwig " from multiple buffers\n"
119395533d5fSChristoph Hellwig "\n"
119495533d5fSChristoph Hellwig " Example:\n"
119595533d5fSChristoph Hellwig " 'aio_write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n"
119695533d5fSChristoph Hellwig "\n"
119795533d5fSChristoph Hellwig " Writes into a segment of the currently open file, using a buffer\n"
119895533d5fSChristoph Hellwig " filled with a set pattern (0xcdcdcdcd).\n"
1199e432cef9SChristoph Hellwig " The write is performed asynchronously and the aio_flush command must be\n"
1200e432cef9SChristoph Hellwig " used to ensure all outstanding aio requests have been completed\n"
120195533d5fSChristoph Hellwig " -P, -- use different pattern to fill file\n"
120295533d5fSChristoph Hellwig " -C, -- report statistics in a machine parsable format\n"
1203095343adSKevin Wolf " -q, -- quiet mode, do not show I/O statistics\n"
120495533d5fSChristoph Hellwig "\n");
120595533d5fSChristoph Hellwig }
120695533d5fSChristoph Hellwig 
120722a2bdcbSBlue Swirl static int aio_write_f(int argc, char **argv);
120822a2bdcbSBlue Swirl 
120922a2bdcbSBlue Swirl static const cmdinfo_t aio_write_cmd = {
121022a2bdcbSBlue Swirl 	.name		= "aio_write",
121122a2bdcbSBlue Swirl 	.cfunc		= aio_write_f,
121222a2bdcbSBlue Swirl 	.argmin		= 2,
121322a2bdcbSBlue Swirl 	.argmax		= -1,
121422a2bdcbSBlue Swirl 	.args		= "[-Cq] [-P pattern ] off len [len..]",
121522a2bdcbSBlue Swirl 	.oneline	= "asynchronously writes a number of bytes",
121622a2bdcbSBlue Swirl 	.help		= aio_write_help,
121722a2bdcbSBlue Swirl };
121895533d5fSChristoph Hellwig 
121995533d5fSChristoph Hellwig static int
122095533d5fSChristoph Hellwig aio_write_f(int argc, char **argv)
122195533d5fSChristoph Hellwig {
1222cf57298aSChristoph Hellwig 	int nr_iov, c;
122395533d5fSChristoph Hellwig 	int pattern = 0xcd;
122495533d5fSChristoph Hellwig 	struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx));
122595533d5fSChristoph Hellwig 	BlockDriverAIOCB *acb;
122695533d5fSChristoph Hellwig 
122795533d5fSChristoph Hellwig 	while ((c = getopt(argc, argv, "CqP:")) != EOF) {
122895533d5fSChristoph Hellwig 		switch (c) {
122995533d5fSChristoph Hellwig 		case 'C':
123095533d5fSChristoph Hellwig 			ctx->Cflag = 1;
123195533d5fSChristoph Hellwig 			break;
123295533d5fSChristoph Hellwig 		case 'q':
123395533d5fSChristoph Hellwig 			ctx->qflag = 1;
123495533d5fSChristoph Hellwig 			break;
123595533d5fSChristoph Hellwig 		case 'P':
1236cf070d7eSChristoph Hellwig 			pattern = parse_pattern(optarg);
1237cf070d7eSChristoph Hellwig 			if (pattern < 0)
1238cf070d7eSChristoph Hellwig 				return 0;
123995533d5fSChristoph Hellwig 			break;
124095533d5fSChristoph Hellwig 		default:
12417d8abfcbSKevin Wolf 			free(ctx);
124295533d5fSChristoph Hellwig 			return command_usage(&aio_write_cmd);
124395533d5fSChristoph Hellwig 		}
124495533d5fSChristoph Hellwig 	}
124595533d5fSChristoph Hellwig 
12467d8abfcbSKevin Wolf 	if (optind > argc - 2) {
12477d8abfcbSKevin Wolf 		free(ctx);
124895533d5fSChristoph Hellwig 		return command_usage(&aio_write_cmd);
12497d8abfcbSKevin Wolf 	}
125095533d5fSChristoph Hellwig 
125195533d5fSChristoph Hellwig 	ctx->offset = cvtnum(argv[optind]);
125295533d5fSChristoph Hellwig 	if (ctx->offset < 0) {
125395533d5fSChristoph Hellwig 		printf("non-numeric length argument -- %s\n", argv[optind]);
12547d8abfcbSKevin Wolf 		free(ctx);
125595533d5fSChristoph Hellwig 		return 0;
125695533d5fSChristoph Hellwig 	}
125795533d5fSChristoph Hellwig 	optind++;
125895533d5fSChristoph Hellwig 
125995533d5fSChristoph Hellwig 	if (ctx->offset & 0x1ff) {
12600bfcd599SBlue Swirl 		printf("offset %" PRId64 " is not sector aligned\n",
12610bfcd599SBlue Swirl                        ctx->offset);
12627d8abfcbSKevin Wolf 		free(ctx);
126395533d5fSChristoph Hellwig 		return 0;
126495533d5fSChristoph Hellwig 	}
126595533d5fSChristoph Hellwig 
126695533d5fSChristoph Hellwig 	nr_iov = argc - optind;
1267cf57298aSChristoph Hellwig 	ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, pattern);
126895533d5fSChristoph Hellwig 
126995533d5fSChristoph Hellwig 	gettimeofday(&ctx->t1, NULL);
127095533d5fSChristoph Hellwig 	acb = bdrv_aio_writev(bs, ctx->offset >> 9, &ctx->qiov,
127195533d5fSChristoph Hellwig 			      ctx->qiov.size >> 9, aio_write_done, ctx);
12727d8abfcbSKevin Wolf 	if (!acb) {
12737d8abfcbSKevin Wolf 		free(ctx->buf);
12747d8abfcbSKevin Wolf 		free(ctx);
127595533d5fSChristoph Hellwig 		return -EIO;
12767d8abfcbSKevin Wolf 	}
127795533d5fSChristoph Hellwig 
127895533d5fSChristoph Hellwig 	return 0;
127995533d5fSChristoph Hellwig }
128095533d5fSChristoph Hellwig 
128195533d5fSChristoph Hellwig static int
128295533d5fSChristoph Hellwig aio_flush_f(int argc, char **argv)
128395533d5fSChristoph Hellwig {
128495533d5fSChristoph Hellwig 	qemu_aio_flush();
128595533d5fSChristoph Hellwig 	return 0;
128695533d5fSChristoph Hellwig }
128795533d5fSChristoph Hellwig 
128895533d5fSChristoph Hellwig static const cmdinfo_t aio_flush_cmd = {
128995533d5fSChristoph Hellwig 	.name		= "aio_flush",
129095533d5fSChristoph Hellwig 	.cfunc		= aio_flush_f,
1291e432cef9SChristoph Hellwig 	.oneline	= "completes all outstanding aio requests"
129295533d5fSChristoph Hellwig };
129395533d5fSChristoph Hellwig 
1294e3aff4f6Saliguori static int
1295e3aff4f6Saliguori flush_f(int argc, char **argv)
1296e3aff4f6Saliguori {
1297e3aff4f6Saliguori 	bdrv_flush(bs);
1298e3aff4f6Saliguori 	return 0;
1299e3aff4f6Saliguori }
1300e3aff4f6Saliguori 
1301e3aff4f6Saliguori static const cmdinfo_t flush_cmd = {
1302e3aff4f6Saliguori 	.name		= "flush",
1303e3aff4f6Saliguori 	.altname	= "f",
1304e3aff4f6Saliguori 	.cfunc		= flush_f,
1305e3aff4f6Saliguori 	.oneline	= "flush all in-core file state to disk",
1306e3aff4f6Saliguori };
1307e3aff4f6Saliguori 
1308e3aff4f6Saliguori static int
1309e3aff4f6Saliguori truncate_f(int argc, char **argv)
1310e3aff4f6Saliguori {
1311e3aff4f6Saliguori 	int64_t offset;
1312e3aff4f6Saliguori 	int ret;
1313e3aff4f6Saliguori 
1314e3aff4f6Saliguori 	offset = cvtnum(argv[1]);
1315e3aff4f6Saliguori 	if (offset < 0) {
1316e3aff4f6Saliguori 		printf("non-numeric truncate argument -- %s\n", argv[1]);
1317e3aff4f6Saliguori 		return 0;
1318e3aff4f6Saliguori 	}
1319e3aff4f6Saliguori 
1320e3aff4f6Saliguori 	ret = bdrv_truncate(bs, offset);
1321e3aff4f6Saliguori 	if (ret < 0) {
13220923c577SKevin Wolf 		printf("truncate: %s\n", strerror(-ret));
1323e3aff4f6Saliguori 		return 0;
1324e3aff4f6Saliguori 	}
1325e3aff4f6Saliguori 
1326e3aff4f6Saliguori 	return 0;
1327e3aff4f6Saliguori }
1328e3aff4f6Saliguori 
1329e3aff4f6Saliguori static const cmdinfo_t truncate_cmd = {
1330e3aff4f6Saliguori 	.name		= "truncate",
1331e3aff4f6Saliguori 	.altname	= "t",
1332e3aff4f6Saliguori 	.cfunc		= truncate_f,
1333e3aff4f6Saliguori 	.argmin		= 1,
1334e3aff4f6Saliguori 	.argmax		= 1,
1335e3aff4f6Saliguori 	.args		= "off",
1336e3aff4f6Saliguori 	.oneline	= "truncates the current file at the given offset",
1337e3aff4f6Saliguori };
1338e3aff4f6Saliguori 
1339e3aff4f6Saliguori static int
1340e3aff4f6Saliguori length_f(int argc, char **argv)
1341e3aff4f6Saliguori {
1342e3aff4f6Saliguori         int64_t size;
1343e3aff4f6Saliguori 	char s1[64];
1344e3aff4f6Saliguori 
1345e3aff4f6Saliguori 	size = bdrv_getlength(bs);
1346e3aff4f6Saliguori 	if (size < 0) {
13470923c577SKevin Wolf 		printf("getlength: %s\n", strerror(-size));
1348e3aff4f6Saliguori 		return 0;
1349e3aff4f6Saliguori 	}
1350e3aff4f6Saliguori 
1351e3aff4f6Saliguori 	cvtstr(size, s1, sizeof(s1));
1352e3aff4f6Saliguori 	printf("%s\n", s1);
1353e3aff4f6Saliguori 	return 0;
1354e3aff4f6Saliguori }
1355e3aff4f6Saliguori 
1356e3aff4f6Saliguori 
1357e3aff4f6Saliguori static const cmdinfo_t length_cmd = {
1358e3aff4f6Saliguori 	.name		= "length",
1359e3aff4f6Saliguori 	.altname	= "l",
1360e3aff4f6Saliguori 	.cfunc		= length_f,
1361e3aff4f6Saliguori 	.oneline	= "gets the length of the current file",
1362e3aff4f6Saliguori };
1363e3aff4f6Saliguori 
1364e3aff4f6Saliguori 
1365e3aff4f6Saliguori static int
1366e3aff4f6Saliguori info_f(int argc, char **argv)
1367e3aff4f6Saliguori {
1368e3aff4f6Saliguori 	BlockDriverInfo bdi;
1369e3aff4f6Saliguori 	char s1[64], s2[64];
1370e3aff4f6Saliguori 	int ret;
1371e3aff4f6Saliguori 
1372e3aff4f6Saliguori 	if (bs->drv && bs->drv->format_name)
1373e3aff4f6Saliguori 		printf("format name: %s\n", bs->drv->format_name);
1374e3aff4f6Saliguori 	if (bs->drv && bs->drv->protocol_name)
1375e3aff4f6Saliguori 		printf("format name: %s\n", bs->drv->protocol_name);
1376e3aff4f6Saliguori 
1377e3aff4f6Saliguori 	ret = bdrv_get_info(bs, &bdi);
1378e3aff4f6Saliguori 	if (ret)
1379e3aff4f6Saliguori 		return 0;
1380e3aff4f6Saliguori 
1381e3aff4f6Saliguori 	cvtstr(bdi.cluster_size, s1, sizeof(s1));
1382e3aff4f6Saliguori 	cvtstr(bdi.vm_state_offset, s2, sizeof(s2));
1383e3aff4f6Saliguori 
1384e3aff4f6Saliguori 	printf("cluster size: %s\n", s1);
1385e3aff4f6Saliguori 	printf("vm state offset: %s\n", s2);
1386e3aff4f6Saliguori 
1387e3aff4f6Saliguori 	return 0;
1388e3aff4f6Saliguori }
1389e3aff4f6Saliguori 
1390e3aff4f6Saliguori 
1391e3aff4f6Saliguori 
1392e3aff4f6Saliguori static const cmdinfo_t info_cmd = {
1393e3aff4f6Saliguori 	.name		= "info",
1394e3aff4f6Saliguori 	.altname	= "i",
1395e3aff4f6Saliguori 	.cfunc		= info_f,
1396e3aff4f6Saliguori 	.oneline	= "prints information about the current file",
1397e3aff4f6Saliguori };
1398e3aff4f6Saliguori 
1399edff5db1SStefan Hajnoczi static void
1400edff5db1SStefan Hajnoczi discard_help(void)
1401edff5db1SStefan Hajnoczi {
1402edff5db1SStefan Hajnoczi 	printf(
1403edff5db1SStefan Hajnoczi "\n"
1404edff5db1SStefan Hajnoczi " discards a range of bytes from the given offset\n"
1405edff5db1SStefan Hajnoczi "\n"
1406edff5db1SStefan Hajnoczi " Example:\n"
1407edff5db1SStefan Hajnoczi " 'discard 512 1k' - discards 1 kilobyte from 512 bytes into the file\n"
1408edff5db1SStefan Hajnoczi "\n"
1409edff5db1SStefan Hajnoczi " Discards a segment of the currently open file.\n"
1410edff5db1SStefan Hajnoczi " -C, -- report statistics in a machine parsable format\n"
1411095343adSKevin Wolf " -q, -- quiet mode, do not show I/O statistics\n"
1412edff5db1SStefan Hajnoczi "\n");
1413edff5db1SStefan Hajnoczi }
1414edff5db1SStefan Hajnoczi 
1415edff5db1SStefan Hajnoczi static int discard_f(int argc, char **argv);
1416edff5db1SStefan Hajnoczi 
1417edff5db1SStefan Hajnoczi static const cmdinfo_t discard_cmd = {
1418edff5db1SStefan Hajnoczi 	.name		= "discard",
1419edff5db1SStefan Hajnoczi 	.altname	= "d",
1420edff5db1SStefan Hajnoczi 	.cfunc		= discard_f,
1421edff5db1SStefan Hajnoczi 	.argmin		= 2,
1422edff5db1SStefan Hajnoczi 	.argmax		= -1,
1423edff5db1SStefan Hajnoczi 	.args		= "[-Cq] off len",
1424edff5db1SStefan Hajnoczi 	.oneline	= "discards a number of bytes at a specified offset",
1425edff5db1SStefan Hajnoczi 	.help		= discard_help,
1426edff5db1SStefan Hajnoczi };
1427edff5db1SStefan Hajnoczi 
1428edff5db1SStefan Hajnoczi static int
1429edff5db1SStefan Hajnoczi discard_f(int argc, char **argv)
1430edff5db1SStefan Hajnoczi {
1431edff5db1SStefan Hajnoczi 	struct timeval t1, t2;
1432edff5db1SStefan Hajnoczi 	int Cflag = 0, qflag = 0;
1433edff5db1SStefan Hajnoczi 	int c, ret;
1434edff5db1SStefan Hajnoczi 	int64_t offset;
1435edff5db1SStefan Hajnoczi 	int count;
1436edff5db1SStefan Hajnoczi 
1437edff5db1SStefan Hajnoczi 	while ((c = getopt(argc, argv, "Cq")) != EOF) {
1438edff5db1SStefan Hajnoczi 		switch (c) {
1439edff5db1SStefan Hajnoczi 		case 'C':
1440edff5db1SStefan Hajnoczi 			Cflag = 1;
1441edff5db1SStefan Hajnoczi 			break;
1442edff5db1SStefan Hajnoczi 		case 'q':
1443edff5db1SStefan Hajnoczi 			qflag = 1;
1444edff5db1SStefan Hajnoczi 			break;
1445edff5db1SStefan Hajnoczi 		default:
1446edff5db1SStefan Hajnoczi 			return command_usage(&discard_cmd);
1447edff5db1SStefan Hajnoczi 		}
1448edff5db1SStefan Hajnoczi 	}
1449edff5db1SStefan Hajnoczi 
1450edff5db1SStefan Hajnoczi 	if (optind != argc - 2) {
1451edff5db1SStefan Hajnoczi 		return command_usage(&discard_cmd);
1452edff5db1SStefan Hajnoczi 	}
1453edff5db1SStefan Hajnoczi 
1454edff5db1SStefan Hajnoczi 	offset = cvtnum(argv[optind]);
1455edff5db1SStefan Hajnoczi 	if (offset < 0) {
1456edff5db1SStefan Hajnoczi 		printf("non-numeric length argument -- %s\n", argv[optind]);
1457edff5db1SStefan Hajnoczi 		return 0;
1458edff5db1SStefan Hajnoczi 	}
1459edff5db1SStefan Hajnoczi 
1460edff5db1SStefan Hajnoczi 	optind++;
1461edff5db1SStefan Hajnoczi 	count = cvtnum(argv[optind]);
1462edff5db1SStefan Hajnoczi 	if (count < 0) {
1463edff5db1SStefan Hajnoczi 		printf("non-numeric length argument -- %s\n", argv[optind]);
1464edff5db1SStefan Hajnoczi 		return 0;
1465edff5db1SStefan Hajnoczi 	}
1466edff5db1SStefan Hajnoczi 
1467edff5db1SStefan Hajnoczi 	gettimeofday(&t1, NULL);
1468edff5db1SStefan Hajnoczi 	ret = bdrv_discard(bs, offset, count);
1469edff5db1SStefan Hajnoczi 	gettimeofday(&t2, NULL);
1470edff5db1SStefan Hajnoczi 
1471edff5db1SStefan Hajnoczi 	if (ret < 0) {
1472edff5db1SStefan Hajnoczi 		printf("discard failed: %s\n", strerror(-ret));
1473edff5db1SStefan Hajnoczi 		goto out;
1474edff5db1SStefan Hajnoczi 	}
1475edff5db1SStefan Hajnoczi 
1476edff5db1SStefan Hajnoczi 	/* Finally, report back -- -C gives a parsable format */
1477edff5db1SStefan Hajnoczi 	if (!qflag) {
1478edff5db1SStefan Hajnoczi 		t2 = tsub(t2, t1);
1479edff5db1SStefan Hajnoczi 		print_report("discard", &t2, offset, count, count, 1, Cflag);
1480edff5db1SStefan Hajnoczi 	}
1481edff5db1SStefan Hajnoczi 
1482edff5db1SStefan Hajnoczi out:
1483edff5db1SStefan Hajnoczi 	return 0;
1484edff5db1SStefan Hajnoczi }
1485edff5db1SStefan Hajnoczi 
1486e3aff4f6Saliguori static int
1487e3aff4f6Saliguori alloc_f(int argc, char **argv)
1488e3aff4f6Saliguori {
1489e3aff4f6Saliguori 	int64_t offset;
1490a7824a88SKevin Wolf 	int nb_sectors, remaining;
1491e3aff4f6Saliguori 	char s1[64];
1492a7824a88SKevin Wolf 	int num, sum_alloc;
1493e3aff4f6Saliguori 	int ret;
1494e3aff4f6Saliguori 
1495e3aff4f6Saliguori 	offset = cvtnum(argv[1]);
1496e3aff4f6Saliguori 	if (offset & 0x1ff) {
14970bfcd599SBlue Swirl                 printf("offset %" PRId64 " is not sector aligned\n",
14980bfcd599SBlue Swirl                        offset);
1499e3aff4f6Saliguori 		return 0;
1500e3aff4f6Saliguori 	}
1501e3aff4f6Saliguori 
1502e3aff4f6Saliguori 	if (argc == 3)
1503e3aff4f6Saliguori 		nb_sectors = cvtnum(argv[2]);
1504e3aff4f6Saliguori 	else
1505e3aff4f6Saliguori 		nb_sectors = 1;
1506e3aff4f6Saliguori 
1507a7824a88SKevin Wolf 	remaining = nb_sectors;
1508a7824a88SKevin Wolf 	sum_alloc = 0;
1509a7824a88SKevin Wolf 	while (remaining) {
1510e3aff4f6Saliguori 		ret = bdrv_is_allocated(bs, offset >> 9, nb_sectors, &num);
1511a7824a88SKevin Wolf 		remaining -= num;
1512a7824a88SKevin Wolf 		if (ret) {
1513a7824a88SKevin Wolf 			sum_alloc += num;
1514a7824a88SKevin Wolf 		}
1515a7824a88SKevin Wolf 	}
1516e3aff4f6Saliguori 
1517e3aff4f6Saliguori 	cvtstr(offset, s1, sizeof(s1));
1518e3aff4f6Saliguori 
1519a7824a88SKevin Wolf 	printf("%d/%d sectors allocated at offset %s\n",
1520a7824a88SKevin Wolf 	       sum_alloc, nb_sectors, s1);
1521e3aff4f6Saliguori 	return 0;
1522e3aff4f6Saliguori }
1523e3aff4f6Saliguori 
1524e3aff4f6Saliguori static const cmdinfo_t alloc_cmd = {
1525e3aff4f6Saliguori 	.name		= "alloc",
1526e3aff4f6Saliguori 	.altname	= "a",
1527e3aff4f6Saliguori 	.argmin		= 1,
1528e3aff4f6Saliguori 	.argmax		= 2,
1529e3aff4f6Saliguori 	.cfunc		= alloc_f,
1530e3aff4f6Saliguori 	.args		= "off [sectors]",
1531e3aff4f6Saliguori 	.oneline	= "checks if a sector is present in the file",
1532e3aff4f6Saliguori };
1533e3aff4f6Saliguori 
1534e3aff4f6Saliguori static int
1535191c2890SKevin Wolf map_f(int argc, char **argv)
1536191c2890SKevin Wolf {
1537191c2890SKevin Wolf 	int64_t offset;
1538191c2890SKevin Wolf 	int64_t nb_sectors;
1539191c2890SKevin Wolf 	char s1[64];
1540191c2890SKevin Wolf 	int num, num_checked;
1541191c2890SKevin Wolf 	int ret;
1542191c2890SKevin Wolf 	const char *retstr;
1543191c2890SKevin Wolf 
1544191c2890SKevin Wolf 	offset = 0;
1545191c2890SKevin Wolf 	nb_sectors = bs->total_sectors;
1546191c2890SKevin Wolf 
1547191c2890SKevin Wolf 	do {
1548191c2890SKevin Wolf 		num_checked = MIN(nb_sectors, INT_MAX);
1549191c2890SKevin Wolf 		ret = bdrv_is_allocated(bs, offset, num_checked, &num);
1550191c2890SKevin Wolf 		retstr = ret ? "    allocated" : "not allocated";
1551191c2890SKevin Wolf 		cvtstr(offset << 9ULL, s1, sizeof(s1));
1552191c2890SKevin Wolf 		printf("[% 24" PRId64 "] % 8d/% 8d sectors %s at offset %s (%d)\n",
1553191c2890SKevin Wolf 				offset << 9ULL, num, num_checked, retstr, s1, ret);
1554191c2890SKevin Wolf 
1555191c2890SKevin Wolf 		offset += num;
1556191c2890SKevin Wolf 		nb_sectors -= num;
1557191c2890SKevin Wolf 	} while(offset < bs->total_sectors);
1558191c2890SKevin Wolf 
1559191c2890SKevin Wolf 	return 0;
1560191c2890SKevin Wolf }
1561191c2890SKevin Wolf 
1562191c2890SKevin Wolf static const cmdinfo_t map_cmd = {
1563191c2890SKevin Wolf        .name           = "map",
1564191c2890SKevin Wolf        .argmin         = 0,
1565191c2890SKevin Wolf        .argmax         = 0,
1566191c2890SKevin Wolf        .cfunc          = map_f,
1567191c2890SKevin Wolf        .args           = "",
1568191c2890SKevin Wolf        .oneline        = "prints the allocated areas of a file",
1569191c2890SKevin Wolf };
1570191c2890SKevin Wolf 
1571191c2890SKevin Wolf 
1572191c2890SKevin Wolf static int
1573e3aff4f6Saliguori close_f(int argc, char **argv)
1574e3aff4f6Saliguori {
1575e3aff4f6Saliguori 	bdrv_close(bs);
1576e3aff4f6Saliguori 	bs = NULL;
1577e3aff4f6Saliguori 	return 0;
1578e3aff4f6Saliguori }
1579e3aff4f6Saliguori 
1580e3aff4f6Saliguori static const cmdinfo_t close_cmd = {
1581e3aff4f6Saliguori 	.name		= "close",
1582e3aff4f6Saliguori 	.altname	= "c",
1583e3aff4f6Saliguori 	.cfunc		= close_f,
1584e3aff4f6Saliguori 	.oneline	= "close the current open file",
1585e3aff4f6Saliguori };
1586e3aff4f6Saliguori 
15879c4bab26SChristoph Hellwig static int openfile(char *name, int flags, int growable)
1588e3aff4f6Saliguori {
1589e3aff4f6Saliguori 	if (bs) {
1590e3aff4f6Saliguori 		fprintf(stderr, "file open already, try 'help close'\n");
1591e3aff4f6Saliguori 		return 1;
1592e3aff4f6Saliguori 	}
1593e3aff4f6Saliguori 
15946db95603SChristoph Hellwig 	if (growable) {
15956db95603SChristoph Hellwig 		if (bdrv_file_open(&bs, name, flags)) {
15966db95603SChristoph Hellwig 			fprintf(stderr, "%s: can't open device %s\n", progname, name);
15976db95603SChristoph Hellwig 			return 1;
15986db95603SChristoph Hellwig 		}
15996db95603SChristoph Hellwig 	} else {
1600e3aff4f6Saliguori 		bs = bdrv_new("hda");
1601e3aff4f6Saliguori 
1602d6e9098eSKevin Wolf 		if (bdrv_open(bs, name, flags, NULL) < 0) {
1603e3aff4f6Saliguori 			fprintf(stderr, "%s: can't open device %s\n", progname, name);
1604e3aff4f6Saliguori 			bs = NULL;
1605e3aff4f6Saliguori 			return 1;
1606e3aff4f6Saliguori 		}
16079c4bab26SChristoph Hellwig 	}
16086db95603SChristoph Hellwig 
1609e3aff4f6Saliguori 	return 0;
1610e3aff4f6Saliguori }
1611e3aff4f6Saliguori 
1612e3aff4f6Saliguori static void
1613e3aff4f6Saliguori open_help(void)
1614e3aff4f6Saliguori {
1615e3aff4f6Saliguori 	printf(
1616e3aff4f6Saliguori "\n"
1617e3aff4f6Saliguori " opens a new file in the requested mode\n"
1618e3aff4f6Saliguori "\n"
1619e3aff4f6Saliguori " Example:\n"
1620e3aff4f6Saliguori " 'open -Cn /tmp/data' - creates/opens data file read-write and uncached\n"
1621e3aff4f6Saliguori "\n"
1622e3aff4f6Saliguori " Opens a file for subsequent use by all of the other qemu-io commands.\n"
1623e3aff4f6Saliguori " -r, -- open file read-only\n"
1624e3aff4f6Saliguori " -s, -- use snapshot file\n"
1625e3aff4f6Saliguori " -n, -- disable host cache\n"
16269c4bab26SChristoph Hellwig " -g, -- allow file to grow (only applies to protocols)"
1627e3aff4f6Saliguori "\n");
1628e3aff4f6Saliguori }
1629e3aff4f6Saliguori 
163022a2bdcbSBlue Swirl static int open_f(int argc, char **argv);
163122a2bdcbSBlue Swirl 
163222a2bdcbSBlue Swirl static const cmdinfo_t open_cmd = {
163322a2bdcbSBlue Swirl 	.name		= "open",
163422a2bdcbSBlue Swirl 	.altname	= "o",
163522a2bdcbSBlue Swirl 	.cfunc		= open_f,
163622a2bdcbSBlue Swirl 	.argmin		= 1,
163722a2bdcbSBlue Swirl 	.argmax		= -1,
163822a2bdcbSBlue Swirl 	.flags		= CMD_NOFILE_OK,
163922a2bdcbSBlue Swirl 	.args		= "[-Crsn] [path]",
164022a2bdcbSBlue Swirl 	.oneline	= "open the file specified by path",
164122a2bdcbSBlue Swirl 	.help		= open_help,
164222a2bdcbSBlue Swirl };
1643e3aff4f6Saliguori 
1644e3aff4f6Saliguori static int
1645e3aff4f6Saliguori open_f(int argc, char **argv)
1646e3aff4f6Saliguori {
1647e3aff4f6Saliguori 	int flags = 0;
1648e3aff4f6Saliguori 	int readonly = 0;
16499c4bab26SChristoph Hellwig 	int growable = 0;
1650e3aff4f6Saliguori 	int c;
1651e3aff4f6Saliguori 
16529a2d77adSChristoph Hellwig 	while ((c = getopt(argc, argv, "snrg")) != EOF) {
1653e3aff4f6Saliguori 		switch (c) {
1654e3aff4f6Saliguori 		case 's':
1655e3aff4f6Saliguori 			flags |= BDRV_O_SNAPSHOT;
1656e3aff4f6Saliguori 			break;
1657e3aff4f6Saliguori 		case 'n':
1658e3aff4f6Saliguori 			flags |= BDRV_O_NOCACHE;
1659e3aff4f6Saliguori 			break;
1660e3aff4f6Saliguori 		case 'r':
1661e3aff4f6Saliguori 			readonly = 1;
1662e3aff4f6Saliguori 			break;
16639c4bab26SChristoph Hellwig 		case 'g':
16649c4bab26SChristoph Hellwig 			growable = 1;
16659c4bab26SChristoph Hellwig 			break;
1666e3aff4f6Saliguori 		default:
1667e3aff4f6Saliguori 			return command_usage(&open_cmd);
1668e3aff4f6Saliguori 		}
1669e3aff4f6Saliguori 	}
1670e3aff4f6Saliguori 
1671f5edb014SNaphtali Sprei 	if (!readonly) {
1672e3aff4f6Saliguori             flags |= BDRV_O_RDWR;
1673f5edb014SNaphtali Sprei         }
1674e3aff4f6Saliguori 
1675e3aff4f6Saliguori 	if (optind != argc - 1)
1676e3aff4f6Saliguori 		return command_usage(&open_cmd);
1677e3aff4f6Saliguori 
16789c4bab26SChristoph Hellwig 	return openfile(argv[optind], flags, growable);
1679e3aff4f6Saliguori }
1680e3aff4f6Saliguori 
1681e3aff4f6Saliguori static int
1682e3aff4f6Saliguori init_args_command(
1683e3aff4f6Saliguori         int     index)
1684e3aff4f6Saliguori {
1685e3aff4f6Saliguori 	/* only one device allowed so far */
1686e3aff4f6Saliguori 	if (index >= 1)
1687e3aff4f6Saliguori 		return 0;
1688e3aff4f6Saliguori 	return ++index;
1689e3aff4f6Saliguori }
1690e3aff4f6Saliguori 
1691e3aff4f6Saliguori static int
1692e3aff4f6Saliguori init_check_command(
1693e3aff4f6Saliguori 	const cmdinfo_t *ct)
1694e3aff4f6Saliguori {
1695e3aff4f6Saliguori 	if (ct->flags & CMD_FLAG_GLOBAL)
1696e3aff4f6Saliguori 		return 1;
1697e3aff4f6Saliguori 	if (!(ct->flags & CMD_NOFILE_OK) && !bs) {
1698e3aff4f6Saliguori 		fprintf(stderr, "no file open, try 'help open'\n");
1699e3aff4f6Saliguori 		return 0;
1700e3aff4f6Saliguori 	}
1701e3aff4f6Saliguori 	return 1;
1702e3aff4f6Saliguori }
1703e3aff4f6Saliguori 
1704e3aff4f6Saliguori static void usage(const char *name)
1705e3aff4f6Saliguori {
1706e3aff4f6Saliguori 	printf(
17079a2d77adSChristoph Hellwig "Usage: %s [-h] [-V] [-rsnm] [-c cmd] ... [file]\n"
170884844a20SStefan Weil "QEMU Disk exerciser\n"
1709e3aff4f6Saliguori "\n"
1710e3aff4f6Saliguori "  -c, --cmd            command to execute\n"
1711e3aff4f6Saliguori "  -r, --read-only      export read-only\n"
1712e3aff4f6Saliguori "  -s, --snapshot       use snapshot file\n"
1713e3aff4f6Saliguori "  -n, --nocache        disable host cache\n"
17141db6947dSChristoph Hellwig "  -g, --growable       allow file to grow (only applies to protocols)\n"
1715e3aff4f6Saliguori "  -m, --misalign       misalign allocations for O_DIRECT\n"
17165c6c3a6cSChristoph Hellwig "  -k, --native-aio     use kernel AIO implementation (on Linux only)\n"
1717e3aff4f6Saliguori "  -h, --help           display this help and exit\n"
1718e3aff4f6Saliguori "  -V, --version        output version information and exit\n"
1719e3aff4f6Saliguori "\n",
1720e3aff4f6Saliguori 	name);
1721e3aff4f6Saliguori }
1722e3aff4f6Saliguori 
1723e3aff4f6Saliguori 
1724e3aff4f6Saliguori int main(int argc, char **argv)
1725e3aff4f6Saliguori {
1726e3aff4f6Saliguori 	int readonly = 0;
17279c4bab26SChristoph Hellwig 	int growable = 0;
17289a2d77adSChristoph Hellwig 	const char *sopt = "hVc:rsnmgk";
1729b32bb952SBlue Swirl         const struct option lopt[] = {
1730660f11beSBlue Swirl 		{ "help", 0, NULL, 'h' },
1731660f11beSBlue Swirl 		{ "version", 0, NULL, 'V' },
1732660f11beSBlue Swirl 		{ "offset", 1, NULL, 'o' },
1733660f11beSBlue Swirl 		{ "cmd", 1, NULL, 'c' },
1734660f11beSBlue Swirl 		{ "read-only", 0, NULL, 'r' },
1735660f11beSBlue Swirl 		{ "snapshot", 0, NULL, 's' },
1736660f11beSBlue Swirl 		{ "nocache", 0, NULL, 'n' },
1737660f11beSBlue Swirl 		{ "misalign", 0, NULL, 'm' },
1738660f11beSBlue Swirl 		{ "growable", 0, NULL, 'g' },
17395c6c3a6cSChristoph Hellwig 		{ "native-aio", 0, NULL, 'k' },
1740660f11beSBlue Swirl 		{ NULL, 0, NULL, 0 }
1741e3aff4f6Saliguori 	};
1742e3aff4f6Saliguori 	int c;
1743e3aff4f6Saliguori 	int opt_index = 0;
1744e3aff4f6Saliguori 	int flags = 0;
1745e3aff4f6Saliguori 
1746e3aff4f6Saliguori 	progname = basename(argv[0]);
1747e3aff4f6Saliguori 
1748e3aff4f6Saliguori 	while ((c = getopt_long(argc, argv, sopt, lopt, &opt_index)) != -1) {
1749e3aff4f6Saliguori 		switch (c) {
1750e3aff4f6Saliguori 		case 's':
1751e3aff4f6Saliguori 			flags |= BDRV_O_SNAPSHOT;
1752e3aff4f6Saliguori 			break;
1753e3aff4f6Saliguori 		case 'n':
1754e3aff4f6Saliguori 			flags |= BDRV_O_NOCACHE;
1755e3aff4f6Saliguori 			break;
1756e3aff4f6Saliguori 		case 'c':
1757e3aff4f6Saliguori 			add_user_command(optarg);
1758e3aff4f6Saliguori 			break;
1759e3aff4f6Saliguori 		case 'r':
1760e3aff4f6Saliguori 			readonly = 1;
1761e3aff4f6Saliguori 			break;
1762e3aff4f6Saliguori 		case 'm':
1763e3aff4f6Saliguori 			misalign = 1;
1764e3aff4f6Saliguori 			break;
17659c4bab26SChristoph Hellwig 		case 'g':
17669c4bab26SChristoph Hellwig 			growable = 1;
17679c4bab26SChristoph Hellwig 			break;
17685c6c3a6cSChristoph Hellwig 		case 'k':
17695c6c3a6cSChristoph Hellwig 			flags |= BDRV_O_NATIVE_AIO;
17705c6c3a6cSChristoph Hellwig 			break;
1771e3aff4f6Saliguori 		case 'V':
1772e3aff4f6Saliguori 			printf("%s version %s\n", progname, VERSION);
1773e3aff4f6Saliguori 			exit(0);
1774e3aff4f6Saliguori 		case 'h':
1775e3aff4f6Saliguori 			usage(progname);
1776e3aff4f6Saliguori 			exit(0);
1777e3aff4f6Saliguori 		default:
1778e3aff4f6Saliguori 			usage(progname);
1779e3aff4f6Saliguori 			exit(1);
1780e3aff4f6Saliguori 		}
1781e3aff4f6Saliguori 	}
1782e3aff4f6Saliguori 
1783e3aff4f6Saliguori 	if ((argc - optind) > 1) {
1784e3aff4f6Saliguori 		usage(progname);
1785e3aff4f6Saliguori 		exit(1);
1786e3aff4f6Saliguori 	}
1787e3aff4f6Saliguori 
1788e3aff4f6Saliguori 	bdrv_init();
1789e3aff4f6Saliguori 
1790e3aff4f6Saliguori 	/* initialize commands */
1791e3aff4f6Saliguori 	quit_init();
1792e3aff4f6Saliguori 	help_init();
1793e3aff4f6Saliguori 	add_command(&open_cmd);
1794e3aff4f6Saliguori 	add_command(&close_cmd);
1795e3aff4f6Saliguori 	add_command(&read_cmd);
1796e3aff4f6Saliguori 	add_command(&readv_cmd);
1797e3aff4f6Saliguori 	add_command(&write_cmd);
1798e3aff4f6Saliguori 	add_command(&writev_cmd);
1799776cbbbdSKevin Wolf 	add_command(&multiwrite_cmd);
180095533d5fSChristoph Hellwig 	add_command(&aio_read_cmd);
180195533d5fSChristoph Hellwig 	add_command(&aio_write_cmd);
180295533d5fSChristoph Hellwig 	add_command(&aio_flush_cmd);
1803e3aff4f6Saliguori 	add_command(&flush_cmd);
1804e3aff4f6Saliguori 	add_command(&truncate_cmd);
1805e3aff4f6Saliguori 	add_command(&length_cmd);
1806e3aff4f6Saliguori 	add_command(&info_cmd);
1807edff5db1SStefan Hajnoczi 	add_command(&discard_cmd);
1808e3aff4f6Saliguori 	add_command(&alloc_cmd);
1809191c2890SKevin Wolf 	add_command(&map_cmd);
1810e3aff4f6Saliguori 
1811e3aff4f6Saliguori 	add_args_command(init_args_command);
1812e3aff4f6Saliguori 	add_check_command(init_check_command);
1813e3aff4f6Saliguori 
1814e3aff4f6Saliguori 	/* open the device */
1815f5edb014SNaphtali Sprei 	if (!readonly) {
1816e3aff4f6Saliguori             flags |= BDRV_O_RDWR;
1817f5edb014SNaphtali Sprei         }
1818e3aff4f6Saliguori 
1819e3aff4f6Saliguori 	if ((argc - optind) == 1)
18209c4bab26SChristoph Hellwig 		openfile(argv[optind], flags, growable);
1821e3aff4f6Saliguori 	command_loop();
1822e3aff4f6Saliguori 
182395533d5fSChristoph Hellwig 	/*
182495533d5fSChristoph Hellwig 	 * Make sure all outstanding requests get flushed the program exits.
182595533d5fSChristoph Hellwig 	 */
182695533d5fSChristoph Hellwig 	qemu_aio_flush();
182795533d5fSChristoph Hellwig 
1828e3aff4f6Saliguori 	if (bs)
1829e3aff4f6Saliguori 		bdrv_close(bs);
1830e3aff4f6Saliguori 	return 0;
1831e3aff4f6Saliguori }
1832