Block patches for 2.7

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iQEcBAABCAAGBQJXNIZVAAoJEDuxQgLoOKytrQcH/1PleLZ6jzu1ZQLmrCx73OBf
 B8pLjSNvGxGQaFfc0SZi4kLhsVtk5s7CZwwY2i0xSnYetcrOa/w9ioLj4j9CkSpb
 zU80k+HeYagLGpF5TbVbMaBcZK0UAu0ti4eWGcbwN5rdpmO4sdpTrR5rx8n0dziW
 qj20p7Z9NfDPEQfMJ45Aco0cQ//NsAh4FaPCHdJvgIsrL7uoD9dQ6CN+DrstXQsq
 GRSS/doWCxohtdX01C5OLATvTKkEO10hrO9INo27Db/XC0PovaELZTa5lfQgYBlD
 zx4Xv2ga/dEf3pYWTj2/wPmBa06GUV3xts3WpWJqjbXkYbczWllYoqA4z7R0/lw=
 =A6+m
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'mreitz/tags/pull-block-for-kevin-2016-05-12' into queue-block

Block patches for 2.7

# gpg: Signature made Thu May 12 15:34:13 2016 CEST using RSA key ID E838ACAD
# gpg: Good signature from "Max Reitz <mreitz@redhat.com>"

* mreitz/tags/pull-block-for-kevin-2016-05-12:
  qemu-iotests: iotests: fail hard if not run via "check"
  block: enable testing of LUKS driver with block I/O tests
  block: add support for encryption secrets in block I/O tests
  block: add support for --image-opts in block I/O tests
  qemu-io: Add 'write -z -u' to test MAY_UNMAP flag
  qemu-io: Add 'write -f' to test FUA flag
  qemu-io: Allow unaligned access by default
  qemu-io: Use bool for command line flags
  qemu-io: Make 'open' subcommand more like command line
  qemu-io: Add missing option documentation
  qmp: add monitor command to add/remove a child
  quorum: implement bdrv_add_child() and bdrv_del_child()
  Add new block driver interface to add/delete a BDS's child
  qemu-img: check block status of backing file when converting.
  iotests: fix the redirection order in 083

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
Kevin Wolf 2016-05-12 15:35:20 +02:00
commit efc2645f71
28 changed files with 2053 additions and 900 deletions

51
block.c
View File

@ -1174,7 +1174,7 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
return child; return child;
} }
static BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
BlockDriverState *child_bs, BlockDriverState *child_bs,
const char *child_name, const char *child_name,
const BdrvChildRole *child_role) const BdrvChildRole *child_role)
@ -4011,3 +4011,52 @@ void bdrv_refresh_filename(BlockDriverState *bs)
QDECREF(json); QDECREF(json);
} }
} }
/*
* Hot add/remove a BDS's child. So the user can take a child offline when
* it is broken and take a new child online
*/
void bdrv_add_child(BlockDriverState *parent_bs, BlockDriverState *child_bs,
Error **errp)
{
if (!parent_bs->drv || !parent_bs->drv->bdrv_add_child) {
error_setg(errp, "The node %s does not support adding a child",
bdrv_get_device_or_node_name(parent_bs));
return;
}
if (!QLIST_EMPTY(&child_bs->parents)) {
error_setg(errp, "The node %s already has a parent",
child_bs->node_name);
return;
}
parent_bs->drv->bdrv_add_child(parent_bs, child_bs, errp);
}
void bdrv_del_child(BlockDriverState *parent_bs, BdrvChild *child, Error **errp)
{
BdrvChild *tmp;
if (!parent_bs->drv || !parent_bs->drv->bdrv_del_child) {
error_setg(errp, "The node %s does not support removing a child",
bdrv_get_device_or_node_name(parent_bs));
return;
}
QLIST_FOREACH(tmp, &parent_bs->children, next) {
if (tmp == child) {
break;
}
}
if (!tmp) {
error_setg(errp, "The node %s does not have a child named %s",
bdrv_get_device_or_node_name(parent_bs),
bdrv_get_device_or_node_name(child->bs));
return;
}
parent_bs->drv->bdrv_del_child(parent_bs, child, errp);
}

View File

@ -14,6 +14,7 @@
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu/cutils.h"
#include "block/block_int.h" #include "block/block_int.h"
#include "qapi/qmp/qbool.h" #include "qapi/qmp/qbool.h"
#include "qapi/qmp/qdict.h" #include "qapi/qmp/qdict.h"
@ -67,6 +68,9 @@ typedef struct QuorumVotes {
typedef struct BDRVQuorumState { typedef struct BDRVQuorumState {
BdrvChild **children; /* children BlockDriverStates */ BdrvChild **children; /* children BlockDriverStates */
int num_children; /* children count */ int num_children; /* children count */
unsigned next_child_index; /* the index of the next child that should
* be added
*/
int threshold; /* if less than threshold children reads gave the int threshold; /* if less than threshold children reads gave the
* same result a quorum error occurs. * same result a quorum error occurs.
*/ */
@ -883,9 +887,9 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags,
ret = -EINVAL; ret = -EINVAL;
goto exit; goto exit;
} }
if (s->num_children < 2) { if (s->num_children < 1) {
error_setg(&local_err, error_setg(&local_err,
"Number of provided children must be greater than 1"); "Number of provided children must be 1 or more");
ret = -EINVAL; ret = -EINVAL;
goto exit; goto exit;
} }
@ -949,6 +953,7 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags,
opened[i] = true; opened[i] = true;
} }
s->next_child_index = s->num_children;
g_free(opened); g_free(opened);
goto exit; goto exit;
@ -1005,6 +1010,72 @@ static void quorum_attach_aio_context(BlockDriverState *bs,
} }
} }
static void quorum_add_child(BlockDriverState *bs, BlockDriverState *child_bs,
Error **errp)
{
BDRVQuorumState *s = bs->opaque;
BdrvChild *child;
char indexstr[32];
int ret;
assert(s->num_children <= INT_MAX / sizeof(BdrvChild *));
if (s->num_children == INT_MAX / sizeof(BdrvChild *) ||
s->next_child_index == UINT_MAX) {
error_setg(errp, "Too many children");
return;
}
ret = snprintf(indexstr, 32, "children.%u", s->next_child_index);
if (ret < 0 || ret >= 32) {
error_setg(errp, "cannot generate child name");
return;
}
s->next_child_index++;
bdrv_drained_begin(bs);
/* We can safely add the child now */
bdrv_ref(child_bs);
child = bdrv_attach_child(bs, child_bs, indexstr, &child_format);
s->children = g_renew(BdrvChild *, s->children, s->num_children + 1);
s->children[s->num_children++] = child;
bdrv_drained_end(bs);
}
static void quorum_del_child(BlockDriverState *bs, BdrvChild *child,
Error **errp)
{
BDRVQuorumState *s = bs->opaque;
int i;
for (i = 0; i < s->num_children; i++) {
if (s->children[i] == child) {
break;
}
}
/* we have checked it in bdrv_del_child() */
assert(i < s->num_children);
if (s->num_children <= s->threshold) {
error_setg(errp,
"The number of children cannot be lower than the vote threshold %d",
s->threshold);
return;
}
bdrv_drained_begin(bs);
/* We can safely remove this child now */
memmove(&s->children[i], &s->children[i + 1],
(s->num_children - i - 1) * sizeof(BdrvChild *));
s->children = g_renew(BdrvChild *, s->children, --s->num_children);
bdrv_unref_child(bs, child);
bdrv_drained_end(bs);
}
static void quorum_refresh_filename(BlockDriverState *bs, QDict *options) static void quorum_refresh_filename(BlockDriverState *bs, QDict *options)
{ {
BDRVQuorumState *s = bs->opaque; BDRVQuorumState *s = bs->opaque;
@ -1059,6 +1130,9 @@ static BlockDriver bdrv_quorum = {
.bdrv_detach_aio_context = quorum_detach_aio_context, .bdrv_detach_aio_context = quorum_detach_aio_context,
.bdrv_attach_aio_context = quorum_attach_aio_context, .bdrv_attach_aio_context = quorum_attach_aio_context,
.bdrv_add_child = quorum_add_child,
.bdrv_del_child = quorum_del_child,
.is_filter = true, .is_filter = true,
.bdrv_recurse_is_first_non_filter = quorum_recurse_is_first_non_filter, .bdrv_recurse_is_first_non_filter = quorum_recurse_is_first_non_filter,
}; };

View File

@ -4092,6 +4092,61 @@ out:
aio_context_release(aio_context); aio_context_release(aio_context);
} }
static BdrvChild *bdrv_find_child(BlockDriverState *parent_bs,
const char *child_name)
{
BdrvChild *child;
QLIST_FOREACH(child, &parent_bs->children, next) {
if (strcmp(child->name, child_name) == 0) {
return child;
}
}
return NULL;
}
void qmp_x_blockdev_change(const char *parent, bool has_child,
const char *child, bool has_node,
const char *node, Error **errp)
{
BlockDriverState *parent_bs, *new_bs = NULL;
BdrvChild *p_child;
parent_bs = bdrv_lookup_bs(parent, parent, errp);
if (!parent_bs) {
return;
}
if (has_child == has_node) {
if (has_child) {
error_setg(errp, "The parameters child and node are in conflict");
} else {
error_setg(errp, "Either child or node must be specified");
}
return;
}
if (has_child) {
p_child = bdrv_find_child(parent_bs, child);
if (!p_child) {
error_setg(errp, "Node '%s' does not have child '%s'",
parent, child);
return;
}
bdrv_del_child(parent_bs, p_child, errp);
}
if (has_node) {
new_bs = bdrv_find_node(node);
if (!new_bs) {
error_setg(errp, "Node '%s' not found", node);
return;
}
bdrv_add_child(parent_bs, new_bs, errp);
}
}
BlockJobInfoList *qmp_query_block_jobs(Error **errp) BlockJobInfoList *qmp_query_block_jobs(Error **errp)
{ {
BlockJobInfoList *head = NULL, **p_next = &head; BlockJobInfoList *head = NULL, **p_next = &head;

View File

@ -476,6 +476,10 @@ void bdrv_disable_copy_on_read(BlockDriverState *bs);
void bdrv_ref(BlockDriverState *bs); void bdrv_ref(BlockDriverState *bs);
void bdrv_unref(BlockDriverState *bs); void bdrv_unref(BlockDriverState *bs);
void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child); void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child);
BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
BlockDriverState *child_bs,
const char *child_name,
const BdrvChildRole *child_role);
bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp); bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp);
void bdrv_op_block(BlockDriverState *bs, BlockOpType op, Error *reason); void bdrv_op_block(BlockDriverState *bs, BlockOpType op, Error *reason);
@ -542,4 +546,8 @@ void bdrv_drained_begin(BlockDriverState *bs);
*/ */
void bdrv_drained_end(BlockDriverState *bs); void bdrv_drained_end(BlockDriverState *bs);
void bdrv_add_child(BlockDriverState *parent, BlockDriverState *child,
Error **errp);
void bdrv_del_child(BlockDriverState *parent, BdrvChild *child, Error **errp);
#endif #endif

View File

@ -314,6 +314,11 @@ struct BlockDriver {
*/ */
void (*bdrv_drain)(BlockDriverState *bs); void (*bdrv_drain)(BlockDriverState *bs);
void (*bdrv_add_child)(BlockDriverState *parent, BlockDriverState *child,
Error **errp);
void (*bdrv_del_child)(BlockDriverState *parent, BdrvChild *child,
Error **errp);
QLIST_ENTRY(BlockDriver) list; QLIST_ENTRY(BlockDriver) list;
}; };

View File

@ -2556,3 +2556,35 @@
## ##
{ 'command': 'block-set-write-threshold', { 'command': 'block-set-write-threshold',
'data': { 'node-name': 'str', 'write-threshold': 'uint64' } } 'data': { 'node-name': 'str', 'write-threshold': 'uint64' } }
##
# @x-blockdev-change
#
# Dynamically reconfigure the block driver state graph. It can be used
# to add, remove, insert or replace a graph node. Currently only the
# Quorum driver implements this feature to add or remove its child. This
# is useful to fix a broken quorum child.
#
# If @node is specified, it will be inserted under @parent. @child
# may not be specified in this case. If both @parent and @child are
# specified but @node is not, @child will be detached from @parent.
#
# @parent: the id or name of the parent node.
#
# @child: #optional the name of a child under the given parent node.
#
# @node: #optional the name of the node that will be added.
#
# Note: this command is experimental, and its API is not stable. It
# does not support all kinds of operations, all kinds of children, nor
# all block drivers.
#
# Warning: The data in a new quorum child MUST be consistent with that of
# the rest of the array.
#
# Since: 2.7
##
{ 'command': 'x-blockdev-change',
'data' : { 'parent': 'str',
'*child': 'str',
'*node': 'str' } }

View File

@ -1475,10 +1475,21 @@ static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num)
} else if (!s->target_has_backing) { } else if (!s->target_has_backing) {
/* Without a target backing file we must copy over the contents of /* Without a target backing file we must copy over the contents of
* the backing file as well. */ * the backing file as well. */
/* TODO Check block status of the backing file chain to avoid /* Check block status of the backing file chain to avoid
* needlessly reading zeroes and limiting the iteration to the * needlessly reading zeroes and limiting the iteration to the
* buffer size */ * buffer size */
ret = bdrv_get_block_status_above(blk_bs(s->src[s->src_cur]), NULL,
sector_num - s->src_cur_offset,
n, &n, &file);
if (ret < 0) {
return ret;
}
if (ret & BDRV_BLOCK_ZERO) {
s->status = BLK_ZERO;
} else {
s->status = BLK_DATA; s->status = BLK_DATA;
}
} else { } else {
s->status = BLK_BACKING_FILE; s->status = BLK_BACKING_FILE;
} }

View File

@ -1,7 +1,7 @@
/* /*
* Command line utility to exercise the QEMU I/O path. * Command line utility to exercise the QEMU I/O path.
* *
* Copyright (C) 2009 Red Hat, Inc. * Copyright (C) 2009-2016 Red Hat, Inc.
* Copyright (c) 2003-2005 Silicon Graphics, Inc. * Copyright (c) 2003-2005 Silicon Graphics, Inc.
* *
* This work is licensed under the terms of the GNU GPL, version 2 or later. * This work is licensed under the terms of the GNU GPL, version 2 or later.
@ -345,7 +345,7 @@ static void dump_buffer(const void *buffer, int64_t offset, int64_t len)
} }
static void print_report(const char *op, struct timeval *t, int64_t offset, static void print_report(const char *op, struct timeval *t, int64_t offset,
int64_t count, int64_t total, int cnt, int Cflag) int64_t count, int64_t total, int cnt, bool Cflag)
{ {
char s1[64], s2[64], ts[64]; char s1[64], s2[64], ts[64];
@ -395,12 +395,6 @@ create_iovec(BlockBackend *blk, QEMUIOVector *qiov, char **argv, int nr_iov,
goto fail; goto fail;
} }
if (len & 0x1ff) {
printf("length argument %" PRId64
" is not sector aligned\n", len);
goto fail;
}
sizes[i] = len; sizes[i] = len;
count += len; count += len;
} }
@ -434,13 +428,13 @@ static int do_pread(BlockBackend *blk, char *buf, int64_t offset,
} }
static int do_pwrite(BlockBackend *blk, char *buf, int64_t offset, static int do_pwrite(BlockBackend *blk, char *buf, int64_t offset,
int64_t count, int64_t *total) int64_t count, int flags, int64_t *total)
{ {
if (count > INT_MAX) { if (count > INT_MAX) {
return -ERANGE; return -ERANGE;
} }
*total = blk_pwrite(blk, offset, (uint8_t *)buf, count, 0); *total = blk_pwrite(blk, offset, (uint8_t *)buf, count, flags);
if (*total < 0) { if (*total < 0) {
return *total; return *total;
} }
@ -452,6 +446,7 @@ typedef struct {
int64_t offset; int64_t offset;
int64_t count; int64_t count;
int64_t *total; int64_t *total;
int flags;
int ret; int ret;
bool done; bool done;
} CoWriteZeroes; } CoWriteZeroes;
@ -460,7 +455,8 @@ static void coroutine_fn co_write_zeroes_entry(void *opaque)
{ {
CoWriteZeroes *data = opaque; CoWriteZeroes *data = opaque;
data->ret = blk_co_write_zeroes(data->blk, data->offset, data->count, 0); data->ret = blk_co_write_zeroes(data->blk, data->offset, data->count,
data->flags);
data->done = true; data->done = true;
if (data->ret < 0) { if (data->ret < 0) {
*data->total = data->ret; *data->total = data->ret;
@ -471,7 +467,7 @@ static void coroutine_fn co_write_zeroes_entry(void *opaque)
} }
static int do_co_write_zeroes(BlockBackend *blk, int64_t offset, int64_t count, static int do_co_write_zeroes(BlockBackend *blk, int64_t offset, int64_t count,
int64_t *total) int flags, int64_t *total)
{ {
Coroutine *co; Coroutine *co;
CoWriteZeroes data = { CoWriteZeroes data = {
@ -479,6 +475,7 @@ static int do_co_write_zeroes(BlockBackend *blk, int64_t offset, int64_t count,
.offset = offset, .offset = offset,
.count = count, .count = count,
.total = total, .total = total,
.flags = flags,
.done = false, .done = false,
}; };
@ -564,11 +561,11 @@ static int do_aio_readv(BlockBackend *blk, QEMUIOVector *qiov,
} }
static int do_aio_writev(BlockBackend *blk, QEMUIOVector *qiov, static int do_aio_writev(BlockBackend *blk, QEMUIOVector *qiov,
int64_t offset, int *total) int64_t offset, int flags, int *total)
{ {
int async_ret = NOT_DONE; int async_ret = NOT_DONE;
blk_aio_pwritev(blk, offset, qiov, 0, aio_rw_done, &async_ret); blk_aio_pwritev(blk, offset, qiov, flags, aio_rw_done, &async_ret);
while (async_ret == NOT_DONE) { while (async_ret == NOT_DONE) {
main_loop_wait(false); main_loop_wait(false);
} }
@ -634,7 +631,7 @@ static void read_help(void)
" -b, -- read from the VM state rather than the virtual disk\n" " -b, -- read from the VM state rather than the virtual disk\n"
" -C, -- report statistics in a machine parsable format\n" " -C, -- report statistics in a machine parsable format\n"
" -l, -- length for pattern verification (only with -P)\n" " -l, -- length for pattern verification (only with -P)\n"
" -p, -- allow unaligned access\n" " -p, -- ignored for backwards compatibility\n"
" -P, -- use a pattern to verify read data\n" " -P, -- use a pattern to verify read data\n"
" -q, -- quiet mode, do not show I/O statistics\n" " -q, -- quiet mode, do not show I/O statistics\n"
" -s, -- start offset for pattern verification (only with -P)\n" " -s, -- start offset for pattern verification (only with -P)\n"
@ -650,7 +647,7 @@ static const cmdinfo_t read_cmd = {
.cfunc = read_f, .cfunc = read_f,
.argmin = 2, .argmin = 2,
.argmax = -1, .argmax = -1,
.args = "[-abCpqv] [-P pattern [-s off] [-l len]] off len", .args = "[-abCqv] [-P pattern [-s off] [-l len]] off len",
.oneline = "reads a number of bytes at a specified offset", .oneline = "reads a number of bytes at a specified offset",
.help = read_help, .help = read_help,
}; };
@ -658,8 +655,8 @@ static const cmdinfo_t read_cmd = {
static int read_f(BlockBackend *blk, int argc, char **argv) static int read_f(BlockBackend *blk, int argc, char **argv)
{ {
struct timeval t1, t2; struct timeval t1, t2;
int Cflag = 0, pflag = 0, qflag = 0, vflag = 0; bool Cflag = false, qflag = false, vflag = false;
int Pflag = 0, sflag = 0, lflag = 0, bflag = 0; bool Pflag = false, sflag = false, lflag = false, bflag = false;
int c, cnt; int c, cnt;
char *buf; char *buf;
int64_t offset; int64_t offset;
@ -672,13 +669,13 @@ static int read_f(BlockBackend *blk, int argc, char **argv)
while ((c = getopt(argc, argv, "bCl:pP:qs:v")) != -1) { while ((c = getopt(argc, argv, "bCl:pP:qs:v")) != -1) {
switch (c) { switch (c) {
case 'b': case 'b':
bflag = 1; bflag = true;
break; break;
case 'C': case 'C':
Cflag = 1; Cflag = true;
break; break;
case 'l': case 'l':
lflag = 1; lflag = true;
pattern_count = cvtnum(optarg); pattern_count = cvtnum(optarg);
if (pattern_count < 0) { if (pattern_count < 0) {
print_cvtnum_err(pattern_count, optarg); print_cvtnum_err(pattern_count, optarg);
@ -686,20 +683,20 @@ static int read_f(BlockBackend *blk, int argc, char **argv)
} }
break; break;
case 'p': case 'p':
pflag = 1; /* Ignored for backwards compatibility */
break; break;
case 'P': case 'P':
Pflag = 1; Pflag = true;
pattern = parse_pattern(optarg); pattern = parse_pattern(optarg);
if (pattern < 0) { if (pattern < 0) {
return 0; return 0;
} }
break; break;
case 'q': case 'q':
qflag = 1; qflag = true;
break; break;
case 's': case 's':
sflag = 1; sflag = true;
pattern_offset = cvtnum(optarg); pattern_offset = cvtnum(optarg);
if (pattern_offset < 0) { if (pattern_offset < 0) {
print_cvtnum_err(pattern_offset, optarg); print_cvtnum_err(pattern_offset, optarg);
@ -707,7 +704,7 @@ static int read_f(BlockBackend *blk, int argc, char **argv)
} }
break; break;
case 'v': case 'v':
vflag = 1; vflag = true;
break; break;
default: default:
return qemuio_command_usage(&read_cmd); return qemuio_command_usage(&read_cmd);
@ -718,11 +715,6 @@ static int read_f(BlockBackend *blk, int argc, char **argv)
return qemuio_command_usage(&read_cmd); return qemuio_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]); offset = cvtnum(argv[optind]);
if (offset < 0) { if (offset < 0) {
print_cvtnum_err(offset, argv[optind]); print_cvtnum_err(offset, argv[optind]);
@ -753,7 +745,7 @@ static int read_f(BlockBackend *blk, int argc, char **argv)
return 0; return 0;
} }
if (!pflag) { if (bflag) {
if (offset & 0x1ff) { if (offset & 0x1ff) {
printf("offset %" PRId64 " is not sector aligned\n", printf("offset %" PRId64 " is not sector aligned\n",
offset); offset);
@ -844,7 +836,7 @@ static const cmdinfo_t readv_cmd = {
static int readv_f(BlockBackend *blk, int argc, char **argv) static int readv_f(BlockBackend *blk, int argc, char **argv)
{ {
struct timeval t1, t2; struct timeval t1, t2;
int Cflag = 0, qflag = 0, vflag = 0; bool Cflag = false, qflag = false, vflag = false;
int c, cnt; int c, cnt;
char *buf; char *buf;
int64_t offset; int64_t offset;
@ -853,25 +845,25 @@ static int readv_f(BlockBackend *blk, int argc, char **argv)
int nr_iov; int nr_iov;
QEMUIOVector qiov; QEMUIOVector qiov;
int pattern = 0; int pattern = 0;
int Pflag = 0; bool Pflag = false;
while ((c = getopt(argc, argv, "CP:qv")) != -1) { while ((c = getopt(argc, argv, "CP:qv")) != -1) {
switch (c) { switch (c) {
case 'C': case 'C':
Cflag = 1; Cflag = true;
break; break;
case 'P': case 'P':
Pflag = 1; Pflag = true;
pattern = parse_pattern(optarg); pattern = parse_pattern(optarg);
if (pattern < 0) { if (pattern < 0) {
return 0; return 0;
} }
break; break;
case 'q': case 'q':
qflag = 1; qflag = true;
break; break;
case 'v': case 'v':
vflag = 1; vflag = true;
break; break;
default: default:
return qemuio_command_usage(&readv_cmd); return qemuio_command_usage(&readv_cmd);
@ -890,12 +882,6 @@ static int readv_f(BlockBackend *blk, int argc, char **argv)
} }
optind++; optind++;
if (offset & 0x1ff) {
printf("offset %" PRId64 " is not sector aligned\n",
offset);
return 0;
}
nr_iov = argc - optind; nr_iov = argc - optind;
buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, 0xab); buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, 0xab);
if (buf == NULL) { if (buf == NULL) {
@ -952,10 +938,12 @@ static void write_help(void)
" filled with a set pattern (0xcdcdcdcd).\n" " filled with a set pattern (0xcdcdcdcd).\n"
" -b, -- write to the VM state rather than the virtual disk\n" " -b, -- write to the VM state rather than the virtual disk\n"
" -c, -- write compressed data with blk_write_compressed\n" " -c, -- write compressed data with blk_write_compressed\n"
" -p, -- allow unaligned access\n" " -f, -- use Force Unit Access semantics\n"
" -p, -- ignored for backwards compatibility\n"
" -P, -- use different pattern to fill file\n" " -P, -- use different pattern to fill file\n"
" -C, -- report statistics in a machine parsable format\n" " -C, -- report statistics in a machine parsable format\n"
" -q, -- quiet mode, do not show I/O statistics\n" " -q, -- quiet mode, do not show I/O statistics\n"
" -u, -- with -z, allow unmapping\n"
" -z, -- write zeroes using blk_co_write_zeroes\n" " -z, -- write zeroes using blk_co_write_zeroes\n"
"\n"); "\n");
} }
@ -968,7 +956,7 @@ static const cmdinfo_t write_cmd = {
.cfunc = write_f, .cfunc = write_f,
.argmin = 2, .argmin = 2,
.argmax = -1, .argmax = -1,
.args = "[-bcCpqz] [-P pattern ] off len", .args = "[-bcCfquz] [-P pattern] off len",
.oneline = "writes a number of bytes at a specified offset", .oneline = "writes a number of bytes at a specified offset",
.help = write_help, .help = write_help,
}; };
@ -976,8 +964,9 @@ static const cmdinfo_t write_cmd = {
static int write_f(BlockBackend *blk, int argc, char **argv) static int write_f(BlockBackend *blk, int argc, char **argv)
{ {
struct timeval t1, t2; struct timeval t1, t2;
int Cflag = 0, pflag = 0, qflag = 0, bflag = 0, Pflag = 0, zflag = 0; bool Cflag = false, qflag = false, bflag = false;
int cflag = 0; bool Pflag = false, zflag = false, cflag = false;
int flags = 0;
int c, cnt; int c, cnt;
char *buf = NULL; char *buf = NULL;
int64_t offset; int64_t offset;
@ -986,32 +975,38 @@ static int write_f(BlockBackend *blk, int argc, char **argv)
int64_t total = 0; int64_t total = 0;
int pattern = 0xcd; int pattern = 0xcd;
while ((c = getopt(argc, argv, "bcCpP:qz")) != -1) { while ((c = getopt(argc, argv, "bcCfpP:quz")) != -1) {
switch (c) { switch (c) {
case 'b': case 'b':
bflag = 1; bflag = true;
break; break;
case 'c': case 'c':
cflag = 1; cflag = true;
break; break;
case 'C': case 'C':
Cflag = 1; Cflag = true;
break;
case 'f':
flags |= BDRV_REQ_FUA;
break; break;
case 'p': case 'p':
pflag = 1; /* Ignored for backwards compatibility */
break; break;
case 'P': case 'P':
Pflag = 1; Pflag = true;
pattern = parse_pattern(optarg); pattern = parse_pattern(optarg);
if (pattern < 0) { if (pattern < 0) {
return 0; return 0;
} }
break; break;
case 'q': case 'q':
qflag = 1; qflag = true;
break;
case 'u':
flags |= BDRV_REQ_MAY_UNMAP;
break; break;
case 'z': case 'z':
zflag = 1; zflag = true;
break; break;
default: default:
return qemuio_command_usage(&write_cmd); return qemuio_command_usage(&write_cmd);
@ -1022,8 +1017,18 @@ static int write_f(BlockBackend *blk, int argc, char **argv)
return qemuio_command_usage(&write_cmd); return qemuio_command_usage(&write_cmd);
} }
if (bflag + pflag + zflag > 1) { if (bflag && zflag) {
printf("-b, -p, or -z cannot be specified at the same time\n"); printf("-b and -z cannot be specified at the same time\n");
return 0;
}
if ((flags & BDRV_REQ_FUA) && (bflag || cflag)) {
printf("-f and -b or -c cannot be specified at the same time\n");
return 0;
}
if ((flags & BDRV_REQ_MAY_UNMAP) && !zflag) {
printf("-u requires -z to be specified\n");
return 0; return 0;
} }
@ -1049,7 +1054,7 @@ static int write_f(BlockBackend *blk, int argc, char **argv)
return 0; return 0;
} }
if (!pflag) { if (bflag || cflag) {
if (offset & 0x1ff) { if (offset & 0x1ff) {
printf("offset %" PRId64 " is not sector aligned\n", printf("offset %" PRId64 " is not sector aligned\n",
offset); offset);
@ -1071,11 +1076,11 @@ static int write_f(BlockBackend *blk, int argc, char **argv)
if (bflag) { if (bflag) {
cnt = do_save_vmstate(blk, buf, offset, count, &total); cnt = do_save_vmstate(blk, buf, offset, count, &total);
} else if (zflag) { } else if (zflag) {
cnt = do_co_write_zeroes(blk, offset, count, &total); cnt = do_co_write_zeroes(blk, offset, count, flags, &total);
} else if (cflag) { } else if (cflag) {
cnt = do_write_compressed(blk, buf, offset, count, &total); cnt = do_write_compressed(blk, buf, offset, count, &total);
} else { } else {
cnt = do_pwrite(blk, buf, offset, count, &total); cnt = do_pwrite(blk, buf, offset, count, flags, &total);
} }
gettimeofday(&t2, NULL); gettimeofday(&t2, NULL);
@ -1114,6 +1119,7 @@ writev_help(void)
" filled with a set pattern (0xcdcdcdcd).\n" " filled with a set pattern (0xcdcdcdcd).\n"
" -P, -- use different pattern to fill file\n" " -P, -- use different pattern to fill file\n"
" -C, -- report statistics in a machine parsable format\n" " -C, -- report statistics in a machine parsable format\n"
" -f, -- use Force Unit Access semantics\n"
" -q, -- quiet mode, do not show I/O statistics\n" " -q, -- quiet mode, do not show I/O statistics\n"
"\n"); "\n");
} }
@ -1125,7 +1131,7 @@ static const cmdinfo_t writev_cmd = {
.cfunc = writev_f, .cfunc = writev_f,
.argmin = 2, .argmin = 2,
.argmax = -1, .argmax = -1,
.args = "[-Cq] [-P pattern ] off len [len..]", .args = "[-Cfq] [-P pattern] off len [len..]",
.oneline = "writes a number of bytes at a specified offset", .oneline = "writes a number of bytes at a specified offset",
.help = writev_help, .help = writev_help,
}; };
@ -1133,7 +1139,8 @@ static const cmdinfo_t writev_cmd = {
static int writev_f(BlockBackend *blk, int argc, char **argv) static int writev_f(BlockBackend *blk, int argc, char **argv)
{ {
struct timeval t1, t2; struct timeval t1, t2;
int Cflag = 0, qflag = 0; bool Cflag = false, qflag = false;
int flags = 0;
int c, cnt; int c, cnt;
char *buf; char *buf;
int64_t offset; int64_t offset;
@ -1146,10 +1153,13 @@ static int writev_f(BlockBackend *blk, int argc, char **argv)
while ((c = getopt(argc, argv, "CqP:")) != -1) { while ((c = getopt(argc, argv, "CqP:")) != -1) {
switch (c) { switch (c) {
case 'C': case 'C':
Cflag = 1; Cflag = true;
break;
case 'f':
flags |= BDRV_REQ_FUA;
break; break;
case 'q': case 'q':
qflag = 1; qflag = true;
break; break;
case 'P': case 'P':
pattern = parse_pattern(optarg); pattern = parse_pattern(optarg);
@ -1173,12 +1183,6 @@ static int writev_f(BlockBackend *blk, int argc, char **argv)
} }
optind++; optind++;
if (offset & 0x1ff) {
printf("offset %" PRId64 " is not sector aligned\n",
offset);
return 0;
}
nr_iov = argc - optind; nr_iov = argc - optind;
buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, pattern); buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, pattern);
if (buf == NULL) { if (buf == NULL) {
@ -1186,7 +1190,7 @@ static int writev_f(BlockBackend *blk, int argc, char **argv)
} }
gettimeofday(&t1, NULL); gettimeofday(&t1, NULL);
cnt = do_aio_writev(blk, &qiov, offset, &total); cnt = do_aio_writev(blk, &qiov, offset, flags, &total);
gettimeofday(&t2, NULL); gettimeofday(&t2, NULL);
if (cnt < 0) { if (cnt < 0) {
@ -1242,7 +1246,7 @@ static const cmdinfo_t multiwrite_cmd = {
static int multiwrite_f(BlockBackend *blk, int argc, char **argv) static int multiwrite_f(BlockBackend *blk, int argc, char **argv)
{ {
struct timeval t1, t2; struct timeval t1, t2;
int Cflag = 0, qflag = 0; bool Cflag = false, qflag = false;
int c, cnt; int c, cnt;
char **buf; char **buf;
int64_t offset, first_offset = 0; int64_t offset, first_offset = 0;
@ -1258,10 +1262,10 @@ static int multiwrite_f(BlockBackend *blk, int argc, char **argv)
while ((c = getopt(argc, argv, "CqP:")) != -1) { while ((c = getopt(argc, argv, "CqP:")) != -1) {
switch (c) { switch (c) {
case 'C': case 'C':
Cflag = 1; Cflag = true;
break; break;
case 'q': case 'q':
qflag = 1; qflag = true;
break; break;
case 'P': case 'P':
pattern = parse_pattern(optarg); pattern = parse_pattern(optarg);
@ -1371,11 +1375,11 @@ struct aio_ctx {
QEMUIOVector qiov; QEMUIOVector qiov;
int64_t offset; int64_t offset;
char *buf; char *buf;
int qflag; bool qflag;
int vflag; bool vflag;
int Cflag; bool Cflag;
int Pflag; bool Pflag;
int zflag; bool zflag;
BlockAcctCookie acct; BlockAcctCookie acct;
int pattern; int pattern;
struct timeval t1; struct timeval t1;
@ -1498,10 +1502,10 @@ static int aio_read_f(BlockBackend *blk, int argc, char **argv)
while ((c = getopt(argc, argv, "CP:qv")) != -1) { while ((c = getopt(argc, argv, "CP:qv")) != -1) {
switch (c) { switch (c) {
case 'C': case 'C':
ctx->Cflag = 1; ctx->Cflag = true;
break; break;
case 'P': case 'P':
ctx->Pflag = 1; ctx->Pflag = true;
ctx->pattern = parse_pattern(optarg); ctx->pattern = parse_pattern(optarg);
if (ctx->pattern < 0) { if (ctx->pattern < 0) {
g_free(ctx); g_free(ctx);
@ -1509,10 +1513,10 @@ static int aio_read_f(BlockBackend *blk, int argc, char **argv)
} }
break; break;
case 'q': case 'q':
ctx->qflag = 1; ctx->qflag = true;
break; break;
case 'v': case 'v':
ctx->vflag = 1; ctx->vflag = true;
break; break;
default: default:
g_free(ctx); g_free(ctx);
@ -1533,14 +1537,6 @@ static int aio_read_f(BlockBackend *blk, int argc, char **argv)
} }
optind++; optind++;
if (ctx->offset & 0x1ff) {
printf("offset %" PRId64 " is not sector aligned\n",
ctx->offset);
block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_READ);
g_free(ctx);
return 0;
}
nr_iov = argc - optind; nr_iov = argc - optind;
ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov, 0xab); ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov, 0xab);
if (ctx->buf == NULL) { if (ctx->buf == NULL) {
@ -1572,7 +1568,9 @@ static void aio_write_help(void)
" used to ensure all outstanding aio requests have been completed.\n" " used to ensure all outstanding aio requests have been completed.\n"
" -P, -- use different pattern to fill file\n" " -P, -- use different pattern to fill file\n"
" -C, -- report statistics in a machine parsable format\n" " -C, -- report statistics in a machine parsable format\n"
" -f, -- use Force Unit Access semantics\n"
" -q, -- quiet mode, do not show I/O statistics\n" " -q, -- quiet mode, do not show I/O statistics\n"
" -u, -- with -z, allow unmapping\n"
" -z, -- write zeroes using blk_aio_write_zeroes\n" " -z, -- write zeroes using blk_aio_write_zeroes\n"
"\n"); "\n");
} }
@ -1584,7 +1582,7 @@ static const cmdinfo_t aio_write_cmd = {
.cfunc = aio_write_f, .cfunc = aio_write_f,
.argmin = 2, .argmin = 2,
.argmax = -1, .argmax = -1,
.args = "[-Cqz] [-P pattern ] off len [len..]", .args = "[-Cfquz] [-P pattern] off len [len..]",
.oneline = "asynchronously writes a number of bytes", .oneline = "asynchronously writes a number of bytes",
.help = aio_write_help, .help = aio_write_help,
}; };
@ -1594,15 +1592,22 @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv)
int nr_iov, c; int nr_iov, c;
int pattern = 0xcd; int pattern = 0xcd;
struct aio_ctx *ctx = g_new0(struct aio_ctx, 1); struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
int flags = 0;
ctx->blk = blk; ctx->blk = blk;
while ((c = getopt(argc, argv, "CqP:z")) != -1) { while ((c = getopt(argc, argv, "CfqP:z")) != -1) {
switch (c) { switch (c) {
case 'C': case 'C':
ctx->Cflag = 1; ctx->Cflag = true;
break;
case 'f':
flags |= BDRV_REQ_FUA;
break; break;
case 'q': case 'q':
ctx->qflag = 1; ctx->qflag = true;
break;
case 'u':
flags |= BDRV_REQ_MAY_UNMAP;
break; break;
case 'P': case 'P':
pattern = parse_pattern(optarg); pattern = parse_pattern(optarg);
@ -1612,7 +1617,7 @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv)
} }
break; break;
case 'z': case 'z':
ctx->zflag = 1; ctx->zflag = true;
break; break;
default: default:
g_free(ctx); g_free(ctx);
@ -1631,6 +1636,11 @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv)
return 0; return 0;
} }
if ((flags & BDRV_REQ_MAY_UNMAP) && !ctx->zflag) {
printf("-u requires -z to be specified\n");
return 0;
}
if (ctx->zflag && ctx->Pflag) { if (ctx->zflag && ctx->Pflag) {
printf("-z and -P cannot be specified at the same time\n"); printf("-z and -P cannot be specified at the same time\n");
g_free(ctx); g_free(ctx);
@ -1645,14 +1655,6 @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv)
} }
optind++; optind++;
if (ctx->offset & 0x1ff) {
printf("offset %" PRId64 " is not sector aligned\n",
ctx->offset);
block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_WRITE);
g_free(ctx);
return 0;
}
if (ctx->zflag) { if (ctx->zflag) {
int64_t count = cvtnum(argv[optind]); int64_t count = cvtnum(argv[optind]);
if (count < 0) { if (count < 0) {
@ -1662,7 +1664,8 @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv)
} }
ctx->qiov.size = count; ctx->qiov.size = count;
blk_aio_write_zeroes(blk, ctx->offset, count, 0, aio_write_done, ctx); blk_aio_write_zeroes(blk, ctx->offset, count, flags, aio_write_done,
ctx);
} else { } else {
nr_iov = argc - optind; nr_iov = argc - optind;
ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov, ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov,
@ -1677,7 +1680,8 @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv)
block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size, block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size,
BLOCK_ACCT_WRITE); BLOCK_ACCT_WRITE);
blk_aio_pwritev(blk, ctx->offset, &ctx->qiov, 0, aio_write_done, ctx); blk_aio_pwritev(blk, ctx->offset, &ctx->qiov, flags, aio_write_done,
ctx);
} }
return 0; return 0;
} }
@ -1841,17 +1845,17 @@ static const cmdinfo_t discard_cmd = {
static int discard_f(BlockBackend *blk, int argc, char **argv) static int discard_f(BlockBackend *blk, int argc, char **argv)
{ {
struct timeval t1, t2; struct timeval t1, t2;
int Cflag = 0, qflag = 0; bool Cflag = false, qflag = false;
int c, ret; int c, ret;
int64_t offset, count; int64_t offset, count;
while ((c = getopt(argc, argv, "Cq")) != -1) { while ((c = getopt(argc, argv, "Cq")) != -1) {
switch (c) { switch (c) {
case 'C': case 'C':
Cflag = 1; Cflag = true;
break; break;
case 'q': case 'q':
qflag = 1; qflag = true;
break; break;
default: default:
return qemuio_command_usage(&discard_cmd); return qemuio_command_usage(&discard_cmd);

View File

@ -101,12 +101,15 @@ static void open_help(void)
" opens a new file in the requested mode\n" " opens a new file in the requested mode\n"
"\n" "\n"
" Example:\n" " Example:\n"
" 'open -Cn /tmp/data' - creates/opens data file read-write and uncached\n" " 'open -n -o driver=raw /tmp/data' - opens raw data file read-write, uncached\n"
"\n" "\n"
" Opens a file for subsequent use by all of the other qemu-io commands.\n" " Opens a file for subsequent use by all of the other qemu-io commands.\n"
" -r, -- open file read-only\n" " -r, -- open file read-only\n"
" -s, -- use snapshot file\n" " -s, -- use snapshot file\n"
" -n, -- disable host cache\n" " -n, -- disable host cache, short for -t none\n"
" -k, -- use kernel AIO implementation (on Linux only)\n"
" -t, -- use the given cache mode for the image\n"
" -d, -- use the given discard mode for the image\n"
" -o, -- options to be given to the block driver" " -o, -- options to be given to the block driver"
"\n"); "\n");
} }
@ -120,7 +123,7 @@ static const cmdinfo_t open_cmd = {
.argmin = 1, .argmin = 1,
.argmax = -1, .argmax = -1,
.flags = CMD_NOFILE_OK, .flags = CMD_NOFILE_OK,
.args = "[-Crsn] [-o options] [path]", .args = "[-rsnk] [-t cache] [-d discard] [-o options] [path]",
.oneline = "open the file specified by path", .oneline = "open the file specified by path",
.help = open_help, .help = open_help,
}; };
@ -137,14 +140,14 @@ static QemuOptsList empty_opts = {
static int open_f(BlockBackend *blk, int argc, char **argv) static int open_f(BlockBackend *blk, int argc, char **argv)
{ {
int flags = 0; int flags = BDRV_O_UNMAP;
int readonly = 0; int readonly = 0;
bool writethrough = true; bool writethrough = true;
int c; int c;
QemuOpts *qopts; QemuOpts *qopts;
QDict *opts; QDict *opts;
while ((c = getopt(argc, argv, "snrgo:")) != -1) { while ((c = getopt(argc, argv, "snro:kt:d:")) != -1) {
switch (c) { switch (c) {
case 's': case 's':
flags |= BDRV_O_SNAPSHOT; flags |= BDRV_O_SNAPSHOT;
@ -156,9 +159,27 @@ static int open_f(BlockBackend *blk, int argc, char **argv)
case 'r': case 'r':
readonly = 1; readonly = 1;
break; break;
case 'k':
flags |= BDRV_O_NATIVE_AIO;
break;
case 't':
if (bdrv_parse_cache_mode(optarg, &flags, &writethrough) < 0) {
error_report("Invalid cache option: %s", optarg);
qemu_opts_reset(&empty_opts);
return 0;
}
break;
case 'd':
if (bdrv_parse_discard_flags(optarg, &flags) < 0) {
error_report("Invalid discard option: %s", optarg);
qemu_opts_reset(&empty_opts);
return 0;
}
break;
case 'o': case 'o':
if (imageOpts) { if (imageOpts) {
printf("--image-opts and 'open -o' are mutually exclusive\n"); printf("--image-opts and 'open -o' are mutually exclusive\n");
qemu_opts_reset(&empty_opts);
return 0; return 0;
} }
if (!qemu_opts_parse_noisily(&empty_opts, optarg, false)) { if (!qemu_opts_parse_noisily(&empty_opts, optarg, false)) {
@ -216,20 +237,22 @@ static const cmdinfo_t quit_cmd = {
static void usage(const char *name) static void usage(const char *name)
{ {
printf( printf(
"Usage: %s [-h] [-V] [-rsnm] [-f FMT] [-c STRING] ... [file]\n" "Usage: %s [OPTIONS]... [-c STRING]... [file]\n"
"QEMU Disk exerciser\n" "QEMU Disk exerciser\n"
"\n" "\n"
" --object OBJECTDEF define an object such as 'secret' for\n" " --object OBJECTDEF define an object such as 'secret' for\n"
" passwords and/or encryption keys\n" " passwords and/or encryption keys\n"
" --image-opts treat file as option string\n"
" -c, --cmd STRING execute command with its arguments\n" " -c, --cmd STRING execute command with its arguments\n"
" from the given string\n" " from the given string\n"
" -f, --format FMT specifies the block driver to use\n" " -f, --format FMT specifies the block driver to use\n"
" -r, --read-only export read-only\n" " -r, --read-only export read-only\n"
" -s, --snapshot use snapshot file\n" " -s, --snapshot use snapshot file\n"
" -n, --nocache disable host cache\n" " -n, --nocache disable host cache, short for -t none\n"
" -m, --misalign misalign allocations for O_DIRECT\n" " -m, --misalign misalign allocations for O_DIRECT\n"
" -k, --native-aio use kernel AIO implementation (on Linux only)\n" " -k, --native-aio use kernel AIO implementation (on Linux only)\n"
" -t, --cache=MODE use the given cache mode for the image\n" " -t, --cache=MODE use the given cache mode for the image\n"
" -d, --discard=MODE use the given discard mode for the image\n"
" -T, --trace FILE enable trace events listed in the given file\n" " -T, --trace FILE enable trace events listed in the given file\n"
" -h, --help display this help and exit\n" " -h, --help display this help and exit\n"
" -V, --version output version information and exit\n" " -V, --version output version information and exit\n"
@ -410,11 +433,10 @@ static QemuOptsList file_opts = {
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int readonly = 0; int readonly = 0;
const char *sopt = "hVc:d:f:rsnmgkt:T:"; const char *sopt = "hVc:d:f:rsnmkt:T:";
const struct option lopt[] = { const struct option lopt[] = {
{ "help", no_argument, NULL, 'h' }, { "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' }, { "version", no_argument, NULL, 'V' },
{ "offset", required_argument, NULL, 'o' },
{ "cmd", required_argument, NULL, 'c' }, { "cmd", required_argument, NULL, 'c' },
{ "format", required_argument, NULL, 'f' }, { "format", required_argument, NULL, 'f' },
{ "read-only", no_argument, NULL, 'r' }, { "read-only", no_argument, NULL, 'r' },

View File

@ -4395,6 +4395,59 @@ Example:
<- { "return": {} } <- { "return": {} }
EQMP
{
.name = "x-blockdev-change",
.args_type = "parent:B,child:B?,node:B?",
.mhandler.cmd_new = qmp_marshal_x_blockdev_change,
},
SQMP
x-blockdev-change
-----------------
Dynamically reconfigure the block driver state graph. It can be used
to add, remove, insert or replace a graph node. Currently only the
Quorum driver implements this feature to add or remove its child. This
is useful to fix a broken quorum child.
If @node is specified, it will be inserted under @parent. @child
may not be specified in this case. If both @parent and @child are
specified but @node is not, @child will be detached from @parent.
Arguments:
- "parent": the id or name of the parent node (json-string)
- "child": the name of a child under the given parent node (json-string, optional)
- "node": the name of the node that will be added (json-string, optional)
Note: this command is experimental, and not a stable API. It doesn't
support all kinds of operations, all kinds of children, nor all block
drivers.
Warning: The data in a new quorum child MUST be consistent with that of
the rest of the array.
Example:
Add a new node to a quorum
-> { "execute": "blockdev-add",
"arguments": { "options": { "driver": "raw",
"node-name": "new_node",
"file": { "driver": "file",
"filename": "test.raw" } } } }
<- { "return": {} }
-> { "execute": "x-blockdev-change",
"arguments": { "parent": "disk1",
"node": "new_node" } }
<- { "return": {} }
Delete a quorum's node
-> { "execute": "x-blockdev-change",
"arguments": { "parent": "disk1",
"child": "children.1" } }
<- { "return": {} }
EQMP EQMP
{ {

View File

@ -37,7 +37,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
. ./common.rc . ./common.rc
. ./common.filter . ./common.filter
_supported_fmt raw qcow qcow2 qed vdi vmdk vhdx _supported_fmt raw qcow qcow2 qed vdi vmdk vhdx luks
_supported_proto generic _supported_proto generic
_supported_os Linux _supported_os Linux

View File

@ -43,13 +43,16 @@ _supported_fmt generic
_supported_proto file _supported_proto file
_supported_os Linux _supported_os Linux
# Remove once all tests are fixed to use TEST_IMG_FILE
# correctly and common.rc sets it unconditionally
test -z "$TEST_IMG_FILE" && TEST_IMG_FILE=$TEST_IMG
size=128M size=128M
_make_test_img $size _make_test_img $size
echo echo
echo "== mark image read-only" echo "== mark image read-only"
chmod a-w "$TEST_IMG" chmod a-w "$TEST_IMG_FILE"
echo echo
echo "== read from read-only image" echo "== read from read-only image"

File diff suppressed because it is too large Load Diff

View File

@ -12,9 +12,9 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 512/512 bytes at offset 0 wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then ./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"; exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
else else
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"; exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
fi ) fi )
incompatible_features 0x1 incompatible_features 0x1
ERROR cluster 5 refcount=0 reference=1 ERROR cluster 5 refcount=0 reference=1
@ -51,9 +51,9 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 512/512 bytes at offset 0 wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then ./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"; exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
else else
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"; exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
fi ) fi )
incompatible_features 0x1 incompatible_features 0x1
ERROR cluster 5 refcount=0 reference=1 ERROR cluster 5 refcount=0 reference=1
@ -69,9 +69,9 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 512/512 bytes at offset 0 wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then ./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"; exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
else else
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"; exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
fi ) fi )
incompatible_features 0x0 incompatible_features 0x0
No errors were found on the image. No errors were found on the image.
@ -92,9 +92,9 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 512/512 bytes at offset 0 wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then ./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"; exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
else else
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"; exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
fi ) fi )
incompatible_features 0x1 incompatible_features 0x1
ERROR cluster 5 refcount=0 reference=1 ERROR cluster 5 refcount=0 reference=1
@ -106,9 +106,9 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 512/512 bytes at offset 0 wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then ./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"; exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
else else
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"; exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
fi ) fi )
incompatible_features 0x0 incompatible_features 0x0
No errors were found on the image. No errors were found on the image.

View File

@ -31,13 +31,13 @@ _cleanup()
{ {
echo "Cleanup" echo "Cleanup"
_cleanup_test_img _cleanup_test_img
rm "${TEST_IMG2}" rm "${TEST_IMG_FILE2}"
} }
trap "_cleanup; exit \$status" 0 1 2 3 15 trap "_cleanup; exit \$status" 0 1 2 3 15
_compare() _compare()
{ {
$QEMU_IMG compare "$@" "$TEST_IMG" "${TEST_IMG2}" $QEMU_IMG compare $QEMU_IMG_EXTRA_ARGS "$@" "$TEST_IMG" "${TEST_IMG2}"
echo $? echo $?
} }
@ -46,25 +46,37 @@ _compare()
. ./common.filter . ./common.filter
. ./common.pattern . ./common.pattern
_supported_fmt raw qcow qcow2 qed _supported_fmt raw qcow qcow2 qed luks
_supported_proto file _supported_proto file
_supported_os Linux _supported_os Linux
# Remove once all tests are fixed to use TEST_IMG_FILE
# correctly and common.rc sets it unconditionally
test -z "$TEST_IMG_FILE" && TEST_IMG_FILE=$TEST_IMG
# Setup test basic parameters # Setup test basic parameters
TEST_IMG2=$TEST_IMG.2 TEST_IMG2=$TEST_IMG.2
TEST_IMG_FILE2=$TEST_IMG_FILE.2
CLUSTER_SIZE=4096 CLUSTER_SIZE=4096
size=1024M size=128M
_make_test_img $size _make_test_img $size
io_pattern write 524288 $CLUSTER_SIZE $CLUSTER_SIZE 4 45 io_pattern write 524288 $CLUSTER_SIZE $CLUSTER_SIZE 4 45
# Compare identical images # Compare identical images
cp "$TEST_IMG" "${TEST_IMG2}" cp "$TEST_IMG_FILE" "${TEST_IMG_FILE2}"
_compare _compare
_compare -q _compare -q
# Compare images with different size # Compare images with different size
$QEMU_IMG resize -f $IMGFMT "$TEST_IMG" +512M if [ "$IMGOPTSSYNTAX" = "true" ]; then
$QEMU_IMG resize $QEMU_IMG_EXTRA_ARGS "$TEST_IMG" +32M
else
$QEMU_IMG resize -f $IMGFMT "$TEST_IMG" +32M
fi
# Ensure extended space is zero-initialized
$QEMU_IO "$TEST_IMG" -c "write -z $size 32M" | _filter_qemu_io
_compare _compare
_compare -s _compare -s
@ -77,7 +89,7 @@ _compare
# Test unaligned case of mismatch offsets in allocated clusters # Test unaligned case of mismatch offsets in allocated clusters
_make_test_img $size _make_test_img $size
io_pattern write 0 512 0 1 100 io_pattern write 0 512 0 1 100
cp "$TEST_IMG" "$TEST_IMG2" cp "$TEST_IMG_FILE" "$TEST_IMG_FILE2"
io_pattern write 512 512 0 1 101 io_pattern write 512 512 0 1 101
_compare _compare

View File

@ -1,5 +1,5 @@
QA output created by 048 QA output created by 048
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
=== IO: pattern 45 === IO: pattern 45
wrote 4096/4096 bytes at offset 524288 wrote 4096/4096 bytes at offset 524288
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@ -13,6 +13,8 @@ Images are identical.
0 0
0 0
Image resized. Image resized.
wrote 33554432/33554432 bytes at offset 134217728
32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Warning: Image size mismatch! Warning: Image size mismatch!
Images are identical. Images are identical.
0 0
@ -28,7 +30,7 @@ wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Content mismatch at offset 0! Content mismatch at offset 0!
1 1
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
=== IO: pattern 100 === IO: pattern 100
wrote 512/512 bytes at offset 0 wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)

View File

@ -47,6 +47,10 @@ _supported_cache_modes "writeback" "writethrough" "unsafe"
size=128M size=128M
_make_test_img $size _make_test_img $size
echo
echo "== initializing whole image =="
$QEMU_IO -c "write -z 0 $size" "$TEST_IMG" | _filter_qemu_io
echo echo
echo "== reading whole image ==" echo "== reading whole image =="
$QEMU_IO -s -c "read 0 $size" "$TEST_IMG" | _filter_qemu_io $QEMU_IO -s -c "read 0 $size" "$TEST_IMG" | _filter_qemu_io

View File

@ -1,6 +1,10 @@
QA output created by 052 QA output created by 052
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
== initializing whole image ==
wrote 134217728/134217728 bytes at offset 0
128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
== reading whole image == == reading whole image ==
read 134217728/134217728 bytes at offset 0 read 134217728/134217728 bytes at offset 0
128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)

View File

@ -58,9 +58,9 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
wrote 131072/131072 bytes at offset 0 wrote 131072/131072 bytes at offset 0
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then ./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"; exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
else else
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"; exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
fi ) fi )
magic 0x514649fb magic 0x514649fb
version 3 version 3
@ -220,9 +220,9 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
wrote 131072/131072 bytes at offset 0 wrote 131072/131072 bytes at offset 0
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then ./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"; exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
else else
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"; exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
fi ) fi )
magic 0x514649fb magic 0x514649fb
version 3 version 3

View File

@ -43,7 +43,7 @@ choose_tcp_port() {
wait_for_tcp_port() { wait_for_tcp_port() {
while ! (netstat --tcp --listening --numeric | \ while ! (netstat --tcp --listening --numeric | \
grep "$1.*0\\.0\\.0\\.0:\\*.*LISTEN") 2>&1 >/dev/null; do grep "$1.*0\\.0\\.0\\.0:\\*.*LISTEN") >/dev/null 2>&1; do
sleep 0.1 sleep 0.1
done done
} }
@ -70,7 +70,7 @@ EOF
nbd_url="nbd:127.0.0.1:$port:exportname=foo" nbd_url="nbd:127.0.0.1:$port:exportname=foo"
fi fi
$PYTHON nbd-fault-injector.py $extra_args "127.0.0.1:$port" "$TEST_DIR/nbd-fault-injector.conf" 2>&1 >/dev/null & $PYTHON nbd-fault-injector.py $extra_args "127.0.0.1:$port" "$TEST_DIR/nbd-fault-injector.conf" >/dev/null 2>&1 &
wait_for_tcp_port "127\\.0\\.0\\.1:$port" wait_for_tcp_port "127\\.0\\.0\\.1:$port"
$QEMU_IO -c "read 0 512" "$nbd_url" 2>&1 | _filter_qemu_io | _filter_nbd $QEMU_IO -c "read 0 512" "$nbd_url" 2>&1 | _filter_qemu_io | _filter_nbd

View File

@ -47,6 +47,7 @@ size=128M
echo echo
echo "== Single request ==" echo "== Single request =="
_make_test_img $size _make_test_img $size
$QEMU_IO -c "write -z 0 8k" "$TEST_IMG" | _filter_qemu_io
$QEMU_IO -c "multiwrite 0 4k" "$TEST_IMG" | _filter_qemu_io $QEMU_IO -c "multiwrite 0 4k" "$TEST_IMG" | _filter_qemu_io
echo echo
@ -59,6 +60,7 @@ _cleanup_test_img
echo echo
echo "== Sequential requests ==" echo "== Sequential requests =="
_make_test_img $size _make_test_img $size
$QEMU_IO -c "write -z 0 12k" "$TEST_IMG" | _filter_qemu_io
$QEMU_IO -c "multiwrite 0 4k ; 4k 4k" "$TEST_IMG" | _filter_qemu_io $QEMU_IO -c "multiwrite 0 4k ; 4k 4k" "$TEST_IMG" | _filter_qemu_io
echo echo
@ -72,6 +74,7 @@ _cleanup_test_img
echo echo
echo "== Superset overlapping requests ==" echo "== Superset overlapping requests =="
_make_test_img $size _make_test_img $size
$QEMU_IO -c "write -z 0 8k" "$TEST_IMG" | _filter_qemu_io
$QEMU_IO -c "multiwrite 0 4k ; 1k 2k" "$TEST_IMG" | _filter_qemu_io $QEMU_IO -c "multiwrite 0 4k ; 1k 2k" "$TEST_IMG" | _filter_qemu_io
echo echo
@ -87,6 +90,7 @@ _cleanup_test_img
echo echo
echo "== Subset overlapping requests ==" echo "== Subset overlapping requests =="
_make_test_img $size _make_test_img $size
$QEMU_IO -c "write -z 0 8k" "$TEST_IMG" | _filter_qemu_io
$QEMU_IO -c "multiwrite 1k 2k ; 0k 4k" "$TEST_IMG" | _filter_qemu_io $QEMU_IO -c "multiwrite 1k 2k ; 0k 4k" "$TEST_IMG" | _filter_qemu_io
echo echo
@ -102,6 +106,7 @@ _cleanup_test_img
echo echo
echo "== Head overlapping requests ==" echo "== Head overlapping requests =="
_make_test_img $size _make_test_img $size
$QEMU_IO -c "write -z 0 8k" "$TEST_IMG" | _filter_qemu_io
$QEMU_IO -c "multiwrite 0k 2k ; 0k 4k" "$TEST_IMG" | _filter_qemu_io $QEMU_IO -c "multiwrite 0k 2k ; 0k 4k" "$TEST_IMG" | _filter_qemu_io
echo echo
@ -116,6 +121,7 @@ _cleanup_test_img
echo echo
echo "== Tail overlapping requests ==" echo "== Tail overlapping requests =="
_make_test_img $size _make_test_img $size
$QEMU_IO -c "write -z 0 8k" "$TEST_IMG" | _filter_qemu_io
$QEMU_IO -c "multiwrite 2k 2k ; 0k 4k" "$TEST_IMG" | _filter_qemu_io $QEMU_IO -c "multiwrite 2k 2k ; 0k 4k" "$TEST_IMG" | _filter_qemu_io
echo echo
@ -130,6 +136,7 @@ _cleanup_test_img
echo echo
echo "== Disjoint requests ==" echo "== Disjoint requests =="
_make_test_img $size _make_test_img $size
$QEMU_IO -c "write -z 0 72k" "$TEST_IMG" | _filter_qemu_io
$QEMU_IO -c "multiwrite 0 4k ; 64k 4k" "$TEST_IMG" | _filter_qemu_io $QEMU_IO -c "multiwrite 0 4k ; 64k 4k" "$TEST_IMG" | _filter_qemu_io
echo echo

View File

@ -2,6 +2,8 @@ QA output created by 100
== Single request == == Single request ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 8192/8192 bytes at offset 0
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 4096/4096 bytes at offset 0 wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@ -13,6 +15,8 @@ read 4096/4096 bytes at offset 4096
== Sequential requests == == Sequential requests ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 12288/12288 bytes at offset 0
12 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 8192/8192 bytes at offset 0 wrote 8192/8192 bytes at offset 0
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@ -26,6 +30,8 @@ read 4096/4096 bytes at offset 8192
== Superset overlapping requests == == Superset overlapping requests ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 8192/8192 bytes at offset 0
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 6144/6144 bytes at offset 0 wrote 6144/6144 bytes at offset 0
6 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 6 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@ -39,6 +45,8 @@ read 4096/4096 bytes at offset 4096
== Subset overlapping requests == == Subset overlapping requests ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 8192/8192 bytes at offset 0
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 6144/6144 bytes at offset 1024 wrote 6144/6144 bytes at offset 1024
6 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 6 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@ -52,6 +60,8 @@ read 4096/4096 bytes at offset 4096
== Head overlapping requests == == Head overlapping requests ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 8192/8192 bytes at offset 0
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 6144/6144 bytes at offset 0 wrote 6144/6144 bytes at offset 0
6 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 6 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@ -63,6 +73,8 @@ read 4096/4096 bytes at offset 4096
== Tail overlapping requests == == Tail overlapping requests ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 8192/8192 bytes at offset 0
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 6144/6144 bytes at offset 2048 wrote 6144/6144 bytes at offset 2048
6 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 6 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@ -74,6 +86,8 @@ read 4096/4096 bytes at offset 4096
== Disjoint requests == == Disjoint requests ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 73728/73728 bytes at offset 0
72 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 8192/8192 bytes at offset 0 wrote 8192/8192 bytes at offset 0
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)

View File

@ -32,9 +32,9 @@ Unsupported value 'blubb' for qcow2 option 'overlap-check'. Allowed are any of t
wrote 512/512 bytes at offset 0 wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then ./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"; exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
else else
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"; exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
fi ) fi )
incompatible_features 0x0 incompatible_features 0x0
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864

View File

@ -53,6 +53,8 @@ export QEMU_IO_OPTIONS=""
export CACHEMODE_IS_DEFAULT=true export CACHEMODE_IS_DEFAULT=true
export QEMU_OPTIONS="-nodefaults" export QEMU_OPTIONS="-nodefaults"
export VALGRIND_QEMU= export VALGRIND_QEMU=
export IMGKEYSECRET=
export IMGOPTSSYNTAX=false
for r for r
do do
@ -207,6 +209,13 @@ testlist options
xpand=false xpand=false
;; ;;
-luks)
IMGOPTSSYNTAX=true
IMGFMT=luks
IMGKEYSECRET=123456
xpand=false
;;
-qed) -qed)
IMGFMT=qed IMGFMT=qed
xpand=false xpand=false
@ -399,7 +408,11 @@ BEGIN { for (t='$start'; t<='$end'; t++) printf "%03d\n",t }' \
done done
# Set qemu-io cache mode with $CACHEMODE we have # Set qemu-io cache mode with $CACHEMODE we have
if [ "$IMGOPTSSYNTAX" = "true" ]; then
QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS --cache $CACHEMODE"
else
QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS -f $IMGFMT --cache $CACHEMODE" QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS -f $IMGFMT --cache $CACHEMODE"
fi
# Set default options for qemu-img create -o if they were not specified # Set default options for qemu-img create -o if they were not specified
_set_default_imgopts _set_default_imgopts

View File

@ -123,12 +123,19 @@ _qemu_img_wrapper()
_qemu_io_wrapper() _qemu_io_wrapper()
{ {
local VALGRIND_LOGFILE="${TEST_DIR}"/$$.valgrind local VALGRIND_LOGFILE="${TEST_DIR}"/$$.valgrind
local QEMU_IO_ARGS="$QEMU_IO_OPTIONS"
if [ "$IMGOPTSSYNTAX" = "true" ]; then
QEMU_IO_ARGS="--image-opts $QEMU_IO_ARGS"
if [ -n "$IMGKEYSECRET" ]; then
QEMU_IO_ARGS="--object secret,id=keysec0,data=$IMGKEYSECRET $QEMU_IO_ARGS"
fi
fi
local RETVAL local RETVAL
( (
if [ "${VALGRIND_QEMU}" == "y" ]; then if [ "${VALGRIND_QEMU}" == "y" ]; then
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@" exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@"
else else
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@" exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@"
fi fi
) )
RETVAL=$? RETVAL=$?
@ -154,6 +161,16 @@ export QEMU_IMG=_qemu_img_wrapper
export QEMU_IO=_qemu_io_wrapper export QEMU_IO=_qemu_io_wrapper
export QEMU_NBD=_qemu_nbd_wrapper export QEMU_NBD=_qemu_nbd_wrapper
QEMU_IMG_EXTRA_ARGS=
if [ "$IMGOPTSSYNTAX" = "true" ]; then
QEMU_IMG_EXTRA_ARGS="--image-opts $QEMU_IMG_EXTRA_ARGS"
if [ -n "$IMGKEYSECRET" ]; then
QEMU_IMG_EXTRA_ARGS="--object secret,id=keysec0,data=$IMGKEYSECRET $QEMU_IMG_EXTRA_ARGS"
fi
fi
export QEMU_IMG_EXTRA_ARGS
default_machine=$($QEMU -machine help | sed -n '/(default)/ s/ .*//p') default_machine=$($QEMU -machine help | sed -n '/(default)/ s/ .*//p')
default_alias_machine=$($QEMU -machine help | \ default_alias_machine=$($QEMU -machine help | \
sed -n "/(alias of $default_machine)/ { s/ .*//p; q; }") sed -n "/(alias of $default_machine)/ { s/ .*//p; q; }")

View File

@ -98,7 +98,8 @@ _filter_img_create()
-e "s# block_state_zero=\\(on\\|off\\)##g" \ -e "s# block_state_zero=\\(on\\|off\\)##g" \
-e "s# log_size=[0-9]\\+##g" \ -e "s# log_size=[0-9]\\+##g" \
-e "s/archipelago:a/TEST_DIR\//g" \ -e "s/archipelago:a/TEST_DIR\//g" \
-e "s# refcount_bits=[0-9]\\+##g" -e "s# refcount_bits=[0-9]\\+##g" \
-e "s# key-secret=[a-zA-Z0-9]\\+##g"
} }
_filter_img_info() _filter_img_info()

View File

@ -53,6 +53,29 @@ fi
# make sure we have a standard umask # make sure we have a standard umask
umask 022 umask 022
if [ "$IMGOPTSSYNTAX" = "true" ]; then
DRIVER="driver=$IMGFMT"
if [ "$IMGFMT" = "luks" ]; then
DRIVER="$DRIVER,key-secret=keysec0"
fi
if [ "$IMGPROTO" = "file" ]; then
TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
TEST_IMG="$DRIVER,file.filename=$TEST_DIR/t.$IMGFMT"
elif [ "$IMGPROTO" = "nbd" ]; then
TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
TEST_IMG="$DRIVER,file.driver=nbd,file.host=127.0.0.1,file.port=10810"
elif [ "$IMGPROTO" = "ssh" ]; then
TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
TEST_IMG="$DRIVER,file.driver=ssh,file.host=127.0.0.1,file.path=$TEST_IMG_FILE"
elif [ "$IMGPROTO" = "nfs" ]; then
TEST_DIR="$DRIVER,file.driver=nfs,file.filename=nfs://127.0.0.1/$TEST_DIR"
TEST_IMG=$TEST_DIR_OPTS/t.$IMGFMT
elif [ "$IMGPROTO" = "archipelago" ]; then
TEST_IMG="$DRIVER,file.driver=archipelago,file.volume=:at.$IMGFMT"
else
TEST_IMG="$DRIVER,file.driver=$IMGPROTO,file.filename=$TEST_DIR/t.$IMGFMT"
fi
else
if [ "$IMGPROTO" = "file" ]; then if [ "$IMGPROTO" = "file" ]; then
TEST_IMG=$TEST_DIR/t.$IMGFMT TEST_IMG=$TEST_DIR/t.$IMGFMT
elif [ "$IMGPROTO" = "nbd" ]; then elif [ "$IMGPROTO" = "nbd" ]; then
@ -69,6 +92,7 @@ elif [ "$IMGPROTO" = "archipelago" ]; then
else else
TEST_IMG=$IMGPROTO:$TEST_DIR/t.$IMGFMT TEST_IMG=$IMGPROTO:$TEST_DIR/t.$IMGFMT
fi fi
fi
_optstr_add() _optstr_add()
{ {
@ -108,6 +132,7 @@ _make_test_img()
local img_name="" local img_name=""
local use_backing=0 local use_backing=0
local backing_file="" local backing_file=""
local object_options=""
if [ -n "$TEST_IMG_FILE" ]; then if [ -n "$TEST_IMG_FILE" ]; then
img_name=$TEST_IMG_FILE img_name=$TEST_IMG_FILE
@ -118,6 +143,10 @@ _make_test_img()
if [ -n "$IMGOPTS" ]; then if [ -n "$IMGOPTS" ]; then
optstr=$(_optstr_add "$optstr" "$IMGOPTS") optstr=$(_optstr_add "$optstr" "$IMGOPTS")
fi fi
if [ -n "$IMGKEYSECRET" ]; then
object_options="--object secret,id=keysec0,data=$IMGKEYSECRET"
optstr=$(_optstr_add "$optstr" "key-secret=keysec0")
fi
if [ "$1" = "-b" ]; then if [ "$1" = "-b" ]; then
use_backing=1 use_backing=1
@ -135,9 +164,9 @@ _make_test_img()
# XXX(hch): have global image options? # XXX(hch): have global image options?
( (
if [ $use_backing = 1 ]; then if [ $use_backing = 1 ]; then
$QEMU_IMG create -f $IMGFMT $extra_img_options -b "$backing_file" "$img_name" $image_size 2>&1 $QEMU_IMG create $object_options -f $IMGFMT $extra_img_options -b "$backing_file" "$img_name" $image_size 2>&1
else else
$QEMU_IMG create -f $IMGFMT $extra_img_options "$img_name" $image_size 2>&1 $QEMU_IMG create $object_options -f $IMGFMT $extra_img_options "$img_name" $image_size 2>&1
fi fi
) | _filter_img_create ) | _filter_img_create
@ -199,7 +228,13 @@ _cleanup_test_img()
_check_test_img() _check_test_img()
{ {
$QEMU_IMG check "$@" -f $IMGFMT "$TEST_IMG" 2>&1 | _filter_testdir | \ (
if [ "$IMGOPTSSYNTAX" = "true" ]; then
$QEMU_IMG check $QEMU_IMG_EXTRA_ARGS "$@" "$TEST_IMG" 2>&1
else
$QEMU_IMG check "$@" -f $IMGFMT "$TEST_IMG" 2>&1
fi
) | _filter_testdir | \
sed -e '/allocated.*fragmented.*compressed clusters/d' \ sed -e '/allocated.*fragmented.*compressed clusters/d' \
-e 's/qemu-img: This image format does not support checks/No errors were found on the image./' \ -e 's/qemu-img: This image format does not support checks/No errors were found on the image./' \
-e '/Image end offset: [0-9]\+/d' -e '/Image end offset: [0-9]\+/d'

View File

@ -47,7 +47,7 @@ if os.environ.get('QEMU_OPTIONS'):
imgfmt = os.environ.get('IMGFMT', 'raw') imgfmt = os.environ.get('IMGFMT', 'raw')
imgproto = os.environ.get('IMGPROTO', 'file') imgproto = os.environ.get('IMGPROTO', 'file')
test_dir = os.environ.get('TEST_DIR', '/var/tmp') test_dir = os.environ.get('TEST_DIR')
output_dir = os.environ.get('OUTPUT_DIR', '.') output_dir = os.environ.get('OUTPUT_DIR', '.')
cachemode = os.environ.get('CACHEMODE') cachemode = os.environ.get('CACHEMODE')
qemu_default_machine = os.environ.get('QEMU_DEFAULT_MACHINE') qemu_default_machine = os.environ.get('QEMU_DEFAULT_MACHINE')
@ -461,6 +461,14 @@ def verify_quorum():
def main(supported_fmts=[], supported_oses=['linux']): def main(supported_fmts=[], supported_oses=['linux']):
'''Run tests''' '''Run tests'''
# We are using TEST_DIR and QEMU_DEFAULT_MACHINE as proxies to
# indicate that we're not being run via "check". There may be
# other things set up by "check" that individual test cases rely
# on.
if test_dir is None or qemu_default_machine is None:
sys.stderr.write('Please run this test via the "check" script\n')
sys.exit(os.EX_USAGE)
debug = '-d' in sys.argv debug = '-d' in sys.argv
verbosity = 1 verbosity = 1
verify_image_format(supported_fmts) verify_image_format(supported_fmts)