* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
+#include <sys/time.h>
#include <sys/types.h>
#include <stdarg.h>
#include <stdio.h>
#include <getopt.h>
+#include <libgen.h>
#include "qemu-common.h"
#include "block_int.h"
static int misalign;
+/*
+ * Parse the pattern argument to various sub-commands.
+ *
+ * Because the pattern is used as an argument to memset it must evaluate
+ * to an unsigned integer that fits into a single byte.
+ */
+static int parse_pattern(const char *arg)
+{
+ char *endptr = NULL;
+ long pattern;
+
+ pattern = strtol(arg, &endptr, 0);
+ if (pattern < 0 || pattern > UCHAR_MAX || *endptr != '\0') {
+ printf("%s is not a valid pattern byte\n", arg);
+ return -1;
+ }
+
+ return pattern;
+}
+
/*
* Memory allocation helpers.
*
}
}
+/*
+ * Parse multiple length statements for vectored I/O, and construct an I/O
+ * vector matching it.
+ */
+static void *
+create_iovec(QEMUIOVector *qiov, char **argv, int nr_iov, int pattern)
+{
+ size_t *sizes = calloc(nr_iov, sizeof(size_t));
+ size_t count = 0;
+ void *buf = NULL;
+ void *p;
+ int i;
+
+ for (i = 0; i < nr_iov; i++) {
+ char *arg = argv[i];
+ long long len;
+
+ len = cvtnum(arg);
+ if (len < 0) {
+ printf("non-numeric length argument -- %s\n", arg);
+ goto fail;
+ }
+
+ /* should be SIZE_T_MAX, but that doesn't exist */
+ if (len > UINT_MAX) {
+ printf("too large length argument -- %s\n", arg);
+ goto fail;
+ }
+
+ if (len & 0x1ff) {
+ printf("length argument %lld is not sector aligned\n",
+ len);
+ goto fail;
+ }
+
+ sizes[i] = len;
+ count += len;
+ }
+
+ qemu_iovec_init(qiov, nr_iov);
+
+ buf = p = qemu_io_alloc(count, pattern);
+
+ for (i = 0; i < nr_iov; i++) {
+ qemu_iovec_add(qiov, p, sizes[i]);
+ p += sizes[i];
+ }
+
+fail:
+ free(sizes);
+ return buf;
+}
+
static int do_read(char *buf, int64_t offset, int count, int *total)
{
int ret;
return 1;
}
+static int do_load_vmstate(char *buf, int64_t offset, int count, int *total)
+{
+ *total = bdrv_load_vmstate(bs, (uint8_t *)buf, offset, count);
+ if (*total < 0)
+ return *total;
+ return 1;
+}
+
+static int do_save_vmstate(char *buf, int64_t offset, int count, int *total)
+{
+ *total = bdrv_save_vmstate(bs, (uint8_t *)buf, offset, count);
+ if (*total < 0)
+ return *total;
+ return 1;
+}
+
#define NOT_DONE 0x7fffffff
static void aio_rw_done(void *opaque, int ret)
{
}
-static const cmdinfo_t read_cmd;
-
static void
read_help(void)
{
"\n"
" Reads a segment of the currently open file, optionally dumping it to the\n"
" standard output stream (with -v option) for subsequent inspection.\n"
+" -b, -- read from the VM state rather than the virtual disk\n"
" -C, -- report statistics in a machine parsable format\n"
" -l, -- length for pattern verification (only with -P)\n"
" -p, -- use bdrv_pread to read the file\n"
"\n");
}
+static int read_f(int argc, char **argv);
+
+static const cmdinfo_t read_cmd = {
+ .name = "read",
+ .altname = "r",
+ .cfunc = read_f,
+ .argmin = 2,
+ .argmax = -1,
+ .args = "[-abCpqv] [-P pattern [-s off] [-l len]] off len",
+ .oneline = "reads a number of bytes at a specified offset",
+ .help = read_help,
+};
+
static int
read_f(int argc, char **argv)
{
struct timeval t1, t2;
int Cflag = 0, pflag = 0, qflag = 0, vflag = 0;
- int Pflag = 0, sflag = 0, lflag = 0;
+ int Pflag = 0, sflag = 0, lflag = 0, bflag = 0;
int c, cnt;
char *buf;
int64_t offset;
int total = 0;
int pattern = 0, pattern_offset = 0, pattern_count = 0;
- while ((c = getopt(argc, argv, "Cl:pP:qs:v")) != EOF) {
+ while ((c = getopt(argc, argv, "bCl:pP:qs:v")) != EOF) {
switch (c) {
+ case 'b':
+ bflag = 1;
+ break;
case 'C':
Cflag = 1;
break;
break;
case 'P':
Pflag = 1;
- pattern = atoi(optarg);
+ pattern = parse_pattern(optarg);
+ if (pattern < 0)
+ return 0;
break;
case 'q':
qflag = 1;
if (optind != argc - 2)
return command_usage(&read_cmd);
+ if (bflag && pflag) {
+ printf("-b and -p cannot be specified at the same time\n");
+ return 0;
+ }
+
offset = cvtnum(argv[optind]);
if (offset < 0) {
printf("non-numeric length argument -- %s\n", argv[optind]);
gettimeofday(&t1, NULL);
if (pflag)
cnt = do_pread(buf, offset, count, &total);
+ else if (bflag)
+ cnt = do_load_vmstate(buf, offset, count, &total);
else
cnt = do_read(buf, offset, count, &total);
gettimeofday(&t2, NULL);
if (cnt < 0) {
printf("read failed: %s\n", strerror(-cnt));
- return 0;
+ goto out;
}
if (Pflag) {
}
if (qflag)
- return 0;
+ goto out;
if (vflag)
dump_buffer(buf, offset, count);
t2 = tsub(t2, t1);
print_report("read", &t2, offset, count, total, cnt, Cflag);
+out:
qemu_io_free(buf);
return 0;
}
-static const cmdinfo_t read_cmd = {
- .name = "read",
- .altname = "r",
- .cfunc = read_f,
- .argmin = 2,
- .argmax = -1,
- .args = "[-aCpqv] [-P pattern [-s off] [-l len]] off len",
- .oneline = "reads a number of bytes at a specified offset",
- .help = read_help,
-};
-
-static const cmdinfo_t readv_cmd;
-
static void
readv_help(void)
{
"\n");
}
+static int readv_f(int argc, char **argv);
+
+static const cmdinfo_t readv_cmd = {
+ .name = "readv",
+ .cfunc = readv_f,
+ .argmin = 2,
+ .argmax = -1,
+ .args = "[-Cqv] [-P pattern ] off len [len..]",
+ .oneline = "reads a number of bytes at a specified offset",
+ .help = readv_help,
+};
+
static int
readv_f(int argc, char **argv)
{
struct timeval t1, t2;
int Cflag = 0, qflag = 0, vflag = 0;
int c, cnt;
- char *buf, *p;
+ char *buf;
int64_t offset;
- int count = 0, total;
- int nr_iov, i;
+ /* Some compilers get confused and warn if this is not initialized. */
+ int total = 0;
+ int nr_iov;
QEMUIOVector qiov;
int pattern = 0;
int Pflag = 0;
break;
case 'P':
Pflag = 1;
- pattern = atoi(optarg);
+ pattern = parse_pattern(optarg);
+ if (pattern < 0)
+ return 0;
break;
case 'q':
qflag = 1;
return 0;
}
- if (count & 0x1ff) {
- printf("count %d is not sector aligned\n",
- count);
- return 0;
- }
-
- for (i = optind; i < argc; i++) {
- size_t len;
-
- len = cvtnum(argv[i]);
- if (len < 0) {
- printf("non-numeric length argument -- %s\n", argv[i]);
- return 0;
- }
- count += len;
- }
-
nr_iov = argc - optind;
- qemu_iovec_init(&qiov, nr_iov);
- buf = p = qemu_io_alloc(count, 0xab);
- for (i = 0; i < nr_iov; i++) {
- size_t len;
-
- len = cvtnum(argv[optind]);
- if (len < 0) {
- printf("non-numeric length argument -- %s\n",
- argv[optind]);
- return 0;
- }
-
- qemu_iovec_add(&qiov, p, len);
- p += len;
- optind++;
- }
+ buf = create_iovec(&qiov, &argv[optind], nr_iov, 0xab);
gettimeofday(&t1, NULL);
cnt = do_aio_readv(&qiov, offset, &total);
if (cnt < 0) {
printf("readv failed: %s\n", strerror(-cnt));
- return 0;
+ goto out;
}
if (Pflag) {
- void* cmp_buf = malloc(count);
- memset(cmp_buf, pattern, count);
- if (memcmp(buf, cmp_buf, count)) {
+ void* cmp_buf = malloc(qiov.size);
+ memset(cmp_buf, pattern, qiov.size);
+ if (memcmp(buf, cmp_buf, qiov.size)) {
printf("Pattern verification failed at offset %lld, "
- "%d bytes\n",
- (long long) offset, count);
+ "%zd bytes\n",
+ (long long) offset, qiov.size);
}
free(cmp_buf);
}
if (qflag)
- return 0;
+ goto out;
if (vflag)
dump_buffer(buf, offset, qiov.size);
t2 = tsub(t2, t1);
print_report("read", &t2, offset, qiov.size, total, cnt, Cflag);
+out:
qemu_io_free(buf);
-
return 0;
}
-static const cmdinfo_t readv_cmd = {
- .name = "readv",
- .cfunc = readv_f,
- .argmin = 2,
- .argmax = -1,
- .args = "[-Cqv] [-P pattern ] off len [len..]",
- .oneline = "reads a number of bytes at a specified offset",
- .help = readv_help,
-};
-
-static const cmdinfo_t write_cmd;
-
static void
write_help(void)
{
"\n"
" Writes into a segment of the currently open file, using a buffer\n"
" filled with a set pattern (0xcdcdcdcd).\n"
+" -b, -- write to the VM state rather than the virtual disk\n"
" -p, -- use bdrv_pwrite to write the file\n"
" -P, -- use different pattern to fill file\n"
" -C, -- report statistics in a machine parsable format\n"
"\n");
}
+static int write_f(int argc, char **argv);
+
+static const cmdinfo_t write_cmd = {
+ .name = "write",
+ .altname = "w",
+ .cfunc = write_f,
+ .argmin = 2,
+ .argmax = -1,
+ .args = "[-abCpq] [-P pattern ] off len",
+ .oneline = "writes a number of bytes at a specified offset",
+ .help = write_help,
+};
+
static int
write_f(int argc, char **argv)
{
struct timeval t1, t2;
- int Cflag = 0, pflag = 0, qflag = 0;
+ int Cflag = 0, pflag = 0, qflag = 0, bflag = 0;
int c, cnt;
char *buf;
int64_t offset;
int total = 0;
int pattern = 0xcd;
- while ((c = getopt(argc, argv, "CpP:q")) != EOF) {
+ while ((c = getopt(argc, argv, "bCpP:q")) != EOF) {
switch (c) {
+ case 'b':
+ bflag = 1;
+ break;
case 'C':
Cflag = 1;
break;
pflag = 1;
break;
case 'P':
- pattern = atoi(optarg);
+ pattern = parse_pattern(optarg);
+ if (pattern < 0)
+ return 0;
break;
case 'q':
qflag = 1;
if (optind != argc - 2)
return command_usage(&write_cmd);
+ if (bflag && pflag) {
+ printf("-b and -p cannot be specified at the same time\n");
+ return 0;
+ }
+
offset = cvtnum(argv[optind]);
if (offset < 0) {
printf("non-numeric length argument -- %s\n", argv[optind]);
gettimeofday(&t1, NULL);
if (pflag)
cnt = do_pwrite(buf, offset, count, &total);
+ else if (bflag)
+ cnt = do_save_vmstate(buf, offset, count, &total);
else
cnt = do_write(buf, offset, count, &total);
gettimeofday(&t2, NULL);
if (cnt < 0) {
printf("write failed: %s\n", strerror(-cnt));
- return 0;
+ goto out;
}
if (qflag)
- return 0;
+ goto out;
/* Finally, report back -- -C gives a parsable format */
t2 = tsub(t2, t1);
print_report("wrote", &t2, offset, count, total, cnt, Cflag);
+out:
qemu_io_free(buf);
return 0;
}
-static const cmdinfo_t write_cmd = {
- .name = "write",
- .altname = "w",
- .cfunc = write_f,
- .argmin = 2,
- .argmax = -1,
- .args = "[-aCpq] [-P pattern ] off len",
- .oneline = "writes a number of bytes at a specified offset",
- .help = write_help,
-};
-
-static const cmdinfo_t writev_cmd;
-
static void
writev_help(void)
{
"\n");
}
+static int writev_f(int argc, char **argv);
+
+static const cmdinfo_t writev_cmd = {
+ .name = "writev",
+ .cfunc = writev_f,
+ .argmin = 2,
+ .argmax = -1,
+ .args = "[-Cq] [-P pattern ] off len [len..]",
+ .oneline = "writes a number of bytes at a specified offset",
+ .help = writev_help,
+};
+
static int
writev_f(int argc, char **argv)
{
struct timeval t1, t2;
int Cflag = 0, qflag = 0;
int c, cnt;
- char *buf, *p;
+ char *buf;
int64_t offset;
- int count = 0, total;
- int nr_iov, i;
+ /* Some compilers get confused and warn if this is not initialized. */
+ int total = 0;
+ int nr_iov;
int pattern = 0xcd;
QEMUIOVector qiov;
qflag = 1;
break;
case 'P':
- pattern = atoi(optarg);
+ pattern = parse_pattern(optarg);
+ if (pattern < 0)
+ return 0;
break;
default:
return command_usage(&writev_cmd);
return 0;
}
- if (count & 0x1ff) {
- printf("count %d is not sector aligned\n",
- count);
- return 0;
- }
-
-
- for (i = optind; i < argc; i++) {
- size_t len;
-
- len = cvtnum(argv[optind]);
- if (len < 0) {
- printf("non-numeric length argument -- %s\n", argv[i]);
- return 0;
- }
- count += len;
- }
-
nr_iov = argc - optind;
- qemu_iovec_init(&qiov, nr_iov);
- buf = p = qemu_io_alloc(count, pattern);
- for (i = 0; i < nr_iov; i++) {
- size_t len;
-
- len = cvtnum(argv[optind]);
- if (len < 0) {
- printf("non-numeric length argument -- %s\n",
- argv[optind]);
- return 0;
- }
-
- qemu_iovec_add(&qiov, p, len);
- p += len;
- optind++;
- }
+ buf = create_iovec(&qiov, &argv[optind], nr_iov, pattern);
gettimeofday(&t1, NULL);
cnt = do_aio_writev(&qiov, offset, &total);
if (cnt < 0) {
printf("writev failed: %s\n", strerror(-cnt));
- return 0;
+ goto out;
}
if (qflag)
- return 0;
+ goto out;
/* Finally, report back -- -C gives a parsable format */
t2 = tsub(t2, t1);
print_report("wrote", &t2, offset, qiov.size, total, cnt, Cflag);
-
+out:
qemu_io_free(buf);
-
return 0;
}
-static const cmdinfo_t writev_cmd = {
- .name = "writev",
- .cfunc = writev_f,
- .argmin = 2,
- .argmax = -1,
- .args = "[-Cq] [-P pattern ] off len [len..]",
- .oneline = "writes a number of bytes at a specified offset",
- .help = writev_help,
-};
-
struct aio_ctx {
QEMUIOVector qiov;
int64_t offset;
if (ret < 0) {
printf("aio_write failed: %s\n", strerror(-ret));
- return;
+ goto out;
}
if (ctx->qflag) {
- return;
+ goto out;
}
/* Finally, report back -- -C gives a parsable format */
t2 = tsub(t2, ctx->t1);
print_report("wrote", &t2, ctx->offset, ctx->qiov.size,
ctx->qiov.size, 1, ctx->Cflag);
-
+out:
qemu_io_free(ctx->buf);
free(ctx);
}
-static const cmdinfo_t aio_read_cmd;
-
static void
aio_read_done(void *opaque, int ret)
{
if (ret < 0) {
printf("readv failed: %s\n", strerror(-ret));
- return;
+ goto out;
}
if (ctx->Pflag) {
}
if (ctx->qflag) {
- return;
+ goto out;
}
if (ctx->vflag) {
t2 = tsub(t2, ctx->t1);
print_report("read", &t2, ctx->offset, ctx->qiov.size,
ctx->qiov.size, 1, ctx->Cflag);
-
+out:
qemu_io_free(ctx->buf);
free(ctx);
}
"\n");
}
+static int aio_read_f(int argc, char **argv);
+
+static const cmdinfo_t aio_read_cmd = {
+ .name = "aio_read",
+ .cfunc = aio_read_f,
+ .argmin = 2,
+ .argmax = -1,
+ .args = "[-Cqv] [-P pattern ] off len [len..]",
+ .oneline = "asynchronously reads a number of bytes",
+ .help = aio_read_help,
+};
+
static int
aio_read_f(int argc, char **argv)
{
- char *p;
- int count = 0;
- int nr_iov, i, c;
+ int nr_iov, c;
struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx));
BlockDriverAIOCB *acb;
break;
case 'P':
ctx->Pflag = 1;
- ctx->pattern = atoi(optarg);
+ ctx->pattern = parse_pattern(optarg);
+ if (ctx->pattern < 0)
+ return 0;
break;
case 'q':
ctx->qflag = 1;
ctx->vflag = 1;
break;
default:
+ free(ctx);
return command_usage(&aio_read_cmd);
}
}
- if (optind > argc - 2)
+ if (optind > argc - 2) {
+ free(ctx);
return command_usage(&aio_read_cmd);
-
+ }
ctx->offset = cvtnum(argv[optind]);
if (ctx->offset < 0) {
printf("non-numeric length argument -- %s\n", argv[optind]);
+ free(ctx);
return 0;
}
optind++;
if (ctx->offset & 0x1ff) {
printf("offset %lld is not sector aligned\n",
(long long)ctx->offset);
+ free(ctx);
return 0;
}
- if (count & 0x1ff) {
- printf("count %d is not sector aligned\n",
- count);
- return 0;
- }
-
- for (i = optind; i < argc; i++) {
- size_t len;
-
- len = cvtnum(argv[i]);
- if (len < 0) {
- printf("non-numeric length argument -- %s\n", argv[i]);
- return 0;
- }
- count += len;
- }
-
nr_iov = argc - optind;
- qemu_iovec_init(&ctx->qiov, nr_iov);
- ctx->buf = p = qemu_io_alloc(count, 0xab);
- for (i = 0; i < nr_iov; i++) {
- size_t len;
-
- len = cvtnum(argv[optind]);
- if (len < 0) {
- printf("non-numeric length argument -- %s\n",
- argv[optind]);
- return 0;
- }
-
- qemu_iovec_add(&ctx->qiov, p, len);
- p += len;
- optind++;
- }
+ ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, 0xab);
gettimeofday(&ctx->t1, NULL);
acb = bdrv_aio_readv(bs, ctx->offset >> 9, &ctx->qiov,
ctx->qiov.size >> 9, aio_read_done, ctx);
- if (!acb)
+ if (!acb) {
+ free(ctx->buf);
+ free(ctx);
return -EIO;
+ }
return 0;
}
-static const cmdinfo_t aio_read_cmd = {
- .name = "aio_read",
- .cfunc = aio_read_f,
- .argmin = 2,
- .argmax = -1,
- .args = "[-Cqv] [-P pattern ] off len [len..]",
- .oneline = "asynchronously reads a number of bytes",
- .help = aio_read_help,
-};
-
-static const cmdinfo_t aio_write_cmd;
-
static void
aio_write_help(void)
{
"\n");
}
+static int aio_write_f(int argc, char **argv);
+
+static const cmdinfo_t aio_write_cmd = {
+ .name = "aio_write",
+ .cfunc = aio_write_f,
+ .argmin = 2,
+ .argmax = -1,
+ .args = "[-Cq] [-P pattern ] off len [len..]",
+ .oneline = "asynchronously writes a number of bytes",
+ .help = aio_write_help,
+};
static int
aio_write_f(int argc, char **argv)
{
- char *p;
- int count = 0;
- int nr_iov, i, c;
+ int nr_iov, c;
int pattern = 0xcd;
struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx));
BlockDriverAIOCB *acb;
ctx->qflag = 1;
break;
case 'P':
- pattern = atoi(optarg);
+ pattern = parse_pattern(optarg);
+ if (pattern < 0)
+ return 0;
break;
default:
+ free(ctx);
return command_usage(&aio_write_cmd);
}
}
- if (optind > argc - 2)
+ if (optind > argc - 2) {
+ free(ctx);
return command_usage(&aio_write_cmd);
+ }
ctx->offset = cvtnum(argv[optind]);
if (ctx->offset < 0) {
printf("non-numeric length argument -- %s\n", argv[optind]);
+ free(ctx);
return 0;
}
optind++;
if (ctx->offset & 0x1ff) {
printf("offset %lld is not sector aligned\n",
(long long)ctx->offset);
+ free(ctx);
return 0;
}
- if (count & 0x1ff) {
- printf("count %d is not sector aligned\n",
- count);
- return 0;
- }
-
- for (i = optind; i < argc; i++) {
- size_t len;
-
- len = cvtnum(argv[optind]);
- if (len < 0) {
- printf("non-numeric length argument -- %s\n", argv[i]);
- return 0;
- }
- count += len;
- }
-
nr_iov = argc - optind;
- qemu_iovec_init(&ctx->qiov, nr_iov);
- ctx->buf = p = qemu_io_alloc(count, pattern);
- for (i = 0; i < nr_iov; i++) {
- size_t len;
-
- len = cvtnum(argv[optind]);
- if (len < 0) {
- printf("non-numeric length argument -- %s\n",
- argv[optind]);
- return 0;
- }
-
- qemu_iovec_add(&ctx->qiov, p, len);
- p += len;
- optind++;
- }
+ ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, pattern);
gettimeofday(&ctx->t1, NULL);
acb = bdrv_aio_writev(bs, ctx->offset >> 9, &ctx->qiov,
ctx->qiov.size >> 9, aio_write_done, ctx);
- if (!acb)
+ if (!acb) {
+ free(ctx->buf);
+ free(ctx);
return -EIO;
+ }
return 0;
}
-static const cmdinfo_t aio_write_cmd = {
- .name = "aio_write",
- .cfunc = aio_write_f,
- .argmin = 2,
- .argmax = -1,
- .args = "[-Cq] [-P pattern ] off len [len..]",
- .oneline = "asynchronously writes a number of bytes",
- .help = aio_write_help,
-};
-
static int
aio_flush_f(int argc, char **argv)
{
alloc_f(int argc, char **argv)
{
int64_t offset;
- int nb_sectors;
+ int nb_sectors, remaining;
char s1[64];
- int num;
+ int num, sum_alloc;
int ret;
- const char *retstr;
offset = cvtnum(argv[1]);
if (offset & 0x1ff) {
else
nb_sectors = 1;
- ret = bdrv_is_allocated(bs, offset >> 9, nb_sectors, &num);
+ remaining = nb_sectors;
+ sum_alloc = 0;
+ while (remaining) {
+ ret = bdrv_is_allocated(bs, offset >> 9, nb_sectors, &num);
+ remaining -= num;
+ if (ret) {
+ sum_alloc += num;
+ }
+ }
cvtstr(offset, s1, sizeof(s1));
- retstr = ret ? "allocated" : "not allocated";
if (nb_sectors == 1)
- printf("sector %s at offset %s\n", retstr, s1);
+ printf("sector allocated at offset %s\n", s1);
else
- printf("%d/%d sectors %s at offset %s\n",
- num, nb_sectors, retstr, s1);
+ printf("%d/%d sectors allocated at offset %s\n",
+ sum_alloc, nb_sectors, s1);
return 0;
}
.oneline = "close the current open file",
};
-static int openfile(char *name, int flags)
+static int openfile(char *name, int flags, int growable)
{
if (bs) {
fprintf(stderr, "file open already, try 'help close'\n");
if (!bs)
return 1;
+ if (growable) {
+ flags |= BDRV_O_FILE;
+ }
+
if (bdrv_open(bs, name, flags) == -1) {
fprintf(stderr, "%s: can't open device %s\n", progname, name);
bs = NULL;
return 1;
}
+ if (growable) {
+ bs->growable = 1;
+ }
return 0;
}
" 'open -Cn /tmp/data' - creates/opens data file read-write and uncached\n"
"\n"
" Opens a file for subsequent use by all of the other qemu-io commands.\n"
-" -C, -- create new file if it doesn't exist\n"
" -r, -- open file read-only\n"
" -s, -- use snapshot file\n"
" -n, -- disable host cache\n"
+" -g, -- allow file to grow (only applies to protocols)"
"\n");
}
-static const cmdinfo_t open_cmd;
+static int open_f(int argc, char **argv);
+
+static const cmdinfo_t open_cmd = {
+ .name = "open",
+ .altname = "o",
+ .cfunc = open_f,
+ .argmin = 1,
+ .argmax = -1,
+ .flags = CMD_NOFILE_OK,
+ .args = "[-Crsn] [path]",
+ .oneline = "open the file specified by path",
+ .help = open_help,
+};
static int
open_f(int argc, char **argv)
{
int flags = 0;
int readonly = 0;
+ int growable = 0;
int c;
- while ((c = getopt(argc, argv, "snCr")) != EOF) {
+ while ((c = getopt(argc, argv, "snrg")) != EOF) {
switch (c) {
case 's':
flags |= BDRV_O_SNAPSHOT;
case 'n':
flags |= BDRV_O_NOCACHE;
break;
- case 'C':
- flags |= BDRV_O_CREAT;
- break;
case 'r':
readonly = 1;
break;
+ case 'g':
+ growable = 1;
+ break;
default:
return command_usage(&open_cmd);
}
}
- if (readonly)
- flags |= BDRV_O_RDONLY;
- else
- flags |= BDRV_O_RDWR;
+ if (!readonly) {
+ flags |= BDRV_O_RDWR;
+ }
if (optind != argc - 1)
return command_usage(&open_cmd);
- return openfile(argv[optind], flags);
+ return openfile(argv[optind], flags, growable);
}
-static const cmdinfo_t open_cmd = {
- .name = "open",
- .altname = "o",
- .cfunc = open_f,
- .argmin = 1,
- .argmax = -1,
- .flags = CMD_NOFILE_OK,
- .args = "[-Crsn] [path]",
- .oneline = "open the file specified by path",
- .help = open_help,
-};
-
static int
init_args_command(
int index)
static void usage(const char *name)
{
printf(
-"Usage: %s [-h] [-V] [-Crsnm] [-c cmd] ... [file]\n"
+"Usage: %s [-h] [-V] [-rsnm] [-c cmd] ... [file]\n"
"QEMU Disk exerciser\n"
"\n"
-" -C, --create create new file if it doesn't exist\n"
" -c, --cmd command to execute\n"
" -r, --read-only export read-only\n"
" -s, --snapshot use snapshot file\n"
" -n, --nocache disable host cache\n"
+" -g, --growable allow file to grow (only applies to protocols)\n"
" -m, --misalign misalign allocations for O_DIRECT\n"
+" -k, --native-aio use kernel AIO implementation (on Linux only)\n"
" -h, --help display this help and exit\n"
" -V, --version output version information and exit\n"
"\n",
int main(int argc, char **argv)
{
int readonly = 0;
- const char *sopt = "hVc:Crsnm";
- struct option lopt[] = {
- { "help", 0, 0, 'h' },
- { "version", 0, 0, 'V' },
- { "offset", 1, 0, 'o' },
- { "cmd", 1, 0, 'c' },
- { "create", 0, 0, 'C' },
- { "read-only", 0, 0, 'r' },
- { "snapshot", 0, 0, 's' },
- { "nocache", 0, 0, 'n' },
- { "misalign", 0, 0, 'm' },
- { NULL, 0, 0, 0 }
+ int growable = 0;
+ const char *sopt = "hVc:rsnmgk";
+ const struct option lopt[] = {
+ { "help", 0, NULL, 'h' },
+ { "version", 0, NULL, 'V' },
+ { "offset", 1, NULL, 'o' },
+ { "cmd", 1, NULL, 'c' },
+ { "read-only", 0, NULL, 'r' },
+ { "snapshot", 0, NULL, 's' },
+ { "nocache", 0, NULL, 'n' },
+ { "misalign", 0, NULL, 'm' },
+ { "growable", 0, NULL, 'g' },
+ { "native-aio", 0, NULL, 'k' },
+ { NULL, 0, NULL, 0 }
};
int c;
int opt_index = 0;
case 'c':
add_user_command(optarg);
break;
- case 'C':
- flags |= BDRV_O_CREAT;
- break;
case 'r':
readonly = 1;
break;
case 'm':
misalign = 1;
break;
+ case 'g':
+ growable = 1;
+ break;
+ case 'k':
+ flags |= BDRV_O_NATIVE_AIO;
+ break;
case 'V':
printf("%s version %s\n", progname, VERSION);
exit(0);
add_check_command(init_check_command);
/* open the device */
- if (readonly)
- flags |= BDRV_O_RDONLY;
- else
- flags |= BDRV_O_RDWR;
+ if (!readonly) {
+ flags |= BDRV_O_RDWR;
+ }
if ((argc - optind) == 1)
- openfile(argv[optind], flags);
+ openfile(argv[optind], flags, growable);
command_loop();
/*