2012-09-27 21:29:13 +04:00
|
|
|
/*
|
|
|
|
* Live block commit
|
|
|
|
*
|
|
|
|
* Copyright Red Hat, Inc. 2012
|
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Jeff Cody <jcody@redhat.com>
|
|
|
|
* Based on stream.c by Stefan Hajnoczi
|
|
|
|
*
|
|
|
|
* This work is licensed under the terms of the GNU LGPL, version 2 or later.
|
|
|
|
* See the COPYING.LIB file in the top-level directory.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2016-01-18 21:01:42 +03:00
|
|
|
#include "qemu/osdep.h"
|
2012-09-27 21:29:13 +04:00
|
|
|
#include "trace.h"
|
2012-12-17 21:19:44 +04:00
|
|
|
#include "block/block_int.h"
|
2016-10-27 19:07:00 +03:00
|
|
|
#include "block/blockjob_int.h"
|
include/qemu/osdep.h: Don't include qapi/error.h
Commit 57cb38b included qapi/error.h into qemu/osdep.h to get the
Error typedef. Since then, we've moved to include qemu/osdep.h
everywhere. Its file comment explains: "To avoid getting into
possible circular include dependencies, this file should not include
any other QEMU headers, with the exceptions of config-host.h,
compiler.h, os-posix.h and os-win32.h, all of which are doing a
similar job to this file and are under similar constraints."
qapi/error.h doesn't do a similar job, and it doesn't adhere to
similar constraints: it includes qapi-types.h. That's in excess of
100KiB of crap most .c files don't actually need.
Add the typedef to qemu/typedefs.h, and include that instead of
qapi/error.h. Include qapi/error.h in .c files that need it and don't
get it now. Include qapi-types.h in qom/object.h for uint16List.
Update scripts/clean-includes accordingly. Update it further to match
reality: replace config.h by config-target.h, add sysemu/os-posix.h,
sysemu/os-win32.h. Update the list of includes in the qemu/osdep.h
comment quoted above similarly.
This reduces the number of objects depending on qapi/error.h from "all
of them" to less than a third. Unfortunately, the number depending on
qapi-types.h shrinks only a little. More work is needed for that one.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
[Fix compilation without the spice devel packages. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2016-03-14 11:01:28 +03:00
|
|
|
#include "qapi/error.h"
|
2015-03-17 19:22:46 +03:00
|
|
|
#include "qapi/qmp/qerror.h"
|
2012-09-27 21:29:13 +04:00
|
|
|
#include "qemu/ratelimit.h"
|
2015-10-19 18:53:22 +03:00
|
|
|
#include "sysemu/block-backend.h"
|
2012-09-27 21:29:13 +04:00
|
|
|
|
|
|
|
enum {
|
|
|
|
/*
|
|
|
|
* Size of data buffer for populating the image file. This should be large
|
|
|
|
* enough to process multiple clusters in a single call, so that populating
|
|
|
|
* contiguous regions of the image is efficient.
|
|
|
|
*/
|
|
|
|
COMMIT_BUFFER_SIZE = 512 * 1024, /* in bytes */
|
|
|
|
};
|
|
|
|
|
|
|
|
#define SLICE_TIME 100000000ULL /* ns */
|
|
|
|
|
|
|
|
typedef struct CommitBlockJob {
|
|
|
|
BlockJob common;
|
|
|
|
RateLimit limit;
|
|
|
|
BlockDriverState *active;
|
2016-04-14 14:09:53 +03:00
|
|
|
BlockBackend *top;
|
|
|
|
BlockBackend *base;
|
2012-09-28 19:22:55 +04:00
|
|
|
BlockdevOnError on_error;
|
2012-09-27 21:29:13 +04:00
|
|
|
int base_flags;
|
|
|
|
int orig_overlay_flags;
|
block: extend block-commit to accept a string for the backing file
On some image chains, QEMU may not always be able to resolve the
filenames properly, when updating the backing file of an image
after a block commit.
For instance, certain relative pathnames may fail, or drives may
have been specified originally by file descriptor (e.g. /dev/fd/???),
or a relative protocol pathname may have been used.
In these instances, QEMU may lack the information to be able to make
the correct choice, but the user or management layer most likely does
have that knowledge.
With this extension to the block-commit api, the user is able to change
the backing file of the overlay image as part of the block-commit
operation.
This allows the change to be 'safe', in the sense that if the attempt
to write the overlay image metadata fails, then the block-commit
operation returns failure, without disrupting the guest.
If the commit top is the active layer, then specifying the backing
file string will be treated as an error (there is no overlay image
to modify in that case).
If a backing file string is not specified in the command, the backing
file string to use is determined in the same manner as it was
previously.
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Jeff Cody <jcody@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2014-06-25 23:40:10 +04:00
|
|
|
char *backing_file_str;
|
2012-09-27 21:29:13 +04:00
|
|
|
} CommitBlockJob;
|
|
|
|
|
2016-04-14 14:09:53 +03:00
|
|
|
static int coroutine_fn commit_populate(BlockBackend *bs, BlockBackend *base,
|
2012-09-27 21:29:13 +04:00
|
|
|
int64_t sector_num, int nb_sectors,
|
|
|
|
void *buf)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
2016-04-14 14:09:53 +03:00
|
|
|
QEMUIOVector qiov;
|
|
|
|
struct iovec iov = {
|
|
|
|
.iov_base = buf,
|
|
|
|
.iov_len = nb_sectors * BDRV_SECTOR_SIZE,
|
|
|
|
};
|
2012-09-27 21:29:13 +04:00
|
|
|
|
2016-04-14 14:09:53 +03:00
|
|
|
qemu_iovec_init_external(&qiov, &iov, 1);
|
|
|
|
|
|
|
|
ret = blk_co_preadv(bs, sector_num * BDRV_SECTOR_SIZE,
|
|
|
|
qiov.size, &qiov, 0);
|
|
|
|
if (ret < 0) {
|
2012-09-27 21:29:13 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-04-14 14:09:53 +03:00
|
|
|
ret = blk_co_pwritev(base, sector_num * BDRV_SECTOR_SIZE,
|
|
|
|
qiov.size, &qiov, 0);
|
|
|
|
if (ret < 0) {
|
2012-09-27 21:29:13 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-10-21 15:03:59 +04:00
|
|
|
typedef struct {
|
|
|
|
int ret;
|
|
|
|
} CommitCompleteData;
|
|
|
|
|
|
|
|
static void commit_complete(BlockJob *job, void *opaque)
|
2012-09-27 21:29:13 +04:00
|
|
|
{
|
2014-10-21 15:03:59 +04:00
|
|
|
CommitBlockJob *s = container_of(job, CommitBlockJob, common);
|
|
|
|
CommitCompleteData *data = opaque;
|
2012-09-27 21:29:13 +04:00
|
|
|
BlockDriverState *active = s->active;
|
2016-04-14 14:09:53 +03:00
|
|
|
BlockDriverState *top = blk_bs(s->top);
|
|
|
|
BlockDriverState *base = blk_bs(s->base);
|
2016-08-22 06:36:03 +03:00
|
|
|
BlockDriverState *overlay_bs = bdrv_find_overlay(active, top);
|
2014-10-21 15:03:59 +04:00
|
|
|
int ret = data->ret;
|
|
|
|
|
|
|
|
if (!block_job_is_cancelled(&s->common) && ret == 0) {
|
|
|
|
/* success */
|
|
|
|
ret = bdrv_drop_intermediate(active, top, base, s->backing_file_str);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* restore base open flags here if appropriate (e.g., change the base back
|
|
|
|
* to r/o). These reopens do not need to be atomic, since we won't abort
|
|
|
|
* even on failure here */
|
|
|
|
if (s->base_flags != bdrv_get_flags(base)) {
|
|
|
|
bdrv_reopen(base, s->base_flags, NULL);
|
|
|
|
}
|
|
|
|
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);
|
2016-04-14 14:09:53 +03:00
|
|
|
blk_unref(s->top);
|
|
|
|
blk_unref(s->base);
|
2014-10-21 15:03:59 +04:00
|
|
|
block_job_completed(&s->common, ret);
|
|
|
|
g_free(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void coroutine_fn commit_run(void *opaque)
|
|
|
|
{
|
|
|
|
CommitBlockJob *s = opaque;
|
|
|
|
CommitCompleteData *data;
|
2012-09-27 21:29:13 +04:00
|
|
|
int64_t sector_num, end;
|
Improve block job rate limiting for small bandwidth values
ratelimit_calculate_delay() previously reset the accounting every time
slice, no matter how much data had been processed before. This had (at
least) two consequences:
1. The minimum speed is rather large, e.g. 5 MiB/s for commit and stream.
Not sure if there are real-world use cases where this would be a
problem. Mirroring and backup over a slow link (e.g. DSL) would
come to mind, though.
2. Tests for block job operations (e.g. cancel) were rather racy
All block jobs currently use a time slice of 100ms. That's a
reasonable value to get smooth output during regular
operation. However this also meant that the state of block jobs
changed every 100ms, no matter how low the configured limit was. On
busy hosts, qemu often transferred additional chunks until the test
case had a chance to cancel the job.
Fix the block job rate limit code to delay for more than one time
slice to address the above issues. To make it easier to handle
oversized chunks we switch the semantics from returning a delay
_before_ the current request to a delay _after_ the current
request. If necessary, this delay consists of multiple time slice
units.
Since the mirror job sends multiple chunks in one go even if the rate
limit was exceeded in between, we need to keep track of the start of
the current time slice so we can correctly re-compute the delay for
the updated amount of data.
The minimum bandwidth now is 1 data unit per time slice. The block
jobs are currently passing the amount of data transferred in sectors
and using 100ms time slices, so this translates to 5120
bytes/second. With chunk sizes usually being O(512KiB), tests have
plenty of time (O(100s)) to operate on block jobs. The chance of a
race condition now is fairly remote, except possibly on insanely
loaded systems.
Signed-off-by: Sascha Silbe <silbe@linux.vnet.ibm.com>
Message-id: 1467127721-9564-2-git-send-email-silbe@linux.vnet.ibm.com
Reviewed-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Max Reitz <mreitz@redhat.com>
2016-06-28 18:28:41 +03:00
|
|
|
uint64_t delay_ns = 0;
|
2012-09-27 21:29:13 +04:00
|
|
|
int ret = 0;
|
|
|
|
int n = 0;
|
2014-10-21 15:03:59 +04:00
|
|
|
void *buf = NULL;
|
2012-09-27 21:29:13 +04:00
|
|
|
int bytes_written = 0;
|
|
|
|
int64_t base_len;
|
|
|
|
|
2016-04-14 14:09:53 +03:00
|
|
|
ret = s->common.len = blk_getlength(s->top);
|
2012-09-27 21:29:13 +04:00
|
|
|
|
|
|
|
|
|
|
|
if (s->common.len < 0) {
|
2014-10-21 15:03:59 +04:00
|
|
|
goto out;
|
2012-09-27 21:29:13 +04:00
|
|
|
}
|
|
|
|
|
2016-04-14 14:09:53 +03:00
|
|
|
ret = base_len = blk_getlength(s->base);
|
2012-09-27 21:29:13 +04:00
|
|
|
if (base_len < 0) {
|
2014-10-21 15:03:59 +04:00
|
|
|
goto out;
|
2012-09-27 21:29:13 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (base_len < s->common.len) {
|
2016-04-14 14:09:53 +03:00
|
|
|
ret = blk_truncate(s->base, s->common.len);
|
2012-09-27 21:29:13 +04:00
|
|
|
if (ret) {
|
2014-10-21 15:03:59 +04:00
|
|
|
goto out;
|
2012-09-27 21:29:13 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
end = s->common.len >> BDRV_SECTOR_BITS;
|
2016-04-14 14:09:53 +03:00
|
|
|
buf = blk_blockalign(s->top, COMMIT_BUFFER_SIZE);
|
2012-09-27 21:29:13 +04:00
|
|
|
|
|
|
|
for (sector_num = 0; sector_num < end; sector_num += n) {
|
|
|
|
bool copy;
|
|
|
|
|
|
|
|
/* Note that even when no rate limit is applied we need to yield
|
2012-11-13 19:35:13 +04:00
|
|
|
* with no pending I/O here so that bdrv_drain_all() returns.
|
2012-09-27 21:29:13 +04:00
|
|
|
*/
|
2013-08-21 19:03:05 +04:00
|
|
|
block_job_sleep_ns(&s->common, QEMU_CLOCK_REALTIME, delay_ns);
|
2012-09-27 21:29:13 +04:00
|
|
|
if (block_job_is_cancelled(&s->common)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* Copy if allocated above the base */
|
2016-04-14 14:09:53 +03:00
|
|
|
ret = bdrv_is_allocated_above(blk_bs(s->top), blk_bs(s->base),
|
|
|
|
sector_num,
|
2013-09-04 21:00:24 +04:00
|
|
|
COMMIT_BUFFER_SIZE / BDRV_SECTOR_SIZE,
|
|
|
|
&n);
|
2012-09-27 21:29:13 +04:00
|
|
|
copy = (ret == 1);
|
|
|
|
trace_commit_one_iteration(s, sector_num, n, ret);
|
|
|
|
if (copy) {
|
2016-04-14 14:09:53 +03:00
|
|
|
ret = commit_populate(s->top, s->base, sector_num, n, buf);
|
2012-09-27 21:29:13 +04:00
|
|
|
bytes_written += n * BDRV_SECTOR_SIZE;
|
|
|
|
}
|
|
|
|
if (ret < 0) {
|
2016-06-29 18:38:57 +03:00
|
|
|
BlockErrorAction action =
|
|
|
|
block_job_error_action(&s->common, false, s->on_error, -ret);
|
|
|
|
if (action == BLOCK_ERROR_ACTION_REPORT) {
|
2014-10-21 15:03:59 +04:00
|
|
|
goto out;
|
2012-09-27 21:29:13 +04:00
|
|
|
} else {
|
|
|
|
n = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Publish progress */
|
|
|
|
s->common.offset += n * BDRV_SECTOR_SIZE;
|
Improve block job rate limiting for small bandwidth values
ratelimit_calculate_delay() previously reset the accounting every time
slice, no matter how much data had been processed before. This had (at
least) two consequences:
1. The minimum speed is rather large, e.g. 5 MiB/s for commit and stream.
Not sure if there are real-world use cases where this would be a
problem. Mirroring and backup over a slow link (e.g. DSL) would
come to mind, though.
2. Tests for block job operations (e.g. cancel) were rather racy
All block jobs currently use a time slice of 100ms. That's a
reasonable value to get smooth output during regular
operation. However this also meant that the state of block jobs
changed every 100ms, no matter how low the configured limit was. On
busy hosts, qemu often transferred additional chunks until the test
case had a chance to cancel the job.
Fix the block job rate limit code to delay for more than one time
slice to address the above issues. To make it easier to handle
oversized chunks we switch the semantics from returning a delay
_before_ the current request to a delay _after_ the current
request. If necessary, this delay consists of multiple time slice
units.
Since the mirror job sends multiple chunks in one go even if the rate
limit was exceeded in between, we need to keep track of the start of
the current time slice so we can correctly re-compute the delay for
the updated amount of data.
The minimum bandwidth now is 1 data unit per time slice. The block
jobs are currently passing the amount of data transferred in sectors
and using 100ms time slices, so this translates to 5120
bytes/second. With chunk sizes usually being O(512KiB), tests have
plenty of time (O(100s)) to operate on block jobs. The chance of a
race condition now is fairly remote, except possibly on insanely
loaded systems.
Signed-off-by: Sascha Silbe <silbe@linux.vnet.ibm.com>
Message-id: 1467127721-9564-2-git-send-email-silbe@linux.vnet.ibm.com
Reviewed-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Max Reitz <mreitz@redhat.com>
2016-06-28 18:28:41 +03:00
|
|
|
|
|
|
|
if (copy && s->common.speed) {
|
|
|
|
delay_ns = ratelimit_calculate_delay(&s->limit, n);
|
|
|
|
}
|
2012-09-27 21:29:13 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-10-21 15:03:59 +04:00
|
|
|
out:
|
2012-09-27 21:29:13 +04:00
|
|
|
qemu_vfree(buf);
|
|
|
|
|
2014-10-21 15:03:59 +04:00
|
|
|
data = g_malloc(sizeof(*data));
|
|
|
|
data->ret = ret;
|
|
|
|
block_job_defer_to_main_loop(&s->common, commit_complete, data);
|
2012-09-27 21:29:13 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void commit_set_speed(BlockJob *job, int64_t speed, Error **errp)
|
|
|
|
{
|
|
|
|
CommitBlockJob *s = container_of(job, CommitBlockJob, common);
|
|
|
|
|
|
|
|
if (speed < 0) {
|
2015-03-17 13:54:50 +03:00
|
|
|
error_setg(errp, QERR_INVALID_PARAMETER, "speed");
|
2012-09-27 21:29:13 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
ratelimit_set_speed(&s->limit, speed / BDRV_SECTOR_SIZE, SLICE_TIME);
|
|
|
|
}
|
|
|
|
|
2013-10-08 13:29:38 +04:00
|
|
|
static const BlockJobDriver commit_job_driver = {
|
2012-09-27 21:29:13 +04:00
|
|
|
.instance_size = sizeof(CommitBlockJob),
|
2013-10-08 13:29:40 +04:00
|
|
|
.job_type = BLOCK_JOB_TYPE_COMMIT,
|
2012-09-27 21:29:13 +04:00
|
|
|
.set_speed = commit_set_speed,
|
2016-11-08 09:50:36 +03:00
|
|
|
.start = commit_run,
|
2012-09-27 21:29:13 +04:00
|
|
|
};
|
|
|
|
|
2016-07-05 17:29:00 +03:00
|
|
|
void commit_start(const char *job_id, BlockDriverState *bs,
|
|
|
|
BlockDriverState *base, BlockDriverState *top, int64_t speed,
|
2016-10-27 19:06:58 +03:00
|
|
|
BlockdevOnError on_error, const char *backing_file_str,
|
|
|
|
Error **errp)
|
2012-09-27 21:29:13 +04:00
|
|
|
{
|
|
|
|
CommitBlockJob *s;
|
|
|
|
BlockReopenQueue *reopen_queue = NULL;
|
|
|
|
int orig_overlay_flags;
|
|
|
|
int orig_base_flags;
|
2016-10-28 10:08:08 +03:00
|
|
|
BlockDriverState *iter;
|
2012-09-27 21:29:13 +04:00
|
|
|
BlockDriverState *overlay_bs;
|
|
|
|
Error *local_err = NULL;
|
|
|
|
|
2013-12-16 10:45:33 +04:00
|
|
|
assert(top != bs);
|
2012-09-27 21:29:13 +04:00
|
|
|
if (top == base) {
|
|
|
|
error_setg(errp, "Invalid files for merge: top and base are the same");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
overlay_bs = bdrv_find_overlay(bs, top);
|
|
|
|
|
|
|
|
if (overlay_bs == NULL) {
|
|
|
|
error_setg(errp, "Could not find overlay image for %s:", top->filename);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-07-05 17:29:00 +03:00
|
|
|
s = block_job_create(job_id, &commit_job_driver, bs, speed,
|
2016-10-27 19:06:58 +03:00
|
|
|
BLOCK_JOB_DEFAULT, NULL, NULL, errp);
|
2016-05-27 13:53:39 +03:00
|
|
|
if (!s) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-09-27 21:29:13 +04:00
|
|
|
orig_base_flags = bdrv_get_flags(base);
|
|
|
|
orig_overlay_flags = bdrv_get_flags(overlay_bs);
|
|
|
|
|
|
|
|
/* convert base & overlay_bs to r/w, if necessary */
|
2015-10-28 16:43:49 +03:00
|
|
|
if (!(orig_base_flags & BDRV_O_RDWR)) {
|
|
|
|
reopen_queue = bdrv_reopen_queue(reopen_queue, base, NULL,
|
|
|
|
orig_base_flags | BDRV_O_RDWR);
|
|
|
|
}
|
2016-09-15 17:53:04 +03:00
|
|
|
if (!(orig_overlay_flags & BDRV_O_RDWR)) {
|
|
|
|
reopen_queue = bdrv_reopen_queue(reopen_queue, overlay_bs, NULL,
|
|
|
|
orig_overlay_flags | BDRV_O_RDWR);
|
|
|
|
}
|
2012-09-27 21:29:13 +04:00
|
|
|
if (reopen_queue) {
|
2016-10-27 13:49:02 +03:00
|
|
|
bdrv_reopen_multiple(bdrv_get_aio_context(bs), reopen_queue, &local_err);
|
2012-09-27 21:29:13 +04:00
|
|
|
if (local_err != NULL) {
|
|
|
|
error_propagate(errp, local_err);
|
2016-05-27 13:53:39 +03:00
|
|
|
block_job_unref(&s->common);
|
2012-09-27 21:29:13 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-10-28 10:08:08 +03:00
|
|
|
/* Block all nodes between top and base, because they will
|
|
|
|
* disappear from the chain after this operation. */
|
|
|
|
assert(bdrv_chain_contains(top, base));
|
|
|
|
for (iter = top; iter != backing_bs(base); iter = backing_bs(iter)) {
|
|
|
|
block_job_add_bdrv(&s->common, iter);
|
|
|
|
}
|
|
|
|
/* overlay_bs must be blocked because it needs to be modified to
|
|
|
|
* update the backing image string, but if it's the root node then
|
|
|
|
* don't block it again */
|
|
|
|
if (bs != overlay_bs) {
|
|
|
|
block_job_add_bdrv(&s->common, overlay_bs);
|
|
|
|
}
|
|
|
|
|
2016-04-14 14:09:53 +03:00
|
|
|
s->base = blk_new();
|
|
|
|
blk_insert_bs(s->base, base);
|
|
|
|
|
|
|
|
s->top = blk_new();
|
|
|
|
blk_insert_bs(s->top, top);
|
|
|
|
|
2012-09-27 21:29:13 +04:00
|
|
|
s->active = bs;
|
|
|
|
|
|
|
|
s->base_flags = orig_base_flags;
|
|
|
|
s->orig_overlay_flags = orig_overlay_flags;
|
|
|
|
|
block: extend block-commit to accept a string for the backing file
On some image chains, QEMU may not always be able to resolve the
filenames properly, when updating the backing file of an image
after a block commit.
For instance, certain relative pathnames may fail, or drives may
have been specified originally by file descriptor (e.g. /dev/fd/???),
or a relative protocol pathname may have been used.
In these instances, QEMU may lack the information to be able to make
the correct choice, but the user or management layer most likely does
have that knowledge.
With this extension to the block-commit api, the user is able to change
the backing file of the overlay image as part of the block-commit
operation.
This allows the change to be 'safe', in the sense that if the attempt
to write the overlay image metadata fails, then the block-commit
operation returns failure, without disrupting the guest.
If the commit top is the active layer, then specifying the backing
file string will be treated as an error (there is no overlay image
to modify in that case).
If a backing file string is not specified in the command, the backing
file string to use is determined in the same manner as it was
previously.
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Jeff Cody <jcody@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2014-06-25 23:40:10 +04:00
|
|
|
s->backing_file_str = g_strdup(backing_file_str);
|
|
|
|
|
2012-09-27 21:29:13 +04:00
|
|
|
s->on_error = on_error;
|
|
|
|
|
2016-11-08 09:50:37 +03:00
|
|
|
trace_commit_start(bs, base, top, s);
|
|
|
|
block_job_start(&s->common);
|
2012-09-27 21:29:13 +04:00
|
|
|
}
|
2016-05-30 16:53:15 +03:00
|
|
|
|
|
|
|
|
|
|
|
#define COMMIT_BUF_SECTORS 2048
|
|
|
|
|
|
|
|
/* commit COW file into the raw image */
|
|
|
|
int bdrv_commit(BlockDriverState *bs)
|
|
|
|
{
|
2016-05-30 17:29:47 +03:00
|
|
|
BlockBackend *src, *backing;
|
2016-05-30 16:53:15 +03:00
|
|
|
BlockDriver *drv = bs->drv;
|
|
|
|
int64_t sector, total_sectors, length, backing_length;
|
|
|
|
int n, ro, open_flags;
|
|
|
|
int ret = 0;
|
|
|
|
uint8_t *buf = NULL;
|
|
|
|
|
|
|
|
if (!drv)
|
|
|
|
return -ENOMEDIUM;
|
|
|
|
|
|
|
|
if (!bs->backing) {
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_COMMIT_SOURCE, NULL) ||
|
|
|
|
bdrv_op_is_blocked(bs->backing->bs, BLOCK_OP_TYPE_COMMIT_TARGET, NULL)) {
|
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
|
|
|
|
ro = bs->backing->bs->read_only;
|
|
|
|
open_flags = bs->backing->bs->open_flags;
|
|
|
|
|
|
|
|
if (ro) {
|
|
|
|
if (bdrv_reopen(bs->backing->bs, open_flags | BDRV_O_RDWR, NULL)) {
|
|
|
|
return -EACCES;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-30 17:29:47 +03:00
|
|
|
src = blk_new();
|
|
|
|
blk_insert_bs(src, bs);
|
|
|
|
|
|
|
|
backing = blk_new();
|
|
|
|
blk_insert_bs(backing, bs->backing->bs);
|
|
|
|
|
|
|
|
length = blk_getlength(src);
|
2016-05-30 16:53:15 +03:00
|
|
|
if (length < 0) {
|
|
|
|
ret = length;
|
|
|
|
goto ro_cleanup;
|
|
|
|
}
|
|
|
|
|
2016-05-30 17:29:47 +03:00
|
|
|
backing_length = blk_getlength(backing);
|
2016-05-30 16:53:15 +03:00
|
|
|
if (backing_length < 0) {
|
|
|
|
ret = backing_length;
|
|
|
|
goto ro_cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If our top snapshot is larger than the backing file image,
|
|
|
|
* grow the backing file image if possible. If not possible,
|
|
|
|
* we must return an error */
|
|
|
|
if (length > backing_length) {
|
2016-05-30 17:29:47 +03:00
|
|
|
ret = blk_truncate(backing, length);
|
2016-05-30 16:53:15 +03:00
|
|
|
if (ret < 0) {
|
|
|
|
goto ro_cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
total_sectors = length >> BDRV_SECTOR_BITS;
|
|
|
|
|
2016-05-30 17:29:47 +03:00
|
|
|
/* blk_try_blockalign() for src will choose an alignment that works for
|
|
|
|
* backing as well, so no need to compare the alignment manually. */
|
|
|
|
buf = blk_try_blockalign(src, COMMIT_BUF_SECTORS * BDRV_SECTOR_SIZE);
|
2016-05-30 16:53:15 +03:00
|
|
|
if (buf == NULL) {
|
|
|
|
ret = -ENOMEM;
|
|
|
|
goto ro_cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (sector = 0; sector < total_sectors; sector += n) {
|
|
|
|
ret = bdrv_is_allocated(bs, sector, COMMIT_BUF_SECTORS, &n);
|
|
|
|
if (ret < 0) {
|
|
|
|
goto ro_cleanup;
|
|
|
|
}
|
|
|
|
if (ret) {
|
2016-05-30 17:29:47 +03:00
|
|
|
ret = blk_pread(src, sector * BDRV_SECTOR_SIZE, buf,
|
|
|
|
n * BDRV_SECTOR_SIZE);
|
2016-05-30 16:53:15 +03:00
|
|
|
if (ret < 0) {
|
|
|
|
goto ro_cleanup;
|
|
|
|
}
|
|
|
|
|
2016-05-30 17:29:47 +03:00
|
|
|
ret = blk_pwrite(backing, sector * BDRV_SECTOR_SIZE, buf,
|
|
|
|
n * BDRV_SECTOR_SIZE, 0);
|
2016-05-30 16:53:15 +03:00
|
|
|
if (ret < 0) {
|
|
|
|
goto ro_cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (drv->bdrv_make_empty) {
|
|
|
|
ret = drv->bdrv_make_empty(bs);
|
|
|
|
if (ret < 0) {
|
|
|
|
goto ro_cleanup;
|
|
|
|
}
|
2016-05-30 17:29:47 +03:00
|
|
|
blk_flush(src);
|
2016-05-30 16:53:15 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make sure all data we wrote to the backing device is actually
|
|
|
|
* stable on disk.
|
|
|
|
*/
|
2016-05-30 17:29:47 +03:00
|
|
|
blk_flush(backing);
|
2016-05-30 16:53:15 +03:00
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
ro_cleanup:
|
|
|
|
qemu_vfree(buf);
|
|
|
|
|
2016-05-30 17:29:47 +03:00
|
|
|
blk_unref(src);
|
|
|
|
blk_unref(backing);
|
|
|
|
|
2016-05-30 16:53:15 +03:00
|
|
|
if (ro) {
|
|
|
|
/* ignoring error return here */
|
|
|
|
bdrv_reopen(bs->backing->bs, open_flags & ~BDRV_O_RDWR, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|