Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging

Block layer patches:

- Fix check_to_replace_node()
- commit: Expose on-error option in QMP
- qcow2: Fix qcow2_alloc_cluster_abort() for external data file
- mirror: Fix deadlock
- vvfat: Fix segfault while closing read-write node
- Code cleanups

# gpg: Signature made Tue 18 Feb 2020 14:04:43 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: (36 commits)
  iotests: Check that @replaces can replace filters
  iotests: Add tests for invalid Quorum @replaces
  iotests: Use self.image_len in TestRepairQuorum
  iotests: Resolve TODOs in 041
  iotests/041: Drop superfluous shutdowns
  iotests: Add VM.assert_block_path()
  iotests: Use complete_and_wait() in 155
  quorum: Stop marking it as a filter
  mirror: Double-check immediately before replacing
  block: Remove bdrv_recurse_is_first_non_filter()
  block: Use bdrv_recurse_can_replace()
  quorum: Implement .bdrv_recurse_can_replace()
  blkverify: Implement .bdrv_recurse_can_replace()
  block: Add bdrv_recurse_can_replace()
  quorum: Fix child permissions
  iotests: Let 041 use -blockdev for quorum children
  block: Drop bdrv_is_first_non_filter()
  blockdev: Allow resizing everywhere
  blockdev: Allow external snapshots everywhere
  block/io_uring: Remove superfluous semicolon
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell
2020-02-18 14:23:43 +00:00
28 changed files with 678 additions and 209 deletions
+44 -51
View File
@@ -2435,13 +2435,13 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
if (bdrv_get_aio_context(child_bs) != ctx) {
ret = bdrv_try_set_aio_context(child_bs, ctx, &local_err);
if (ret < 0 && child_role->can_set_aio_ctx) {
GSList *ignore = g_slist_prepend(NULL, child);;
GSList *ignore = g_slist_prepend(NULL, child);
ctx = bdrv_get_aio_context(child_bs);
if (child_role->can_set_aio_ctx(child, ctx, &ignore, NULL)) {
error_free(local_err);
ret = 0;
g_slist_free(ignore);
ignore = g_slist_prepend(NULL, child);;
ignore = g_slist_prepend(NULL, child);
child_role->set_aio_ctx(child, ctx, &ignore);
}
g_slist_free(ignore);
@@ -6201,65 +6201,55 @@ int bdrv_amend_options(BlockDriverState *bs, QemuOpts *opts,
return bs->drv->bdrv_amend_options(bs, opts, status_cb, cb_opaque, errp);
}
/* This function will be called by the bdrv_recurse_is_first_non_filter method
* of block filter and by bdrv_is_first_non_filter.
* It is used to test if the given bs is the candidate or recurse more in the
* node graph.
/*
* This function checks whether the given @to_replace is allowed to be
* replaced by a node that always shows the same data as @bs. This is
* used for example to verify whether the mirror job can replace
* @to_replace by the target mirrored from @bs.
* To be replaceable, @bs and @to_replace may either be guaranteed to
* always show the same data (because they are only connected through
* filters), or some driver may allow replacing one of its children
* because it can guarantee that this child's data is not visible at
* all (for example, for dissenting quorum children that have no other
* parents).
*/
bool bdrv_recurse_is_first_non_filter(BlockDriverState *bs,
BlockDriverState *candidate)
bool bdrv_recurse_can_replace(BlockDriverState *bs,
BlockDriverState *to_replace)
{
/* return false if basic checks fails */
if (!bs || !bs->drv) {
return false;
}
/* the code reached a non block filter driver -> check if the bs is
* the same as the candidate. It's the recursion termination condition.
*/
if (!bs->drv->is_filter) {
return bs == candidate;
}
/* Down this path the driver is a block filter driver */
/* If the block filter recursion method is defined use it to recurse down
* the node graph.
*/
if (bs->drv->bdrv_recurse_is_first_non_filter) {
return bs->drv->bdrv_recurse_is_first_non_filter(bs, candidate);
if (bs == to_replace) {
return true;
}
/* the driver is a block filter but don't allow to recurse -> return false
*/
/* See what the driver can do */
if (bs->drv->bdrv_recurse_can_replace) {
return bs->drv->bdrv_recurse_can_replace(bs, to_replace);
}
/* For filters without an own implementation, we can recurse on our own */
if (bs->drv->is_filter) {
BdrvChild *child = bs->file ?: bs->backing;
return bdrv_recurse_can_replace(child->bs, to_replace);
}
/* Safe default */
return false;
}
/* This function checks if the candidate is the first non filter bs down it's
* bs chain. Since we don't have pointers to parents it explore all bs chains
* from the top. Some filters can choose not to pass down the recursion.
/*
* Check whether the given @node_name can be replaced by a node that
* has the same data as @parent_bs. If so, return @node_name's BDS;
* NULL otherwise.
*
* @node_name must be a (recursive) *child of @parent_bs (or this
* function will return NULL).
*
* The result (whether the node can be replaced or not) is only valid
* for as long as no graph or permission changes occur.
*/
bool bdrv_is_first_non_filter(BlockDriverState *candidate)
{
BlockDriverState *bs;
BdrvNextIterator it;
/* walk down the bs forest recursively */
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
bool perm;
/* try to recurse in this top level bs */
perm = bdrv_recurse_is_first_non_filter(bs, candidate);
/* candidate is the first non filter */
if (perm) {
bdrv_next_cleanup(&it);
return true;
}
}
return false;
}
BlockDriverState *check_to_replace_node(BlockDriverState *parent_bs,
const char *node_name, Error **errp)
{
@@ -6284,8 +6274,11 @@ BlockDriverState *check_to_replace_node(BlockDriverState *parent_bs,
* Another benefit is that this tests exclude backing files which are
* blocked by the backing blockers.
*/
if (!bdrv_recurse_is_first_non_filter(parent_bs, to_replace_bs)) {
error_setg(errp, "Only top most non filter can be replaced");
if (!bdrv_recurse_can_replace(parent_bs, to_replace_bs)) {
error_setg(errp, "Cannot replace '%s' by a node mirrored from '%s', "
"because it cannot be guaranteed that doing so would not "
"lead to an abrupt change of visible data",
node_name, parent_bs->node_name);
to_replace_bs = NULL;
goto out;
}
+10 -10
View File
@@ -268,18 +268,18 @@ static int blkverify_co_flush(BlockDriverState *bs)
return bdrv_co_flush(s->test_file->bs);
}
static bool blkverify_recurse_is_first_non_filter(BlockDriverState *bs,
BlockDriverState *candidate)
static bool blkverify_recurse_can_replace(BlockDriverState *bs,
BlockDriverState *to_replace)
{
BDRVBlkverifyState *s = bs->opaque;
bool perm = bdrv_recurse_is_first_non_filter(bs->file->bs, candidate);
if (perm) {
return true;
}
return bdrv_recurse_is_first_non_filter(s->test_file->bs, candidate);
/*
* blkverify quits the whole qemu process if there is a mismatch
* between bs->file->bs and s->test_file->bs. Therefore, we know
* know that both must match bs and we can recurse down to either.
*/
return bdrv_recurse_can_replace(bs->file->bs, to_replace) ||
bdrv_recurse_can_replace(s->test_file->bs, to_replace);
}
static void blkverify_refresh_filename(BlockDriverState *bs)
@@ -327,7 +327,7 @@ static BlockDriver bdrv_blkverify = {
.bdrv_co_flush = blkverify_co_flush,
.is_filter = true,
.bdrv_recurse_is_first_non_filter = blkverify_recurse_is_first_non_filter,
.bdrv_recurse_can_replace = blkverify_recurse_can_replace,
};
static void bdrv_blkverify_init(void)
+12 -25
View File
@@ -43,27 +43,6 @@ typedef struct CommitBlockJob {
char *backing_file_str;
} CommitBlockJob;
static int coroutine_fn commit_populate(BlockBackend *bs, BlockBackend *base,
int64_t offset, uint64_t bytes,
void *buf)
{
int ret = 0;
assert(bytes < SIZE_MAX);
ret = blk_co_pread(bs, offset, bytes, buf, 0);
if (ret < 0) {
return ret;
}
ret = blk_co_pwrite(base, offset, bytes, buf, 0);
if (ret < 0) {
return ret;
}
return 0;
}
static int commit_prepare(Job *job)
{
CommitBlockJob *s = container_of(job, CommitBlockJob, common.job);
@@ -140,7 +119,6 @@ static int coroutine_fn commit_run(Job *job, Error **errp)
int ret = 0;
int64_t n = 0; /* bytes */
void *buf = NULL;
int bytes_written = 0;
int64_t len, base_len;
ret = len = blk_getlength(s->top);
@@ -165,6 +143,7 @@ static int coroutine_fn commit_run(Job *job, Error **errp)
for (offset = 0; offset < len; offset += n) {
bool copy;
bool error_in_source = true;
/* Note that even when no rate limit is applied we need to yield
* with no pending I/O here so that bdrv_drain_all() returns.
@@ -179,12 +158,20 @@ static int coroutine_fn commit_run(Job *job, Error **errp)
copy = (ret == 1);
trace_commit_one_iteration(s, offset, n, ret);
if (copy) {
ret = commit_populate(s->top, s->base, offset, n, buf);
bytes_written += n;
assert(n < SIZE_MAX);
ret = blk_co_pread(s->top, offset, n, buf, 0);
if (ret >= 0) {
ret = blk_co_pwrite(s->base, offset, n, buf, 0);
if (ret < 0) {
error_in_source = false;
}
}
}
if (ret < 0) {
BlockErrorAction action =
block_job_error_action(&s->common, false, s->on_error, -ret);
block_job_error_action(&s->common, s->on_error,
error_in_source, -ret);
if (action == BLOCK_ERROR_ACTION_REPORT) {
goto out;
} else {
-9
View File
@@ -118,13 +118,6 @@ static void cor_lock_medium(BlockDriverState *bs, bool locked)
}
static bool cor_recurse_is_first_non_filter(BlockDriverState *bs,
BlockDriverState *candidate)
{
return bdrv_recurse_is_first_non_filter(bs->file->bs, candidate);
}
static BlockDriver bdrv_copy_on_read = {
.format_name = "copy-on-read",
@@ -143,8 +136,6 @@ static BlockDriver bdrv_copy_on_read = {
.bdrv_co_block_status = bdrv_co_block_status_from_file,
.bdrv_recurse_is_first_non_filter = cor_recurse_is_first_non_filter,
.has_variable_length = true,
.is_filter = true,
};
-9
View File
@@ -128,13 +128,6 @@ static void compress_lock_medium(BlockDriverState *bs, bool locked)
}
static bool compress_recurse_is_first_non_filter(BlockDriverState *bs,
BlockDriverState *candidate)
{
return bdrv_recurse_is_first_non_filter(bs->file->bs, candidate);
}
static BlockDriver bdrv_compress = {
.format_name = "compress",
@@ -154,8 +147,6 @@ static BlockDriver bdrv_compress = {
.bdrv_co_block_status = bdrv_co_block_status_from_file,
.bdrv_recurse_is_first_non_filter = compress_recurse_is_first_non_filter,
.has_variable_length = true,
.is_filter = true,
};
+1 -1
View File
@@ -187,7 +187,7 @@ static void luring_process_completions(LuringState *s)
ret = 0;
}
} else {
ret = -ENOSPC;;
ret = -ENOSPC;
}
}
end:
+27 -10
View File
@@ -103,6 +103,7 @@ struct MirrorOp {
bool is_pseudo_op;
bool is_active_write;
CoQueue waiting_requests;
Coroutine *co;
QTAILQ_ENTRY(MirrorOp) next;
};
@@ -282,11 +283,14 @@ static int mirror_cow_align(MirrorBlockJob *s, int64_t *offset,
}
static inline void coroutine_fn
mirror_wait_for_any_operation(MirrorBlockJob *s, bool active)
mirror_wait_for_any_operation(MirrorBlockJob *s, MirrorOp *self, bool active)
{
MirrorOp *op;
QTAILQ_FOREACH(op, &s->ops_in_flight, next) {
if (self == op) {
continue;
}
/* Do not wait on pseudo ops, because it may in turn wait on
* some other operation to start, which may in fact be the
* caller of this function. Since there is only one pseudo op
@@ -301,10 +305,10 @@ mirror_wait_for_any_operation(MirrorBlockJob *s, bool active)
}
static inline void coroutine_fn
mirror_wait_for_free_in_flight_slot(MirrorBlockJob *s)
mirror_wait_for_free_in_flight_slot(MirrorBlockJob *s, MirrorOp *self)
{
/* Only non-active operations use up in-flight slots */
mirror_wait_for_any_operation(s, false);
mirror_wait_for_any_operation(s, self, false);
}
/* Perform a mirror copy operation.
@@ -347,7 +351,7 @@ static void coroutine_fn mirror_co_read(void *opaque)
while (s->buf_free_count < nb_chunks) {
trace_mirror_yield_in_flight(s, op->offset, s->in_flight);
mirror_wait_for_free_in_flight_slot(s);
mirror_wait_for_free_in_flight_slot(s, op);
}
/* Now make a QEMUIOVector taking enough granularity-sized chunks
@@ -429,6 +433,7 @@ static unsigned mirror_perform(MirrorBlockJob *s, int64_t offset,
default:
abort();
}
op->co = co;
QTAILQ_INSERT_TAIL(&s->ops_in_flight, op, next);
qemu_coroutine_enter(co);
@@ -553,7 +558,7 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
while (s->in_flight >= MAX_IN_FLIGHT) {
trace_mirror_yield_in_flight(s, offset, s->in_flight);
mirror_wait_for_free_in_flight_slot(s);
mirror_wait_for_free_in_flight_slot(s, pseudo_op);
}
if (s->ret < 0) {
@@ -607,7 +612,7 @@ static void mirror_free_init(MirrorBlockJob *s)
static void coroutine_fn mirror_wait_for_all_io(MirrorBlockJob *s)
{
while (s->in_flight > 0) {
mirror_wait_for_free_in_flight_slot(s);
mirror_wait_for_free_in_flight_slot(s, NULL);
}
}
@@ -695,7 +700,19 @@ static int mirror_exit_common(Job *job)
* drain potential other users of the BDS before changing the graph. */
assert(s->in_drain);
bdrv_drained_begin(target_bs);
bdrv_replace_node(to_replace, target_bs, &local_err);
/*
* Cannot use check_to_replace_node() here, because that would
* check for an op blocker on @to_replace, and we have our own
* there.
*/
if (bdrv_recurse_can_replace(src, to_replace)) {
bdrv_replace_node(to_replace, target_bs, &local_err);
} else {
error_setg(&local_err, "Can no longer replace '%s' by '%s', "
"because it can no longer be guaranteed that doing so "
"would not lead to an abrupt change of visible data",
to_replace->node_name, target_bs->node_name);
}
bdrv_drained_end(target_bs);
if (local_err) {
error_report_err(local_err);
@@ -792,7 +809,7 @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s)
if (s->in_flight >= MAX_IN_FLIGHT) {
trace_mirror_yield(s, UINT64_MAX, s->buf_free_count,
s->in_flight);
mirror_wait_for_free_in_flight_slot(s);
mirror_wait_for_free_in_flight_slot(s, NULL);
continue;
}
@@ -945,7 +962,7 @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
/* Do not start passive operations while there are active
* writes in progress */
while (s->in_active_write_counter) {
mirror_wait_for_any_operation(s, true);
mirror_wait_for_any_operation(s, NULL, true);
}
if (s->ret < 0) {
@@ -971,7 +988,7 @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
if (s->in_flight >= MAX_IN_FLIGHT || s->buf_free_count == 0 ||
(cnt == 0 && s->in_flight > 0)) {
trace_mirror_yield(s, cnt, s->buf_free_count, s->in_flight);
mirror_wait_for_free_in_flight_slot(s);
mirror_wait_for_free_in_flight_slot(s, NULL);
continue;
} else if (cnt != 0) {
delay_ns = mirror_iteration(s);
-1
View File
@@ -647,7 +647,6 @@ static Qcow2BitmapList *bitmap_list_load(BlockDriverState *bs, uint64_t offset,
return bm_list;
broken_dir:
ret = -EINVAL;
error_setg(errp, "Broken bitmap directory");
fail:
+5 -2
View File
@@ -1026,8 +1026,11 @@ err:
void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m)
{
BDRVQcow2State *s = bs->opaque;
qcow2_free_clusters(bs, m->alloc_offset, m->nb_clusters << s->cluster_bits,
QCOW2_DISCARD_NEVER);
if (!has_data_file(bs)) {
qcow2_free_clusters(bs, m->alloc_offset,
m->nb_clusters << s->cluster_bits,
QCOW2_DISCARD_NEVER);
}
}
/*
+1
View File
@@ -889,6 +889,7 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
offset);
if (table != NULL) {
qcow2_cache_put(s->refcount_block_cache, &refcount_block);
old_table_index = -1;
qcow2_cache_discard(s->refcount_block_cache, table);
}
+8 -4
View File
@@ -246,12 +246,15 @@ qcow2_co_encdec(BlockDriverState *bs, uint64_t host_offset,
.len = len,
.func = func,
};
uint64_t sector_size;
assert(QEMU_IS_ALIGNED(guest_offset, BDRV_SECTOR_SIZE));
assert(QEMU_IS_ALIGNED(host_offset, BDRV_SECTOR_SIZE));
assert(QEMU_IS_ALIGNED(len, BDRV_SECTOR_SIZE));
assert(s->crypto);
sector_size = qcrypto_block_get_sector_size(s->crypto);
assert(QEMU_IS_ALIGNED(guest_offset, sector_size));
assert(QEMU_IS_ALIGNED(host_offset, sector_size));
assert(QEMU_IS_ALIGNED(len, sector_size));
return len == 0 ? 0 : qcow2_co_process(bs, qcow2_encdec_pool_func, &arg);
}
@@ -270,7 +273,8 @@ qcow2_co_encdec(BlockDriverState *bs, uint64_t host_offset,
* will be written to the underlying storage device at
* @host_offset
*
* @len - length of the buffer (must be a BDRV_SECTOR_SIZE multiple)
* @len - length of the buffer (must be a multiple of the encryption
* sector size)
*
* Depending on the encryption method, @host_offset and/or @guest_offset
* may be used for generating the initialization vector for
-2
View File
@@ -2068,8 +2068,6 @@ qcow2_co_preadv_encrypted(BlockDriverState *bs,
goto fail;
}
assert(QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE));
assert(QEMU_IS_ALIGNED(bytes, BDRV_SECTOR_SIZE));
if (qcow2_co_decrypt(bs,
file_cluster_offset + offset_into_cluster(s, offset),
offset, buf, bytes) < 0)
+61 -9
View File
@@ -796,17 +796,53 @@ static coroutine_fn int quorum_co_flush(BlockDriverState *bs)
return result;
}
static bool quorum_recurse_is_first_non_filter(BlockDriverState *bs,
BlockDriverState *candidate)
static bool quorum_recurse_can_replace(BlockDriverState *bs,
BlockDriverState *to_replace)
{
BDRVQuorumState *s = bs->opaque;
int i;
for (i = 0; i < s->num_children; i++) {
bool perm = bdrv_recurse_is_first_non_filter(s->children[i]->bs,
candidate);
if (perm) {
return true;
/*
* We have no idea whether our children show the same data as
* this node (@bs). It is actually highly likely that
* @to_replace does not, because replacing a broken child is
* one of the main use cases here.
*
* We do know that the new BDS will match @bs, so replacing
* any of our children by it will be safe. It cannot change
* the data this quorum node presents to its parents.
*
* However, replacing @to_replace by @bs in any of our
* children's chains may change visible data somewhere in
* there. We therefore cannot recurse down those chains with
* bdrv_recurse_can_replace().
* (More formally, bdrv_recurse_can_replace() requires that
* @to_replace will be replaced by something matching the @bs
* passed to it. We cannot guarantee that.)
*
* Thus, we can only check whether any of our immediate
* children matches @to_replace.
*
* (In the future, we might add a function to recurse down a
* chain that checks that nothing there cares about a change
* in data from the respective child in question. For
* example, most filters do not care when their child's data
* suddenly changes, as long as their parents do not care.)
*/
if (s->children[i]->bs == to_replace) {
/*
* We now have to ensure that there is no other parent
* that cares about replacing this child by a node with
* potentially different data.
* We do so by checking whether there are any other parents
* at all, which is stricter than necessary, but also very
* simple. (We may decide to implement something more
* complex and permissive when there is an actual need for
* it.)
*/
return QLIST_FIRST(&to_replace->parents) == s->children[i] &&
QLIST_NEXT(s->children[i], next_parent) == NULL;
}
}
@@ -1114,6 +1150,23 @@ static char *quorum_dirname(BlockDriverState *bs, Error **errp)
return NULL;
}
static void quorum_child_perm(BlockDriverState *bs, BdrvChild *c,
const BdrvChildRole *role,
BlockReopenQueue *reopen_queue,
uint64_t perm, uint64_t shared,
uint64_t *nperm, uint64_t *nshared)
{
*nperm = perm & DEFAULT_PERM_PASSTHROUGH;
/*
* We cannot share RESIZE or WRITE, as this would make the
* children differ from each other.
*/
*nshared = (shared & (BLK_PERM_CONSISTENT_READ |
BLK_PERM_WRITE_UNCHANGED))
| DEFAULT_PERM_UNCHANGED;
}
static const char *const quorum_strong_runtime_opts[] = {
QUORUM_OPT_VOTE_THRESHOLD,
QUORUM_OPT_BLKVERIFY,
@@ -1143,10 +1196,9 @@ static BlockDriver bdrv_quorum = {
.bdrv_add_child = quorum_add_child,
.bdrv_del_child = quorum_del_child,
.bdrv_child_perm = bdrv_filter_default_perms,
.bdrv_child_perm = quorum_child_perm,
.is_filter = true,
.bdrv_recurse_is_first_non_filter = quorum_recurse_is_first_non_filter,
.bdrv_recurse_can_replace = quorum_recurse_can_replace,
.strong_runtime_opts = quorum_strong_runtime_opts,
};
-7
View File
@@ -306,12 +306,6 @@ out:
return ret;
}
static bool replication_recurse_is_first_non_filter(BlockDriverState *bs,
BlockDriverState *candidate)
{
return bdrv_recurse_is_first_non_filter(bs->file->bs, candidate);
}
static void secondary_do_checkpoint(BDRVReplicationState *s, Error **errp)
{
Error *local_err = NULL;
@@ -699,7 +693,6 @@ static BlockDriver bdrv_replication = {
.bdrv_co_writev = replication_co_writev,
.is_filter = true,
.bdrv_recurse_is_first_non_filter = replication_recurse_is_first_non_filter,
.has_variable_length = true,
.strong_runtime_opts = replication_strong_runtime_opts,
-8
View File
@@ -207,12 +207,6 @@ static void throttle_reopen_abort(BDRVReopenState *reopen_state)
reopen_state->opaque = NULL;
}
static bool throttle_recurse_is_first_non_filter(BlockDriverState *bs,
BlockDriverState *candidate)
{
return bdrv_recurse_is_first_non_filter(bs->file->bs, candidate);
}
static void coroutine_fn throttle_co_drain_begin(BlockDriverState *bs)
{
ThrottleGroupMember *tgm = bs->opaque;
@@ -252,8 +246,6 @@ static BlockDriver bdrv_throttle = {
.bdrv_co_pwrite_zeroes = throttle_co_pwrite_zeroes,
.bdrv_co_pdiscard = throttle_co_pdiscard,
.bdrv_recurse_is_first_non_filter = throttle_recurse_is_first_non_filter,
.bdrv_attach_aio_context = throttle_attach_aio_context,
.bdrv_detach_aio_context = throttle_detach_aio_context,
-7
View File
@@ -3124,17 +3124,10 @@ write_target_commit(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
return ret;
}
static void write_target_close(BlockDriverState *bs) {
BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
bdrv_unref_child(s->bs, s->qcow);
g_free(s->qcow_filename);
}
static BlockDriver vvfat_write_target = {
.format_name = "vvfat_write_target",
.instance_size = sizeof(void*),
.bdrv_co_pwritev = write_target_commit,
.bdrv_close = write_target_close,
};
static void vvfat_qcow_options(int *child_flags, QDict *child_options,
+4 -14
View File
@@ -1592,11 +1592,6 @@ static void external_snapshot_prepare(BlkActionState *common,
}
}
if (!bdrv_is_first_non_filter(state->old_bs)) {
error_setg(errp, QERR_FEATURE_DISABLED, "snapshot");
goto out;
}
if (action->type == TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC) {
BlockdevSnapshotSync *s = action->u.blockdev_snapshot_sync.data;
const char *format = s->has_format ? s->format : "qcow2";
@@ -3336,11 +3331,6 @@ void qmp_block_resize(bool has_device, const char *device,
aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context);
if (!bdrv_is_first_non_filter(bs)) {
error_setg(errp, QERR_FEATURE_DISABLED, "resize");
goto out;
}
if (size < 0) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "size", "a >0 size");
goto out;
@@ -3471,6 +3461,7 @@ void qmp_block_commit(bool has_job_id, const char *job_id, const char *device,
bool has_top, const char *top,
bool has_backing_file, const char *backing_file,
bool has_speed, int64_t speed,
bool has_on_error, BlockdevOnError on_error,
bool has_filter_node_name, const char *filter_node_name,
bool has_auto_finalize, bool auto_finalize,
bool has_auto_dismiss, bool auto_dismiss,
@@ -3481,15 +3472,14 @@ void qmp_block_commit(bool has_job_id, const char *job_id, const char *device,
BlockDriverState *base_bs, *top_bs;
AioContext *aio_context;
Error *local_err = NULL;
/* This will be part of the QMP command, if/when the
* BlockdevOnError change for blkmirror makes it in
*/
BlockdevOnError on_error = BLOCKDEV_ON_ERROR_REPORT;
int job_flags = JOB_DEFAULT;
if (!has_speed) {
speed = 0;
}
if (!has_on_error) {
on_error = BLOCKDEV_ON_ERROR_REPORT;
}
if (!has_filter_node_name) {
filter_node_name = NULL;
}
-5
View File
@@ -391,11 +391,6 @@ int bdrv_amend_options(BlockDriverState *bs_new, QemuOpts *opts,
BlockDriverAmendStatusCB *status_cb, void *cb_opaque,
Error **errp);
/* external snapshots */
bool bdrv_recurse_is_first_non_filter(BlockDriverState *bs,
BlockDriverState *candidate);
bool bdrv_is_first_non_filter(BlockDriverState *candidate);
/* check if a named node can be replaced when doing drive-mirror */
BlockDriverState *check_to_replace_node(BlockDriverState *parent_bs,
const char *node_name, Error **errp);
+9 -7
View File
@@ -94,14 +94,13 @@ struct BlockDriver {
* must implement them and return -ENOTSUP.
*/
bool is_filter;
/* for snapshots block filter like Quorum can implement the
* following recursive callback.
* It's purpose is to recurse on the filter children while calling
* bdrv_recurse_is_first_non_filter on them.
* For a sample implementation look in the future Quorum block filter.
/*
* Return true if @to_replace can be replaced by a BDS with the
* same data as @bs without it affecting @bs's behavior (that is,
* without it being visible to @bs's parents).
*/
bool (*bdrv_recurse_is_first_non_filter)(BlockDriverState *bs,
BlockDriverState *candidate);
bool (*bdrv_recurse_can_replace)(BlockDriverState *bs,
BlockDriverState *to_replace);
int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename);
int (*bdrv_probe_device)(const char *filename);
@@ -1263,6 +1262,9 @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
uint64_t perm, uint64_t shared,
uint64_t *nperm, uint64_t *nshared);
bool bdrv_recurse_can_replace(BlockDriverState *bs,
BlockDriverState *to_replace);
/*
* Default implementation for drivers to pass bdrv_co_block_status() to
* their file.
+8 -1
View File
@@ -1164,7 +1164,10 @@
# for jobs, cancel the job
#
# @ignore: ignore the error, only report a QMP event (BLOCK_IO_ERROR
# or BLOCK_JOB_ERROR)
# or BLOCK_JOB_ERROR). The backup, mirror and commit block jobs retry
# the failing request later and may still complete successfully. The
# stream block job continues to stream and will complete with an
# error.
#
# @enospc: same as @stop on ENOSPC, same as @report otherwise.
#
@@ -1655,6 +1658,9 @@
#
# @speed: the maximum speed, in bytes per second
#
# @on-error: the action to take on an error. 'ignore' means that the request
# should be retried. (default: report; Since: 5.0)
#
# @filter-node-name: the node name that should be assigned to the
# filter driver that the commit job inserts into the graph
# above @top. If this option is not given, a node name is
@@ -1691,6 +1697,7 @@
'data': { '*job-id': 'str', 'device': 'str', '*base-node': 'str',
'*base': 'str', '*top-node': 'str', '*top': 'str',
'*backing-file': 'str', '*speed': 'int',
'*on-error': 'BlockdevOnError',
'*filter-node-name': 'str',
'*auto-finalize': 'bool', '*auto-dismiss': 'bool' } }

Some files were not shown because too many files have changed in this diff Show More