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 for 2.11.0-rc2 # gpg: Signature made Fri 17 Nov 2017 17:58:36 GMT # gpg: using RSA key 0x7F09B272C88F2FD6 # gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" # Primary key fingerprint: DC3D EB15 9A9A F95D 3D74 56FE 7F09 B272 C88F 2FD6 * remotes/kevin/tags/for-upstream: (25 commits) iotests: Make 087 pass without AIO enabled block: Make bdrv_next() keep strong references qcow2: Fix overly broad madvise() qcow2: Refuse to get unaligned offsets from cache qcow2: Add bounds check to get_refblock_offset() block: Guard against NULL bs->drv qcow2: Unaligned zero cluster in handle_alloc() qcow2: check_errors are fatal qcow2: reject unaligned offsets in write compressed iotests: Add test for failing qemu-img commit tests: Add check-qobject for equality tests iotests: Add test for non-string option reopening block: qobject_is_equal() in bdrv_reopen_prepare() qapi: Add qobject_is_equal() qapi/qlist: Add qlist_append_null() macro qapi/qnull: Add own header qcow2: fix image corruption on commit with persistent bitmap iotests: test clearing unknown autoclear_features by qcow2 block: Fix permissions in image activation qcow2: fix image corruption after committing qcow2 image into base ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
@@ -261,6 +261,11 @@ int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TODO Remove (deprecated since 2.11)
|
||||
* Block drivers are not supposed to automatically change bs->read_only.
|
||||
* Instead, they should just check whether they can provide what the user
|
||||
* explicitly requested and error out if read-write is requested, but they can
|
||||
* only provide read-only access. */
|
||||
int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -715,6 +720,10 @@ static int refresh_total_sectors(BlockDriverState *bs, int64_t hint)
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
|
||||
if (!drv) {
|
||||
return -ENOMEDIUM;
|
||||
}
|
||||
|
||||
/* Do not attempt drv->bdrv_getlength() on scsi-generic devices */
|
||||
if (bdrv_is_sg(bs))
|
||||
return 0;
|
||||
@@ -998,7 +1007,7 @@ static int bdrv_backing_update_filename(BdrvChild *c, BlockDriverState *base,
|
||||
ret = bdrv_change_backing_file(parent, filename,
|
||||
base->drv ? base->drv->format_name : "");
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, ret, "Could not update backing file link");
|
||||
error_setg_errno(errp, -ret, "Could not update backing file link");
|
||||
}
|
||||
|
||||
if (!(orig_flags & BDRV_O_RDWR)) {
|
||||
@@ -3069,19 +3078,26 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
|
||||
const QDictEntry *entry = qdict_first(reopen_state->options);
|
||||
|
||||
do {
|
||||
QString *new_obj = qobject_to_qstring(entry->value);
|
||||
const char *new = qstring_get_str(new_obj);
|
||||
/*
|
||||
* Caution: while qdict_get_try_str() is fine, getting
|
||||
* non-string types would require more care. When
|
||||
* bs->options come from -blockdev or blockdev_add, its
|
||||
* members are typed according to the QAPI schema, but
|
||||
* when they come from -drive, they're all QString.
|
||||
*/
|
||||
const char *old = qdict_get_try_str(reopen_state->bs->options,
|
||||
entry->key);
|
||||
QObject *new = entry->value;
|
||||
QObject *old = qdict_get(reopen_state->bs->options, entry->key);
|
||||
|
||||
if (!old || strcmp(new, old)) {
|
||||
/*
|
||||
* TODO: When using -drive to specify blockdev options, all values
|
||||
* will be strings; however, when using -blockdev, blockdev-add or
|
||||
* filenames using the json:{} pseudo-protocol, they will be
|
||||
* correctly typed.
|
||||
* In contrast, reopening options are (currently) always strings
|
||||
* (because you can only specify them through qemu-io; all other
|
||||
* callers do not specify any options).
|
||||
* Therefore, when using anything other than -drive to create a BDS,
|
||||
* this cannot detect non-string options as unchanged, because
|
||||
* qobject_is_equal() always returns false for objects of different
|
||||
* type. In the future, this should be remedied by correctly typing
|
||||
* all options. For now, this is not too big of an issue because
|
||||
* the user can simply omit options which cannot be changed anyway,
|
||||
* so they will stay unchanged.
|
||||
*/
|
||||
if (!qobject_is_equal(new, old)) {
|
||||
error_setg(errp, "Cannot change the option '%s'", entry->key);
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
@@ -3419,6 +3435,10 @@ int bdrv_change_backing_file(BlockDriverState *bs,
|
||||
BlockDriver *drv = bs->drv;
|
||||
int ret;
|
||||
|
||||
if (!drv) {
|
||||
return -ENOMEDIUM;
|
||||
}
|
||||
|
||||
/* Backing file format doesn't make sense without a backing file */
|
||||
if (backing_fmt && !backing_file) {
|
||||
return -EINVAL;
|
||||
@@ -3904,7 +3924,9 @@ int bdrv_has_zero_init_1(BlockDriverState *bs)
|
||||
|
||||
int bdrv_has_zero_init(BlockDriverState *bs)
|
||||
{
|
||||
assert(bs->drv);
|
||||
if (!bs->drv) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If BS is a copy on write image, it is initialized to
|
||||
the contents of the base image, which may not be zeroes. */
|
||||
@@ -4169,7 +4191,29 @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Update permissions, they may differ for inactive nodes.
|
||||
*
|
||||
* Note that the required permissions of inactive images are always a
|
||||
* subset of the permissions required after activating the image. This
|
||||
* allows us to just get the permissions upfront without restricting
|
||||
* drv->bdrv_invalidate_cache().
|
||||
*
|
||||
* It also means that in error cases, we don't have to try and revert to
|
||||
* the old permissions (which is an operation that could fail, too). We can
|
||||
* just keep the extended permissions for the next time that an activation
|
||||
* of the image is tried.
|
||||
*/
|
||||
bs->open_flags &= ~BDRV_O_INACTIVE;
|
||||
bdrv_get_cumulative_perm(bs, &perm, &shared_perm);
|
||||
ret = bdrv_check_perm(bs, NULL, perm, shared_perm, NULL, &local_err);
|
||||
if (ret < 0) {
|
||||
bs->open_flags |= BDRV_O_INACTIVE;
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
bdrv_set_perm(bs, perm, shared_perm);
|
||||
|
||||
if (bs->drv->bdrv_invalidate_cache) {
|
||||
bs->drv->bdrv_invalidate_cache(bs, &local_err);
|
||||
if (local_err) {
|
||||
@@ -4186,16 +4230,6 @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Update permissions, they may differ for inactive nodes */
|
||||
bdrv_get_cumulative_perm(bs, &perm, &shared_perm);
|
||||
ret = bdrv_check_perm(bs, NULL, perm, shared_perm, NULL, &local_err);
|
||||
if (ret < 0) {
|
||||
bs->open_flags |= BDRV_O_INACTIVE;
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
bdrv_set_perm(bs, perm, shared_perm);
|
||||
|
||||
QLIST_FOREACH(parent, &bs->parents, next_parent) {
|
||||
if (parent->role->activate) {
|
||||
parent->role->activate(parent, &local_err);
|
||||
@@ -4221,6 +4255,7 @@ void bdrv_invalidate_cache_all(Error **errp)
|
||||
aio_context_release(aio_context);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
bdrv_next_cleanup(&it);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -4232,6 +4267,10 @@ static int bdrv_inactivate_recurse(BlockDriverState *bs,
|
||||
BdrvChild *child, *parent;
|
||||
int ret;
|
||||
|
||||
if (!bs->drv) {
|
||||
return -ENOMEDIUM;
|
||||
}
|
||||
|
||||
if (!setting_flag && bs->drv->bdrv_inactivate) {
|
||||
ret = bs->drv->bdrv_inactivate(bs);
|
||||
if (ret < 0) {
|
||||
@@ -4292,6 +4331,7 @@ int bdrv_inactivate_all(void)
|
||||
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
|
||||
ret = bdrv_inactivate_recurse(bs, pass);
|
||||
if (ret < 0) {
|
||||
bdrv_next_cleanup(&it);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -4766,6 +4806,9 @@ void bdrv_remove_aio_context_notifier(BlockDriverState *bs,
|
||||
int bdrv_amend_options(BlockDriverState *bs, QemuOpts *opts,
|
||||
BlockDriverAmendStatusCB *status_cb, void *cb_opaque)
|
||||
{
|
||||
if (!bs->drv) {
|
||||
return -ENOMEDIUM;
|
||||
}
|
||||
if (!bs->drv->bdrv_amend_options) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
@@ -4823,6 +4866,7 @@ bool bdrv_is_first_non_filter(BlockDriverState *candidate)
|
||||
|
||||
/* candidate is the first non filter */
|
||||
if (perm) {
|
||||
bdrv_next_cleanup(&it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
+46
-2
@@ -442,21 +442,37 @@ BlockBackend *blk_next(BlockBackend *blk)
|
||||
* the monitor or attached to a BlockBackend */
|
||||
BlockDriverState *bdrv_next(BdrvNextIterator *it)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
BlockDriverState *bs, *old_bs;
|
||||
|
||||
/* Must be called from the main loop */
|
||||
assert(qemu_get_current_aio_context() == qemu_get_aio_context());
|
||||
|
||||
/* First, return all root nodes of BlockBackends. In order to avoid
|
||||
* returning a BDS twice when multiple BBs refer to it, we only return it
|
||||
* if the BB is the first one in the parent list of the BDS. */
|
||||
if (it->phase == BDRV_NEXT_BACKEND_ROOTS) {
|
||||
BlockBackend *old_blk = it->blk;
|
||||
|
||||
old_bs = old_blk ? blk_bs(old_blk) : NULL;
|
||||
|
||||
do {
|
||||
it->blk = blk_all_next(it->blk);
|
||||
bs = it->blk ? blk_bs(it->blk) : NULL;
|
||||
} while (it->blk && (bs == NULL || bdrv_first_blk(bs) != it->blk));
|
||||
|
||||
if (it->blk) {
|
||||
blk_ref(it->blk);
|
||||
}
|
||||
blk_unref(old_blk);
|
||||
|
||||
if (bs) {
|
||||
bdrv_ref(bs);
|
||||
bdrv_unref(old_bs);
|
||||
return bs;
|
||||
}
|
||||
it->phase = BDRV_NEXT_MONITOR_OWNED;
|
||||
} else {
|
||||
old_bs = it->bs;
|
||||
}
|
||||
|
||||
/* Then return the monitor-owned BDSes without a BB attached. Ignore all
|
||||
@@ -467,18 +483,46 @@ BlockDriverState *bdrv_next(BdrvNextIterator *it)
|
||||
bs = it->bs;
|
||||
} while (bs && bdrv_has_blk(bs));
|
||||
|
||||
if (bs) {
|
||||
bdrv_ref(bs);
|
||||
}
|
||||
bdrv_unref(old_bs);
|
||||
|
||||
return bs;
|
||||
}
|
||||
|
||||
BlockDriverState *bdrv_first(BdrvNextIterator *it)
|
||||
static void bdrv_next_reset(BdrvNextIterator *it)
|
||||
{
|
||||
*it = (BdrvNextIterator) {
|
||||
.phase = BDRV_NEXT_BACKEND_ROOTS,
|
||||
};
|
||||
}
|
||||
|
||||
BlockDriverState *bdrv_first(BdrvNextIterator *it)
|
||||
{
|
||||
bdrv_next_reset(it);
|
||||
return bdrv_next(it);
|
||||
}
|
||||
|
||||
/* Must be called when aborting a bdrv_next() iteration before
|
||||
* bdrv_next() returns NULL */
|
||||
void bdrv_next_cleanup(BdrvNextIterator *it)
|
||||
{
|
||||
/* Must be called from the main loop */
|
||||
assert(qemu_get_current_aio_context() == qemu_get_aio_context());
|
||||
|
||||
if (it->phase == BDRV_NEXT_BACKEND_ROOTS) {
|
||||
if (it->blk) {
|
||||
bdrv_unref(blk_bs(it->blk));
|
||||
blk_unref(it->blk);
|
||||
}
|
||||
} else {
|
||||
bdrv_unref(it->bs);
|
||||
}
|
||||
|
||||
bdrv_next_reset(it);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a BlockBackend into the list of backends referenced by the monitor, with
|
||||
* the given @name acting as the handle for the monitor.
|
||||
|
||||
+10
-3
@@ -28,6 +28,7 @@
|
||||
#include "block/block_int.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/bswap.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
@@ -110,9 +111,15 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = bdrv_set_read_only(bs, true, errp); /* no write support yet */
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
if (!bdrv_is_read_only(bs)) {
|
||||
error_report("Opening bochs images without an explicit read-only=on "
|
||||
"option is deprecated. Future versions will refuse to "
|
||||
"open the image instead of automatically marking the "
|
||||
"image read-only.");
|
||||
ret = bdrv_set_read_only(bs, true, errp); /* no write support yet */
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = bdrv_pread(bs->file, 0, &bochs, sizeof(bochs));
|
||||
|
||||
+10
-3
@@ -23,6 +23,7 @@
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu-common.h"
|
||||
#include "block/block_int.h"
|
||||
#include "qemu/module.h"
|
||||
@@ -72,9 +73,15 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = bdrv_set_read_only(bs, true, errp);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
if (!bdrv_is_read_only(bs)) {
|
||||
error_report("Opening cloop images without an explicit read-only=on "
|
||||
"option is deprecated. Future versions will refuse to "
|
||||
"open the image instead of automatically marking the "
|
||||
"image read-only.");
|
||||
ret = bdrv_set_read_only(bs, true, errp);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* read header */
|
||||
|
||||
+9
-3
@@ -419,9 +419,15 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = bdrv_set_read_only(bs, true, errp);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
if (!bdrv_is_read_only(bs)) {
|
||||
error_report("Opening dmg images without an explicit read-only=on "
|
||||
"option is deprecated. Future versions will refuse to "
|
||||
"open the image instead of automatically marking the "
|
||||
"image read-only.");
|
||||
ret = bdrv_set_read_only(bs, true, errp);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
block_module_load_one("dmg-bz2");
|
||||
|
||||
+36
@@ -853,6 +853,10 @@ static int coroutine_fn bdrv_driver_preadv(BlockDriverState *bs,
|
||||
|
||||
assert(!(flags & ~BDRV_REQ_MASK));
|
||||
|
||||
if (!drv) {
|
||||
return -ENOMEDIUM;
|
||||
}
|
||||
|
||||
if (drv->bdrv_co_preadv) {
|
||||
return drv->bdrv_co_preadv(bs, offset, bytes, qiov, flags);
|
||||
}
|
||||
@@ -894,6 +898,10 @@ static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs,
|
||||
|
||||
assert(!(flags & ~BDRV_REQ_MASK));
|
||||
|
||||
if (!drv) {
|
||||
return -ENOMEDIUM;
|
||||
}
|
||||
|
||||
if (drv->bdrv_co_pwritev) {
|
||||
ret = drv->bdrv_co_pwritev(bs, offset, bytes, qiov,
|
||||
flags & bs->supported_write_flags);
|
||||
@@ -945,6 +953,10 @@ bdrv_driver_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
|
||||
if (!drv) {
|
||||
return -ENOMEDIUM;
|
||||
}
|
||||
|
||||
if (!drv->bdrv_co_pwritev_compressed) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
@@ -975,6 +987,10 @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child,
|
||||
BDRV_REQUEST_MAX_BYTES);
|
||||
unsigned int progress = 0;
|
||||
|
||||
if (!drv) {
|
||||
return -ENOMEDIUM;
|
||||
}
|
||||
|
||||
/* FIXME We cannot require callers to have write permissions when all they
|
||||
* are doing is a read request. If we did things right, write permissions
|
||||
* would be obtained anyway, but internally by the copy-on-read code. As
|
||||
@@ -1291,6 +1307,10 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
|
||||
bs->bl.request_alignment);
|
||||
int max_transfer = MIN_NON_ZERO(bs->bl.max_transfer, MAX_BOUNCE_BUFFER);
|
||||
|
||||
if (!drv) {
|
||||
return -ENOMEDIUM;
|
||||
}
|
||||
|
||||
assert(alignment % bs->bl.request_alignment == 0);
|
||||
head = offset % alignment;
|
||||
tail = (offset + bytes) % alignment;
|
||||
@@ -1397,6 +1417,10 @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
|
||||
uint64_t bytes_remaining = bytes;
|
||||
int max_transfer;
|
||||
|
||||
if (!drv) {
|
||||
return -ENOMEDIUM;
|
||||
}
|
||||
|
||||
if (bdrv_has_readonly_bitmaps(bs)) {
|
||||
return -EPERM;
|
||||
}
|
||||
@@ -1863,6 +1887,8 @@ static int coroutine_fn bdrv_co_block_status(BlockDriverState *bs,
|
||||
bytes = n;
|
||||
}
|
||||
|
||||
/* Must be non-NULL or bdrv_getlength() would have failed */
|
||||
assert(bs->drv);
|
||||
if (!bs->drv->bdrv_co_get_block_status) {
|
||||
*pnum = bytes;
|
||||
ret = BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED;
|
||||
@@ -2373,6 +2399,12 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
|
||||
}
|
||||
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_FLUSH_TO_DISK);
|
||||
if (!bs->drv) {
|
||||
/* bs->drv->bdrv_co_flush() might have ejected the BDS
|
||||
* (even in case of apparent success) */
|
||||
ret = -ENOMEDIUM;
|
||||
goto out;
|
||||
}
|
||||
if (bs->drv->bdrv_co_flush_to_disk) {
|
||||
ret = bs->drv->bdrv_co_flush_to_disk(bs);
|
||||
} else if (bs->drv->bdrv_aio_flush) {
|
||||
@@ -2542,6 +2574,10 @@ int coroutine_fn bdrv_co_pdiscard(BlockDriverState *bs, int64_t offset,
|
||||
num = max_pdiscard;
|
||||
}
|
||||
|
||||
if (!bs->drv) {
|
||||
ret = -ENOMEDIUM;
|
||||
goto out;
|
||||
}
|
||||
if (bs->drv->bdrv_co_pdiscard) {
|
||||
ret = bs->drv->bdrv_co_pdiscard(bs, offset, num);
|
||||
} else {
|
||||
|
||||
+7
-1
@@ -39,8 +39,14 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
|
||||
{
|
||||
ImageInfo **p_image_info;
|
||||
BlockDriverState *bs0;
|
||||
BlockDeviceInfo *info = g_malloc0(sizeof(*info));
|
||||
BlockDeviceInfo *info;
|
||||
|
||||
if (!bs->drv) {
|
||||
error_setg(errp, "Block device %s is ejected", bs->node_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
info = g_malloc0(sizeof(*info));
|
||||
info->file = g_strdup(bs->filename);
|
||||
info->ro = bs->read_only;
|
||||
info->drv = g_strdup(bs->drv->format_name);
|
||||
|
||||
+22
-1
@@ -62,6 +62,18 @@ static inline int qcow2_cache_get_table_idx(BlockDriverState *bs,
|
||||
return idx;
|
||||
}
|
||||
|
||||
static inline const char *qcow2_cache_get_name(BDRVQcow2State *s, Qcow2Cache *c)
|
||||
{
|
||||
if (c == s->refcount_block_cache) {
|
||||
return "refcount block";
|
||||
} else if (c == s->l2_table_cache) {
|
||||
return "L2 table";
|
||||
} else {
|
||||
/* Do not abort, because this is not critical */
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static void qcow2_cache_table_release(BlockDriverState *bs, Qcow2Cache *c,
|
||||
int i, int num_tables)
|
||||
{
|
||||
@@ -73,7 +85,7 @@ static void qcow2_cache_table_release(BlockDriverState *bs, Qcow2Cache *c,
|
||||
size_t mem_size = (size_t) s->cluster_size * num_tables;
|
||||
size_t offset = QEMU_ALIGN_UP((uintptr_t) t, align) - (uintptr_t) t;
|
||||
size_t length = QEMU_ALIGN_DOWN(mem_size - offset, align);
|
||||
if (length > 0) {
|
||||
if (mem_size > offset && length > 0) {
|
||||
madvise((uint8_t *) t + offset, length, MADV_DONTNEED);
|
||||
}
|
||||
#endif
|
||||
@@ -314,9 +326,18 @@ static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
|
||||
uint64_t min_lru_counter = UINT64_MAX;
|
||||
int min_lru_index = -1;
|
||||
|
||||
assert(offset != 0);
|
||||
|
||||
trace_qcow2_cache_get(qemu_coroutine_self(), c == s->l2_table_cache,
|
||||
offset, read_from_disk);
|
||||
|
||||
if (offset_into_cluster(s, offset)) {
|
||||
qcow2_signal_corruption(bs, true, -1, -1, "Cannot get entry from %s "
|
||||
"cache: Offset %#" PRIx64 " is unaligned",
|
||||
qcow2_cache_get_name(s, c), offset);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Check if the table is already cached */
|
||||
i = lookup_index = (offset / s->cluster_size * 4) % c->size;
|
||||
do {
|
||||
|
||||
+12
-1
@@ -1308,10 +1308,21 @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
|
||||
(!*host_offset ||
|
||||
start_of_cluster(s, *host_offset) == (entry & L2E_OFFSET_MASK)))
|
||||
{
|
||||
int preallocated_nb_clusters;
|
||||
|
||||
if (offset_into_cluster(s, entry & L2E_OFFSET_MASK)) {
|
||||
qcow2_signal_corruption(bs, true, -1, -1, "Preallocated zero "
|
||||
"cluster offset %#llx unaligned (guest "
|
||||
"offset: %#" PRIx64 ")",
|
||||
entry & L2E_OFFSET_MASK, guest_offset);
|
||||
ret = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Try to reuse preallocated zero clusters; contiguous normal clusters
|
||||
* would be fine, too, but count_cow_clusters() above has limited
|
||||
* nb_clusters already to a range of COW clusters */
|
||||
int preallocated_nb_clusters =
|
||||
preallocated_nb_clusters =
|
||||
count_contiguous_clusters(nb_clusters, s->cluster_size,
|
||||
&l2_table[l2_index], QCOW_OFLAG_COPIED);
|
||||
assert(preallocated_nb_clusters > 0);
|
||||
|
||||
+25
-1
@@ -3077,16 +3077,40 @@ done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int64_t get_refblock_offset(BlockDriverState *bs, uint64_t offset)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
uint32_t index = offset_to_reftable_index(s, offset);
|
||||
int64_t covering_refblock_offset = 0;
|
||||
|
||||
if (index < s->refcount_table_size) {
|
||||
covering_refblock_offset = s->refcount_table[index] & REFT_OFFSET_MASK;
|
||||
}
|
||||
if (!covering_refblock_offset) {
|
||||
qcow2_signal_corruption(bs, true, -1, -1, "Refblock at %#" PRIx64 " is "
|
||||
"not covered by the refcount structures",
|
||||
offset);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return covering_refblock_offset;
|
||||
}
|
||||
|
||||
static int qcow2_discard_refcount_block(BlockDriverState *bs,
|
||||
uint64_t discard_block_offs)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
uint64_t refblock_offs = get_refblock_offset(s, discard_block_offs);
|
||||
int64_t refblock_offs;
|
||||
uint64_t cluster_index = discard_block_offs >> s->cluster_bits;
|
||||
uint32_t block_index = cluster_index & (s->refcount_block_size - 1);
|
||||
void *refblock;
|
||||
int ret;
|
||||
|
||||
refblock_offs = get_refblock_offset(bs, discard_block_offs);
|
||||
if (refblock_offs < 0) {
|
||||
return refblock_offs;
|
||||
}
|
||||
|
||||
assert(discard_block_offs != 0);
|
||||
|
||||
ret = qcow2_cache_get(bs, s->refcount_block_cache, refblock_offs,
|
||||
|
||||
+23
-8
@@ -376,6 +376,8 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
|
||||
|
||||
default:
|
||||
/* unknown magic - save it in case we need to rewrite the header */
|
||||
/* If you add a new feature, make sure to also update the fast
|
||||
* path of qcow2_make_empty() to deal with it. */
|
||||
{
|
||||
Qcow2UnknownHeaderExtension *uext;
|
||||
|
||||
@@ -1475,7 +1477,10 @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
BdrvCheckResult result = {0};
|
||||
|
||||
ret = qcow2_check(bs, &result, BDRV_FIX_ERRORS | BDRV_FIX_LEAKS);
|
||||
if (ret < 0) {
|
||||
if (ret < 0 || result.check_errors) {
|
||||
if (ret >= 0) {
|
||||
ret = -EIO;
|
||||
}
|
||||
error_setg_errno(errp, -ret, "Could not repair dirty image");
|
||||
goto fail;
|
||||
}
|
||||
@@ -3356,6 +3361,10 @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
|
||||
return bdrv_truncate(bs->file, cluster_offset, PREALLOC_MODE_OFF, NULL);
|
||||
}
|
||||
|
||||
if (offset_into_cluster(s, offset)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
buf = qemu_blockalign(bs, s->cluster_size);
|
||||
if (bytes != s->cluster_size) {
|
||||
if (bytes > s->cluster_size ||
|
||||
@@ -3600,13 +3609,16 @@ static int qcow2_make_empty(BlockDriverState *bs)
|
||||
|
||||
l1_clusters = DIV_ROUND_UP(s->l1_size, s->cluster_size / sizeof(uint64_t));
|
||||
|
||||
if (s->qcow_version >= 3 && !s->snapshots &&
|
||||
3 + l1_clusters <= s->refcount_block_size) {
|
||||
/* The following function only works for qcow2 v3 images (it requires
|
||||
* the dirty flag) and only as long as there are no snapshots (because
|
||||
* it completely empties the image). Furthermore, the L1 table and three
|
||||
* additional clusters (image header, refcount table, one refcount
|
||||
* block) have to fit inside one refcount block. */
|
||||
if (s->qcow_version >= 3 && !s->snapshots && !s->nb_bitmaps &&
|
||||
3 + l1_clusters <= s->refcount_block_size &&
|
||||
s->crypt_method_header != QCOW_CRYPT_LUKS) {
|
||||
/* The following function only works for qcow2 v3 images (it
|
||||
* requires the dirty flag) and only as long as there are no
|
||||
* features that reserve extra clusters (such as snapshots,
|
||||
* LUKS header, or persistent bitmaps), because it completely
|
||||
* empties the image. Furthermore, the L1 table and three
|
||||
* additional clusters (image header, refcount table, one
|
||||
* refcount block) have to fit inside one refcount block. */
|
||||
return make_completely_empty(bs);
|
||||
}
|
||||
|
||||
@@ -4069,6 +4081,9 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
|
||||
error_report("Changing the encryption format is not supported");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
} else if (g_str_has_prefix(desc->name, "encrypt.")) {
|
||||
error_report("Changing the encryption parameters is not supported");
|
||||
return -ENOTSUP;
|
||||
} else if (!strcmp(desc->name, BLOCK_OPT_CLUSTER_SIZE)) {
|
||||
cluster_size = qemu_opt_get_size(opts, BLOCK_OPT_CLUSTER_SIZE,
|
||||
cluster_size);
|
||||
|
||||
@@ -527,12 +527,6 @@ uint32_t offset_to_reftable_index(BDRVQcow2State *s, uint64_t offset)
|
||||
return offset >> (s->refcount_block_bits + s->cluster_bits);
|
||||
}
|
||||
|
||||
static inline uint64_t get_refblock_offset(BDRVQcow2State *s, uint64_t offset)
|
||||
{
|
||||
uint32_t index = offset_to_reftable_index(s, offset);
|
||||
return s->refcount_table[index] & REFT_OFFSET_MASK;
|
||||
}
|
||||
|
||||
/* qcow2.c functions */
|
||||
int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
|
||||
int64_t sector_num, int nb_sectors);
|
||||
|
||||
+10
-4
@@ -665,10 +665,16 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
/* If we are using an rbd snapshot, we must be r/o, otherwise
|
||||
* leave as-is */
|
||||
if (s->snap != NULL) {
|
||||
r = bdrv_set_read_only(bs, true, &local_err);
|
||||
if (r < 0) {
|
||||
error_propagate(errp, local_err);
|
||||
goto failed_open;
|
||||
if (!bdrv_is_read_only(bs)) {
|
||||
error_report("Opening rbd snapshots without an explicit "
|
||||
"read-only=on option is deprecated. Future versions "
|
||||
"will refuse to open the image instead of "
|
||||
"automatically marking the image read-only.");
|
||||
r = bdrv_set_read_only(bs, true, &local_err);
|
||||
if (r < 0) {
|
||||
error_propagate(errp, local_err);
|
||||
goto failed_open;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+22
-4
@@ -161,10 +161,13 @@ static void replication_child_perm(BlockDriverState *bs, BdrvChild *c,
|
||||
uint64_t perm, uint64_t shared,
|
||||
uint64_t *nperm, uint64_t *nshared)
|
||||
{
|
||||
*nperm = *nshared = BLK_PERM_CONSISTENT_READ \
|
||||
| BLK_PERM_WRITE \
|
||||
| BLK_PERM_WRITE_UNCHANGED;
|
||||
|
||||
*nperm = BLK_PERM_CONSISTENT_READ;
|
||||
if ((bs->open_flags & (BDRV_O_INACTIVE | BDRV_O_RDWR)) == BDRV_O_RDWR) {
|
||||
*nperm |= BLK_PERM_WRITE;
|
||||
}
|
||||
*nshared = BLK_PERM_CONSISTENT_READ \
|
||||
| BLK_PERM_WRITE \
|
||||
| BLK_PERM_WRITE_UNCHANGED;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -339,12 +342,24 @@ static void secondary_do_checkpoint(BDRVReplicationState *s, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!s->active_disk->bs->drv) {
|
||||
error_setg(errp, "Active disk %s is ejected",
|
||||
s->active_disk->bs->node_name);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = s->active_disk->bs->drv->bdrv_make_empty(s->active_disk->bs);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Cannot make active disk empty");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!s->hidden_disk->bs->drv) {
|
||||
error_setg(errp, "Hidden disk %s is ejected",
|
||||
s->hidden_disk->bs->node_name);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = s->hidden_disk->bs->drv->bdrv_make_empty(s->hidden_disk->bs);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Cannot make hidden disk empty");
|
||||
@@ -508,6 +523,9 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
|
||||
return;
|
||||
}
|
||||
|
||||
/* Must be true, or the bdrv_getlength() calls would have failed */
|
||||
assert(s->active_disk->bs->drv && s->hidden_disk->bs->drv);
|
||||
|
||||
if (!s->active_disk->bs->drv->bdrv_make_empty ||
|
||||
!s->hidden_disk->bs->drv->bdrv_make_empty) {
|
||||
error_setg(errp,
|
||||
|
||||
@@ -417,6 +417,7 @@ bool bdrv_all_can_snapshot(BlockDriverState **first_bad_bs)
|
||||
}
|
||||
aio_context_release(ctx);
|
||||
if (!ok) {
|
||||
bdrv_next_cleanup(&it);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
@@ -444,6 +445,7 @@ int bdrv_all_delete_snapshot(const char *name, BlockDriverState **first_bad_bs,
|
||||
}
|
||||
aio_context_release(ctx);
|
||||
if (ret < 0) {
|
||||
bdrv_next_cleanup(&it);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
@@ -469,6 +471,7 @@ int bdrv_all_goto_snapshot(const char *name, BlockDriverState **first_bad_bs)
|
||||
}
|
||||
aio_context_release(ctx);
|
||||
if (err < 0) {
|
||||
bdrv_next_cleanup(&it);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
@@ -494,6 +497,7 @@ int bdrv_all_find_snapshot(const char *name, BlockDriverState **first_bad_bs)
|
||||
}
|
||||
aio_context_release(ctx);
|
||||
if (err < 0) {
|
||||
bdrv_next_cleanup(&it);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
@@ -525,6 +529,7 @@ int bdrv_all_create_snapshot(QEMUSnapshotInfo *sn,
|
||||
}
|
||||
aio_context_release(ctx);
|
||||
if (err < 0) {
|
||||
bdrv_next_cleanup(&it);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
@@ -548,6 +553,7 @@ BlockDriverState *bdrv_all_find_vmstate_bs(void)
|
||||
aio_context_release(ctx);
|
||||
|
||||
if (found) {
|
||||
bdrv_next_cleanup(&it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+6
-2
@@ -1259,7 +1259,11 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
"Unable to set VVFAT to 'rw' when drive is read-only");
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
} else if (!bdrv_is_read_only(bs)) {
|
||||
error_report("Opening non-rw vvfat images without an explicit "
|
||||
"read-only=on option is deprecated. Future versions "
|
||||
"will refuse to open the image instead of "
|
||||
"automatically marking the image read-only.");
|
||||
/* read only is the default for safety */
|
||||
ret = bdrv_set_read_only(bs, true, &local_err);
|
||||
if (ret < 0) {
|
||||
@@ -2943,7 +2947,7 @@ static int do_commit(BDRVVVFATState* s)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (s->qcow->bs->drv->bdrv_make_empty) {
|
||||
if (s->qcow->bs->drv && s->qcow->bs->drv->bdrv_make_empty) {
|
||||
s->qcow->bs->drv->bdrv_make_empty(s->qcow->bs);
|
||||
}
|
||||
|
||||
|
||||
@@ -461,6 +461,7 @@ typedef struct BdrvNextIterator {
|
||||
|
||||
BlockDriverState *bdrv_first(BdrvNextIterator *it);
|
||||
BlockDriverState *bdrv_next(BdrvNextIterator *it);
|
||||
void bdrv_next_cleanup(BdrvNextIterator *it);
|
||||
|
||||
BlockDriverState *bdrv_next_monitor_owned(BlockDriverState *bs);
|
||||
bool bdrv_is_encrypted(BlockDriverState *bs);
|
||||
|
||||
@@ -24,6 +24,7 @@ typedef struct QBool {
|
||||
QBool *qbool_from_bool(bool value);
|
||||
bool qbool_get_bool(const QBool *qb);
|
||||
QBool *qobject_to_qbool(const QObject *obj);
|
||||
bool qbool_is_equal(const QObject *x, const QObject *y);
|
||||
void qbool_destroy_obj(QObject *obj);
|
||||
|
||||
#endif /* QBOOL_H */
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "qapi/qmp/qobject.h"
|
||||
#include "qapi/qmp/qlist.h"
|
||||
#include "qapi/qmp/qnull.h"
|
||||
#include "qapi/qmp/qnum.h"
|
||||
#include "qemu/queue.h"
|
||||
|
||||
@@ -42,6 +43,7 @@ void qdict_del(QDict *qdict, const char *key);
|
||||
int qdict_haskey(const QDict *qdict, const char *key);
|
||||
QObject *qdict_get(const QDict *qdict, const char *key);
|
||||
QDict *qobject_to_qdict(const QObject *obj);
|
||||
bool qdict_is_equal(const QObject *x, const QObject *y);
|
||||
void qdict_iter(const QDict *qdict,
|
||||
void (*iter)(const char *key, QObject *obj, void *opaque),
|
||||
void *opaque);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "qapi/qmp/qobject.h"
|
||||
#include "qapi/qmp/qnum.h"
|
||||
#include "qapi/qmp/qnull.h"
|
||||
#include "qemu/queue.h"
|
||||
|
||||
typedef struct QListEntry {
|
||||
@@ -37,6 +38,8 @@ typedef struct QList {
|
||||
qlist_append(qlist, qbool_from_bool(value))
|
||||
#define qlist_append_str(qlist, value) \
|
||||
qlist_append(qlist, qstring_from_str(value))
|
||||
#define qlist_append_null(qlist) \
|
||||
qlist_append(qlist, qnull())
|
||||
|
||||
#define QLIST_FOREACH_ENTRY(qlist, var) \
|
||||
for ((var) = ((qlist)->head.tqh_first); \
|
||||
@@ -58,6 +61,7 @@ QObject *qlist_peek(QList *qlist);
|
||||
int qlist_empty(const QList *qlist);
|
||||
size_t qlist_size(const QList *qlist);
|
||||
QList *qobject_to_qlist(const QObject *obj);
|
||||
bool qlist_is_equal(const QObject *x, const QObject *y);
|
||||
void qlist_destroy_obj(QObject *obj);
|
||||
|
||||
static inline const QListEntry *qlist_first(const QList *qlist)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user