mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/stefanha/tags/block-pull-request' into staging
Block pull request # gpg: Signature made Tue 01 Jul 2014 09:47:15 BST using RSA key ID 81AB73C8 # gpg: Good signature from "Stefan Hajnoczi <stefanha@redhat.com>" # gpg: aka "Stefan Hajnoczi <stefanha@gmail.com>" * remotes/stefanha/tags/block-pull-request: (23 commits) block: add backing-file option to block-stream block: extend block-commit to accept a string for the backing file block: add helper function to determine if a BDS is in a chain block: add QAPI command to allow live backing file change qapi: Change back sector-count to sectors-count in quorum QAPI events. block/cow: Avoid use of uninitialized cow_bs in error path block: simplify bdrv_find_base() and bdrv_find_overlay() block: make 'top' argument to block-commit optional iotests: Add more tests to quick group iotests: Add qemu tests to quick group iotests: Simplify qemu-iotests-quick.sh qemu-img create: add 'nocow' option virtio-blk: remove need for explicit x-data-plane=on option qdev: drop iothread property type virtio-blk: replace x-iothread with iothread link property virtio-blk: move qdev properties into virtio-blk.c virtio: fix virtio-blk child refcount in transports virtio-blk: drop virtio_blk_set_conf() virtio-blk: use aliases instead of duplicate qdev properties qdev: add qdev_alias_all_properties() ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
@@ -2508,32 +2508,23 @@ int bdrv_change_backing_file(BlockDriverState *bs,
|
||||
*
|
||||
* Returns NULL if bs is not found in active's image chain,
|
||||
* or if active == bs.
|
||||
*
|
||||
* Returns the bottommost base image if bs == NULL.
|
||||
*/
|
||||
BlockDriverState *bdrv_find_overlay(BlockDriverState *active,
|
||||
BlockDriverState *bs)
|
||||
{
|
||||
BlockDriverState *overlay = NULL;
|
||||
BlockDriverState *intermediate;
|
||||
|
||||
assert(active != NULL);
|
||||
assert(bs != NULL);
|
||||
|
||||
/* if bs is the same as active, then by definition it has no overlay
|
||||
*/
|
||||
if (active == bs) {
|
||||
return NULL;
|
||||
while (active && bs != active->backing_hd) {
|
||||
active = active->backing_hd;
|
||||
}
|
||||
|
||||
intermediate = active;
|
||||
while (intermediate->backing_hd) {
|
||||
if (intermediate->backing_hd == bs) {
|
||||
overlay = intermediate;
|
||||
break;
|
||||
}
|
||||
intermediate = intermediate->backing_hd;
|
||||
}
|
||||
return active;
|
||||
}
|
||||
|
||||
return overlay;
|
||||
/* Given a BDS, searches for the base layer. */
|
||||
BlockDriverState *bdrv_find_base(BlockDriverState *bs)
|
||||
{
|
||||
return bdrv_find_overlay(bs, NULL);
|
||||
}
|
||||
|
||||
typedef struct BlkIntermediateStates {
|
||||
@@ -2564,12 +2555,15 @@ typedef struct BlkIntermediateStates {
|
||||
*
|
||||
* base <- active
|
||||
*
|
||||
* If backing_file_str is non-NULL, it will be used when modifying top's
|
||||
* overlay image metadata.
|
||||
*
|
||||
* Error conditions:
|
||||
* if active == top, that is considered an error
|
||||
*
|
||||
*/
|
||||
int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top,
|
||||
BlockDriverState *base)
|
||||
BlockDriverState *base, const char *backing_file_str)
|
||||
{
|
||||
BlockDriverState *intermediate;
|
||||
BlockDriverState *base_bs = NULL;
|
||||
@@ -2621,7 +2615,8 @@ int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top,
|
||||
}
|
||||
|
||||
/* success - we can delete the intermediate states, and link top->base */
|
||||
ret = bdrv_change_backing_file(new_top_bs, base_bs->filename,
|
||||
backing_file_str = backing_file_str ? backing_file_str : base_bs->filename;
|
||||
ret = bdrv_change_backing_file(new_top_bs, backing_file_str,
|
||||
base_bs->drv ? base_bs->drv->format_name : "");
|
||||
if (ret) {
|
||||
goto exit;
|
||||
@@ -3783,6 +3778,17 @@ BlockDriverState *bdrv_lookup_bs(const char *device,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* If 'base' is in the same chain as 'top', return true. Otherwise,
|
||||
* return false. If either argument is NULL, return false. */
|
||||
bool bdrv_chain_contains(BlockDriverState *top, BlockDriverState *base)
|
||||
{
|
||||
while (top && top != base) {
|
||||
top = top->backing_hd;
|
||||
}
|
||||
|
||||
return top != NULL;
|
||||
}
|
||||
|
||||
BlockDriverState *bdrv_next(BlockDriverState *bs)
|
||||
{
|
||||
if (!bs) {
|
||||
@@ -4326,22 +4332,6 @@ int bdrv_get_backing_file_depth(BlockDriverState *bs)
|
||||
return 1 + bdrv_get_backing_file_depth(bs->backing_hd);
|
||||
}
|
||||
|
||||
BlockDriverState *bdrv_find_base(BlockDriverState *bs)
|
||||
{
|
||||
BlockDriverState *curr_bs = NULL;
|
||||
|
||||
if (!bs) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
curr_bs = bs;
|
||||
|
||||
while (curr_bs->backing_hd) {
|
||||
curr_bs = curr_bs->backing_hd;
|
||||
}
|
||||
return curr_bs;
|
||||
}
|
||||
|
||||
/**************************************************************/
|
||||
/* async I/Os */
|
||||
|
||||
|
||||
+6
-3
@@ -37,6 +37,7 @@ typedef struct CommitBlockJob {
|
||||
BlockdevOnError on_error;
|
||||
int base_flags;
|
||||
int orig_overlay_flags;
|
||||
char *backing_file_str;
|
||||
} CommitBlockJob;
|
||||
|
||||
static int coroutine_fn commit_populate(BlockDriverState *bs,
|
||||
@@ -141,7 +142,7 @@ wait:
|
||||
|
||||
if (!block_job_is_cancelled(&s->common) && sector_num == end) {
|
||||
/* success */
|
||||
ret = bdrv_drop_intermediate(active, top, base);
|
||||
ret = bdrv_drop_intermediate(active, top, base, s->backing_file_str);
|
||||
}
|
||||
|
||||
exit_free_buf:
|
||||
@@ -158,7 +159,7 @@ exit_restore_reopen:
|
||||
if (overlay_bs && s->orig_overlay_flags != bdrv_get_flags(overlay_bs)) {
|
||||
bdrv_reopen(overlay_bs, s->orig_overlay_flags, NULL);
|
||||
}
|
||||
|
||||
g_free(s->backing_file_str);
|
||||
block_job_completed(&s->common, ret);
|
||||
}
|
||||
|
||||
@@ -182,7 +183,7 @@ static const BlockJobDriver commit_job_driver = {
|
||||
void commit_start(BlockDriverState *bs, BlockDriverState *base,
|
||||
BlockDriverState *top, int64_t speed,
|
||||
BlockdevOnError on_error, BlockDriverCompletionFunc *cb,
|
||||
void *opaque, Error **errp)
|
||||
void *opaque, const char *backing_file_str, Error **errp)
|
||||
{
|
||||
CommitBlockJob *s;
|
||||
BlockReopenQueue *reopen_queue = NULL;
|
||||
@@ -244,6 +245,8 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base,
|
||||
s->base_flags = orig_base_flags;
|
||||
s->orig_overlay_flags = orig_overlay_flags;
|
||||
|
||||
s->backing_file_str = g_strdup(backing_file_str);
|
||||
|
||||
s->on_error = on_error;
|
||||
s->common.co = qemu_coroutine_create(commit_run);
|
||||
|
||||
|
||||
+4
-3
@@ -332,7 +332,7 @@ static int cow_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
char *image_filename = NULL;
|
||||
Error *local_err = NULL;
|
||||
int ret;
|
||||
BlockDriverState *cow_bs;
|
||||
BlockDriverState *cow_bs = NULL;
|
||||
|
||||
/* Read out options */
|
||||
image_sectors = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0) / 512;
|
||||
@@ -344,7 +344,6 @@ static int cow_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
cow_bs = NULL;
|
||||
ret = bdrv_open(&cow_bs, filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_PROTOCOL, NULL, &local_err);
|
||||
if (ret < 0) {
|
||||
@@ -383,7 +382,9 @@ static int cow_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
|
||||
exit:
|
||||
g_free(image_filename);
|
||||
bdrv_unref(cow_bs);
|
||||
if (cow_bs) {
|
||||
bdrv_unref(cow_bs);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -567,7 +567,7 @@ static void bdrv_qed_close(BlockDriverState *bs)
|
||||
static int qed_create(const char *filename, uint32_t cluster_size,
|
||||
uint64_t image_size, uint32_t table_size,
|
||||
const char *backing_file, const char *backing_fmt,
|
||||
Error **errp)
|
||||
QemuOpts *opts, Error **errp)
|
||||
{
|
||||
QEDHeader header = {
|
||||
.magic = QED_MAGIC,
|
||||
@@ -586,7 +586,7 @@ static int qed_create(const char *filename, uint32_t cluster_size,
|
||||
int ret = 0;
|
||||
BlockDriverState *bs;
|
||||
|
||||
ret = bdrv_create_file(filename, NULL, &local_err);
|
||||
ret = bdrv_create_file(filename, opts, &local_err);
|
||||
if (ret < 0) {
|
||||
error_propagate(errp, local_err);
|
||||
return ret;
|
||||
@@ -682,7 +682,7 @@ static int bdrv_qed_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
}
|
||||
|
||||
ret = qed_create(filename, cluster_size, image_size, table_size,
|
||||
backing_file, backing_fmt, errp);
|
||||
backing_file, backing_fmt, opts, errp);
|
||||
|
||||
finish:
|
||||
g_free(backing_file);
|
||||
|
||||
@@ -55,6 +55,9 @@
|
||||
#include <linux/cdrom.h>
|
||||
#include <linux/fd.h>
|
||||
#include <linux/fs.h>
|
||||
#ifndef FS_NOCOW_FL
|
||||
#define FS_NOCOW_FL 0x00800000 /* Do not cow file */
|
||||
#endif
|
||||
#endif
|
||||
#ifdef CONFIG_FIEMAP
|
||||
#include <linux/fiemap.h>
|
||||
@@ -1278,12 +1281,14 @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
int fd;
|
||||
int result = 0;
|
||||
int64_t total_size = 0;
|
||||
bool nocow = false;
|
||||
|
||||
strstart(filename, "file:", &filename);
|
||||
|
||||
/* Read out options */
|
||||
total_size =
|
||||
qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0) / BDRV_SECTOR_SIZE;
|
||||
nocow = qemu_opt_get_bool(opts, BLOCK_OPT_NOCOW, false);
|
||||
|
||||
fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
|
||||
0644);
|
||||
@@ -1291,6 +1296,21 @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
result = -errno;
|
||||
error_setg_errno(errp, -result, "Could not create file");
|
||||
} else {
|
||||
if (nocow) {
|
||||
#ifdef __linux__
|
||||
/* Set NOCOW flag to solve performance issue on fs like btrfs.
|
||||
* This is an optimisation. The FS_IOC_SETFLAGS ioctl return value
|
||||
* will be ignored since any failure of this operation should not
|
||||
* block the left work.
|
||||
*/
|
||||
int attr;
|
||||
if (ioctl(fd, FS_IOC_GETFLAGS, &attr) == 0) {
|
||||
attr |= FS_NOCOW_FL;
|
||||
ioctl(fd, FS_IOC_SETFLAGS, &attr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (ftruncate(fd, total_size * BDRV_SECTOR_SIZE) != 0) {
|
||||
result = -errno;
|
||||
error_setg_errno(errp, -result, "Could not resize file");
|
||||
@@ -1477,6 +1497,11 @@ static QemuOptsList raw_create_opts = {
|
||||
.type = QEMU_OPT_SIZE,
|
||||
.help = "Virtual disk size"
|
||||
},
|
||||
{
|
||||
.name = BLOCK_OPT_NOCOW,
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "Turn off copy-on-write (valid only on btrfs)"
|
||||
},
|
||||
{ /* end of list */ }
|
||||
}
|
||||
};
|
||||
|
||||
+5
-6
@@ -32,7 +32,7 @@ typedef struct StreamBlockJob {
|
||||
RateLimit limit;
|
||||
BlockDriverState *base;
|
||||
BlockdevOnError on_error;
|
||||
char backing_file_id[1024];
|
||||
char *backing_file_str;
|
||||
} StreamBlockJob;
|
||||
|
||||
static int coroutine_fn stream_populate(BlockDriverState *bs,
|
||||
@@ -186,7 +186,7 @@ wait:
|
||||
if (!block_job_is_cancelled(&s->common) && sector_num == end && ret == 0) {
|
||||
const char *base_id = NULL, *base_fmt = NULL;
|
||||
if (base) {
|
||||
base_id = s->backing_file_id;
|
||||
base_id = s->backing_file_str;
|
||||
if (base->drv) {
|
||||
base_fmt = base->drv->format_name;
|
||||
}
|
||||
@@ -196,6 +196,7 @@ wait:
|
||||
}
|
||||
|
||||
qemu_vfree(buf);
|
||||
g_free(s->backing_file_str);
|
||||
block_job_completed(&s->common, ret);
|
||||
}
|
||||
|
||||
@@ -217,7 +218,7 @@ static const BlockJobDriver stream_job_driver = {
|
||||
};
|
||||
|
||||
void stream_start(BlockDriverState *bs, BlockDriverState *base,
|
||||
const char *base_id, int64_t speed,
|
||||
const char *backing_file_str, int64_t speed,
|
||||
BlockdevOnError on_error,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
void *opaque, Error **errp)
|
||||
@@ -237,9 +238,7 @@ void stream_start(BlockDriverState *bs, BlockDriverState *base,
|
||||
}
|
||||
|
||||
s->base = base;
|
||||
if (base_id) {
|
||||
pstrcpy(s->backing_file_id, sizeof(s->backing_file_id), base_id);
|
||||
}
|
||||
s->backing_file_str = g_strdup(backing_file_str);
|
||||
|
||||
s->on_error = on_error;
|
||||
s->common.co = qemu_coroutine_create(stream_run);
|
||||
|
||||
+29
@@ -53,6 +53,13 @@
|
||||
#include "block/block_int.h"
|
||||
#include "qemu/module.h"
|
||||
#include "migration/migration.h"
|
||||
#ifdef __linux__
|
||||
#include <linux/fs.h>
|
||||
#include <sys/ioctl.h>
|
||||
#ifndef FS_NOCOW_FL
|
||||
#define FS_NOCOW_FL 0x00800000 /* Do not cow file */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_UUID)
|
||||
#include <uuid/uuid.h>
|
||||
@@ -683,6 +690,7 @@ static int vdi_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
VdiHeader header;
|
||||
size_t i;
|
||||
size_t bmap_size;
|
||||
bool nocow = false;
|
||||
|
||||
logout("\n");
|
||||
|
||||
@@ -699,6 +707,7 @@ static int vdi_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
image_type = VDI_TYPE_STATIC;
|
||||
}
|
||||
#endif
|
||||
nocow = qemu_opt_get_bool_del(opts, BLOCK_OPT_NOCOW, false);
|
||||
|
||||
if (bytes > VDI_DISK_SIZE_MAX) {
|
||||
result = -ENOTSUP;
|
||||
@@ -716,6 +725,21 @@ static int vdi_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (nocow) {
|
||||
#ifdef __linux__
|
||||
/* Set NOCOW flag to solve performance issue on fs like btrfs.
|
||||
* This is an optimisation. The FS_IOC_SETFLAGS ioctl return value will
|
||||
* be ignored since any failure of this operation should not block the
|
||||
* left work.
|
||||
*/
|
||||
int attr;
|
||||
if (ioctl(fd, FS_IOC_GETFLAGS, &attr) == 0) {
|
||||
attr |= FS_NOCOW_FL;
|
||||
ioctl(fd, FS_IOC_SETFLAGS, &attr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* We need enough blocks to store the given disk size,
|
||||
so always round up. */
|
||||
blocks = (bytes + block_size - 1) / block_size;
|
||||
@@ -818,6 +842,11 @@ static QemuOptsList vdi_create_opts = {
|
||||
.def_value_str = "off"
|
||||
},
|
||||
#endif
|
||||
{
|
||||
.name = BLOCK_OPT_NOCOW,
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "Turn off copy-on-write (valid only on btrfs)"
|
||||
},
|
||||
/* TODO: An additional option to set UUID values might be useful. */
|
||||
{ /* end of list */ }
|
||||
}
|
||||
|
||||
+3
-3
@@ -1529,7 +1529,7 @@ static int coroutine_fn vmdk_co_write_zeroes(BlockDriverState *bs,
|
||||
|
||||
static int vmdk_create_extent(const char *filename, int64_t filesize,
|
||||
bool flat, bool compress, bool zeroed_grain,
|
||||
Error **errp)
|
||||
QemuOpts *opts, Error **errp)
|
||||
{
|
||||
int ret, i;
|
||||
BlockDriverState *bs = NULL;
|
||||
@@ -1539,7 +1539,7 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
|
||||
uint32_t *gd_buf = NULL;
|
||||
int gd_buf_size;
|
||||
|
||||
ret = bdrv_create_file(filename, NULL, &local_err);
|
||||
ret = bdrv_create_file(filename, opts, &local_err);
|
||||
if (ret < 0) {
|
||||
error_propagate(errp, local_err);
|
||||
goto exit;
|
||||
@@ -1845,7 +1845,7 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
path, desc_filename);
|
||||
|
||||
if (vmdk_create_extent(ext_filename, size,
|
||||
flat, compress, zeroed_grain, errp)) {
|
||||
flat, compress, zeroed_grain, opts, errp)) {
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
+29
@@ -29,6 +29,13 @@
|
||||
#if defined(CONFIG_UUID)
|
||||
#include <uuid/uuid.h>
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
#include <linux/fs.h>
|
||||
#include <sys/ioctl.h>
|
||||
#ifndef FS_NOCOW_FL
|
||||
#define FS_NOCOW_FL 0x00800000 /* Do not cow file */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
@@ -751,6 +758,7 @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
int64_t total_size;
|
||||
int disk_type;
|
||||
int ret = -EIO;
|
||||
bool nocow = false;
|
||||
|
||||
/* Read out options */
|
||||
total_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
|
||||
@@ -767,6 +775,7 @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
} else {
|
||||
disk_type = VHD_DYNAMIC;
|
||||
}
|
||||
nocow = qemu_opt_get_bool_del(opts, BLOCK_OPT_NOCOW, false);
|
||||
|
||||
/* Create the file */
|
||||
fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
|
||||
@@ -775,6 +784,21 @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (nocow) {
|
||||
#ifdef __linux__
|
||||
/* Set NOCOW flag to solve performance issue on fs like btrfs.
|
||||
* This is an optimisation. The FS_IOC_SETFLAGS ioctl return value will
|
||||
* be ignored since any failure of this operation should not block the
|
||||
* left work.
|
||||
*/
|
||||
int attr;
|
||||
if (ioctl(fd, FS_IOC_GETFLAGS, &attr) == 0) {
|
||||
attr |= FS_NOCOW_FL;
|
||||
ioctl(fd, FS_IOC_SETFLAGS, &attr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate matching total_size and geometry. Increase the number of
|
||||
* sectors requested until we get enough (or fail). This ensures that
|
||||
@@ -884,6 +908,11 @@ static QemuOptsList vpc_create_opts = {
|
||||
"Type of virtual hard disk format. Supported formats are "
|
||||
"{dynamic (default) | fixed} "
|
||||
},
|
||||
{
|
||||
.name = BLOCK_OPT_NOCOW,
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "Turn off copy-on-write (valid only on btrfs)"
|
||||
},
|
||||
{ /* end of list */ }
|
||||
}
|
||||
};
|
||||
|
||||
+119
-7
@@ -1871,14 +1871,17 @@ static void block_job_cb(void *opaque, int ret)
|
||||
bdrv_put_ref_bh_schedule(bs);
|
||||
}
|
||||
|
||||
void qmp_block_stream(const char *device, bool has_base,
|
||||
const char *base, bool has_speed, int64_t speed,
|
||||
void qmp_block_stream(const char *device,
|
||||
bool has_base, const char *base,
|
||||
bool has_backing_file, const char *backing_file,
|
||||
bool has_speed, int64_t speed,
|
||||
bool has_on_error, BlockdevOnError on_error,
|
||||
Error **errp)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
BlockDriverState *base_bs = NULL;
|
||||
Error *local_err = NULL;
|
||||
const char *base_name = NULL;
|
||||
|
||||
if (!has_on_error) {
|
||||
on_error = BLOCKDEV_ON_ERROR_REPORT;
|
||||
@@ -1894,15 +1897,27 @@ void qmp_block_stream(const char *device, bool has_base,
|
||||
return;
|
||||
}
|
||||
|
||||
if (base) {
|
||||
if (has_base) {
|
||||
base_bs = bdrv_find_backing_image(bs, base);
|
||||
if (base_bs == NULL) {
|
||||
error_set(errp, QERR_BASE_NOT_FOUND, base);
|
||||
return;
|
||||
}
|
||||
base_name = base;
|
||||
}
|
||||
|
||||
stream_start(bs, base_bs, base, has_speed ? speed : 0,
|
||||
/* if we are streaming the entire chain, the result will have no backing
|
||||
* file, and specifying one is therefore an error */
|
||||
if (base_bs == NULL && has_backing_file) {
|
||||
error_setg(errp, "backing file specified, but streaming the "
|
||||
"entire chain");
|
||||
return;
|
||||
}
|
||||
|
||||
/* backing_file string overrides base bs filename */
|
||||
base_name = has_backing_file ? backing_file : base_name;
|
||||
|
||||
stream_start(bs, base_bs, base_name, has_speed ? speed : 0,
|
||||
on_error, block_job_cb, bs, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
@@ -1913,7 +1928,9 @@ void qmp_block_stream(const char *device, bool has_base,
|
||||
}
|
||||
|
||||
void qmp_block_commit(const char *device,
|
||||
bool has_base, const char *base, const char *top,
|
||||
bool has_base, const char *base,
|
||||
bool has_top, const char *top,
|
||||
bool has_backing_file, const char *backing_file,
|
||||
bool has_speed, int64_t speed,
|
||||
Error **errp)
|
||||
{
|
||||
@@ -1932,6 +1949,11 @@ void qmp_block_commit(const char *device,
|
||||
/* drain all i/o before commits */
|
||||
bdrv_drain_all();
|
||||
|
||||
/* Important Note:
|
||||
* libvirt relies on the DeviceNotFound error class in order to probe for
|
||||
* live commit feature versions; for this to work, we must make sure to
|
||||
* perform the device lookup before any generic errors that may occur in a
|
||||
* scenario in which all optional arguments are omitted. */
|
||||
bs = bdrv_find(device);
|
||||
if (!bs) {
|
||||
error_set(errp, QERR_DEVICE_NOT_FOUND, device);
|
||||
@@ -1945,7 +1967,7 @@ void qmp_block_commit(const char *device,
|
||||
/* default top_bs is the active layer */
|
||||
top_bs = bs;
|
||||
|
||||
if (top) {
|
||||
if (has_top && top) {
|
||||
if (strcmp(bs->filename, top) != 0) {
|
||||
top_bs = bdrv_find_backing_image(bs, top);
|
||||
}
|
||||
@@ -1967,12 +1989,23 @@ void qmp_block_commit(const char *device,
|
||||
return;
|
||||
}
|
||||
|
||||
/* Do not allow attempts to commit an image into itself */
|
||||
if (top_bs == base_bs) {
|
||||
error_setg(errp, "cannot commit an image into itself");
|
||||
return;
|
||||
}
|
||||
|
||||
if (top_bs == bs) {
|
||||
if (has_backing_file) {
|
||||
error_setg(errp, "'backing-file' specified,"
|
||||
" but 'top' is the active layer");
|
||||
return;
|
||||
}
|
||||
commit_active_start(bs, base_bs, speed, on_error, block_job_cb,
|
||||
bs, &local_err);
|
||||
} else {
|
||||
commit_start(bs, base_bs, top_bs, speed, on_error, block_job_cb, bs,
|
||||
&local_err);
|
||||
has_backing_file ? backing_file : NULL, &local_err);
|
||||
}
|
||||
if (local_err != NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
@@ -2355,6 +2388,85 @@ void qmp_block_job_complete(const char *device, Error **errp)
|
||||
block_job_complete(job, errp);
|
||||
}
|
||||
|
||||
void qmp_change_backing_file(const char *device,
|
||||
const char *image_node_name,
|
||||
const char *backing_file,
|
||||
Error **errp)
|
||||
{
|
||||
BlockDriverState *bs = NULL;
|
||||
BlockDriverState *image_bs = NULL;
|
||||
Error *local_err = NULL;
|
||||
bool ro;
|
||||
int open_flags;
|
||||
int ret;
|
||||
|
||||
/* find the top layer BDS of the chain */
|
||||
bs = bdrv_find(device);
|
||||
if (!bs) {
|
||||
error_set(errp, QERR_DEVICE_NOT_FOUND, device);
|
||||
return;
|
||||
}
|
||||
|
||||
image_bs = bdrv_lookup_bs(NULL, image_node_name, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!image_bs) {
|
||||
error_setg(errp, "image file not found");
|
||||
return;
|
||||
}
|
||||
|
||||
if (bdrv_find_base(image_bs) == image_bs) {
|
||||
error_setg(errp, "not allowing backing file change on an image "
|
||||
"without a backing file");
|
||||
return;
|
||||
}
|
||||
|
||||
/* even though we are not necessarily operating on bs, we need it to
|
||||
* determine if block ops are currently prohibited on the chain */
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_CHANGE, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* final sanity check */
|
||||
if (!bdrv_chain_contains(bs, image_bs)) {
|
||||
error_setg(errp, "'%s' and image file are not in the same chain",
|
||||
device);
|
||||
return;
|
||||
}
|
||||
|
||||
/* if not r/w, reopen to make r/w */
|
||||
open_flags = image_bs->open_flags;
|
||||
ro = bdrv_is_read_only(image_bs);
|
||||
|
||||
if (ro) {
|
||||
bdrv_reopen(image_bs, open_flags | BDRV_O_RDWR, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ret = bdrv_change_backing_file(image_bs, backing_file,
|
||||
image_bs->drv ? image_bs->drv->format_name : "");
|
||||
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not change backing file to '%s'",
|
||||
backing_file);
|
||||
/* don't exit here, so we can try to restore open flags if
|
||||
* appropriate */
|
||||
}
|
||||
|
||||
if (ro) {
|
||||
bdrv_reopen(image_bs, open_flags, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err); /* will preserve prior errp */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
|
||||
{
|
||||
QmpOutputVisitor *ov = qmp_output_visitor_new();
|
||||
|
||||
+13
-13
@@ -250,14 +250,14 @@ Emitted by the Quorum block driver if it fails to establish a quorum.
|
||||
|
||||
Data:
|
||||
|
||||
- "reference": device name if defined else node name.
|
||||
- "sector-num": Number of the first sector of the failed read operation.
|
||||
- "sector-count": Failed read operation sector count.
|
||||
- "reference": device name if defined else node name.
|
||||
- "sector-num": Number of the first sector of the failed read operation.
|
||||
- "sectors-count": Failed read operation sector count.
|
||||
|
||||
Example:
|
||||
|
||||
{ "event": "QUORUM_FAILURE",
|
||||
"data": { "reference": "usr1", "sector-num": 345435, "sector-count": 5 },
|
||||
"data": { "reference": "usr1", "sector-num": 345435, "sectors-count": 5 },
|
||||
"timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
|
||||
|
||||
QUORUM_REPORT_BAD
|
||||
@@ -267,19 +267,19 @@ Emitted to report a corruption of a Quorum file.
|
||||
|
||||
Data:
|
||||
|
||||
- "error": Error message (json-string, optional)
|
||||
Only present on failure. This field contains a human-readable
|
||||
error message. There are no semantics other than that the
|
||||
block layer reported an error and clients should not try to
|
||||
interpret the error string.
|
||||
- "node-name": The graph node name of the block driver state.
|
||||
- "sector-num": Number of the first sector of the failed read operation.
|
||||
- "sector-count": Failed read operation sector count.
|
||||
- "error": Error message (json-string, optional)
|
||||
Only present on failure. This field contains a human-readable
|
||||
error message. There are no semantics other than that the
|
||||
block layer reported an error and clients should not try to
|
||||
interpret the error string.
|
||||
- "node-name": The graph node name of the block driver state.
|
||||
- "sector-num": Number of the first sector of the failed read operation.
|
||||
- "sectors-count": Failed read operation sector count.
|
||||
|
||||
Example:
|
||||
|
||||
{ "event": "QUORUM_REPORT_BAD",
|
||||
"data": { "node-name": "1.raw", "sector-num": 345435, "sector-count": 5 },
|
||||
"data": { "node-name": "1.raw", "sector-num": 345435, "sectors-count": 5 },
|
||||
"timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
|
||||
|
||||
RESET
|
||||
|
||||
@@ -1176,7 +1176,7 @@ void hmp_block_stream(Monitor *mon, const QDict *qdict)
|
||||
const char *base = qdict_get_try_str(qdict, "base");
|
||||
int64_t speed = qdict_get_try_int(qdict, "speed", 0);
|
||||
|
||||
qmp_block_stream(device, base != NULL, base,
|
||||
qmp_block_stream(device, base != NULL, base, false, NULL,
|
||||
qdict_haskey(qdict, "speed"), speed,
|
||||
true, BLOCKDEV_ON_ERROR_REPORT, &error);
|
||||
|
||||
|
||||
@@ -127,10 +127,20 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
|
||||
VirtIOBlockDataPlane *s;
|
||||
VirtIOBlock *vblk = VIRTIO_BLK(vdev);
|
||||
Error *local_err = NULL;
|
||||
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
|
||||
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
|
||||
|
||||
*dataplane = NULL;
|
||||
|
||||
if (!blk->data_plane) {
|
||||
if (!blk->data_plane && !blk->iothread) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Don't try if transport does not support notifiers. */
|
||||
if (!k->set_guest_notifiers || !k->set_host_notifier) {
|
||||
error_setg(errp,
|
||||
"device is incompatible with x-data-plane "
|
||||
"(transport does not support notifiers)");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+21
-7
@@ -677,12 +677,6 @@ static const BlockDevOps virtio_block_ops = {
|
||||
.resize_cb = virtio_blk_resize,
|
||||
};
|
||||
|
||||
void virtio_blk_set_conf(DeviceState *dev, VirtIOBlkConf *blk)
|
||||
{
|
||||
VirtIOBlock *s = VIRTIO_BLK(dev);
|
||||
memcpy(&(s->blk), blk, sizeof(struct VirtIOBlkConf));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
|
||||
/* Disable dataplane thread during live migration since it does not
|
||||
* update the dirty memory bitmap yet.
|
||||
@@ -790,8 +784,27 @@ static void virtio_blk_device_unrealize(DeviceState *dev, Error **errp)
|
||||
virtio_cleanup(vdev);
|
||||
}
|
||||
|
||||
static void virtio_blk_instance_init(Object *obj)
|
||||
{
|
||||
VirtIOBlock *s = VIRTIO_BLK(obj);
|
||||
|
||||
object_property_add_link(obj, "iothread", TYPE_IOTHREAD,
|
||||
(Object **)&s->blk.iothread,
|
||||
qdev_prop_allow_set_link_before_realize,
|
||||
OBJ_PROP_LINK_UNREF_ON_RELEASE, NULL);
|
||||
}
|
||||
|
||||
static Property virtio_blk_properties[] = {
|
||||
DEFINE_VIRTIO_BLK_PROPERTIES(VirtIOBlock, blk),
|
||||
DEFINE_BLOCK_PROPERTIES(VirtIOBlock, blk.conf),
|
||||
DEFINE_BLOCK_CHS_PROPERTIES(VirtIOBlock, blk.conf),
|
||||
DEFINE_PROP_STRING("serial", VirtIOBlock, blk.serial),
|
||||
DEFINE_PROP_BIT("config-wce", VirtIOBlock, blk.config_wce, 0, true),
|
||||
#ifdef __linux__
|
||||
DEFINE_PROP_BIT("scsi", VirtIOBlock, blk.scsi, 0, true),
|
||||
#endif
|
||||
#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
|
||||
DEFINE_PROP_BIT("x-data-plane", VirtIOBlock, blk.data_plane, 0, false),
|
||||
#endif
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
@@ -817,6 +830,7 @@ static const TypeInfo virtio_device_info = {
|
||||
.name = TYPE_VIRTIO_BLK,
|
||||
.parent = TYPE_VIRTIO_DEVICE,
|
||||
.instance_size = sizeof(VirtIOBlock),
|
||||
.instance_init = virtio_blk_instance_init,
|
||||
.class_init = virtio_blk_class_init,
|
||||
};
|
||||
|
||||
|
||||
@@ -385,56 +385,6 @@ void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
|
||||
nd->instantiated = 1;
|
||||
}
|
||||
|
||||
/* --- iothread --- */
|
||||
|
||||
static char *print_iothread(void *ptr)
|
||||
{
|
||||
return iothread_get_id(ptr);
|
||||
}
|
||||
|
||||
static int parse_iothread(DeviceState *dev, const char *str, void **ptr)
|
||||
{
|
||||
IOThread *iothread;
|
||||
|
||||
iothread = iothread_find(str);
|
||||
if (!iothread) {
|
||||
return -ENOENT;
|
||||
}
|
||||
object_ref(OBJECT(iothread));
|
||||
*ptr = iothread;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void get_iothread(Object *obj, struct Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
get_pointer(obj, v, opaque, print_iothread, name, errp);
|
||||
}
|
||||
|
||||
static void set_iothread(Object *obj, struct Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
set_pointer(obj, v, opaque, parse_iothread, name, errp);
|
||||
}
|
||||
|
||||
static void release_iothread(Object *obj, const char *name, void *opaque)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
Property *prop = opaque;
|
||||
IOThread **ptr = qdev_get_prop_ptr(dev, prop);
|
||||
|
||||
if (*ptr) {
|
||||
object_unref(OBJECT(*ptr));
|
||||
}
|
||||
}
|
||||
|
||||
PropertyInfo qdev_prop_iothread = {
|
||||
.name = "iothread",
|
||||
.get = get_iothread,
|
||||
.set = set_iothread,
|
||||
.release = release_iothread,
|
||||
};
|
||||
|
||||
static int qdev_add_one_global(QemuOpts *opts, void *opaque)
|
||||
{
|
||||
GlobalProperty *g;
|
||||
|
||||
@@ -780,6 +780,27 @@ void qdev_property_add_static(DeviceState *dev, Property *prop,
|
||||
}
|
||||
}
|
||||
|
||||
/* @qdev_alias_all_properties - Add alias properties to the source object for
|
||||
* all qdev properties on the target DeviceState.
|
||||
*/
|
||||
void qdev_alias_all_properties(DeviceState *target, Object *source)
|
||||
{
|
||||
ObjectClass *class;
|
||||
Property *prop;
|
||||
|
||||
class = object_get_class(OBJECT(target));
|
||||
do {
|
||||
DeviceClass *dc = DEVICE_CLASS(class);
|
||||
|
||||
for (prop = dc->props; prop && prop->name; prop++) {
|
||||
object_property_add_alias(source, prop->name,
|
||||
OBJECT(target), prop->name,
|
||||
&error_abort);
|
||||
}
|
||||
class = object_class_get_parent(class);
|
||||
} while (class != object_class_by_name(TYPE_DEVICE));
|
||||
}
|
||||
|
||||
static bool device_get_realized(Object *obj, Error **errp)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
|
||||
@@ -167,7 +167,6 @@ static int s390_virtio_blk_init(VirtIOS390Device *s390_dev)
|
||||
{
|
||||
VirtIOBlkS390 *dev = VIRTIO_BLK_S390(s390_dev);
|
||||
DeviceState *vdev = DEVICE(&dev->vdev);
|
||||
virtio_blk_set_conf(vdev, &(dev->blk));
|
||||
qdev_set_parent_bus(vdev, BUS(&s390_dev->bus));
|
||||
if (qdev_init(vdev) < 0) {
|
||||
return -1;
|
||||
@@ -180,6 +179,10 @@ static void s390_virtio_blk_instance_init(Object *obj)
|
||||
VirtIOBlkS390 *dev = VIRTIO_BLK_S390(obj);
|
||||
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_BLK);
|
||||
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
||||
object_unref(OBJECT(&dev->vdev));
|
||||
qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
|
||||
object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev),"iothread",
|
||||
&error_abort);
|
||||
}
|
||||
|
||||
static int s390_virtio_serial_init(VirtIOS390Device *s390_dev)
|
||||
@@ -513,18 +516,11 @@ static const TypeInfo s390_virtio_net = {
|
||||
.class_init = s390_virtio_net_class_init,
|
||||
};
|
||||
|
||||
static Property s390_virtio_blk_properties[] = {
|
||||
DEFINE_VIRTIO_BLK_PROPERTIES(VirtIOBlkS390, blk),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void s390_virtio_blk_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = s390_virtio_blk_init;
|
||||
dc->props = s390_virtio_blk_properties;
|
||||
}
|
||||
|
||||
static const TypeInfo s390_virtio_blk = {
|
||||
|
||||
@@ -124,7 +124,6 @@ void s390_virtio_reset_idx(VirtIOS390Device *dev);
|
||||
typedef struct VirtIOBlkS390 {
|
||||
VirtIOS390Device parent_obj;
|
||||
VirtIOBlock vdev;
|
||||
VirtIOBlkConf blk;
|
||||
} VirtIOBlkS390;
|
||||
|
||||
/* virtio-scsi-s390 */
|
||||
|
||||
@@ -800,7 +800,6 @@ static int virtio_ccw_blk_init(VirtioCcwDevice *ccw_dev)
|
||||
{
|
||||
VirtIOBlkCcw *dev = VIRTIO_BLK_CCW(ccw_dev);
|
||||
DeviceState *vdev = DEVICE(&dev->vdev);
|
||||
virtio_blk_set_conf(vdev, &(dev->blk));
|
||||
qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
|
||||
if (qdev_init(vdev) < 0) {
|
||||
return -1;
|
||||
@@ -814,6 +813,10 @@ static void virtio_ccw_blk_instance_init(Object *obj)
|
||||
VirtIOBlkCcw *dev = VIRTIO_BLK_CCW(obj);
|
||||
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_BLK);
|
||||
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
||||
object_unref(OBJECT(&dev->vdev));
|
||||
qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
|
||||
object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev),"iothread",
|
||||
&error_abort);
|
||||
}
|
||||
|
||||
static int virtio_ccw_serial_init(VirtioCcwDevice *ccw_dev)
|
||||
@@ -1400,12 +1403,8 @@ static const TypeInfo virtio_ccw_net = {
|
||||
static Property virtio_ccw_blk_properties[] = {
|
||||
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
|
||||
DEFINE_VIRTIO_BLK_FEATURES(VirtioCcwDevice, host_features[0]),
|
||||
DEFINE_VIRTIO_BLK_PROPERTIES(VirtIOBlkCcw, blk),
|
||||
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
|
||||
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
|
||||
#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
|
||||
DEFINE_PROP_BIT("x-data-plane", VirtIOBlkCcw, blk.data_plane, 0, false),
|
||||
#endif
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
||||
@@ -144,7 +144,6 @@ typedef struct VHostSCSICcw {
|
||||
typedef struct VirtIOBlkCcw {
|
||||
VirtioCcwDevice parent_obj;
|
||||
VirtIOBlock vdev;
|
||||
VirtIOBlkConf blk;
|
||||
} VirtIOBlkCcw;
|
||||
|
||||
/* virtio-balloon-ccw */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user