mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging
Block layer patches: - file-posix: Make auto-read-only dynamic - Add x-blockdev-reopen QMP command - Finalize block-latency-histogram QMP command - gluster: Build fixes for newer lib version # gpg: Signature made Tue 12 Mar 2019 19:30:31 GMT # gpg: using RSA key 7F09B272C88F2FD6 # gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" [full] # Primary key fingerprint: DC3D EB15 9A9A F95D 3D74 56FE 7F09 B272 C88F 2FD6 * remotes/kevin/tags/for-upstream: (28 commits) qemu-iotests: Test the x-blockdev-reopen QMP command block: Add an 'x-blockdev-reopen' QMP command block: Remove the AioContext parameter from bdrv_reopen_multiple() block: Add bdrv_reset_options_allowed() block: Add a 'mutable_opts' field to BlockDriver block: Allow changing the backing file on reopen block: Allow omitting the 'backing' option in certain cases block: Handle child references in bdrv_reopen_queue() block: Add 'keep_old_opts' parameter to bdrv_reopen_queue() block: Freeze the backing chain for the duration of the stream job block: Freeze the backing chain for the duration of the mirror job block: Freeze the backing chain for the duration of the commit job block: Allow freezing BdrvChild links nvme: fix write zeroes offset and count file-posix: Make auto-read-only dynamic file-posix: Prepare permission code for fd switching file-posix: Lock new fd in raw_reopen_prepare() file-posix: Store BDRVRawState.reopen_state during reopen file-posix: Factor out raw_reconfigure_getfd() file-posix: Fix bdrv_open_flags() for snapshot=on ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
@@ -39,6 +39,7 @@ typedef struct CommitBlockJob {
|
||||
BlockDriverState *base_bs;
|
||||
BlockdevOnError on_error;
|
||||
bool base_read_only;
|
||||
bool chain_frozen;
|
||||
char *backing_file_str;
|
||||
} CommitBlockJob;
|
||||
|
||||
@@ -68,6 +69,9 @@ static int commit_prepare(Job *job)
|
||||
{
|
||||
CommitBlockJob *s = container_of(job, CommitBlockJob, common.job);
|
||||
|
||||
bdrv_unfreeze_backing_chain(s->commit_top_bs, s->base_bs);
|
||||
s->chain_frozen = false;
|
||||
|
||||
/* Remove base node parent that still uses BLK_PERM_WRITE/RESIZE before
|
||||
* the normal backing chain can be restored. */
|
||||
blk_unref(s->base);
|
||||
@@ -84,6 +88,10 @@ static void commit_abort(Job *job)
|
||||
CommitBlockJob *s = container_of(job, CommitBlockJob, common.job);
|
||||
BlockDriverState *top_bs = blk_bs(s->top);
|
||||
|
||||
if (s->chain_frozen) {
|
||||
bdrv_unfreeze_backing_chain(s->commit_top_bs, s->base_bs);
|
||||
}
|
||||
|
||||
/* Make sure commit_top_bs and top stay around until bdrv_replace_node() */
|
||||
bdrv_ref(top_bs);
|
||||
bdrv_ref(s->commit_top_bs);
|
||||
@@ -330,6 +338,11 @@ void commit_start(const char *job_id, BlockDriverState *bs,
|
||||
}
|
||||
}
|
||||
|
||||
if (bdrv_freeze_backing_chain(commit_top_bs, base, errp) < 0) {
|
||||
goto fail;
|
||||
}
|
||||
s->chain_frozen = true;
|
||||
|
||||
ret = block_job_add_bdrv(&s->common, "base", base, 0, BLK_PERM_ALL, errp);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
@@ -362,6 +375,9 @@ void commit_start(const char *job_id, BlockDriverState *bs,
|
||||
return;
|
||||
|
||||
fail:
|
||||
if (s->chain_frozen) {
|
||||
bdrv_unfreeze_backing_chain(commit_top_bs, base);
|
||||
}
|
||||
if (s->base) {
|
||||
blk_unref(s->base);
|
||||
}
|
||||
|
||||
+182
-72
@@ -144,6 +144,9 @@ typedef struct BDRVRawState {
|
||||
uint64_t locked_perm;
|
||||
uint64_t locked_shared_perm;
|
||||
|
||||
int perm_change_fd;
|
||||
BDRVReopenState *reopen_state;
|
||||
|
||||
#ifdef CONFIG_XFS
|
||||
bool is_xfs:1;
|
||||
#endif
|
||||
@@ -373,13 +376,21 @@ static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
static void raw_parse_flags(int bdrv_flags, int *open_flags)
|
||||
static void raw_parse_flags(int bdrv_flags, int *open_flags, bool has_writers)
|
||||
{
|
||||
bool read_write = false;
|
||||
assert(open_flags != NULL);
|
||||
|
||||
*open_flags |= O_BINARY;
|
||||
*open_flags &= ~O_ACCMODE;
|
||||
if (bdrv_flags & BDRV_O_RDWR) {
|
||||
|
||||
if (bdrv_flags & BDRV_O_AUTO_RDONLY) {
|
||||
read_write = has_writers;
|
||||
} else if (bdrv_flags & BDRV_O_RDWR) {
|
||||
read_write = true;
|
||||
}
|
||||
|
||||
if (read_write) {
|
||||
*open_flags |= O_RDWR;
|
||||
} else {
|
||||
*open_flags |= O_RDONLY;
|
||||
@@ -431,6 +442,8 @@ static QemuOptsList raw_runtime_opts = {
|
||||
},
|
||||
};
|
||||
|
||||
static const char *const mutable_opts[] = { "x-check-cache-dropped", NULL };
|
||||
|
||||
static int raw_open_common(BlockDriverState *bs, QDict *options,
|
||||
int bdrv_flags, int open_flags,
|
||||
bool device, Error **errp)
|
||||
@@ -515,24 +528,12 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
||||
false);
|
||||
|
||||
s->open_flags = open_flags;
|
||||
raw_parse_flags(bdrv_flags, &s->open_flags);
|
||||
raw_parse_flags(bdrv_flags, &s->open_flags, false);
|
||||
|
||||
s->fd = -1;
|
||||
fd = qemu_open(filename, s->open_flags, 0644);
|
||||
ret = fd < 0 ? -errno : 0;
|
||||
|
||||
if (ret == -EACCES || ret == -EROFS) {
|
||||
/* Try to degrade to read-only, but if it doesn't work, still use the
|
||||
* normal error message. */
|
||||
if (bdrv_apply_auto_read_only(bs, NULL, NULL) == 0) {
|
||||
bdrv_flags &= ~BDRV_O_RDWR;
|
||||
raw_parse_flags(bdrv_flags, &s->open_flags);
|
||||
assert(!(s->open_flags & O_CREAT));
|
||||
fd = qemu_open(filename, s->open_flags);
|
||||
ret = fd < 0 ? -errno : 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not open '%s'", filename);
|
||||
if (ret == -EROFS) {
|
||||
@@ -842,13 +843,77 @@ static int raw_handle_perm_lock(BlockDriverState *bs,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int raw_reconfigure_getfd(BlockDriverState *bs, int flags,
|
||||
int *open_flags, uint64_t perm, bool force_dup,
|
||||
Error **errp)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
int fd = -1;
|
||||
int ret;
|
||||
bool has_writers = perm &
|
||||
(BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED | BLK_PERM_RESIZE);
|
||||
int fcntl_flags = O_APPEND | O_NONBLOCK;
|
||||
#ifdef O_NOATIME
|
||||
fcntl_flags |= O_NOATIME;
|
||||
#endif
|
||||
|
||||
*open_flags = 0;
|
||||
if (s->type == FTYPE_CD) {
|
||||
*open_flags |= O_NONBLOCK;
|
||||
}
|
||||
|
||||
raw_parse_flags(flags, open_flags, has_writers);
|
||||
|
||||
#ifdef O_ASYNC
|
||||
/* Not all operating systems have O_ASYNC, and those that don't
|
||||
* will not let us track the state into rs->open_flags (typically
|
||||
* you achieve the same effect with an ioctl, for example I_SETSIG
|
||||
* on Solaris). But we do not use O_ASYNC, so that's fine.
|
||||
*/
|
||||
assert((s->open_flags & O_ASYNC) == 0);
|
||||
#endif
|
||||
|
||||
if (!force_dup && *open_flags == s->open_flags) {
|
||||
/* We're lucky, the existing fd is fine */
|
||||
return s->fd;
|
||||
}
|
||||
|
||||
if ((*open_flags & ~fcntl_flags) == (s->open_flags & ~fcntl_flags)) {
|
||||
/* dup the original fd */
|
||||
fd = qemu_dup(s->fd);
|
||||
if (fd >= 0) {
|
||||
ret = fcntl_setfl(fd, *open_flags);
|
||||
if (ret) {
|
||||
qemu_close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If we cannot use fcntl, or fcntl failed, fall back to qemu_open() */
|
||||
if (fd == -1) {
|
||||
const char *normalized_filename = bs->filename;
|
||||
ret = raw_normalize_devicepath(&normalized_filename, errp);
|
||||
if (ret >= 0) {
|
||||
assert(!(*open_flags & O_CREAT));
|
||||
fd = qemu_open(normalized_filename, *open_flags);
|
||||
if (fd == -1) {
|
||||
error_setg_errno(errp, errno, "Could not reopen file");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int raw_reopen_prepare(BDRVReopenState *state,
|
||||
BlockReopenQueue *queue, Error **errp)
|
||||
{
|
||||
BDRVRawState *s;
|
||||
BDRVRawReopenState *rs;
|
||||
QemuOpts *opts;
|
||||
int ret = 0;
|
||||
int ret;
|
||||
Error *local_err = NULL;
|
||||
|
||||
assert(state != NULL);
|
||||
@@ -858,7 +923,6 @@ static int raw_reopen_prepare(BDRVReopenState *state,
|
||||
|
||||
state->opaque = g_new0(BDRVRawReopenState, 1);
|
||||
rs = state->opaque;
|
||||
rs->fd = -1;
|
||||
|
||||
/* Handle options changes */
|
||||
opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, &error_abort);
|
||||
@@ -877,50 +941,12 @@ static int raw_reopen_prepare(BDRVReopenState *state,
|
||||
* bdrv_reopen_prepare() will detect changes and complain. */
|
||||
qemu_opts_to_qdict(opts, state->options);
|
||||
|
||||
if (s->type == FTYPE_CD) {
|
||||
rs->open_flags |= O_NONBLOCK;
|
||||
}
|
||||
|
||||
raw_parse_flags(state->flags, &rs->open_flags);
|
||||
|
||||
int fcntl_flags = O_APPEND | O_NONBLOCK;
|
||||
#ifdef O_NOATIME
|
||||
fcntl_flags |= O_NOATIME;
|
||||
#endif
|
||||
|
||||
#ifdef O_ASYNC
|
||||
/* Not all operating systems have O_ASYNC, and those that don't
|
||||
* will not let us track the state into rs->open_flags (typically
|
||||
* you achieve the same effect with an ioctl, for example I_SETSIG
|
||||
* on Solaris). But we do not use O_ASYNC, so that's fine.
|
||||
*/
|
||||
assert((s->open_flags & O_ASYNC) == 0);
|
||||
#endif
|
||||
|
||||
if ((rs->open_flags & ~fcntl_flags) == (s->open_flags & ~fcntl_flags)) {
|
||||
/* dup the original fd */
|
||||
rs->fd = qemu_dup(s->fd);
|
||||
if (rs->fd >= 0) {
|
||||
ret = fcntl_setfl(rs->fd, rs->open_flags);
|
||||
if (ret) {
|
||||
qemu_close(rs->fd);
|
||||
rs->fd = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If we cannot use fcntl, or fcntl failed, fall back to qemu_open() */
|
||||
if (rs->fd == -1) {
|
||||
const char *normalized_filename = state->bs->filename;
|
||||
ret = raw_normalize_devicepath(&normalized_filename, errp);
|
||||
if (ret >= 0) {
|
||||
assert(!(rs->open_flags & O_CREAT));
|
||||
rs->fd = qemu_open(normalized_filename, rs->open_flags);
|
||||
if (rs->fd == -1) {
|
||||
error_setg_errno(errp, errno, "Could not reopen file");
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
rs->fd = raw_reconfigure_getfd(state->bs, state->flags, &rs->open_flags,
|
||||
state->perm, true, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Fail already reopen_prepare() if we can't get a working O_DIRECT
|
||||
@@ -928,13 +954,19 @@ static int raw_reopen_prepare(BDRVReopenState *state,
|
||||
if (rs->fd != -1) {
|
||||
raw_probe_alignment(state->bs, rs->fd, &local_err);
|
||||
if (local_err) {
|
||||
qemu_close(rs->fd);
|
||||
rs->fd = -1;
|
||||
error_propagate(errp, local_err);
|
||||
ret = -EINVAL;
|
||||
goto out_fd;
|
||||
}
|
||||
}
|
||||
|
||||
s->reopen_state = state;
|
||||
ret = 0;
|
||||
out_fd:
|
||||
if (ret < 0) {
|
||||
qemu_close(rs->fd);
|
||||
rs->fd = -1;
|
||||
}
|
||||
out:
|
||||
qemu_opts_del(opts);
|
||||
return ret;
|
||||
@@ -944,29 +976,25 @@ static void raw_reopen_commit(BDRVReopenState *state)
|
||||
{
|
||||
BDRVRawReopenState *rs = state->opaque;
|
||||
BDRVRawState *s = state->bs->opaque;
|
||||
Error *local_err = NULL;
|
||||
|
||||
s->check_cache_dropped = rs->check_cache_dropped;
|
||||
s->open_flags = rs->open_flags;
|
||||
|
||||
/* Copy locks to the new fd before closing the old one. */
|
||||
raw_apply_lock_bytes(NULL, rs->fd, s->locked_perm,
|
||||
s->locked_shared_perm, false, &local_err);
|
||||
if (local_err) {
|
||||
/* shouldn't fail in a sane host, but report it just in case. */
|
||||
error_report_err(local_err);
|
||||
}
|
||||
qemu_close(s->fd);
|
||||
s->fd = rs->fd;
|
||||
|
||||
g_free(state->opaque);
|
||||
state->opaque = NULL;
|
||||
|
||||
assert(s->reopen_state == state);
|
||||
s->reopen_state = NULL;
|
||||
}
|
||||
|
||||
|
||||
static void raw_reopen_abort(BDRVReopenState *state)
|
||||
{
|
||||
BDRVRawReopenState *rs = state->opaque;
|
||||
BDRVRawState *s = state->bs->opaque;
|
||||
|
||||
/* nothing to do if NULL, we didn't get far enough */
|
||||
if (rs == NULL) {
|
||||
@@ -979,6 +1007,9 @@ static void raw_reopen_abort(BDRVReopenState *state)
|
||||
}
|
||||
g_free(state->opaque);
|
||||
state->opaque = NULL;
|
||||
|
||||
assert(s->reopen_state == state);
|
||||
s->reopen_state = NULL;
|
||||
}
|
||||
|
||||
static int hdev_get_max_transfer_length(BlockDriverState *bs, int fd)
|
||||
@@ -2664,12 +2695,78 @@ static QemuOptsList raw_create_opts = {
|
||||
static int raw_check_perm(BlockDriverState *bs, uint64_t perm, uint64_t shared,
|
||||
Error **errp)
|
||||
{
|
||||
return raw_handle_perm_lock(bs, RAW_PL_PREPARE, perm, shared, errp);
|
||||
BDRVRawState *s = bs->opaque;
|
||||
BDRVRawReopenState *rs = NULL;
|
||||
int open_flags;
|
||||
int ret;
|
||||
|
||||
if (s->perm_change_fd) {
|
||||
/*
|
||||
* In the context of reopen, this function may be called several times
|
||||
* (directly and recursively while change permissions of the parent).
|
||||
* This is even true for children that don't inherit from the original
|
||||
* reopen node, so s->reopen_state is not set.
|
||||
*
|
||||
* Ignore all but the first call.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (s->reopen_state) {
|
||||
/* We already have a new file descriptor to set permissions for */
|
||||
assert(s->reopen_state->perm == perm);
|
||||
assert(s->reopen_state->shared_perm == shared);
|
||||
rs = s->reopen_state->opaque;
|
||||
s->perm_change_fd = rs->fd;
|
||||
} else {
|
||||
/* We may need a new fd if auto-read-only switches the mode */
|
||||
ret = raw_reconfigure_getfd(bs, bs->open_flags, &open_flags, perm,
|
||||
false, errp);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
} else if (ret != s->fd) {
|
||||
s->perm_change_fd = ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Prepare permissions on old fd to avoid conflicts between old and new,
|
||||
* but keep everything locked that new will need. */
|
||||
ret = raw_handle_perm_lock(bs, RAW_PL_PREPARE, perm, shared, errp);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Copy locks to the new fd */
|
||||
if (s->perm_change_fd) {
|
||||
ret = raw_apply_lock_bytes(NULL, s->perm_change_fd, perm, ~shared,
|
||||
false, errp);
|
||||
if (ret < 0) {
|
||||
raw_handle_perm_lock(bs, RAW_PL_ABORT, 0, 0, NULL);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (s->perm_change_fd && !s->reopen_state) {
|
||||
qemu_close(s->perm_change_fd);
|
||||
}
|
||||
s->perm_change_fd = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void raw_set_perm(BlockDriverState *bs, uint64_t perm, uint64_t shared)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
|
||||
/* For reopen, we have already switched to the new fd (.bdrv_set_perm is
|
||||
* called after .bdrv_reopen_commit) */
|
||||
if (s->perm_change_fd && s->fd != s->perm_change_fd) {
|
||||
qemu_close(s->fd);
|
||||
s->fd = s->perm_change_fd;
|
||||
}
|
||||
s->perm_change_fd = 0;
|
||||
|
||||
raw_handle_perm_lock(bs, RAW_PL_COMMIT, perm, shared, NULL);
|
||||
s->perm = perm;
|
||||
s->shared_perm = shared;
|
||||
@@ -2677,6 +2774,15 @@ static void raw_set_perm(BlockDriverState *bs, uint64_t perm, uint64_t shared)
|
||||
|
||||
static void raw_abort_perm_update(BlockDriverState *bs)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
|
||||
/* For reopen, .bdrv_reopen_abort is called afterwards and will close
|
||||
* the file descriptor. */
|
||||
if (s->perm_change_fd && !s->reopen_state) {
|
||||
qemu_close(s->perm_change_fd);
|
||||
}
|
||||
s->perm_change_fd = 0;
|
||||
|
||||
raw_handle_perm_lock(bs, RAW_PL_ABORT, 0, 0, NULL);
|
||||
}
|
||||
|
||||
@@ -2766,6 +2872,7 @@ BlockDriver bdrv_file = {
|
||||
.bdrv_set_perm = raw_set_perm,
|
||||
.bdrv_abort_perm_update = raw_abort_perm_update,
|
||||
.create_opts = &raw_create_opts,
|
||||
.mutable_opts = mutable_opts,
|
||||
};
|
||||
|
||||
/***********************************************/
|
||||
@@ -3217,6 +3324,7 @@ static BlockDriver bdrv_host_device = {
|
||||
.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,
|
||||
|
||||
@@ -3343,6 +3451,7 @@ static BlockDriver bdrv_host_cdrom = {
|
||||
.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,
|
||||
|
||||
|
||||
@@ -3476,6 +3585,7 @@ static BlockDriver bdrv_host_cdrom = {
|
||||
.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,
|
||||
.bdrv_co_pwritev = raw_co_pwritev,
|
||||
|
||||
+9
-1
@@ -20,6 +20,10 @@
|
||||
#include "qemu/option.h"
|
||||
#include "qemu/cutils.h"
|
||||
|
||||
#ifdef CONFIG_GLUSTERFS_FTRUNCATE_HAS_STAT
|
||||
# define glfs_ftruncate(fd, offset) glfs_ftruncate(fd, offset, NULL, NULL)
|
||||
#endif
|
||||
|
||||
#define GLUSTER_OPT_FILENAME "filename"
|
||||
#define GLUSTER_OPT_VOLUME "volume"
|
||||
#define GLUSTER_OPT_PATH "path"
|
||||
@@ -725,7 +729,11 @@ static struct glfs *qemu_gluster_init(BlockdevOptionsGluster *gconf,
|
||||
/*
|
||||
* AIO callback routine called from GlusterFS thread.
|
||||
*/
|
||||
static void gluster_finish_aiocb(struct glfs_fd *fd, ssize_t ret, void *arg)
|
||||
static void gluster_finish_aiocb(struct glfs_fd *fd, ssize_t ret,
|
||||
#ifdef CONFIG_GLUSTERFS_IOCB_HAS_STAT
|
||||
struct glfs_stat *pre, struct glfs_stat *post,
|
||||
#endif
|
||||
void *arg)
|
||||
{
|
||||
GlusterAIOCB *acb = (GlusterAIOCB *)arg;
|
||||
|
||||
|
||||
@@ -630,6 +630,10 @@ static int mirror_exit_common(Job *job)
|
||||
}
|
||||
s->prepared = true;
|
||||
|
||||
if (bdrv_chain_contains(src, target_bs)) {
|
||||
bdrv_unfreeze_backing_chain(mirror_top_bs, target_bs);
|
||||
}
|
||||
|
||||
bdrv_release_dirty_bitmap(src, s->dirty_bitmap);
|
||||
|
||||
/* Make sure that the source BDS doesn't go away during bdrv_replace_node,
|
||||
@@ -1639,6 +1643,10 @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (bdrv_freeze_backing_chain(mirror_top_bs, target, errp) < 0) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
QTAILQ_INIT(&s->ops_in_flight);
|
||||
|
||||
+6
-6
@@ -493,14 +493,14 @@ static void bdrv_query_blk_stats(BlockDeviceStats *ds, BlockBackend *blk)
|
||||
}
|
||||
|
||||
bdrv_latency_histogram_stats(&stats->latency_histogram[BLOCK_ACCT_READ],
|
||||
&ds->has_x_rd_latency_histogram,
|
||||
&ds->x_rd_latency_histogram);
|
||||
&ds->has_rd_latency_histogram,
|
||||
&ds->rd_latency_histogram);
|
||||
bdrv_latency_histogram_stats(&stats->latency_histogram[BLOCK_ACCT_WRITE],
|
||||
&ds->has_x_wr_latency_histogram,
|
||||
&ds->x_wr_latency_histogram);
|
||||
&ds->has_wr_latency_histogram,
|
||||
&ds->wr_latency_histogram);
|
||||
bdrv_latency_histogram_stats(&stats->latency_histogram[BLOCK_ACCT_FLUSH],
|
||||
&ds->has_x_flush_latency_histogram,
|
||||
&ds->x_flush_latency_histogram);
|
||||
&ds->has_flush_latency_histogram,
|
||||
&ds->flush_latency_histogram);
|
||||
}
|
||||
|
||||
static BlockStats *bdrv_query_bds_stats(BlockDriverState *bs,
|
||||
|
||||
@@ -627,6 +627,30 @@ int qcow2_validate_table(BlockDriverState *bs, uint64_t offset,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *const mutable_opts[] = {
|
||||
QCOW2_OPT_LAZY_REFCOUNTS,
|
||||
QCOW2_OPT_DISCARD_REQUEST,
|
||||
QCOW2_OPT_DISCARD_SNAPSHOT,
|
||||
QCOW2_OPT_DISCARD_OTHER,
|
||||
QCOW2_OPT_OVERLAP,
|
||||
QCOW2_OPT_OVERLAP_TEMPLATE,
|
||||
QCOW2_OPT_OVERLAP_MAIN_HEADER,
|
||||
QCOW2_OPT_OVERLAP_ACTIVE_L1,
|
||||
QCOW2_OPT_OVERLAP_ACTIVE_L2,
|
||||
QCOW2_OPT_OVERLAP_REFCOUNT_TABLE,
|
||||
QCOW2_OPT_OVERLAP_REFCOUNT_BLOCK,
|
||||
QCOW2_OPT_OVERLAP_SNAPSHOT_TABLE,
|
||||
QCOW2_OPT_OVERLAP_INACTIVE_L1,
|
||||
QCOW2_OPT_OVERLAP_INACTIVE_L2,
|
||||
QCOW2_OPT_OVERLAP_BITMAP_DIRECTORY,
|
||||
QCOW2_OPT_CACHE_SIZE,
|
||||
QCOW2_OPT_L2_CACHE_SIZE,
|
||||
QCOW2_OPT_L2_CACHE_ENTRY_SIZE,
|
||||
QCOW2_OPT_REFCOUNT_CACHE_SIZE,
|
||||
QCOW2_OPT_CACHE_CLEAN_INTERVAL,
|
||||
NULL
|
||||
};
|
||||
|
||||
static QemuOptsList qcow2_runtime_opts = {
|
||||
.name = "qcow2",
|
||||
.head = QTAILQ_HEAD_INITIALIZER(qcow2_runtime_opts.head),
|
||||
@@ -5275,6 +5299,7 @@ BlockDriver bdrv_qcow2 = {
|
||||
|
||||
.create_opts = &qcow2_create_opts,
|
||||
.strong_runtime_opts = qcow2_strong_runtime_opts,
|
||||
.mutable_opts = mutable_opts,
|
||||
.bdrv_co_check = qcow2_co_check,
|
||||
.bdrv_amend_options = qcow2_amend_options,
|
||||
|
||||
|
||||
@@ -37,6 +37,8 @@ typedef struct BDRVRawState {
|
||||
bool has_size;
|
||||
} BDRVRawState;
|
||||
|
||||
static const char *const mutable_opts[] = { "offset", "size", NULL };
|
||||
|
||||
static QemuOptsList raw_runtime_opts = {
|
||||
.name = "raw",
|
||||
.head = QTAILQ_HEAD_INITIALIZER(raw_runtime_opts.head),
|
||||
@@ -570,6 +572,7 @@ BlockDriver bdrv_raw = {
|
||||
.create_opts = &raw_create_opts,
|
||||
.bdrv_has_zero_init = &raw_has_zero_init,
|
||||
.strong_runtime_opts = raw_strong_runtime_opts,
|
||||
.mutable_opts = mutable_opts,
|
||||
};
|
||||
|
||||
static void bdrv_raw_init(void)
|
||||
|
||||
+3
-4
@@ -374,19 +374,18 @@ static void reopen_backing_file(BlockDriverState *bs, bool writable,
|
||||
QDict *opts = qdict_new();
|
||||
qdict_put_bool(opts, BDRV_OPT_READ_ONLY, !writable);
|
||||
reopen_queue = bdrv_reopen_queue(reopen_queue, s->hidden_disk->bs,
|
||||
opts);
|
||||
opts, true);
|
||||
}
|
||||
|
||||
if (s->orig_secondary_read_only) {
|
||||
QDict *opts = qdict_new();
|
||||
qdict_put_bool(opts, BDRV_OPT_READ_ONLY, !writable);
|
||||
reopen_queue = bdrv_reopen_queue(reopen_queue, s->secondary_disk->bs,
|
||||
opts);
|
||||
opts, true);
|
||||
}
|
||||
|
||||
if (reopen_queue) {
|
||||
bdrv_reopen_multiple(bdrv_get_aio_context(bs),
|
||||
reopen_queue, &local_err);
|
||||
bdrv_reopen_multiple(reopen_queue, &local_err);
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ typedef struct StreamBlockJob {
|
||||
BlockdevOnError on_error;
|
||||
char *backing_file_str;
|
||||
bool bs_read_only;
|
||||
bool chain_frozen;
|
||||
} StreamBlockJob;
|
||||
|
||||
static int coroutine_fn stream_populate(BlockBackend *blk,
|
||||
@@ -49,6 +50,16 @@ static int coroutine_fn stream_populate(BlockBackend *blk,
|
||||
return blk_co_preadv(blk, offset, qiov.size, &qiov, BDRV_REQ_COPY_ON_READ);
|
||||
}
|
||||
|
||||
static void stream_abort(Job *job)
|
||||
{
|
||||
StreamBlockJob *s = container_of(job, StreamBlockJob, common.job);
|
||||
|
||||
if (s->chain_frozen) {
|
||||
BlockJob *bjob = &s->common;
|
||||
bdrv_unfreeze_backing_chain(blk_bs(bjob->blk), s->base);
|
||||
}
|
||||
}
|
||||
|
||||
static int stream_prepare(Job *job)
|
||||
{
|
||||
StreamBlockJob *s = container_of(job, StreamBlockJob, common.job);
|
||||
@@ -58,6 +69,9 @@ static int stream_prepare(Job *job)
|
||||
Error *local_err = NULL;
|
||||
int ret = 0;
|
||||
|
||||
bdrv_unfreeze_backing_chain(bs, base);
|
||||
s->chain_frozen = false;
|
||||
|
||||
if (bs->backing) {
|
||||
const char *base_id = NULL, *base_fmt = NULL;
|
||||
if (base) {
|
||||
@@ -208,6 +222,7 @@ static const BlockJobDriver stream_job_driver = {
|
||||
.free = block_job_free,
|
||||
.run = stream_run,
|
||||
.prepare = stream_prepare,
|
||||
.abort = stream_abort,
|
||||
.clean = stream_clean,
|
||||
.user_resume = block_job_user_resume,
|
||||
.drain = block_job_drain,
|
||||
@@ -254,9 +269,15 @@ void stream_start(const char *job_id, BlockDriverState *bs,
|
||||
&error_abort);
|
||||
}
|
||||
|
||||
if (bdrv_freeze_backing_chain(bs, base, errp) < 0) {
|
||||
job_early_fail(&s->common.job);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
s->base = base;
|
||||
s->backing_file_str = g_strdup(backing_file_str);
|
||||
s->bs_read_only = bs_read_only;
|
||||
s->chain_frozen = true;
|
||||
|
||||
s->on_error = on_error;
|
||||
trace_stream_start(bs, base, s);
|
||||
|
||||
+54
-7
@@ -4287,6 +4287,53 @@ fail:
|
||||
visit_free(v);
|
||||
}
|
||||
|
||||
void qmp_x_blockdev_reopen(BlockdevOptions *options, Error **errp)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
AioContext *ctx;
|
||||
QObject *obj;
|
||||
Visitor *v = qobject_output_visitor_new(&obj);
|
||||
Error *local_err = NULL;
|
||||
BlockReopenQueue *queue;
|
||||
QDict *qdict;
|
||||
|
||||
/* Check for the selected node name */
|
||||
if (!options->has_node_name) {
|
||||
error_setg(errp, "Node name not specified");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
bs = bdrv_find_node(options->node_name);
|
||||
if (!bs) {
|
||||
error_setg(errp, "Cannot find node named '%s'", options->node_name);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Put all options in a QDict and flatten it */
|
||||
visit_type_BlockdevOptions(v, NULL, &options, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
visit_complete(v, &obj);
|
||||
qdict = qobject_to(QDict, obj);
|
||||
|
||||
qdict_flatten(qdict);
|
||||
|
||||
/* Perform the reopen operation */
|
||||
ctx = bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(ctx);
|
||||
bdrv_subtree_drained_begin(bs);
|
||||
queue = bdrv_reopen_queue(NULL, bs, qdict, false);
|
||||
bdrv_reopen_multiple(queue, errp);
|
||||
bdrv_subtree_drained_end(bs);
|
||||
aio_context_release(ctx);
|
||||
|
||||
fail:
|
||||
visit_free(v);
|
||||
}
|
||||
|
||||
void qmp_blockdev_del(const char *node_name, Error **errp)
|
||||
{
|
||||
AioContext *aio_context;
|
||||
@@ -4452,22 +4499,22 @@ void qmp_x_blockdev_set_iothread(const char *node_name, StrOrNull *iothread,
|
||||
aio_context_release(old_context);
|
||||
}
|
||||
|
||||
void qmp_x_block_latency_histogram_set(
|
||||
const char *device,
|
||||
void qmp_block_latency_histogram_set(
|
||||
const char *id,
|
||||
bool has_boundaries, uint64List *boundaries,
|
||||
bool has_boundaries_read, uint64List *boundaries_read,
|
||||
bool has_boundaries_write, uint64List *boundaries_write,
|
||||
bool has_boundaries_flush, uint64List *boundaries_flush,
|
||||
Error **errp)
|
||||
{
|
||||
BlockBackend *blk = blk_by_name(device);
|
||||
BlockBackend *blk = qmp_get_blk(NULL, id, errp);
|
||||
BlockAcctStats *stats;
|
||||
int ret;
|
||||
|
||||
if (!blk) {
|
||||
error_setg(errp, "Device '%s' not found", device);
|
||||
return;
|
||||
}
|
||||
|
||||
stats = blk_get_stats(blk);
|
||||
|
||||
if (!has_boundaries && !has_boundaries_read && !has_boundaries_write &&
|
||||
@@ -4482,7 +4529,7 @@ void qmp_x_block_latency_histogram_set(
|
||||
stats, BLOCK_ACCT_READ,
|
||||
has_boundaries_read ? boundaries_read : boundaries);
|
||||
if (ret) {
|
||||
error_setg(errp, "Device '%s' set read boundaries fail", device);
|
||||
error_setg(errp, "Device '%s' set read boundaries fail", id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -4492,7 +4539,7 @@ void qmp_x_block_latency_histogram_set(
|
||||
stats, BLOCK_ACCT_WRITE,
|
||||
has_boundaries_write ? boundaries_write : boundaries);
|
||||
if (ret) {
|
||||
error_setg(errp, "Device '%s' set write boundaries fail", device);
|
||||
error_setg(errp, "Device '%s' set write boundaries fail", id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -4502,7 +4549,7 @@ void qmp_x_block_latency_histogram_set(
|
||||
stats, BLOCK_ACCT_FLUSH,
|
||||
has_boundaries_flush ? boundaries_flush : boundaries);
|
||||
if (ret) {
|
||||
error_setg(errp, "Device '%s' set flush boundaries fail", device);
|
||||
error_setg(errp, "Device '%s' set flush boundaries fail", id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -456,6 +456,8 @@ glusterfs_xlator_opt="no"
|
||||
glusterfs_discard="no"
|
||||
glusterfs_fallocate="no"
|
||||
glusterfs_zerofill="no"
|
||||
glusterfs_ftruncate_has_stat="no"
|
||||
glusterfs_iocb_has_stat="no"
|
||||
gtk=""
|
||||
gtk_gl="no"
|
||||
tls_priority="NORMAL"
|
||||
@@ -4091,6 +4093,38 @@ if test "$glusterfs" != "no" ; then
|
||||
glusterfs_fallocate="yes"
|
||||
glusterfs_zerofill="yes"
|
||||
fi
|
||||
cat > $TMPC << EOF
|
||||
#include <glusterfs/api/glfs.h>
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
/* new glfs_ftruncate() passes two additional args */
|
||||
return glfs_ftruncate(NULL, 0, NULL, NULL);
|
||||
}
|
||||
EOF
|
||||
if compile_prog "$glusterfs_cflags" "$glusterfs_libs" ; then
|
||||
glusterfs_ftruncate_has_stat="yes"
|
||||
fi
|
||||
cat > $TMPC << EOF
|
||||
#include <glusterfs/api/glfs.h>
|
||||
|
||||
/* new glfs_io_cbk() passes two additional glfs_stat structs */
|
||||
static void
|
||||
glusterfs_iocb(glfs_fd_t *fd, ssize_t ret, struct glfs_stat *prestat, struct glfs_stat *poststat, void *data)
|
||||
{}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
glfs_io_cbk iocb = &glusterfs_iocb;
|
||||
iocb(NULL, 0 , NULL, NULL, NULL);
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if compile_prog "$glusterfs_cflags" "$glusterfs_libs" ; then
|
||||
glusterfs_iocb_has_stat="yes"
|
||||
fi
|
||||
else
|
||||
if test "$glusterfs" = "yes" ; then
|
||||
feature_not_found "GlusterFS backend support" \
|
||||
@@ -6976,6 +7010,14 @@ if test "$glusterfs_zerofill" = "yes" ; then
|
||||
echo "CONFIG_GLUSTERFS_ZEROFILL=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$glusterfs_ftruncate_has_stat" = "yes" ; then
|
||||
echo "CONFIG_GLUSTERFS_FTRUNCATE_HAS_STAT=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$glusterfs_iocb_has_stat" = "yes" ; then
|
||||
echo "CONFIG_GLUSTERFS_IOCB_HAS_STAT=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$libssh2" = "yes" ; then
|
||||
echo "CONFIG_LIBSSH2=m" >> $config_host_mak
|
||||
echo "LIBSSH2_CFLAGS=$libssh2_cflags" >> $config_host_mak
|
||||
|
||||
+3
-3
@@ -324,8 +324,8 @@ static uint16_t nvme_write_zeros(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
|
||||
const uint8_t data_shift = ns->id_ns.lbaf[lba_index].ds;
|
||||
uint64_t slba = le64_to_cpu(rw->slba);
|
||||
uint32_t nlb = le16_to_cpu(rw->nlb) + 1;
|
||||
uint64_t aio_slba = slba << (data_shift - BDRV_SECTOR_BITS);
|
||||
uint32_t aio_nlb = nlb << (data_shift - BDRV_SECTOR_BITS);
|
||||
uint64_t offset = slba << data_shift;
|
||||
uint32_t count = nlb << data_shift;
|
||||
|
||||
if (unlikely(slba + nlb > ns->id_ns.nsze)) {
|
||||
trace_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze);
|
||||
@@ -335,7 +335,7 @@ static uint16_t nvme_write_zeros(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
|
||||
req->has_sg = false;
|
||||
block_acct_start(blk_get_stats(n->conf.blk), &req->acct, 0,
|
||||
BLOCK_ACCT_WRITE);
|
||||
req->aiocb = blk_aio_pwrite_zeroes(n->conf.blk, aio_slba, aio_nlb,
|
||||
req->aiocb = blk_aio_pwrite_zeroes(n->conf.blk, offset, count,
|
||||
BDRV_REQ_MAY_UNMAP, nvme_rw_cb, req);
|
||||
return NVME_NO_COMPLETE;
|
||||
}
|
||||
|
||||
+11
-2
@@ -187,6 +187,9 @@ typedef struct BDRVReopenState {
|
||||
BlockDriverState *bs;
|
||||
int flags;
|
||||
BlockdevDetectZeroesOptions detect_zeroes;
|
||||
bool backing_missing;
|
||||
bool replace_backing_bs; /* new_backing_bs is ignored if this is false */
|
||||
BlockDriverState *new_backing_bs; /* If NULL then detach the current bs */
|
||||
uint64_t perm, shared_perm;
|
||||
QDict *options;
|
||||
QDict *explicit_options;
|
||||
@@ -299,8 +302,9 @@ BlockDriverState *bdrv_open(const char *filename, const char *reference,
|
||||
BlockDriverState *bdrv_new_open_driver(BlockDriver *drv, const char *node_name,
|
||||
int flags, Error **errp);
|
||||
BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
|
||||
BlockDriverState *bs, QDict *options);
|
||||
int bdrv_reopen_multiple(AioContext *ctx, BlockReopenQueue *bs_queue, Error **errp);
|
||||
BlockDriverState *bs, QDict *options,
|
||||
bool keep_old_opts);
|
||||
int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp);
|
||||
int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only,
|
||||
Error **errp);
|
||||
int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
|
||||
@@ -353,6 +357,11 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
|
||||
BlockDriverState *bdrv_find_overlay(BlockDriverState *active,
|
||||
BlockDriverState *bs);
|
||||
BlockDriverState *bdrv_find_base(BlockDriverState *bs);
|
||||
bool bdrv_is_backing_chain_frozen(BlockDriverState *bs, BlockDriverState *base,
|
||||
Error **errp);
|
||||
int bdrv_freeze_backing_chain(BlockDriverState *bs, BlockDriverState *base,
|
||||
Error **errp);
|
||||
void bdrv_unfreeze_backing_chain(BlockDriverState *bs, BlockDriverState *base);
|
||||
|
||||
|
||||
typedef struct BdrvCheckResult {
|
||||
|
||||
@@ -383,6 +383,14 @@ struct BlockDriver {
|
||||
|
||||
/* List of options for creating images, terminated by name == NULL */
|
||||
QemuOptsList *create_opts;
|
||||
/*
|
||||
* If this driver supports reopening images this contains a
|
||||
* NULL-terminated list of the runtime options that can be
|
||||
* modified. If an option in this list is unspecified during
|
||||
* reopen then it _must_ be reset to its default value or return
|
||||
* an error.
|
||||
*/
|
||||
const char *const *mutable_opts;
|
||||
|
||||
/*
|
||||
* Returns 0 for completed check, -errno for internal errors.
|
||||
@@ -711,6 +719,12 @@ struct BdrvChild {
|
||||
uint64_t backup_perm;
|
||||
uint64_t backup_shared_perm;
|
||||
|
||||
/*
|
||||
* This link is frozen: the child can neither be replaced nor
|
||||
* detached from the parent.
|
||||
*/
|
||||
bool frozen;
|
||||
|
||||
QLIST_ENTRY(BdrvChild) next;
|
||||
QLIST_ENTRY(BdrvChild) next_parent;
|
||||
};
|
||||
|
||||
+54
-12
@@ -537,20 +537,20 @@
|
||||
# +------------------
|
||||
# 10 50 100
|
||||
#
|
||||
# Since: 2.12
|
||||
# Since: 4.0
|
||||
##
|
||||
{ 'struct': 'BlockLatencyHistogramInfo',
|
||||
'data': {'boundaries': ['uint64'], 'bins': ['uint64'] } }
|
||||
|
||||
##
|
||||
# @x-block-latency-histogram-set:
|
||||
# @block-latency-histogram-set:
|
||||
#
|
||||
# Manage read, write and flush latency histograms for the device.
|
||||
#
|
||||
# If only @device parameter is specified, remove all present latency histograms
|
||||
# for the device. Otherwise, add/reset some of (or all) latency histograms.
|
||||
#
|
||||
# @device: device name to set latency histogram for.
|
||||
# @id: The name or QOM path of the guest device.
|
||||
#
|
||||
# @boundaries: list of interval boundary values (see description in
|
||||
# BlockLatencyHistogramInfo definition). If specified, all
|
||||
@@ -573,7 +573,7 @@
|
||||
#
|
||||
# Returns: error if device is not found or any boundary arrays are invalid.
|
||||
#
|
||||
# Since: 2.12
|
||||
# Since: 4.0
|
||||
#
|
||||
# Example: set new histograms for all io types with intervals
|
||||
# [0, 10), [10, 50), [50, 100), [100, +inf):
|
||||
@@ -607,8 +607,8 @@
|
||||
# "arguments": { "device": "drive0" } }
|
||||
# <- { "return": {} }
|
||||
##
|
||||
{ 'command': 'x-block-latency-histogram-set',
|
||||
'data': {'device': 'str',
|
||||
{ 'command': 'block-latency-histogram-set',
|
||||
'data': {'id': 'str',
|
||||
'*boundaries': ['uint64'],
|
||||
'*boundaries-read': ['uint64'],
|
||||
'*boundaries-write': ['uint64'],
|
||||
@@ -894,11 +894,11 @@
|
||||
# @timed_stats: Statistics specific to the set of previously defined
|
||||
# intervals of time (Since 2.5)
|
||||
#
|
||||
# @x_rd_latency_histogram: @BlockLatencyHistogramInfo. (Since 2.12)
|
||||
# @rd_latency_histogram: @BlockLatencyHistogramInfo. (Since 4.0)
|
||||
#
|
||||
# @x_wr_latency_histogram: @BlockLatencyHistogramInfo. (Since 2.12)
|
||||
# @wr_latency_histogram: @BlockLatencyHistogramInfo. (Since 4.0)
|
||||
#
|
||||
# @x_flush_latency_histogram: @BlockLatencyHistogramInfo. (Since 2.12)
|
||||
# @flush_latency_histogram: @BlockLatencyHistogramInfo. (Since 4.0)
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
@@ -913,9 +913,9 @@
|
||||
'invalid_wr_operations': 'int', 'invalid_flush_operations': 'int',
|
||||
'account_invalid': 'bool', 'account_failed': 'bool',
|
||||
'timed_stats': ['BlockDeviceTimedStats'],
|
||||
'*x_rd_latency_histogram': 'BlockLatencyHistogramInfo',
|
||||
'*x_wr_latency_histogram': 'BlockLatencyHistogramInfo',
|
||||
'*x_flush_latency_histogram': 'BlockLatencyHistogramInfo' } }
|
||||
'*rd_latency_histogram': 'BlockLatencyHistogramInfo',
|
||||
'*wr_latency_histogram': 'BlockLatencyHistogramInfo',
|
||||
'*flush_latency_histogram': 'BlockLatencyHistogramInfo' } }
|
||||
|
||||
##
|
||||
# @BlockStats:
|
||||
@@ -3997,6 +3997,48 @@
|
||||
##
|
||||
{ 'command': 'blockdev-add', 'data': 'BlockdevOptions', 'boxed': true }
|
||||
|
||||
##
|
||||
# @x-blockdev-reopen:
|
||||
#
|
||||
# Reopens a block device using the given set of options. Any option
|
||||
# not specified will be reset to its default value regardless of its
|
||||
# previous status. If an option cannot be changed or a particular
|
||||
# driver does not support reopening then the command will return an
|
||||
# error.
|
||||
#
|
||||
# The top-level @node-name option (from BlockdevOptions) must be
|
||||
# specified and is used to select the block device to be reopened.
|
||||
# Other @node-name options must be either omitted or set to the
|
||||
# current name of the appropriate node. This command won't change any
|
||||
# node name and any attempt to do it will result in an error.
|
||||
#
|
||||
# In the case of options that refer to child nodes, the behavior of
|
||||
# this command depends on the value:
|
||||
#
|
||||
# 1) A set of options (BlockdevOptions): the child is reopened with
|
||||
# the specified set of options.
|
||||
#
|
||||
# 2) A reference to the current child: the child is reopened using
|
||||
# its existing set of options.
|
||||
#
|
||||
# 3) A reference to a different node: the current child is replaced
|
||||
# with the specified one.
|
||||
#
|
||||
# 4) NULL: the current child (if any) is detached.
|
||||
#
|
||||
# Options (1) and (2) are supported in all cases, but at the moment
|
||||
# only @backing allows replacing or detaching an existing child.
|
||||
#
|
||||
# Unlike with blockdev-add, the @backing option must always be present
|
||||
# unless the node being reopened does not have a backing file and its
|
||||
# image does not have a default backing file name as part of its
|
||||
# metadata.
|
||||
#
|
||||
# Since: 4.0
|
||||
##
|
||||
{ 'command': 'x-blockdev-reopen',
|
||||
'data': 'BlockdevOptions', 'boxed': true }
|
||||
|
||||
##
|
||||
# @blockdev-del:
|
||||
#
|
||||
|
||||
+2
-2
@@ -2080,8 +2080,8 @@ static int reopen_f(BlockBackend *blk, int argc, char **argv)
|
||||
}
|
||||
|
||||
bdrv_subtree_drained_begin(bs);
|
||||
brq = bdrv_reopen_queue(NULL, bs, opts);
|
||||
bdrv_reopen_multiple(bdrv_get_aio_context(bs), brq, &local_err);
|
||||
brq = bdrv_reopen_queue(NULL, bs, opts, true);
|
||||
bdrv_reopen_multiple(brq, &local_err);
|
||||
bdrv_subtree_drained_end(bs);
|
||||
|
||||
if (local_err) {
|
||||
|
||||
@@ -356,6 +356,13 @@ $QEMU_IO -c "read -P 0x33 0 4k" "$TEST_IMG" | _filter_qemu_io
|
||||
# Using snapshot=on with a non-existent TMPDIR
|
||||
TMPDIR=/nonexistent run_qemu -drive driver=null-co,snapshot=on
|
||||
|
||||
# Using snapshot=on together with read-only=on
|
||||
echo "info block" |
|
||||
run_qemu -drive file="$TEST_IMG",snapshot=on,read-only=on,if=none,id=$device_id |
|
||||
_filter_qemu_io |
|
||||
sed -e 's#"/[^"]*/vl\.[A-Za-z0-9]\{6\}"#SNAPSHOT_PATH#g'
|
||||
|
||||
|
||||
# success, all done
|
||||
echo "*** done"
|
||||
rm -f $seq.full
|
||||
|
||||
@@ -458,4 +458,13 @@ read 4096/4096 bytes at offset 0
|
||||
Testing: -drive driver=null-co,snapshot=on
|
||||
QEMU_PROG: -drive driver=null-co,snapshot=on: Could not get temporary filename: No such file or directory
|
||||
|
||||
Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,read-only=on,if=none,id=drive0
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
(qemu) info block
|
||||
drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}}, "driver": "qcow2", "file": {"driver": "file", "filename": SNAPSHOT_PATH}} (qcow2, read-only)
|
||||
Removable device: not locked, tray closed
|
||||
Cache mode: writeback, ignore flushes
|
||||
Backing file: TEST_DIR/t.qcow2 (chain depth: 1)
|
||||
(qemu) quit
|
||||
|
||||
*** done
|
||||
|
||||
@@ -530,4 +530,13 @@ read 4096/4096 bytes at offset 0
|
||||
Testing: -drive driver=null-co,snapshot=on
|
||||
QEMU_PROG: -drive driver=null-co,snapshot=on: Could not get temporary filename: No such file or directory
|
||||
|
||||
Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,read-only=on,if=none,id=drive0
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
(qemu) info block
|
||||
drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}}, "driver": "qcow2", "file": {"driver": "file", "filename": SNAPSHOT_PATH}} (qcow2, read-only)
|
||||
Removable device: not locked, tray closed
|
||||
Cache mode: writeback, ignore flushes
|
||||
Backing file: TEST_DIR/t.qcow2 (chain depth: 1)
|
||||
(qemu) quit
|
||||
|
||||
*** done
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user