提交 9e6b7f7e 编写于 作者: P Peter Maydell

Merge remote-tracking branch 'remotes/maxreitz/tags/pull-block-2020-02-20' into staging

Block patches:
- qemu-img convert: New --target-is-zero parameter
- qcow2: Specify non-default compression type flag
- optionally flat output for query-named-block-nodes
- some fixes
- pseudo-creation of images on block devices is now done by a generic
  block layer function

# gpg: Signature made Thu 20 Feb 2020 16:05:34 GMT
# gpg:                using RSA key 91BEB60A30DB3E8857D11829F407DB0061D5CF40
# gpg:                issuer "mreitz@redhat.com"
# gpg: Good signature from "Max Reitz <mreitz@redhat.com>" [full]
# Primary key fingerprint: 91BE B60A 30DB 3E88 57D1  1829 F407 DB00 61D5 CF40

* remotes/maxreitz/tags/pull-block-2020-02-20:
  iotests: Test snapshot -l field separation
  block: Fix VM size field width in snapshot dump
  iotests: Test convert -n -B to backing-less target
  qemu-img: Fix convert -n -B for backing-less targets
  iotests: Add test for image creation fallback
  iscsi: Drop iscsi_co_create_opts()
  file-posix: Drop hdev_co_create_opts()
  block: Generic file creation fallback
  block/nbd: Fix hang in .bdrv_close()
  iotests/279: Fix for non-qcow2 formats
  block/backup-top: fix flags handling
  block: always fill entire LUKS header space with zeros
  qemu-img: Add --target-is-zero to convert
  qapi: Allow getting flat output from 'query-named-block-nodes'
  iotests/147: Fix drive parameters
  iotests: Remove the superfluous 2nd check for the availability of quorum
  docs: qcow2: introduce compression type feature
  docs: improve qcow2 spec about extending image header
Signed-off-by: NPeter Maydell <peter.maydell@linaro.org>
......@@ -532,20 +532,139 @@ out:
return ret;
}
int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp)
/**
* Helper function for bdrv_create_file_fallback(): Resize @blk to at
* least the given @minimum_size.
*
* On success, return @blk's actual length.
* Otherwise, return -errno.
*/
static int64_t create_file_fallback_truncate(BlockBackend *blk,
int64_t minimum_size, Error **errp)
{
BlockDriver *drv;
Error *local_err = NULL;
int64_t size;
int ret;
ret = blk_truncate(blk, minimum_size, false, PREALLOC_MODE_OFF, &local_err);
if (ret < 0 && ret != -ENOTSUP) {
error_propagate(errp, local_err);
return ret;
}
size = blk_getlength(blk);
if (size < 0) {
error_free(local_err);
error_setg_errno(errp, -size,
"Failed to inquire the new image file's length");
return size;
}
if (size < minimum_size) {
/* Need to grow the image, but we failed to do that */
error_propagate(errp, local_err);
return -ENOTSUP;
}
error_free(local_err);
local_err = NULL;
return size;
}
/**
* Helper function for bdrv_create_file_fallback(): Zero the first
* sector to remove any potentially pre-existing image header.
*/
static int create_file_fallback_zero_first_sector(BlockBackend *blk,
int64_t current_size,
Error **errp)
{
int64_t bytes_to_clear;
int ret;
bytes_to_clear = MIN(current_size, BDRV_SECTOR_SIZE);
if (bytes_to_clear) {
ret = blk_pwrite_zeroes(blk, 0, bytes_to_clear, BDRV_REQ_MAY_UNMAP);
if (ret < 0) {
error_setg_errno(errp, -ret,
"Failed to clear the new image's first sector");
return ret;
}
}
return 0;
}
static int bdrv_create_file_fallback(const char *filename, BlockDriver *drv,
QemuOpts *opts, Error **errp)
{
BlockBackend *blk;
QDict *options = qdict_new();
int64_t size = 0;
char *buf = NULL;
PreallocMode prealloc;
Error *local_err = NULL;
int ret;
size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
prealloc = qapi_enum_parse(&PreallocMode_lookup, buf,
PREALLOC_MODE_OFF, &local_err);
g_free(buf);
if (local_err) {
error_propagate(errp, local_err);
return -EINVAL;
}
if (prealloc != PREALLOC_MODE_OFF) {
error_setg(errp, "Unsupported preallocation mode '%s'",
PreallocMode_str(prealloc));
return -ENOTSUP;
}
qdict_put_str(options, "driver", drv->format_name);
blk = blk_new_open(filename, NULL, options,
BDRV_O_RDWR | BDRV_O_RESIZE, errp);
if (!blk) {
error_prepend(errp, "Protocol driver '%s' does not support image "
"creation, and opening the image failed: ",
drv->format_name);
return -EINVAL;
}
size = create_file_fallback_truncate(blk, size, errp);
if (size < 0) {
ret = size;
goto out;
}
ret = create_file_fallback_zero_first_sector(blk, size, errp);
if (ret < 0) {
goto out;
}
ret = 0;
out:
blk_unref(blk);
return ret;
}
int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp)
{
BlockDriver *drv;
drv = bdrv_find_protocol(filename, true, errp);
if (drv == NULL) {
return -ENOENT;
}
ret = bdrv_create(drv, filename, opts, &local_err);
error_propagate(errp, local_err);
return ret;
if (drv->bdrv_co_create_opts) {
return bdrv_create(drv, filename, opts, errp);
} else {
return bdrv_create_file_fallback(filename, drv, opts, errp);
}
}
/**
......@@ -1444,6 +1563,24 @@ QemuOptsList bdrv_runtime_opts = {
},
};
static QemuOptsList fallback_create_opts = {
.name = "fallback-create-opts",
.head = QTAILQ_HEAD_INITIALIZER(fallback_create_opts.head),
.desc = {
{
.name = BLOCK_OPT_SIZE,
.type = QEMU_OPT_SIZE,
.help = "Virtual disk size"
},
{
.name = BLOCK_OPT_PREALLOC,
.type = QEMU_OPT_STRING,
.help = "Preallocation mode (allowed values: off)"
},
{ /* end of list */ }
}
};
/*
* Common part for opening disk images and files
*
......@@ -4807,14 +4944,15 @@ BlockDriverState *bdrv_find_node(const char *node_name)
}
/* Put this QMP function here so it can access the static graph_bdrv_states. */
BlockDeviceInfoList *bdrv_named_nodes_list(Error **errp)
BlockDeviceInfoList *bdrv_named_nodes_list(bool flat,
Error **errp)
{
BlockDeviceInfoList *list, *entry;
BlockDriverState *bs;
list = NULL;
QTAILQ_FOREACH(bs, &graph_bdrv_states, node_list) {
BlockDeviceInfo *info = bdrv_block_device_info(NULL, bs, errp);
BlockDeviceInfo *info = bdrv_block_device_info(NULL, bs, flat, errp);
if (!info) {
qapi_free_BlockDeviceInfoList(list);
return NULL;
......@@ -5771,15 +5909,13 @@ void bdrv_img_create(const char *filename, const char *fmt,
return;
}
if (!proto_drv->create_opts) {
error_setg(errp, "Protocol driver '%s' does not support image creation",
proto_drv->format_name);
return;
}
/* Create parameter list */
create_opts = qemu_opts_append(create_opts, drv->create_opts);
create_opts = qemu_opts_append(create_opts, proto_drv->create_opts);
if (proto_drv->create_opts) {
create_opts = qemu_opts_append(create_opts, proto_drv->create_opts);
} else {
create_opts = qemu_opts_append(create_opts, &fallback_create_opts);
}
opts = qemu_opts_create(create_opts, NULL, 0, &error_abort);
......
......@@ -48,11 +48,17 @@ static coroutine_fn int backup_top_co_preadv(
}
static coroutine_fn int backup_top_cbw(BlockDriverState *bs, uint64_t offset,
uint64_t bytes)
uint64_t bytes, BdrvRequestFlags flags)
{
BDRVBackupTopState *s = bs->opaque;
uint64_t end = QEMU_ALIGN_UP(offset + bytes, s->bcs->cluster_size);
uint64_t off = QEMU_ALIGN_DOWN(offset, s->bcs->cluster_size);
uint64_t off, end;
if (flags & BDRV_REQ_WRITE_UNCHANGED) {
return 0;
}
off = QEMU_ALIGN_DOWN(offset, s->bcs->cluster_size);
end = QEMU_ALIGN_UP(offset + bytes, s->bcs->cluster_size);
return block_copy(s->bcs, off, end - off, NULL);
}
......@@ -60,7 +66,7 @@ static coroutine_fn int backup_top_cbw(BlockDriverState *bs, uint64_t offset,
static int coroutine_fn backup_top_co_pdiscard(BlockDriverState *bs,
int64_t offset, int bytes)
{
int ret = backup_top_cbw(bs, offset, bytes);
int ret = backup_top_cbw(bs, offset, bytes, 0);
if (ret < 0) {
return ret;
}
......@@ -71,7 +77,7 @@ static int coroutine_fn backup_top_co_pdiscard(BlockDriverState *bs,
static int coroutine_fn backup_top_co_pwrite_zeroes(BlockDriverState *bs,
int64_t offset, int bytes, BdrvRequestFlags flags)
{
int ret = backup_top_cbw(bs, offset, bytes);
int ret = backup_top_cbw(bs, offset, bytes, flags);
if (ret < 0) {
return ret;
}
......@@ -84,11 +90,9 @@ static coroutine_fn int backup_top_co_pwritev(BlockDriverState *bs,
uint64_t bytes,
QEMUIOVector *qiov, int flags)
{
if (!(flags & BDRV_REQ_WRITE_UNCHANGED)) {
int ret = backup_top_cbw(bs, offset, bytes);
if (ret < 0) {
return ret;
}
int ret = backup_top_cbw(bs, offset, bytes, flags);
if (ret < 0) {
return ret;
}
return bdrv_co_pwritev(bs->backing, offset, bytes, qiov, flags);
......@@ -196,8 +200,13 @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source,
return NULL;
}
top->total_sectors = source->total_sectors;
state = top->opaque;
top->total_sectors = source->total_sectors;
top->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED |
(BDRV_REQ_FUA & source->supported_write_flags);
top->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) &
source->supported_zero_flags);
bdrv_ref(target);
state->target = bdrv_attach_child(top, target, "target", &child_file, errp);
......
......@@ -3477,67 +3477,6 @@ static coroutine_fn int hdev_co_pwrite_zeroes(BlockDriverState *bs,
return raw_do_pwrite_zeroes(bs, offset, bytes, flags, true);
}
static int coroutine_fn hdev_co_create_opts(const char *filename, QemuOpts *opts,
Error **errp)
{
int fd;
int ret = 0;
struct stat stat_buf;
int64_t total_size = 0;
bool has_prefix;
/* This function is used by both protocol block drivers and therefore either
* of these prefixes may be given.
* The return value has to be stored somewhere, otherwise this is an error
* due to -Werror=unused-value. */
has_prefix =
strstart(filename, "host_device:", &filename) ||
strstart(filename, "host_cdrom:" , &filename);
(void)has_prefix;
ret = raw_normalize_devicepath(&filename, errp);
if (ret < 0) {
return ret;
}
/* Read out options */
total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
BDRV_SECTOR_SIZE);
fd = qemu_open(filename, O_WRONLY | O_BINARY);
if (fd < 0) {
ret = -errno;
error_setg_errno(errp, -ret, "Could not open device");
return ret;
}
if (fstat(fd, &stat_buf) < 0) {
ret = -errno;
error_setg_errno(errp, -ret, "Could not stat device");
} else if (!S_ISBLK(stat_buf.st_mode) && !S_ISCHR(stat_buf.st_mode)) {
error_setg(errp,
"The given file is neither a block nor a character device");
ret = -ENODEV;
} else if (lseek(fd, 0, SEEK_END) < total_size) {
error_setg(errp, "Device is too small");
ret = -ENOSPC;
}
if (!ret && total_size) {
uint8_t buf[BDRV_SECTOR_SIZE] = { 0 };
int64_t zero_size = MIN(BDRV_SECTOR_SIZE, total_size);
if (lseek(fd, 0, SEEK_SET) == -1) {
ret = -errno;
} else {
ret = qemu_write_full(fd, buf, zero_size);
ret = ret == zero_size ? 0 : -errno;
}
}
qemu_close(fd);
return ret;
}
static BlockDriver bdrv_host_device = {
.format_name = "host_device",
.protocol_name = "host_device",
......@@ -3550,8 +3489,6 @@ static BlockDriver bdrv_host_device = {
.bdrv_reopen_prepare = raw_reopen_prepare,
.bdrv_reopen_commit = raw_reopen_commit,
.bdrv_reopen_abort = raw_reopen_abort,
.bdrv_co_create_opts = hdev_co_create_opts,
.create_opts = &raw_create_opts,
.mutable_opts = mutable_opts,
.bdrv_co_invalidate_cache = raw_co_invalidate_cache,
.bdrv_co_pwrite_zeroes = hdev_co_pwrite_zeroes,
......@@ -3678,8 +3615,6 @@ static BlockDriver bdrv_host_cdrom = {
.bdrv_reopen_prepare = raw_reopen_prepare,
.bdrv_reopen_commit = raw_reopen_commit,
.bdrv_reopen_abort = raw_reopen_abort,
.bdrv_co_create_opts = hdev_co_create_opts,
.create_opts = &raw_create_opts,
.mutable_opts = mutable_opts,
.bdrv_co_invalidate_cache = raw_co_invalidate_cache,
......@@ -3812,8 +3747,6 @@ static BlockDriver bdrv_host_cdrom = {
.bdrv_reopen_prepare = raw_reopen_prepare,
.bdrv_reopen_commit = raw_reopen_commit,
.bdrv_reopen_abort = raw_reopen_abort,
.bdrv_co_create_opts = hdev_co_create_opts,
.create_opts = &raw_create_opts,
.mutable_opts = mutable_opts,
.bdrv_co_preadv = raw_co_preadv,
......
......@@ -2164,58 +2164,6 @@ static int coroutine_fn iscsi_co_truncate(BlockDriverState *bs, int64_t offset,
return 0;
}
static int coroutine_fn iscsi_co_create_opts(const char *filename, QemuOpts *opts,
Error **errp)
{
int ret = 0;
int64_t total_size = 0;
BlockDriverState *bs;
IscsiLun *iscsilun = NULL;
QDict *bs_options;
Error *local_err = NULL;
bs = bdrv_new();
/* Read out options */
total_size = DIV_ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
BDRV_SECTOR_SIZE);
bs->opaque = g_new0(struct IscsiLun, 1);
iscsilun = bs->opaque;
bs_options = qdict_new();
iscsi_parse_filename(filename, bs_options, &local_err);
if (local_err) {
error_propagate(errp, local_err);
ret = -EINVAL;
} else {
ret = iscsi_open(bs, bs_options, 0, NULL);
}
qobject_unref(bs_options);
if (ret != 0) {
goto out;
}
iscsi_detach_aio_context(bs);
if (iscsilun->type != TYPE_DISK) {
ret = -ENODEV;
goto out;
}
if (bs->total_sectors < total_size) {
ret = -ENOSPC;
goto out;
}
ret = 0;
out:
if (iscsilun->iscsi != NULL) {
iscsi_destroy_context(iscsilun->iscsi);
}
g_free(bs->opaque);
bs->opaque = NULL;
bdrv_unref(bs);
return ret;
}
static int iscsi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
{
IscsiLun *iscsilun = bs->opaque;
......@@ -2486,8 +2434,6 @@ static BlockDriver bdrv_iscsi = {
.bdrv_parse_filename = iscsi_parse_filename,
.bdrv_file_open = iscsi_open,
.bdrv_close = iscsi_close,
.bdrv_co_create_opts = iscsi_co_create_opts,
.create_opts = &iscsi_create_opts,
.bdrv_reopen_prepare = iscsi_reopen_prepare,
.bdrv_reopen_commit = iscsi_reopen_commit,
.bdrv_co_invalidate_cache = iscsi_co_invalidate_cache,
......@@ -2525,8 +2471,6 @@ static BlockDriver bdrv_iser = {
.bdrv_parse_filename = iscsi_parse_filename,
.bdrv_file_open = iscsi_open,
.bdrv_close = iscsi_close,
.bdrv_co_create_opts = iscsi_co_create_opts,
.create_opts = &iscsi_create_opts,
.bdrv_reopen_prepare = iscsi_reopen_prepare,
.bdrv_reopen_commit = iscsi_reopen_commit,
.bdrv_co_invalidate_cache = iscsi_co_invalidate_cache,
......
......@@ -70,6 +70,7 @@ typedef struct BDRVNBDState {
CoMutex send_mutex;
CoQueue free_sema;
Coroutine *connection_co;
Coroutine *teardown_co;
QemuCoSleepState *connection_co_sleep_ns_state;
bool drained;
bool wait_drained_end;
......@@ -203,7 +204,15 @@ static void nbd_teardown_connection(BlockDriverState *bs)
qemu_co_sleep_wake(s->connection_co_sleep_ns_state);
}
}
BDRV_POLL_WHILE(bs, s->connection_co);
if (qemu_in_coroutine()) {
s->teardown_co = qemu_coroutine_self();
/* connection_co resumes us when it terminates */
qemu_coroutine_yield();
s->teardown_co = NULL;
} else {
BDRV_POLL_WHILE(bs, s->connection_co);
}
assert(!s->connection_co);
}
static bool nbd_client_connecting(BDRVNBDState *s)
......@@ -395,6 +404,9 @@ static coroutine_fn void nbd_connection_entry(void *opaque)
s->ioc = NULL;
}
if (s->teardown_co) {
aio_co_wake(s->teardown_co);
}
aio_wait_kick();
}
......
......@@ -42,7 +42,9 @@
#include "qemu/cutils.h"
BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
BlockDriverState *bs, Error **errp)
BlockDriverState *bs,
bool flat,
Error **errp)
{
ImageInfo **p_image_info;
BlockDriverState *bs0;
......@@ -156,6 +158,11 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
return NULL;
}
/* stop gathering data for flat output */
if (flat) {
break;
}
if (bs0->drv && bs0->backing) {
info->backing_file_depth++;
bs0 = bs0->backing->bs;
......@@ -389,7 +396,7 @@ static void bdrv_query_info(BlockBackend *blk, BlockInfo **p_info,
if (bs && bs->drv) {
info->has_inserted = true;
info->inserted = bdrv_block_device_info(blk, bs, errp);
info->inserted = bdrv_block_device_info(blk, bs, false, errp);
if (info->inserted == NULL) {
goto err;
}
......@@ -657,7 +664,7 @@ void bdrv_snapshot_dump(QEMUSnapshotInfo *sn)
char *sizing = NULL;
if (!sn) {
qemu_printf("%-10s%-20s%7s%20s%15s",
qemu_printf("%-10s%-20s%11s%20s%15s",
"ID", "TAG", "VM SIZE", "DATE", "VM CLOCK");
} else {
ti = sn->date_sec;
......@@ -672,7 +679,7 @@ void bdrv_snapshot_dump(QEMUSnapshotInfo *sn)
(int)(secs % 60),
(int)((sn->vm_clock_nsec / 1000000) % 1000));
sizing = size_to_str(sn->vm_state_size);
qemu_printf("%-10s%-20s%7s%20s%15s",
qemu_printf("%-10s%-20s%11s%20s%15s",
sn->id_str, sn->name,
sizing,
date_buf,
......
......@@ -135,13 +135,16 @@ static ssize_t qcow2_crypto_hdr_init_func(QCryptoBlock *block, size_t headerlen,
s->crypto_header.length = headerlen;
s->crypto_header.offset = ret;
/* Zero fill remaining space in cluster so it has predictable
* content in case of future spec changes */
/*
* Zero fill all space in cluster so it has predictable
* content, as we may not initialize some regions of the
* header (eg only 1 out of 8 key slots will be initialized)
*/
clusterlen = size_to_clusters(s, headerlen) * s->cluster_size;
assert(qcow2_pre_write_overlap_check(bs, 0, ret, clusterlen, false) == 0);
ret = bdrv_pwrite_zeroes(bs->file,
ret + headerlen,
clusterlen - headerlen, 0);
ret,
clusterlen, 0);
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not zero fill encryption header");
return -1;
......
......@@ -3734,9 +3734,13 @@ void qmp_drive_backup(DriveBackup *backup, Error **errp)
blockdev_do_action(&action, errp);
}
BlockDeviceInfoList *qmp_query_named_block_nodes(Error **errp)
BlockDeviceInfoList *qmp_query_named_block_nodes(bool has_flat,
bool flat,
Error **errp)
{
return bdrv_named_nodes_list(errp);
bool return_flat = has_flat && flat;
return bdrv_named_nodes_list(return_flat, errp);
}
XDbgBlockGraph *qmp_x_debug_query_block_graph(Error **errp)
......
......@@ -79,9 +79,9 @@ The first cluster of a qcow2 image contains the file header:
Offset into the image file at which the snapshot table
starts. Must be aligned to a cluster boundary.
If the version is 3 or higher, the header has the following additional fields.
For version 2, the values are assumed to be zero, unless specified otherwise
in the description of a field.
For version 2, the header is exactly 72 bytes in length, and finishes here.
For version 3 or higher, the header length is at least 104 bytes, including
the next fields through header_length.
72 - 79: incompatible_features
Bitmask of incompatible features. An implementation must
......@@ -109,7 +109,12 @@ in the description of a field.
An External Data File Name header extension may
be present if this bit is set.
Bits 3-63: Reserved (set to 0)
Bit 3: Compression type bit. If this bit is set,
a non-default compression is used for compressed
clusters. The compression_type field must be
present and not zero.
Bits 4-63: Reserved (set to 0)
80 - 87: compatible_features
Bitmask of compatible features. An implementation can
......@@ -164,6 +169,57 @@ in the description of a field.
100 - 103: header_length
Length of the header structure in bytes. For version 2
images, the length is always assumed to be 72 bytes.
For version 3 it's at least 104 bytes and must be a multiple
of 8.
=== Additional fields (version 3 and higher) ===
In general, these fields are optional and may be safely ignored by the software,
as well as filled by zeros (which is equal to field absence), if software needs
to set field B, but does not care about field A which precedes B. More
formally, additional fields have the following compatibility rules:
1. If the value of the additional field must not be ignored for correct
handling of the file, it will be accompanied by a corresponding incompatible
feature bit.
2. If there are no unrecognized incompatible feature bits set, an unknown
additional field may be safely ignored other than preserving its value when
rewriting the image header.
3. An explicit value of 0 will have the same behavior as when the field is not
present*, if not altered by a specific incompatible bit.
*. A field is considered not present when header_length is less than or equal
to the field's offset. Also, all additional fields are not present for
version 2.
104: compression_type
Defines the compression method used for compressed clusters.
All compressed clusters in an image use the same compression
type.
If the incompatible bit "Compression type" is set: the field
must be present and non-zero (which means non-zlib
compression type). Otherwise, this field must not be present
or must be zero (which means zlib).
Available compression type values:
0: zlib <https://www.zlib.net/>
=== Header padding ===
@header_length must be a multiple of 8, which means that if the end of the last
additional field is not aligned, some padding is needed. This padding must be
zeroed, so that if some existing (or future) additional field will fall into
the padding, it will be interpreted accordingly to point [3.] of the previous
paragraph, i.e. in the same manner as when this field is not present.
=== Header extensions ===
Directly after the image header, optional sections called header extensions can
be stored. Each extension has a structure like the following:
......
......@@ -214,6 +214,13 @@ Parameters to convert subcommand:
will still be printed. Areas that cannot be read from the source will be
treated as containing only zeroes.
.. option:: --target-is-zero
Assume that reading the destination image will always return
zeros. This parameter is mutually exclusive with a destination image
that has a backing file. It is required to also use the ``-n``
parameter to skip image creation.
Parameters to dd subcommand:
.. program:: qemu-img-dd
......@@ -366,7 +373,7 @@ Command description:
4
Error on reading data
.. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE] [-o OPTIONS] [-l SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-m NUM_COROUTINES] [-W] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME
.. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [--target-is-zero] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE] [-o OPTIONS] [-l SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-m NUM_COROUTINES] [-W] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME
Convert the disk image *FILENAME* or a snapshot *SNAPSHOT_PARAM*
to disk image *OUTPUT_FILENAME* using format *OUTPUT_FMT*. It can
......
......@@ -454,7 +454,7 @@ void bdrv_lock_medium(BlockDriverState *bs, bool locked);
void bdrv_eject(BlockDriverState *bs, bool eject_flag);
const char *bdrv_get_format_name(BlockDriverState *bs);
BlockDriverState *bdrv_find_node(const char *node_name);
BlockDeviceInfoList *bdrv_named_nodes_list(Error **errp);
BlockDeviceInfoList *bdrv_named_nodes_list(bool flat, Error **errp);
XDbgBlockGraph *bdrv_get_xdbg_block_graph(Error **errp);
BlockDriverState *bdrv_lookup_bs(const char *device,
const char *node_name,
......
......@@ -29,7 +29,9 @@
#include "block/snapshot.h"
BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
BlockDriverState *bs, Error **errp);
BlockDriverState *bs,
bool flat,
Error **errp);
int bdrv_query_snapshot_info_list(BlockDriverState *bs,
SnapshotInfoList **p_list,
Error **errp);
......
......@@ -620,7 +620,7 @@ void hmp_info_block(Monitor *mon, const QDict *qdict)
}
/* Print node information */
blockdev_list = qmp_query_named_block_nodes(NULL);
blockdev_list = qmp_query_named_block_nodes(false, false, NULL);
for (blockdev = blockdev_list; blockdev; blockdev = blockdev->next) {
assert(blockdev->value->has_node_name);
if (device && strcmp(device, blockdev->value->node_name)) {
......
......@@ -1758,6 +1758,9 @@
#
# Get the named block driver list
#
# @flat: Omit the nested data about backing image ("backing-image" key) if true.
# Default is false (Since 5.0)
#
# Returns: the list of BlockDeviceInfo
#
# Since: 2.0
......@@ -1811,7 +1814,9 @@
# } } ] }
#
##
{ 'command': 'query-named-block-nodes', 'returns': [ 'BlockDeviceInfo' ] }
{ 'command': 'query-named-block-nodes',
'returns': [ 'BlockDeviceInfo' ],
'data': { '*flat': 'bool' } }
##
# @XDbgBlockGraphNodeType:
......
......@@ -39,9 +39,9 @@ SRST
ERST
DEF("convert", img_convert,
"convert [--object objectdef] [--image-opts] [--target-image-opts] [-U] [-C] [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-B backing_file] [-o options] [-l snapshot_param] [-S sparse_size] [-m num_coroutines] [-W] [--salvage] filename [filename2 [...]] output_filename")
"convert [--object objectdef] [--image-opts] [--target-image-opts] [--target-is-zero] [-U] [-C] [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-B backing_file] [-o options] [-l snapshot_param] [-S sparse_size] [-m num_coroutines] [-W] [--salvage] filename [filename2 [...]] output_filename")
SRST
.. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE] [-o OPTIONS] [-l SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-m NUM_COROUTINES] [-W] [--salvage] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME
.. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [--target-is-zero] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE] [-o OPTIONS] [-l SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-m NUM_COROUTINES] [-W] [--salvage] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME
ERST
DEF("create", img_create,
......
......@@ -70,6 +70,7 @@ enum {
OPTION_PREALLOCATION = 265,
OPTION_SHRINK = 266,
OPTION_SALVAGE = 267,
OPTION_TARGET_IS_ZERO = 268,
};
typedef enum OutputFormat {
......@@ -1984,10 +1985,9 @@ static int convert_do_copy(ImgConvertState *s)
int64_t sector_num = 0;
/* Check whether we have zero initialisation or can get it efficiently */
if (s->target_is_new && s->min_sparse && !s->target_has_backing) {
if (!s->has_zero_init && s->target_is_new && s->min_sparse &&
!s->target_has_backing) {
s->has_zero_init = bdrv_has_zero_init(blk_bs(s->target));
} else {
s->has_zero_init = false;
}
if (!s->has_zero_init && !s->target_has_backing &&
......@@ -2086,6 +2086,7 @@ static int img_convert(int argc, char **argv)
{"force-share", no_argument, 0, 'U'},
{"target-image-opts", no_argument, 0, OPTION_TARGET_IMAGE_OPTS},
{"salvage", no_argument, 0, OPTION_SALVAGE},
{"target-is-zero", no_argument, 0, OPTION_TARGET_IS_ZERO},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv, ":hf:O:B:Cco:l:S:pt:T:qnm:WU",
......@@ -2209,6 +2210,14 @@ static int img_convert(int argc, char **argv)
case OPTION_TARGET_IMAGE_OPTS:
tgt_image_opts = true;
break;
case OPTION_TARGET_IS_ZERO:
/*
* The user asserting that the target is blank has the
* same effect as the target driver supporting zero
* initialisation.
*/
s.has_zero_init = true;
break;
}
}
......@@ -2247,6 +2256,11 @@ static int img_convert(int argc, char **argv)
warn_report("This will become an error in future QEMU versions.");
}
if (s.has_zero_init && !skip_create) {
error_report("--target-is-zero requires use of -n flag");
goto fail_getopt;
}
s.src_num = argc - optind - 1;
out_filename = s.src_num >= 1 ? argv[argc - 1] : NULL;
......@@ -2380,6 +2394,12 @@ static int img_convert(int argc, char **argv)
}
s.target_has_backing = (bool) out_baseimg;
if (s.has_zero_init && s.target_has_backing) {
error_report("Cannot use --target-is-zero when the destination "
"image has a backing file");
goto out;
}
if (s.src_num > 1 && out_baseimg) {
error_report("Having a backing file for the target makes no sense when "
"concatenating multiple input images");
......@@ -2503,7 +2523,7 @@ static int img_convert(int argc, char **argv)
}
}
if (s.target_has_backing) {
if (s.target_has_backing && s.target_is_new) {
/* Errors are treated as "backing length unknown" (which means
* s.target_backing_sectors has to be negative, which it will
* be automatically). The backing file length is used only
......
......@@ -276,6 +276,20 @@ $QEMU_IMG convert -O $IMGFMT -n "$TEST_IMG" "$TEST_IMG".orig
$QEMU_IMG compare "$TEST_IMG" "$TEST_IMG".orig
echo
echo '=== -n -B to an image without a backing file ==='
echo
# Base for the output
TEST_IMG="$TEST_IMG".base _make_test_img 64M
# Output that does have $TEST_IMG.base set as its (implicit) backing file
TEST_IMG="$TEST_IMG".orig _make_test_img 64M
# Convert with -n, which should not confuse -B with "target BDS has a
# backing file"
$QEMU_IMG convert -O $IMGFMT -B "$TEST_IMG".base -n "$TEST_IMG" "$TEST_IMG".orig
# success, all done
echo '*** done'
rm -f $seq.full
......
......@@ -228,4 +228,9 @@ Formatting 'TEST_DIR/t.IMGFMT.orig', fmt=IMGFMT size=67108864
wrote 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Images are identical.
=== -n -B to an image without a backing file ===
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
Formatting 'TEST_DIR/t.IMGFMT.orig', fmt=IMGFMT size=67108864
*** done
......@@ -344,9 +344,6 @@ class TestBlockdevDel(iotests.QMPTestCase):
@iotests.skip_if_unsupported(['quorum'])
def testQuorum(self):
if not iotests.supports_quorum():
return
self.addQuorum('quorum0', 'node0', 'node1')
# We cannot remove the children of a Quorum device
self.delBlockDriverState('node0', expect_error = True)
......
......@@ -134,7 +134,7 @@ class BuiltinNBD(NBDBlockdevAddBase):
self.server.add_drive_raw('if=none,id=nbd-export,' +
'file=%s,' % test_img +
'format=%s,' % imgfmt +
'cache=%s' % cachemode +
'cache=%s,' % cachemode +
'aio=%s' % aiomode)
self.server.launch()
......
#!/usr/bin/env bash
#
# Test generic image creation fallback (by using NBD)
#
# Copyright (C) 2019 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# creator
owner=mreitz@redhat.com
seq=$(basename $0)
echo "QA output created by $seq"
status=1 # failure is the default!
_cleanup()
{
_cleanup_test_img
}
trap "_cleanup; exit \$status" 0 1 2 3 15
# get standard environment, filters and checks
. ./common.rc
. ./common.filter
_supported_fmt raw
_supported_proto nbd
_supported_os Linux
_make_test_img 64M
echo
echo '--- Testing creation ---'
$QEMU_IMG create -f qcow2 "$TEST_IMG" 64M | _filter_img_create
$QEMU_IMG info "$TEST_IMG" | _filter_img_info
echo
echo '--- Testing creation for which the node would need to grow ---'
# NBD does not support resizing, so this will fail
$QEMU_IMG create -f qcow2 -o preallocation=metadata "$TEST_IMG" 64M 2>&1 \
| _filter_img_create
# success, all done
echo "*** done"
rm -f $seq.full
status=0
QA output created by 259
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
--- Testing creation ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=qcow2 size=67108864
image: TEST_DIR/t.IMGFMT
file format: qcow2
virtual size: 64 MiB (67108864 bytes)
disk size: unavailable
--- Testing creation for which the node would need to grow ---
qemu-img: TEST_DIR/t.IMGFMT: Could not resize image: Image format driver does not support resize
Formatting 'TEST_DIR/t.IMGFMT', fmt=qcow2 size=67108864 preallocation=metadata
*** done
......@@ -38,6 +38,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow qcow2 vmdk qed
_supported_proto file
_supported_os Linux
_unsupported_imgopts "subformat=monolithicFlat" \
"subformat=twoGbMaxExtentFlat" \
TEST_IMG="$TEST_IMG.base" _make_test_img 64M
TEST_IMG="$TEST_IMG.mid" _make_test_img -b "$TEST_IMG.base"
......@@ -45,11 +47,12 @@ _make_test_img -b "$TEST_IMG.mid"
echo
echo '== qemu-img info --backing-chain =='
_img_info --backing-chain | _filter_img_info
_img_info --backing-chain | _filter_img_info | grep -v 'backing file format'
echo
echo '== qemu-img info --backing-chain --image-opts =='
TEST_IMG="driver=qcow2,file.driver=file,file.filename=$TEST_IMG" _img_info --backing-chain --image-opts | _filter_img_info
TEST_IMG="driver=$IMGFMT,file.driver=file,file.filename=$TEST_IMG" _img_info --backing-chain --image-opts \
| _filter_img_info | grep -v 'backing file format'
# success, all done
echo "*** done"
......
#!/usr/bin/env bash
#
# Test ref count checks on encrypted images
#
# Copyright (C) 2019 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# creator
owner=berrange@redhat.com
seq=`basename $0`
echo "QA output created by $seq"
status=1 # failure is the default!
_cleanup()
{
_cleanup_test_img
}
trap "_cleanup; exit \$status" 0 1 2 3 15
# get standard environment, filters and checks
. ./common.rc
. ./common.filter
_supported_fmt qcow2
_supported_proto generic
_supported_os Linux
size=1M
SECRET="secret,id=sec0,data=astrochicken"
IMGSPEC="driver=$IMGFMT,file.filename=$TEST_IMG,encrypt.key-secret=sec0"
QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT
_run_test()
{
IMGOPTSSYNTAX=true
OLD_TEST_IMG="$TEST_IMG"
TEST_IMG="driver=$IMGFMT,file.filename=$TEST_IMG,encrypt.key-secret=sec0"
QEMU_IMG_EXTRA_ARGS="--image-opts --object $SECRET"
echo
echo "== cluster size $csize"
echo "== checking image refcounts =="
_check_test_img
echo
echo "== writing some data =="
$QEMU_IO -c "write -P 0x9 0 1" $QEMU_IMG_EXTRA_ARGS $TEST_IMG | _filter_qemu_io | _filter_testdir
echo
echo "== rechecking image refcounts =="
_check_test_img
echo
echo "== writing some more data =="
$QEMU_IO -c "write -P 0x9 $csize 1" $QEMU_IMG_EXTRA_ARGS $TEST_IMG | _filter_qemu_io | _filter_testdir
echo
echo "== rechecking image refcounts =="
_check_test_img
TEST_IMG="$OLD_TEST_IMG"
QEMU_IMG_EXTRA_ARGS=
IMGOPTSSYNTAX=
}
echo
echo "testing LUKS qcow2 encryption"
echo
for csize in 512 2048 32768
do
_make_test_img --object $SECRET -o "encrypt.format=luks,encrypt.key-secret=sec0,encrypt.iter-time=10,cluster_size=$csize" $size
_run_test
_cleanup_test_img
done
# success, all done
echo "*** done"
rm -f $seq.full
status=0
QA output created by 284
testing LUKS qcow2 encryption
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 encrypt.format=luks encrypt.key-secret=sec0 encrypt.iter-time=10
== cluster size 512
== checking image refcounts ==
No errors were found on the image.
== writing some data ==
wrote 1/1 bytes at offset 0
1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
== rechecking image refcounts ==
No errors were found on the image.
== writing some more data ==
wrote 1/1 bytes at offset 512
1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
== rechecking image refcounts ==
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 encrypt.format=luks encrypt.key-secret=sec0 encrypt.iter-time=10
== cluster size 2048
== checking image refcounts ==
No errors were found on the image.
== writing some data ==
wrote 1/1 bytes at offset 0
1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
== rechecking image refcounts ==
No errors were found on the image.
== writing some more data ==
wrote 1/1 bytes at offset 2048
1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
== rechecking image refcounts ==
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 encrypt.format=luks encrypt.key-secret=sec0 encrypt.iter-time=10
== cluster size 32768
== checking image refcounts ==
No errors were found on the image.
== writing some data ==
wrote 1/1 bytes at offset 0
1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
== rechecking image refcounts ==
No errors were found on the image.
== writing some more data ==
wrote 1/1 bytes at offset 32768
1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
== rechecking image refcounts ==
No errors were found on the image.
*** done
#!/usr/bin/env bash
#
# Test qemu-img snapshot -l
#
# Copyright (C) 2019 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
seq=$(basename "$0")
echo "QA output created by $seq"
status=1 # failure is the default!
_cleanup()
{
_cleanup_test_img
}
trap "_cleanup; exit \$status" 0 1 2 3 15
# get standard environment, filters and checks
. ./common.rc
. ./common.filter
. ./common.qemu
_supported_fmt qcow2
_supported_proto file
# Internal snapshots are (currently) impossible with refcount_bits=1,
# and generally impossible with external data files
_unsupported_imgopts 'refcount_bits=1[^0-9]' data_file
_make_test_img 64M
# Should be so long as to take up the whole field width
sn_name=abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
# More memory will give us a larger VM state, i.e. one above 1 MB.
# This way, we get a number with a decimal point.
qemu_comm_method=monitor _launch_qemu -m 512 "$TEST_IMG"
_send_qemu_cmd $QEMU_HANDLE "savevm $sn_name" '(qemu)'
_send_qemu_cmd $QEMU_HANDLE 'quit' '(qemu)'
wait=yes _cleanup_qemu
# Check that all fields are separated by spaces.
# We first collapse all space sequences into one space each;
# then we turn every space-separated field into a '.';
# and finally, we name the '.'s so the output is not just a confusing
# sequence of dots.
echo 'Output structure:'
$QEMU_IMG snapshot -l "$TEST_IMG" | tail -n 1 | tr -s ' ' \
| sed -e 's/\S\+/./g' \
| sed -e 's/\./(snapshot ID)/' \
-e 's/\./(snapshot name)/' \
-e 's/\./(VM state size value)/' \
-e 's/\./(VM state size unit)/' \
-e 's/\./(snapshot date)/' \
-e 's/\./(snapshot time)/' \
-e 's/\./(VM clock)/'
# success, all done
echo "*** done"
rm -f $seq.full
status=0
QA output created by 286
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
QEMU X.Y.Z monitor - type 'help' for more information
(qemu) savevm abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
(qemu) quit
Output structure:
(snapshot ID) (snapshot name) (VM state size value) (VM state size unit) (snapshot date) (snapshot time) (VM clock)
*** done
......@@ -273,6 +273,7 @@
256 rw auto quick
257 rw
258 rw quick
259 rw auto quick
260 rw quick
261 rw
262 rw quick migration
......@@ -290,3 +291,5 @@
280 rw migration quick
281 rw quick
283 auto quick
284 rw
286 rw quick
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册