xref: /qemu/qemu-io.c (revision 0923c577f993d61eeaf41f66db1e1010fa113976)
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;
64e3aff4f6Saliguori 	buf = qemu_memalign(512, 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];
1380bfcd599SBlue Swirl                 uint64_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 */
147cf57298aSChristoph Hellwig 		if (len > UINT_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"
329e3aff4f6Saliguori " -q, -- quite 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"
512e3aff4f6Saliguori " -q, -- quite 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"
636e3aff4f6Saliguori " -q, -- quite 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"
768e3aff4f6Saliguori " -q, -- quite 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"
110395533d5fSChristoph Hellwig " -q, -- quite 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);
1134cf070d7eSChristoph Hellwig 			if (ctx->pattern < 0)
1135cf070d7eSChristoph Hellwig 				return 0;
113695533d5fSChristoph Hellwig 			break;
113795533d5fSChristoph Hellwig 		case 'q':
113895533d5fSChristoph Hellwig 			ctx->qflag = 1;
113995533d5fSChristoph Hellwig 			break;
114095533d5fSChristoph Hellwig 		case 'v':
114195533d5fSChristoph Hellwig 			ctx->vflag = 1;
114295533d5fSChristoph Hellwig 			break;
114395533d5fSChristoph Hellwig 		default:
11447d8abfcbSKevin Wolf 			free(ctx);
114595533d5fSChristoph Hellwig 			return command_usage(&aio_read_cmd);
114695533d5fSChristoph Hellwig 		}
114795533d5fSChristoph Hellwig 	}
114895533d5fSChristoph Hellwig 
11497d8abfcbSKevin Wolf 	if (optind > argc - 2) {
11507d8abfcbSKevin Wolf 		free(ctx);
115195533d5fSChristoph Hellwig 		return command_usage(&aio_read_cmd);
11527d8abfcbSKevin Wolf 	}
115395533d5fSChristoph Hellwig 
115495533d5fSChristoph Hellwig 	ctx->offset = cvtnum(argv[optind]);
115595533d5fSChristoph Hellwig 	if (ctx->offset < 0) {
115695533d5fSChristoph Hellwig 		printf("non-numeric length argument -- %s\n", argv[optind]);
11577d8abfcbSKevin Wolf 		free(ctx);
115895533d5fSChristoph Hellwig 		return 0;
115995533d5fSChristoph Hellwig 	}
116095533d5fSChristoph Hellwig 	optind++;
116195533d5fSChristoph Hellwig 
116295533d5fSChristoph Hellwig 	if (ctx->offset & 0x1ff) {
11630bfcd599SBlue Swirl 		printf("offset %" PRId64 " is not sector aligned\n",
11640bfcd599SBlue Swirl                        ctx->offset);
11657d8abfcbSKevin Wolf 		free(ctx);
116695533d5fSChristoph Hellwig 		return 0;
116795533d5fSChristoph Hellwig 	}
116895533d5fSChristoph Hellwig 
116995533d5fSChristoph Hellwig 	nr_iov = argc - optind;
1170cf57298aSChristoph Hellwig 	ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, 0xab);
117195533d5fSChristoph Hellwig 
117295533d5fSChristoph Hellwig 	gettimeofday(&ctx->t1, NULL);
117395533d5fSChristoph Hellwig 	acb = bdrv_aio_readv(bs, ctx->offset >> 9, &ctx->qiov,
117495533d5fSChristoph Hellwig 			      ctx->qiov.size >> 9, aio_read_done, ctx);
11757d8abfcbSKevin Wolf 	if (!acb) {
11767d8abfcbSKevin Wolf 		free(ctx->buf);
11777d8abfcbSKevin Wolf 		free(ctx);
117895533d5fSChristoph Hellwig 		return -EIO;
11797d8abfcbSKevin Wolf 	}
118095533d5fSChristoph Hellwig 
118195533d5fSChristoph Hellwig 	return 0;
118295533d5fSChristoph Hellwig }
118395533d5fSChristoph Hellwig 
118495533d5fSChristoph Hellwig static void
118595533d5fSChristoph Hellwig aio_write_help(void)
118695533d5fSChristoph Hellwig {
118795533d5fSChristoph Hellwig 	printf(
118895533d5fSChristoph Hellwig "\n"
118995533d5fSChristoph Hellwig " asynchronously writes a range of bytes from the given offset source \n"
119095533d5fSChristoph Hellwig " from multiple buffers\n"
119195533d5fSChristoph Hellwig "\n"
119295533d5fSChristoph Hellwig " Example:\n"
119395533d5fSChristoph Hellwig " 'aio_write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n"
119495533d5fSChristoph Hellwig "\n"
119595533d5fSChristoph Hellwig " Writes into a segment of the currently open file, using a buffer\n"
119695533d5fSChristoph Hellwig " filled with a set pattern (0xcdcdcdcd).\n"
1197e432cef9SChristoph Hellwig " The write is performed asynchronously and the aio_flush command must be\n"
1198e432cef9SChristoph Hellwig " used to ensure all outstanding aio requests have been completed\n"
119995533d5fSChristoph Hellwig " -P, -- use different pattern to fill file\n"
120095533d5fSChristoph Hellwig " -C, -- report statistics in a machine parsable format\n"
120195533d5fSChristoph Hellwig " -q, -- quite mode, do not show I/O statistics\n"
120295533d5fSChristoph Hellwig "\n");
120395533d5fSChristoph Hellwig }
120495533d5fSChristoph Hellwig 
120522a2bdcbSBlue Swirl static int aio_write_f(int argc, char **argv);
120622a2bdcbSBlue Swirl 
120722a2bdcbSBlue Swirl static const cmdinfo_t aio_write_cmd = {
120822a2bdcbSBlue Swirl 	.name		= "aio_write",
120922a2bdcbSBlue Swirl 	.cfunc		= aio_write_f,
121022a2bdcbSBlue Swirl 	.argmin		= 2,
121122a2bdcbSBlue Swirl 	.argmax		= -1,
121222a2bdcbSBlue Swirl 	.args		= "[-Cq] [-P pattern ] off len [len..]",
121322a2bdcbSBlue Swirl 	.oneline	= "asynchronously writes a number of bytes",
121422a2bdcbSBlue Swirl 	.help		= aio_write_help,
121522a2bdcbSBlue Swirl };
121695533d5fSChristoph Hellwig 
121795533d5fSChristoph Hellwig static int
121895533d5fSChristoph Hellwig aio_write_f(int argc, char **argv)
121995533d5fSChristoph Hellwig {
1220cf57298aSChristoph Hellwig 	int nr_iov, c;
122195533d5fSChristoph Hellwig 	int pattern = 0xcd;
122295533d5fSChristoph Hellwig 	struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx));
122395533d5fSChristoph Hellwig 	BlockDriverAIOCB *acb;
122495533d5fSChristoph Hellwig 
122595533d5fSChristoph Hellwig 	while ((c = getopt(argc, argv, "CqP:")) != EOF) {
122695533d5fSChristoph Hellwig 		switch (c) {
122795533d5fSChristoph Hellwig 		case 'C':
122895533d5fSChristoph Hellwig 			ctx->Cflag = 1;
122995533d5fSChristoph Hellwig 			break;
123095533d5fSChristoph Hellwig 		case 'q':
123195533d5fSChristoph Hellwig 			ctx->qflag = 1;
123295533d5fSChristoph Hellwig 			break;
123395533d5fSChristoph Hellwig 		case 'P':
1234cf070d7eSChristoph Hellwig 			pattern = parse_pattern(optarg);
1235cf070d7eSChristoph Hellwig 			if (pattern < 0)
1236cf070d7eSChristoph Hellwig 				return 0;
123795533d5fSChristoph Hellwig 			break;
123895533d5fSChristoph Hellwig 		default:
12397d8abfcbSKevin Wolf 			free(ctx);
124095533d5fSChristoph Hellwig 			return command_usage(&aio_write_cmd);
124195533d5fSChristoph Hellwig 		}
124295533d5fSChristoph Hellwig 	}
124395533d5fSChristoph Hellwig 
12447d8abfcbSKevin Wolf 	if (optind > argc - 2) {
12457d8abfcbSKevin Wolf 		free(ctx);
124695533d5fSChristoph Hellwig 		return command_usage(&aio_write_cmd);
12477d8abfcbSKevin Wolf 	}
124895533d5fSChristoph Hellwig 
124995533d5fSChristoph Hellwig 	ctx->offset = cvtnum(argv[optind]);
125095533d5fSChristoph Hellwig 	if (ctx->offset < 0) {
125195533d5fSChristoph Hellwig 		printf("non-numeric length argument -- %s\n", argv[optind]);
12527d8abfcbSKevin Wolf 		free(ctx);
125395533d5fSChristoph Hellwig 		return 0;
125495533d5fSChristoph Hellwig 	}
125595533d5fSChristoph Hellwig 	optind++;
125695533d5fSChristoph Hellwig 
125795533d5fSChristoph Hellwig 	if (ctx->offset & 0x1ff) {
12580bfcd599SBlue Swirl 		printf("offset %" PRId64 " is not sector aligned\n",
12590bfcd599SBlue Swirl                        ctx->offset);
12607d8abfcbSKevin Wolf 		free(ctx);
126195533d5fSChristoph Hellwig 		return 0;
126295533d5fSChristoph Hellwig 	}
126395533d5fSChristoph Hellwig 
126495533d5fSChristoph Hellwig 	nr_iov = argc - optind;
1265cf57298aSChristoph Hellwig 	ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, pattern);
126695533d5fSChristoph Hellwig 
126795533d5fSChristoph Hellwig 	gettimeofday(&ctx->t1, NULL);
126895533d5fSChristoph Hellwig 	acb = bdrv_aio_writev(bs, ctx->offset >> 9, &ctx->qiov,
126995533d5fSChristoph Hellwig 			      ctx->qiov.size >> 9, aio_write_done, ctx);
12707d8abfcbSKevin Wolf 	if (!acb) {
12717d8abfcbSKevin Wolf 		free(ctx->buf);
12727d8abfcbSKevin Wolf 		free(ctx);
127395533d5fSChristoph Hellwig 		return -EIO;
12747d8abfcbSKevin Wolf 	}
127595533d5fSChristoph Hellwig 
127695533d5fSChristoph Hellwig 	return 0;
127795533d5fSChristoph Hellwig }
127895533d5fSChristoph Hellwig 
127995533d5fSChristoph Hellwig static int
128095533d5fSChristoph Hellwig aio_flush_f(int argc, char **argv)
128195533d5fSChristoph Hellwig {
128295533d5fSChristoph Hellwig 	qemu_aio_flush();
128395533d5fSChristoph Hellwig 	return 0;
128495533d5fSChristoph Hellwig }
128595533d5fSChristoph Hellwig 
128695533d5fSChristoph Hellwig static const cmdinfo_t aio_flush_cmd = {
128795533d5fSChristoph Hellwig 	.name		= "aio_flush",
128895533d5fSChristoph Hellwig 	.cfunc		= aio_flush_f,
1289e432cef9SChristoph Hellwig 	.oneline	= "completes all outstanding aio requests"
129095533d5fSChristoph Hellwig };
129195533d5fSChristoph Hellwig 
1292e3aff4f6Saliguori static int
1293e3aff4f6Saliguori flush_f(int argc, char **argv)
1294e3aff4f6Saliguori {
1295e3aff4f6Saliguori 	bdrv_flush(bs);
1296e3aff4f6Saliguori 	return 0;
1297e3aff4f6Saliguori }
1298e3aff4f6Saliguori 
1299e3aff4f6Saliguori static const cmdinfo_t flush_cmd = {
1300e3aff4f6Saliguori 	.name		= "flush",
1301e3aff4f6Saliguori 	.altname	= "f",
1302e3aff4f6Saliguori 	.cfunc		= flush_f,
1303e3aff4f6Saliguori 	.oneline	= "flush all in-core file state to disk",
1304e3aff4f6Saliguori };
1305e3aff4f6Saliguori 
1306e3aff4f6Saliguori static int
1307e3aff4f6Saliguori truncate_f(int argc, char **argv)
1308e3aff4f6Saliguori {
1309e3aff4f6Saliguori 	int64_t offset;
1310e3aff4f6Saliguori 	int ret;
1311e3aff4f6Saliguori 
1312e3aff4f6Saliguori 	offset = cvtnum(argv[1]);
1313e3aff4f6Saliguori 	if (offset < 0) {
1314e3aff4f6Saliguori 		printf("non-numeric truncate argument -- %s\n", argv[1]);
1315e3aff4f6Saliguori 		return 0;
1316e3aff4f6Saliguori 	}
1317e3aff4f6Saliguori 
1318e3aff4f6Saliguori 	ret = bdrv_truncate(bs, offset);
1319e3aff4f6Saliguori 	if (ret < 0) {
1320*0923c577SKevin Wolf 		printf("truncate: %s\n", strerror(-ret));
1321e3aff4f6Saliguori 		return 0;
1322e3aff4f6Saliguori 	}
1323e3aff4f6Saliguori 
1324e3aff4f6Saliguori 	return 0;
1325e3aff4f6Saliguori }
1326e3aff4f6Saliguori 
1327e3aff4f6Saliguori static const cmdinfo_t truncate_cmd = {
1328e3aff4f6Saliguori 	.name		= "truncate",
1329e3aff4f6Saliguori 	.altname	= "t",
1330e3aff4f6Saliguori 	.cfunc		= truncate_f,
1331e3aff4f6Saliguori 	.argmin		= 1,
1332e3aff4f6Saliguori 	.argmax		= 1,
1333e3aff4f6Saliguori 	.args		= "off",
1334e3aff4f6Saliguori 	.oneline	= "truncates the current file at the given offset",
1335e3aff4f6Saliguori };
1336e3aff4f6Saliguori 
1337e3aff4f6Saliguori static int
1338e3aff4f6Saliguori length_f(int argc, char **argv)
1339e3aff4f6Saliguori {
1340e3aff4f6Saliguori         int64_t size;
1341e3aff4f6Saliguori 	char s1[64];
1342e3aff4f6Saliguori 
1343e3aff4f6Saliguori 	size = bdrv_getlength(bs);
1344e3aff4f6Saliguori 	if (size < 0) {
1345*0923c577SKevin Wolf 		printf("getlength: %s\n", strerror(-size));
1346e3aff4f6Saliguori 		return 0;
1347e3aff4f6Saliguori 	}
1348e3aff4f6Saliguori 
1349e3aff4f6Saliguori 	cvtstr(size, s1, sizeof(s1));
1350e3aff4f6Saliguori 	printf("%s\n", s1);
1351e3aff4f6Saliguori 	return 0;
1352e3aff4f6Saliguori }
1353e3aff4f6Saliguori 
1354e3aff4f6Saliguori 
1355e3aff4f6Saliguori static const cmdinfo_t length_cmd = {
1356e3aff4f6Saliguori 	.name		= "length",
1357e3aff4f6Saliguori 	.altname	= "l",
1358e3aff4f6Saliguori 	.cfunc		= length_f,
1359e3aff4f6Saliguori 	.oneline	= "gets the length of the current file",
1360e3aff4f6Saliguori };
1361e3aff4f6Saliguori 
1362e3aff4f6Saliguori 
1363e3aff4f6Saliguori static int
1364e3aff4f6Saliguori info_f(int argc, char **argv)
1365e3aff4f6Saliguori {
1366e3aff4f6Saliguori 	BlockDriverInfo bdi;
1367e3aff4f6Saliguori 	char s1[64], s2[64];
1368e3aff4f6Saliguori 	int ret;
1369e3aff4f6Saliguori 
1370e3aff4f6Saliguori 	if (bs->drv && bs->drv->format_name)
1371e3aff4f6Saliguori 		printf("format name: %s\n", bs->drv->format_name);
1372e3aff4f6Saliguori 	if (bs->drv && bs->drv->protocol_name)
1373e3aff4f6Saliguori 		printf("format name: %s\n", bs->drv->protocol_name);
1374e3aff4f6Saliguori 
1375e3aff4f6Saliguori 	ret = bdrv_get_info(bs, &bdi);
1376e3aff4f6Saliguori 	if (ret)
1377e3aff4f6Saliguori 		return 0;
1378e3aff4f6Saliguori 
1379e3aff4f6Saliguori 	cvtstr(bdi.cluster_size, s1, sizeof(s1));
1380e3aff4f6Saliguori 	cvtstr(bdi.vm_state_offset, s2, sizeof(s2));
1381e3aff4f6Saliguori 
1382e3aff4f6Saliguori 	printf("cluster size: %s\n", s1);
1383e3aff4f6Saliguori 	printf("vm state offset: %s\n", s2);
1384e3aff4f6Saliguori 
1385e3aff4f6Saliguori 	return 0;
1386e3aff4f6Saliguori }
1387e3aff4f6Saliguori 
1388e3aff4f6Saliguori 
1389e3aff4f6Saliguori 
1390e3aff4f6Saliguori static const cmdinfo_t info_cmd = {
1391e3aff4f6Saliguori 	.name		= "info",
1392e3aff4f6Saliguori 	.altname	= "i",
1393e3aff4f6Saliguori 	.cfunc		= info_f,
1394e3aff4f6Saliguori 	.oneline	= "prints information about the current file",
1395e3aff4f6Saliguori };
1396e3aff4f6Saliguori 
1397e3aff4f6Saliguori static int
1398e3aff4f6Saliguori alloc_f(int argc, char **argv)
1399e3aff4f6Saliguori {
1400e3aff4f6Saliguori 	int64_t offset;
1401a7824a88SKevin Wolf 	int nb_sectors, remaining;
1402e3aff4f6Saliguori 	char s1[64];
1403a7824a88SKevin Wolf 	int num, sum_alloc;
1404e3aff4f6Saliguori 	int ret;
1405e3aff4f6Saliguori 
1406e3aff4f6Saliguori 	offset = cvtnum(argv[1]);
1407e3aff4f6Saliguori 	if (offset & 0x1ff) {
14080bfcd599SBlue Swirl                 printf("offset %" PRId64 " is not sector aligned\n",
14090bfcd599SBlue Swirl                        offset);
1410e3aff4f6Saliguori 		return 0;
1411e3aff4f6Saliguori 	}
1412e3aff4f6Saliguori 
1413e3aff4f6Saliguori 	if (argc == 3)
1414e3aff4f6Saliguori 		nb_sectors = cvtnum(argv[2]);
1415e3aff4f6Saliguori 	else
1416e3aff4f6Saliguori 		nb_sectors = 1;
1417e3aff4f6Saliguori 
1418a7824a88SKevin Wolf 	remaining = nb_sectors;
1419a7824a88SKevin Wolf 	sum_alloc = 0;
1420a7824a88SKevin Wolf 	while (remaining) {
1421e3aff4f6Saliguori 		ret = bdrv_is_allocated(bs, offset >> 9, nb_sectors, &num);
1422a7824a88SKevin Wolf 		remaining -= num;
1423a7824a88SKevin Wolf 		if (ret) {
1424a7824a88SKevin Wolf 			sum_alloc += num;
1425a7824a88SKevin Wolf 		}
1426a7824a88SKevin Wolf 	}
1427e3aff4f6Saliguori 
1428e3aff4f6Saliguori 	cvtstr(offset, s1, sizeof(s1));
1429e3aff4f6Saliguori 
1430e3aff4f6Saliguori 	if (nb_sectors == 1)
1431a7824a88SKevin Wolf 		printf("sector allocated at offset %s\n", s1);
1432e3aff4f6Saliguori 	else
1433a7824a88SKevin Wolf 		printf("%d/%d sectors allocated at offset %s\n",
1434a7824a88SKevin Wolf 			sum_alloc, nb_sectors, s1);
1435e3aff4f6Saliguori 	return 0;
1436e3aff4f6Saliguori }
1437e3aff4f6Saliguori 
1438e3aff4f6Saliguori static const cmdinfo_t alloc_cmd = {
1439e3aff4f6Saliguori 	.name		= "alloc",
1440e3aff4f6Saliguori 	.altname	= "a",
1441e3aff4f6Saliguori 	.argmin		= 1,
1442e3aff4f6Saliguori 	.argmax		= 2,
1443e3aff4f6Saliguori 	.cfunc		= alloc_f,
1444e3aff4f6Saliguori 	.args		= "off [sectors]",
1445e3aff4f6Saliguori 	.oneline	= "checks if a sector is present in the file",
1446e3aff4f6Saliguori };
1447e3aff4f6Saliguori 
1448e3aff4f6Saliguori static int
1449e3aff4f6Saliguori close_f(int argc, char **argv)
1450e3aff4f6Saliguori {
1451e3aff4f6Saliguori 	bdrv_close(bs);
1452e3aff4f6Saliguori 	bs = NULL;
1453e3aff4f6Saliguori 	return 0;
1454e3aff4f6Saliguori }
1455e3aff4f6Saliguori 
1456e3aff4f6Saliguori static const cmdinfo_t close_cmd = {
1457e3aff4f6Saliguori 	.name		= "close",
1458e3aff4f6Saliguori 	.altname	= "c",
1459e3aff4f6Saliguori 	.cfunc		= close_f,
1460e3aff4f6Saliguori 	.oneline	= "close the current open file",
1461e3aff4f6Saliguori };
1462e3aff4f6Saliguori 
14639c4bab26SChristoph Hellwig static int openfile(char *name, int flags, int growable)
1464e3aff4f6Saliguori {
1465e3aff4f6Saliguori 	if (bs) {
1466e3aff4f6Saliguori 		fprintf(stderr, "file open already, try 'help close'\n");
1467e3aff4f6Saliguori 		return 1;
1468e3aff4f6Saliguori 	}
1469e3aff4f6Saliguori 
14706db95603SChristoph Hellwig 	if (growable) {
14716db95603SChristoph Hellwig 		if (bdrv_file_open(&bs, name, flags)) {
14726db95603SChristoph Hellwig 			fprintf(stderr, "%s: can't open device %s\n", progname, name);
14736db95603SChristoph Hellwig 			return 1;
14746db95603SChristoph Hellwig 		}
14756db95603SChristoph Hellwig 	} else {
1476e3aff4f6Saliguori 		bs = bdrv_new("hda");
1477e3aff4f6Saliguori 		if (!bs)
1478e3aff4f6Saliguori 			return 1;
1479e3aff4f6Saliguori 
1480d6e9098eSKevin Wolf 		if (bdrv_open(bs, name, flags, NULL) < 0) {
1481e3aff4f6Saliguori 			fprintf(stderr, "%s: can't open device %s\n", progname, name);
1482e3aff4f6Saliguori 			bs = NULL;
1483e3aff4f6Saliguori 			return 1;
1484e3aff4f6Saliguori 		}
14859c4bab26SChristoph Hellwig 	}
14866db95603SChristoph Hellwig 
1487e3aff4f6Saliguori 	return 0;
1488e3aff4f6Saliguori }
1489e3aff4f6Saliguori 
1490e3aff4f6Saliguori static void
1491e3aff4f6Saliguori open_help(void)
1492e3aff4f6Saliguori {
1493e3aff4f6Saliguori 	printf(
1494e3aff4f6Saliguori "\n"
1495e3aff4f6Saliguori " opens a new file in the requested mode\n"
1496e3aff4f6Saliguori "\n"
1497e3aff4f6Saliguori " Example:\n"
1498e3aff4f6Saliguori " 'open -Cn /tmp/data' - creates/opens data file read-write and uncached\n"
1499e3aff4f6Saliguori "\n"
1500e3aff4f6Saliguori " Opens a file for subsequent use by all of the other qemu-io commands.\n"
1501e3aff4f6Saliguori " -r, -- open file read-only\n"
1502e3aff4f6Saliguori " -s, -- use snapshot file\n"
1503e3aff4f6Saliguori " -n, -- disable host cache\n"
15049c4bab26SChristoph Hellwig " -g, -- allow file to grow (only applies to protocols)"
1505e3aff4f6Saliguori "\n");
1506e3aff4f6Saliguori }
1507e3aff4f6Saliguori 
150822a2bdcbSBlue Swirl static int open_f(int argc, char **argv);
150922a2bdcbSBlue Swirl 
151022a2bdcbSBlue Swirl static const cmdinfo_t open_cmd = {
151122a2bdcbSBlue Swirl 	.name		= "open",
151222a2bdcbSBlue Swirl 	.altname	= "o",
151322a2bdcbSBlue Swirl 	.cfunc		= open_f,
151422a2bdcbSBlue Swirl 	.argmin		= 1,
151522a2bdcbSBlue Swirl 	.argmax		= -1,
151622a2bdcbSBlue Swirl 	.flags		= CMD_NOFILE_OK,
151722a2bdcbSBlue Swirl 	.args		= "[-Crsn] [path]",
151822a2bdcbSBlue Swirl 	.oneline	= "open the file specified by path",
151922a2bdcbSBlue Swirl 	.help		= open_help,
152022a2bdcbSBlue Swirl };
1521e3aff4f6Saliguori 
1522e3aff4f6Saliguori static int
1523e3aff4f6Saliguori open_f(int argc, char **argv)
1524e3aff4f6Saliguori {
1525e3aff4f6Saliguori 	int flags = 0;
1526e3aff4f6Saliguori 	int readonly = 0;
15279c4bab26SChristoph Hellwig 	int growable = 0;
1528e3aff4f6Saliguori 	int c;
1529e3aff4f6Saliguori 
15309a2d77adSChristoph Hellwig 	while ((c = getopt(argc, argv, "snrg")) != EOF) {
1531e3aff4f6Saliguori 		switch (c) {
1532e3aff4f6Saliguori 		case 's':
1533e3aff4f6Saliguori 			flags |= BDRV_O_SNAPSHOT;
1534e3aff4f6Saliguori 			break;
1535e3aff4f6Saliguori 		case 'n':
1536e3aff4f6Saliguori 			flags |= BDRV_O_NOCACHE;
1537e3aff4f6Saliguori 			break;
1538e3aff4f6Saliguori 		case 'r':
1539e3aff4f6Saliguori 			readonly = 1;
1540e3aff4f6Saliguori 			break;
15419c4bab26SChristoph Hellwig 		case 'g':
15429c4bab26SChristoph Hellwig 			growable = 1;
15439c4bab26SChristoph Hellwig 			break;
1544e3aff4f6Saliguori 		default:
1545e3aff4f6Saliguori 			return command_usage(&open_cmd);
1546e3aff4f6Saliguori 		}
1547e3aff4f6Saliguori 	}
1548e3aff4f6Saliguori 
1549f5edb014SNaphtali Sprei 	if (!readonly) {
1550e3aff4f6Saliguori             flags |= BDRV_O_RDWR;
1551f5edb014SNaphtali Sprei         }
1552e3aff4f6Saliguori 
1553e3aff4f6Saliguori 	if (optind != argc - 1)
1554e3aff4f6Saliguori 		return command_usage(&open_cmd);
1555e3aff4f6Saliguori 
15569c4bab26SChristoph Hellwig 	return openfile(argv[optind], flags, growable);
1557e3aff4f6Saliguori }
1558e3aff4f6Saliguori 
1559e3aff4f6Saliguori static int
1560e3aff4f6Saliguori init_args_command(
1561e3aff4f6Saliguori         int     index)
1562e3aff4f6Saliguori {
1563e3aff4f6Saliguori 	/* only one device allowed so far */
1564e3aff4f6Saliguori 	if (index >= 1)
1565e3aff4f6Saliguori 		return 0;
1566e3aff4f6Saliguori 	return ++index;
1567e3aff4f6Saliguori }
1568e3aff4f6Saliguori 
1569e3aff4f6Saliguori static int
1570e3aff4f6Saliguori init_check_command(
1571e3aff4f6Saliguori 	const cmdinfo_t *ct)
1572e3aff4f6Saliguori {
1573e3aff4f6Saliguori 	if (ct->flags & CMD_FLAG_GLOBAL)
1574e3aff4f6Saliguori 		return 1;
1575e3aff4f6Saliguori 	if (!(ct->flags & CMD_NOFILE_OK) && !bs) {
1576e3aff4f6Saliguori 		fprintf(stderr, "no file open, try 'help open'\n");
1577e3aff4f6Saliguori 		return 0;
1578e3aff4f6Saliguori 	}
1579e3aff4f6Saliguori 	return 1;
1580e3aff4f6Saliguori }
1581e3aff4f6Saliguori 
1582e3aff4f6Saliguori static void usage(const char *name)
1583e3aff4f6Saliguori {
1584e3aff4f6Saliguori 	printf(
15859a2d77adSChristoph Hellwig "Usage: %s [-h] [-V] [-rsnm] [-c cmd] ... [file]\n"
158684844a20SStefan Weil "QEMU Disk exerciser\n"
1587e3aff4f6Saliguori "\n"
1588e3aff4f6Saliguori "  -c, --cmd            command to execute\n"
1589e3aff4f6Saliguori "  -r, --read-only      export read-only\n"
1590e3aff4f6Saliguori "  -s, --snapshot       use snapshot file\n"
1591e3aff4f6Saliguori "  -n, --nocache        disable host cache\n"
15921db6947dSChristoph Hellwig "  -g, --growable       allow file to grow (only applies to protocols)\n"
1593e3aff4f6Saliguori "  -m, --misalign       misalign allocations for O_DIRECT\n"
15945c6c3a6cSChristoph Hellwig "  -k, --native-aio     use kernel AIO implementation (on Linux only)\n"
1595e3aff4f6Saliguori "  -h, --help           display this help and exit\n"
1596e3aff4f6Saliguori "  -V, --version        output version information and exit\n"
1597e3aff4f6Saliguori "\n",
1598e3aff4f6Saliguori 	name);
1599e3aff4f6Saliguori }
1600e3aff4f6Saliguori 
1601e3aff4f6Saliguori 
1602e3aff4f6Saliguori int main(int argc, char **argv)
1603e3aff4f6Saliguori {
1604e3aff4f6Saliguori 	int readonly = 0;
16059c4bab26SChristoph Hellwig 	int growable = 0;
16069a2d77adSChristoph Hellwig 	const char *sopt = "hVc:rsnmgk";
1607b32bb952SBlue Swirl         const struct option lopt[] = {
1608660f11beSBlue Swirl 		{ "help", 0, NULL, 'h' },
1609660f11beSBlue Swirl 		{ "version", 0, NULL, 'V' },
1610660f11beSBlue Swirl 		{ "offset", 1, NULL, 'o' },
1611660f11beSBlue Swirl 		{ "cmd", 1, NULL, 'c' },
1612660f11beSBlue Swirl 		{ "read-only", 0, NULL, 'r' },
1613660f11beSBlue Swirl 		{ "snapshot", 0, NULL, 's' },
1614660f11beSBlue Swirl 		{ "nocache", 0, NULL, 'n' },
1615660f11beSBlue Swirl 		{ "misalign", 0, NULL, 'm' },
1616660f11beSBlue Swirl 		{ "growable", 0, NULL, 'g' },
16175c6c3a6cSChristoph Hellwig 		{ "native-aio", 0, NULL, 'k' },
1618660f11beSBlue Swirl 		{ NULL, 0, NULL, 0 }
1619e3aff4f6Saliguori 	};
1620e3aff4f6Saliguori 	int c;
1621e3aff4f6Saliguori 	int opt_index = 0;
1622e3aff4f6Saliguori 	int flags = 0;
1623e3aff4f6Saliguori 
1624e3aff4f6Saliguori 	progname = basename(argv[0]);
1625e3aff4f6Saliguori 
1626e3aff4f6Saliguori 	while ((c = getopt_long(argc, argv, sopt, lopt, &opt_index)) != -1) {
1627e3aff4f6Saliguori 		switch (c) {
1628e3aff4f6Saliguori 		case 's':
1629e3aff4f6Saliguori 			flags |= BDRV_O_SNAPSHOT;
1630e3aff4f6Saliguori 			break;
1631e3aff4f6Saliguori 		case 'n':
1632e3aff4f6Saliguori 			flags |= BDRV_O_NOCACHE;
1633e3aff4f6Saliguori 			break;
1634e3aff4f6Saliguori 		case 'c':
1635e3aff4f6Saliguori 			add_user_command(optarg);
1636e3aff4f6Saliguori 			break;
1637e3aff4f6Saliguori 		case 'r':
1638e3aff4f6Saliguori 			readonly = 1;
1639e3aff4f6Saliguori 			break;
1640e3aff4f6Saliguori 		case 'm':
1641e3aff4f6Saliguori 			misalign = 1;
1642e3aff4f6Saliguori 			break;
16439c4bab26SChristoph Hellwig 		case 'g':
16449c4bab26SChristoph Hellwig 			growable = 1;
16459c4bab26SChristoph Hellwig 			break;
16465c6c3a6cSChristoph Hellwig 		case 'k':
16475c6c3a6cSChristoph Hellwig 			flags |= BDRV_O_NATIVE_AIO;
16485c6c3a6cSChristoph Hellwig 			break;
1649e3aff4f6Saliguori 		case 'V':
1650e3aff4f6Saliguori 			printf("%s version %s\n", progname, VERSION);
1651e3aff4f6Saliguori 			exit(0);
1652e3aff4f6Saliguori 		case 'h':
1653e3aff4f6Saliguori 			usage(progname);
1654e3aff4f6Saliguori 			exit(0);
1655e3aff4f6Saliguori 		default:
1656e3aff4f6Saliguori 			usage(progname);
1657e3aff4f6Saliguori 			exit(1);
1658e3aff4f6Saliguori 		}
1659e3aff4f6Saliguori 	}
1660e3aff4f6Saliguori 
1661e3aff4f6Saliguori 	if ((argc - optind) > 1) {
1662e3aff4f6Saliguori 		usage(progname);
1663e3aff4f6Saliguori 		exit(1);
1664e3aff4f6Saliguori 	}
1665e3aff4f6Saliguori 
1666e3aff4f6Saliguori 	bdrv_init();
1667e3aff4f6Saliguori 
1668e3aff4f6Saliguori 	/* initialize commands */
1669e3aff4f6Saliguori 	quit_init();
1670e3aff4f6Saliguori 	help_init();
1671e3aff4f6Saliguori 	add_command(&open_cmd);
1672e3aff4f6Saliguori 	add_command(&close_cmd);
1673e3aff4f6Saliguori 	add_command(&read_cmd);
1674e3aff4f6Saliguori 	add_command(&readv_cmd);
1675e3aff4f6Saliguori 	add_command(&write_cmd);
1676e3aff4f6Saliguori 	add_command(&writev_cmd);
1677776cbbbdSKevin Wolf 	add_command(&multiwrite_cmd);
167895533d5fSChristoph Hellwig 	add_command(&aio_read_cmd);
167995533d5fSChristoph Hellwig 	add_command(&aio_write_cmd);
168095533d5fSChristoph Hellwig 	add_command(&aio_flush_cmd);
1681e3aff4f6Saliguori 	add_command(&flush_cmd);
1682e3aff4f6Saliguori 	add_command(&truncate_cmd);
1683e3aff4f6Saliguori 	add_command(&length_cmd);
1684e3aff4f6Saliguori 	add_command(&info_cmd);
1685e3aff4f6Saliguori 	add_command(&alloc_cmd);
1686e3aff4f6Saliguori 
1687e3aff4f6Saliguori 	add_args_command(init_args_command);
1688e3aff4f6Saliguori 	add_check_command(init_check_command);
1689e3aff4f6Saliguori 
1690e3aff4f6Saliguori 	/* open the device */
1691f5edb014SNaphtali Sprei 	if (!readonly) {
1692e3aff4f6Saliguori             flags |= BDRV_O_RDWR;
1693f5edb014SNaphtali Sprei         }
1694e3aff4f6Saliguori 
1695e3aff4f6Saliguori 	if ((argc - optind) == 1)
16969c4bab26SChristoph Hellwig 		openfile(argv[optind], flags, growable);
1697e3aff4f6Saliguori 	command_loop();
1698e3aff4f6Saliguori 
169995533d5fSChristoph Hellwig 	/*
170095533d5fSChristoph Hellwig 	 * Make sure all outstanding requests get flushed the program exits.
170195533d5fSChristoph Hellwig 	 */
170295533d5fSChristoph Hellwig 	qemu_aio_flush();
170395533d5fSChristoph Hellwig 
1704e3aff4f6Saliguori 	if (bs)
1705e3aff4f6Saliguori 		bdrv_close(bs);
1706e3aff4f6Saliguori 	return 0;
1707e3aff4f6Saliguori }
1708