mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'mreitz/tags/pull-block-2018-05-15' into queue-block
- Copy-on-read block driver - The qcow2 default refcount cache size has been decreased - Various bug fixes # gpg: Signature made Tue May 15 16:18:25 2018 CEST # gpg: using RSA key F407DB0061D5CF40 # gpg: Good signature from "Max Reitz <mreitz@redhat.com>" # Primary key fingerprint: 91BE B60A 30DB 3E88 57D1 1829 F407 DB00 61D5 CF40 * mreitz/tags/pull-block-2018-05-15: (21 commits) iotests: Add test for -U/force-share conflicts qemu-img: Use only string options in img_open_opts qemu-io: Use purely string blockdev options block: Document BDRV_REQ_WRITE_UNCHANGED support qemu-img: Check post-truncation size iotests: Add test for COR across nodes iotests: Copy 197 for COR filter driver iotests: Clean up wrap image in 197 block: Support BDRV_REQ_WRITE_UNCHANGED in filters block/quorum: Support BDRV_REQ_WRITE_UNCHANGED block: Set BDRV_REQ_WRITE_UNCHANGED for COR writes block: Add BDRV_REQ_WRITE_UNCHANGED flag block: BLK_PERM_WRITE includes ..._UNCHANGED block: Add COR filter driver iotests: Skip 181 and 201 without userfaultfd iotests: Add failure matching to common.qemu docs: Document the new default sizes of the qcow2 caches qcow2: Give the refcount cache the minimum possible size by default specs/qcow2: Clarify that compressed clusters have the COPIED bit reset Fix error message about compressed clusters with OFLAG_COPIED ... Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
+1
-1
@@ -26,7 +26,7 @@ block-obj-y += accounting.o dirty-bitmap.o
|
||||
block-obj-y += write-threshold.o
|
||||
block-obj-y += backup.o
|
||||
block-obj-$(CONFIG_REPLICATION) += replication.o
|
||||
block-obj-y += throttle.o
|
||||
block-obj-y += throttle.o copy-on-read.o
|
||||
|
||||
block-obj-y += crypto.o
|
||||
|
||||
|
||||
+5
-4
@@ -398,10 +398,11 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
goto out;
|
||||
}
|
||||
|
||||
bs->supported_write_flags = BDRV_REQ_FUA &
|
||||
bs->file->bs->supported_write_flags;
|
||||
bs->supported_zero_flags = (BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP) &
|
||||
bs->file->bs->supported_zero_flags;
|
||||
bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED |
|
||||
(BDRV_REQ_FUA & bs->file->bs->supported_write_flags);
|
||||
bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
|
||||
((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP) &
|
||||
bs->file->bs->supported_zero_flags);
|
||||
ret = -EINVAL;
|
||||
|
||||
/* Set alignment overrides */
|
||||
|
||||
@@ -35,6 +35,9 @@ static int blkreplay_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED;
|
||||
bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED;
|
||||
|
||||
ret = 0;
|
||||
fail:
|
||||
return ret;
|
||||
|
||||
@@ -141,6 +141,9 @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED;
|
||||
bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED;
|
||||
|
||||
ret = 0;
|
||||
fail:
|
||||
qemu_opts_del(opts);
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copy-on-read filter block driver
|
||||
*
|
||||
* Copyright (c) 2018 Red Hat, Inc.
|
||||
*
|
||||
* Author:
|
||||
* Max Reitz <mreitz@redhat.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 or
|
||||
* (at your option) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "block/block_int.h"
|
||||
|
||||
|
||||
static int cor_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
Error **errp)
|
||||
{
|
||||
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, false,
|
||||
errp);
|
||||
if (!bs->file) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED |
|
||||
(BDRV_REQ_FUA &
|
||||
bs->file->bs->supported_write_flags);
|
||||
|
||||
bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
|
||||
((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP) &
|
||||
bs->file->bs->supported_zero_flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void cor_close(BlockDriverState *bs)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
#define PERM_PASSTHROUGH (BLK_PERM_CONSISTENT_READ \
|
||||
| BLK_PERM_WRITE \
|
||||
| BLK_PERM_RESIZE)
|
||||
#define PERM_UNCHANGED (BLK_PERM_ALL & ~PERM_PASSTHROUGH)
|
||||
|
||||
static void cor_child_perm(BlockDriverState *bs, BdrvChild *c,
|
||||
const BdrvChildRole *role,
|
||||
BlockReopenQueue *reopen_queue,
|
||||
uint64_t perm, uint64_t shared,
|
||||
uint64_t *nperm, uint64_t *nshared)
|
||||
{
|
||||
if (c == NULL) {
|
||||
*nperm = (perm & PERM_PASSTHROUGH) | BLK_PERM_WRITE_UNCHANGED;
|
||||
*nshared = (shared & PERM_PASSTHROUGH) | PERM_UNCHANGED;
|
||||
return;
|
||||
}
|
||||
|
||||
*nperm = (perm & PERM_PASSTHROUGH) |
|
||||
(c->perm & PERM_UNCHANGED);
|
||||
*nshared = (shared & PERM_PASSTHROUGH) |
|
||||
(c->shared_perm & PERM_UNCHANGED);
|
||||
}
|
||||
|
||||
|
||||
static int64_t cor_getlength(BlockDriverState *bs)
|
||||
{
|
||||
return bdrv_getlength(bs->file->bs);
|
||||
}
|
||||
|
||||
|
||||
static int cor_truncate(BlockDriverState *bs, int64_t offset,
|
||||
PreallocMode prealloc, Error **errp)
|
||||
{
|
||||
return bdrv_truncate(bs->file, offset, prealloc, errp);
|
||||
}
|
||||
|
||||
|
||||
static int coroutine_fn cor_co_preadv(BlockDriverState *bs,
|
||||
uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
return bdrv_co_preadv(bs->file, offset, bytes, qiov,
|
||||
flags | BDRV_REQ_COPY_ON_READ);
|
||||
}
|
||||
|
||||
|
||||
static int coroutine_fn cor_co_pwritev(BlockDriverState *bs,
|
||||
uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
|
||||
return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
|
||||
}
|
||||
|
||||
|
||||
static int coroutine_fn cor_co_pwrite_zeroes(BlockDriverState *bs,
|
||||
int64_t offset, int bytes,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
|
||||
}
|
||||
|
||||
|
||||
static int coroutine_fn cor_co_pdiscard(BlockDriverState *bs,
|
||||
int64_t offset, int bytes)
|
||||
{
|
||||
return bdrv_co_pdiscard(bs->file->bs, offset, bytes);
|
||||
}
|
||||
|
||||
|
||||
static void cor_eject(BlockDriverState *bs, bool eject_flag)
|
||||
{
|
||||
bdrv_eject(bs->file->bs, eject_flag);
|
||||
}
|
||||
|
||||
|
||||
static void cor_lock_medium(BlockDriverState *bs, bool locked)
|
||||
{
|
||||
bdrv_lock_medium(bs->file->bs, locked);
|
||||
}
|
||||
|
||||
|
||||
static bool cor_recurse_is_first_non_filter(BlockDriverState *bs,
|
||||
BlockDriverState *candidate)
|
||||
{
|
||||
return bdrv_recurse_is_first_non_filter(bs->file->bs, candidate);
|
||||
}
|
||||
|
||||
|
||||
BlockDriver bdrv_copy_on_read = {
|
||||
.format_name = "copy-on-read",
|
||||
|
||||
.bdrv_open = cor_open,
|
||||
.bdrv_close = cor_close,
|
||||
.bdrv_child_perm = cor_child_perm,
|
||||
|
||||
.bdrv_getlength = cor_getlength,
|
||||
.bdrv_truncate = cor_truncate,
|
||||
|
||||
.bdrv_co_preadv = cor_co_preadv,
|
||||
.bdrv_co_pwritev = cor_co_pwritev,
|
||||
.bdrv_co_pwrite_zeroes = cor_co_pwrite_zeroes,
|
||||
.bdrv_co_pdiscard = cor_co_pdiscard,
|
||||
|
||||
.bdrv_eject = cor_eject,
|
||||
.bdrv_lock_medium = cor_lock_medium,
|
||||
|
||||
.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,
|
||||
};
|
||||
|
||||
static void bdrv_copy_on_read_init(void)
|
||||
{
|
||||
bdrv_register(&bdrv_copy_on_read);
|
||||
}
|
||||
|
||||
block_init(bdrv_copy_on_read_init);
|
||||
+9
-3
@@ -1118,13 +1118,15 @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child,
|
||||
/* FIXME: Should we (perhaps conditionally) be setting
|
||||
* BDRV_REQ_MAY_UNMAP, if it will allow for a sparser copy
|
||||
* that still correctly reads as zero? */
|
||||
ret = bdrv_co_do_pwrite_zeroes(bs, cluster_offset, pnum, 0);
|
||||
ret = bdrv_co_do_pwrite_zeroes(bs, cluster_offset, pnum,
|
||||
BDRV_REQ_WRITE_UNCHANGED);
|
||||
} else {
|
||||
/* This does not change the data on the disk, it is not
|
||||
* necessary to flush even in cache=writethrough mode.
|
||||
*/
|
||||
ret = bdrv_driver_pwritev(bs, cluster_offset, pnum,
|
||||
&local_qiov, 0);
|
||||
&local_qiov,
|
||||
BDRV_REQ_WRITE_UNCHANGED);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
@@ -1504,7 +1506,11 @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
|
||||
assert(!waited || !req->serialising);
|
||||
assert(req->overlap_offset <= offset);
|
||||
assert(offset + bytes <= req->overlap_offset + req->overlap_bytes);
|
||||
assert(child->perm & BLK_PERM_WRITE);
|
||||
if (flags & BDRV_REQ_WRITE_UNCHANGED) {
|
||||
assert(child->perm & (BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE));
|
||||
} else {
|
||||
assert(child->perm & BLK_PERM_WRITE);
|
||||
}
|
||||
assert(end_sector <= bs->total_sectors || child->perm & BLK_PERM_RESIZE);
|
||||
|
||||
ret = notifier_with_return_list_notify(&bs->before_write_notifiers, req);
|
||||
|
||||
@@ -1134,6 +1134,8 @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
|
||||
mirror_top_bs->implicit = true;
|
||||
}
|
||||
mirror_top_bs->total_sectors = bs->total_sectors;
|
||||
mirror_top_bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED;
|
||||
mirror_top_bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED;
|
||||
bdrv_set_aio_context(mirror_top_bs, bdrv_get_aio_context(bs));
|
||||
|
||||
/* bdrv_append takes ownership of the mirror_top_bs reference, need to keep
|
||||
|
||||
@@ -1577,9 +1577,9 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
case QCOW2_CLUSTER_COMPRESSED:
|
||||
/* Compressed clusters don't have QCOW_OFLAG_COPIED */
|
||||
if (l2_entry & QCOW_OFLAG_COPIED) {
|
||||
fprintf(stderr, "ERROR: cluster %" PRId64 ": "
|
||||
fprintf(stderr, "ERROR: coffset=0x%" PRIx64 ": "
|
||||
"copied flag must never be set for compressed "
|
||||
"clusters\n", l2_entry >> s->cluster_bits);
|
||||
"clusters\n", l2_entry & s->cluster_offset_mask);
|
||||
l2_entry &= ~QCOW_OFLAG_COPIED;
|
||||
res->corruptions++;
|
||||
}
|
||||
|
||||
+19
-12
@@ -802,23 +802,30 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
|
||||
} else if (refcount_cache_size_set) {
|
||||
*l2_cache_size = combined_cache_size - *refcount_cache_size;
|
||||
} else {
|
||||
*refcount_cache_size = combined_cache_size
|
||||
/ (DEFAULT_L2_REFCOUNT_SIZE_RATIO + 1);
|
||||
*l2_cache_size = combined_cache_size - *refcount_cache_size;
|
||||
uint64_t virtual_disk_size = bs->total_sectors * BDRV_SECTOR_SIZE;
|
||||
uint64_t max_l2_cache = virtual_disk_size / (s->cluster_size / 8);
|
||||
uint64_t min_refcount_cache =
|
||||
(uint64_t) MIN_REFCOUNT_CACHE_SIZE * s->cluster_size;
|
||||
|
||||
/* Assign as much memory as possible to the L2 cache, and
|
||||
* use the remainder for the refcount cache */
|
||||
if (combined_cache_size >= max_l2_cache + min_refcount_cache) {
|
||||
*l2_cache_size = max_l2_cache;
|
||||
*refcount_cache_size = combined_cache_size - *l2_cache_size;
|
||||
} else {
|
||||
*refcount_cache_size =
|
||||
MIN(combined_cache_size, min_refcount_cache);
|
||||
*l2_cache_size = combined_cache_size - *refcount_cache_size;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!l2_cache_size_set && !refcount_cache_size_set) {
|
||||
if (!l2_cache_size_set) {
|
||||
*l2_cache_size = MAX(DEFAULT_L2_CACHE_BYTE_SIZE,
|
||||
(uint64_t)DEFAULT_L2_CACHE_CLUSTERS
|
||||
* s->cluster_size);
|
||||
*refcount_cache_size = *l2_cache_size
|
||||
/ DEFAULT_L2_REFCOUNT_SIZE_RATIO;
|
||||
} else if (!l2_cache_size_set) {
|
||||
*l2_cache_size = *refcount_cache_size
|
||||
* DEFAULT_L2_REFCOUNT_SIZE_RATIO;
|
||||
} else if (!refcount_cache_size_set) {
|
||||
*refcount_cache_size = *l2_cache_size
|
||||
/ DEFAULT_L2_REFCOUNT_SIZE_RATIO;
|
||||
}
|
||||
if (!refcount_cache_size_set) {
|
||||
*refcount_cache_size = MIN_REFCOUNT_CACHE_SIZE * s->cluster_size;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -77,10 +77,6 @@
|
||||
#define DEFAULT_L2_CACHE_CLUSTERS 8 /* clusters */
|
||||
#define DEFAULT_L2_CACHE_BYTE_SIZE 1048576 /* bytes */
|
||||
|
||||
/* The refblock cache needs only a fourth of the L2 cache size to cover as many
|
||||
* clusters */
|
||||
#define DEFAULT_L2_REFCOUNT_SIZE_RATIO 4
|
||||
|
||||
#define DEFAULT_CLUSTER_SIZE 65536
|
||||
|
||||
|
||||
|
||||
+13
-6
@@ -115,6 +115,7 @@ struct QuorumAIOCB {
|
||||
/* Request metadata */
|
||||
uint64_t offset;
|
||||
uint64_t bytes;
|
||||
int flags;
|
||||
|
||||
QEMUIOVector *qiov; /* calling IOV */
|
||||
|
||||
@@ -157,7 +158,8 @@ static bool quorum_64bits_compare(QuorumVoteValue *a, QuorumVoteValue *b)
|
||||
static QuorumAIOCB *quorum_aio_get(BlockDriverState *bs,
|
||||
QEMUIOVector *qiov,
|
||||
uint64_t offset,
|
||||
uint64_t bytes)
|
||||
uint64_t bytes,
|
||||
int flags)
|
||||
{
|
||||
BDRVQuorumState *s = bs->opaque;
|
||||
QuorumAIOCB *acb = g_new(QuorumAIOCB, 1);
|
||||
@@ -168,6 +170,7 @@ static QuorumAIOCB *quorum_aio_get(BlockDriverState *bs,
|
||||
.bs = bs,
|
||||
.offset = offset,
|
||||
.bytes = bytes,
|
||||
.flags = flags,
|
||||
.qiov = qiov,
|
||||
.votes.compare = quorum_sha256_compare,
|
||||
.votes.vote_list = QLIST_HEAD_INITIALIZER(acb.votes.vote_list),
|
||||
@@ -271,9 +274,11 @@ static void quorum_rewrite_entry(void *opaque)
|
||||
BDRVQuorumState *s = acb->bs->opaque;
|
||||
|
||||
/* Ignore any errors, it's just a correction attempt for already
|
||||
* corrupted data. */
|
||||
* corrupted data.
|
||||
* Mask out BDRV_REQ_WRITE_UNCHANGED because this overwrites the
|
||||
* area with different data from the other children. */
|
||||
bdrv_co_pwritev(s->children[co->idx], acb->offset, acb->bytes,
|
||||
acb->qiov, 0);
|
||||
acb->qiov, acb->flags & ~BDRV_REQ_WRITE_UNCHANGED);
|
||||
|
||||
/* Wake up the caller after the last rewrite */
|
||||
acb->rewrite_count--;
|
||||
@@ -673,7 +678,7 @@ static int quorum_co_preadv(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
BDRVQuorumState *s = bs->opaque;
|
||||
QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes);
|
||||
QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes, flags);
|
||||
int ret;
|
||||
|
||||
acb->is_read = true;
|
||||
@@ -699,7 +704,7 @@ static void write_quorum_entry(void *opaque)
|
||||
|
||||
sacb->bs = s->children[i]->bs;
|
||||
sacb->ret = bdrv_co_pwritev(s->children[i], acb->offset, acb->bytes,
|
||||
acb->qiov, 0);
|
||||
acb->qiov, acb->flags);
|
||||
if (sacb->ret == 0) {
|
||||
acb->success_count++;
|
||||
} else {
|
||||
@@ -719,7 +724,7 @@ static int quorum_co_pwritev(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
BDRVQuorumState *s = bs->opaque;
|
||||
QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes);
|
||||
QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes, flags);
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
@@ -961,6 +966,8 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
s->next_child_index = s->num_children;
|
||||
|
||||
bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED;
|
||||
|
||||
g_free(opened);
|
||||
goto exit;
|
||||
|
||||
|
||||
+5
-4
@@ -415,10 +415,11 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
|
||||
bs->sg = bs->file->bs->sg;
|
||||
bs->supported_write_flags = BDRV_REQ_FUA &
|
||||
bs->file->bs->supported_write_flags;
|
||||
bs->supported_zero_flags = (BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP) &
|
||||
bs->file->bs->supported_zero_flags;
|
||||
bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED |
|
||||
(BDRV_REQ_FUA & bs->file->bs->supported_write_flags);
|
||||
bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
|
||||
((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP) &
|
||||
bs->file->bs->supported_zero_flags);
|
||||
|
||||
if (bs->probed && !bdrv_is_read_only(bs)) {
|
||||
fprintf(stderr,
|
||||
|
||||
+4
-2
@@ -81,8 +81,10 @@ static int throttle_open(BlockDriverState *bs, QDict *options,
|
||||
if (!bs->file) {
|
||||
return -EINVAL;
|
||||
}
|
||||
bs->supported_write_flags = bs->file->bs->supported_write_flags;
|
||||
bs->supported_zero_flags = bs->file->bs->supported_zero_flags;
|
||||
bs->supported_write_flags = bs->file->bs->supported_write_flags |
|
||||
BDRV_REQ_WRITE_UNCHANGED;
|
||||
bs->supported_zero_flags = bs->file->bs->supported_zero_flags |
|
||||
BDRV_REQ_WRITE_UNCHANGED;
|
||||
|
||||
return throttle_configure_tgm(bs, tgm, options, errp);
|
||||
}
|
||||
|
||||
@@ -400,10 +400,10 @@ L2 table entry:
|
||||
62: 0 for standard clusters
|
||||
1 for compressed clusters
|
||||
|
||||
63: 0 for a cluster that is unused or requires COW, 1 if its
|
||||
refcount is exactly one. This information is only accurate
|
||||
in L2 tables that are reachable from the active L1
|
||||
table.
|
||||
63: 0 for clusters that are unused, compressed or require COW.
|
||||
1 for standard clusters whose refcount is exactly one.
|
||||
This information is only accurate in L2 tables
|
||||
that are reachable from the active L1 table.
|
||||
|
||||
Standard Cluster Descriptor:
|
||||
|
||||
|
||||
+16
-17
@@ -116,31 +116,30 @@ There are three options available, and all of them take bytes:
|
||||
"refcount-cache-size": maximum size of the refcount block cache
|
||||
"cache-size": maximum size of both caches combined
|
||||
|
||||
There are two things that need to be taken into account:
|
||||
There are a few things that need to be taken into account:
|
||||
|
||||
- Both caches must have a size that is a multiple of the cluster size
|
||||
(or the cache entry size: see "Using smaller cache sizes" below).
|
||||
|
||||
- If you only set one of the options above, QEMU will automatically
|
||||
adjust the others so that the L2 cache is 4 times bigger than the
|
||||
refcount cache.
|
||||
- The default L2 cache size is 8 clusters or 1MB (whichever is more),
|
||||
and the minimum is 2 clusters (or 2 cache entries, see below).
|
||||
|
||||
This means that these options are equivalent:
|
||||
- The default (and minimum) refcount cache size is 4 clusters.
|
||||
|
||||
-drive file=hd.qcow2,l2-cache-size=2097152
|
||||
-drive file=hd.qcow2,refcount-cache-size=524288
|
||||
-drive file=hd.qcow2,cache-size=2621440
|
||||
- If only "cache-size" is specified then QEMU will assign as much
|
||||
memory as possible to the L2 cache before increasing the refcount
|
||||
cache size.
|
||||
|
||||
The reason for this 1/4 ratio is to ensure that both caches cover the
|
||||
same amount of disk space. Note however that this is only valid with
|
||||
the default value of refcount_bits (16). If you are using a different
|
||||
value you might want to calculate both cache sizes yourself since QEMU
|
||||
will always use the same 1/4 ratio.
|
||||
Unlike L2 tables, refcount blocks are not used during normal I/O but
|
||||
only during allocations and internal snapshots. In most cases they are
|
||||
accessed sequentially (even during random guest I/O) so increasing the
|
||||
refcount cache size won't have any measurable effect in performance
|
||||
(this can change if you are using internal snapshots, so you may want
|
||||
to think about increasing the cache size if you use them heavily).
|
||||
|
||||
It's also worth mentioning that there's no strict need for both caches
|
||||
to cover the same amount of disk space. The refcount cache is used
|
||||
much less often than the L2 cache, so it's perfectly reasonable to
|
||||
keep it small.
|
||||
Before QEMU 2.12 the refcount cache had a default size of 1/4 of the
|
||||
L2 cache size. This resulted in unnecessarily large caches, so now the
|
||||
refcount cache is as small as possible unless overridden by the user.
|
||||
|
||||
|
||||
Using smaller cache entries
|
||||
|
||||
@@ -54,8 +54,12 @@ typedef enum {
|
||||
BDRV_REQ_FUA = 0x10,
|
||||
BDRV_REQ_WRITE_COMPRESSED = 0x20,
|
||||
|
||||
/* Signifies that this write request will not change the visible disk
|
||||
* content. */
|
||||
BDRV_REQ_WRITE_UNCHANGED = 0x40,
|
||||
|
||||
/* Mask of valid flags */
|
||||
BDRV_REQ_MASK = 0x3f,
|
||||
BDRV_REQ_MASK = 0x7f,
|
||||
} BdrvRequestFlags;
|
||||
|
||||
typedef struct BlockSizes {
|
||||
@@ -205,6 +209,9 @@ enum {
|
||||
* This permission (which is weaker than BLK_PERM_WRITE) is both enough and
|
||||
* required for writes to the block node when the caller promises that
|
||||
* the visible disk content doesn't change.
|
||||
*
|
||||
* As the BLK_PERM_WRITE permission is strictly stronger, either is
|
||||
* sufficient to perform an unchanging write.
|
||||
*/
|
||||
BLK_PERM_WRITE_UNCHANGED = 0x04,
|
||||
|
||||
|
||||
@@ -656,10 +656,24 @@ struct BlockDriverState {
|
||||
/* I/O Limits */
|
||||
BlockLimits bl;
|
||||
|
||||
/* Flags honored during pwrite (so far: BDRV_REQ_FUA) */
|
||||
/* Flags honored during pwrite (so far: BDRV_REQ_FUA,
|
||||
* BDRV_REQ_WRITE_UNCHANGED).
|
||||
* If a driver does not support BDRV_REQ_WRITE_UNCHANGED, those
|
||||
* writes will be issued as normal writes without the flag set.
|
||||
* This is important to note for drivers that do not explicitly
|
||||
* request a WRITE permission for their children and instead take
|
||||
* the same permissions as their parent did (this is commonly what
|
||||
* block filters do). Such drivers have to be aware that the
|
||||
* parent may have taken a WRITE_UNCHANGED permission only and is
|
||||
* issuing such requests. Drivers either must make sure that
|
||||
* these requests do not result in plain WRITE accesses (usually
|
||||
* by supporting BDRV_REQ_WRITE_UNCHANGED, and then forwarding
|
||||
* every incoming write request as-is, including potentially that
|
||||
* flag), or they have to explicitly take the WRITE permission for
|
||||
* their children. */
|
||||
unsigned int supported_write_flags;
|
||||
/* Flags honored during pwrite_zeroes (so far: BDRV_REQ_FUA,
|
||||
* BDRV_REQ_MAY_UNMAP) */
|
||||
* BDRV_REQ_MAY_UNMAP, BDRV_REQ_WRITE_UNCHANGED) */
|
||||
unsigned int supported_zero_flags;
|
||||
|
||||
/* the following member gives a name to every node on the bs graph. */
|
||||
|
||||
@@ -2510,11 +2510,12 @@
|
||||
# @vxhs: Since 2.10
|
||||
# @throttle: Since 2.11
|
||||
# @nvme: Since 2.12
|
||||
# @copy-on-read: Since 2.13
|
||||
#
|
||||
# Since: 2.9
|
||||
##
|
||||
{ 'enum': 'BlockdevDriver',
|
||||
'data': [ 'blkdebug', 'blkverify', 'bochs', 'cloop',
|
||||
'data': [ 'blkdebug', 'blkverify', 'bochs', 'cloop', 'copy-on-read',
|
||||
'dmg', 'file', 'ftp', 'ftps', 'gluster', 'host_cdrom',
|
||||
'host_device', 'http', 'https', 'iscsi', 'luks', 'nbd', 'nfs',
|
||||
'null-aio', 'null-co', 'nvme', 'parallels', 'qcow', 'qcow2', 'qed',
|
||||
@@ -3531,6 +3532,7 @@
|
||||
'blkverify': 'BlockdevOptionsBlkverify',
|
||||
'bochs': 'BlockdevOptionsGenericFormat',
|
||||
'cloop': 'BlockdevOptionsGenericFormat',
|
||||
'copy-on-read':'BlockdevOptionsGenericFormat',
|
||||
'dmg': 'BlockdevOptionsGenericFormat',
|
||||
'file': 'BlockdevOptionsFile',
|
||||
'ftp': 'BlockdevOptionsCurlFtp',
|
||||
@@ -4058,6 +4060,7 @@
|
||||
'blkverify': 'BlockdevCreateNotSupported',
|
||||
'bochs': 'BlockdevCreateNotSupported',
|
||||
'cloop': 'BlockdevCreateNotSupported',
|
||||
'copy-on-read': 'BlockdevCreateNotSupported',
|
||||
'dmg': 'BlockdevCreateNotSupported',
|
||||
'file': 'BlockdevCreateOptionsFile',
|
||||
'ftp': 'BlockdevCreateNotSupported',
|
||||
|
||||
+37
-6
@@ -277,12 +277,12 @@ static BlockBackend *img_open_opts(const char *optstr,
|
||||
options = qemu_opts_to_qdict(opts, NULL);
|
||||
if (force_share) {
|
||||
if (qdict_haskey(options, BDRV_OPT_FORCE_SHARE)
|
||||
&& !qdict_get_bool(options, BDRV_OPT_FORCE_SHARE)) {
|
||||
&& strcmp(qdict_get_str(options, BDRV_OPT_FORCE_SHARE), "on")) {
|
||||
error_report("--force-share/-U conflicts with image options");
|
||||
qobject_unref(options);
|
||||
return NULL;
|
||||
}
|
||||
qdict_put_bool(options, BDRV_OPT_FORCE_SHARE, true);
|
||||
qdict_put_str(options, BDRV_OPT_FORCE_SHARE, "on");
|
||||
}
|
||||
blk = blk_new_open(NULL, NULL, options, flags, &local_err);
|
||||
if (!blk) {
|
||||
@@ -3381,7 +3381,7 @@ static int img_resize(int argc, char **argv)
|
||||
Error *err = NULL;
|
||||
int c, ret, relative;
|
||||
const char *filename, *fmt, *size;
|
||||
int64_t n, total_size, current_size;
|
||||
int64_t n, total_size, current_size, new_size;
|
||||
bool quiet = false;
|
||||
BlockBackend *blk = NULL;
|
||||
PreallocMode prealloc = PREALLOC_MODE_OFF;
|
||||
@@ -3557,11 +3557,42 @@ static int img_resize(int argc, char **argv)
|
||||
}
|
||||
|
||||
ret = blk_truncate(blk, total_size, prealloc, &err);
|
||||
if (!ret) {
|
||||
qprintf(quiet, "Image resized.\n");
|
||||
} else {
|
||||
if (ret < 0) {
|
||||
error_report_err(err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
new_size = blk_getlength(blk);
|
||||
if (new_size < 0) {
|
||||
error_report("Failed to verify truncated image length: %s",
|
||||
strerror(-new_size));
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Some block drivers implement a truncation method, but only so
|
||||
* the user can cause qemu to refresh the image's size from disk.
|
||||
* The idea is that the user resizes the image outside of qemu and
|
||||
* then invokes block_resize to inform qemu about it.
|
||||
* (This includes iscsi and file-posix for device files.)
|
||||
* Of course, that is not the behavior someone invoking
|
||||
* qemu-img resize would find useful, so we catch that behavior
|
||||
* here and tell the user. */
|
||||
if (new_size != total_size && new_size == current_size) {
|
||||
error_report("Image was not resized; resizing may not be supported "
|
||||
"for this image");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (new_size != total_size) {
|
||||
warn_report("Image should have been resized to %" PRIi64
|
||||
" bytes, but was resized to %" PRIi64 " bytes",
|
||||
total_size, new_size);
|
||||
}
|
||||
|
||||
qprintf(quiet, "Image resized.\n");
|
||||
|
||||
out:
|
||||
blk_unref(blk);
|
||||
if (ret) {
|
||||
|
||||
@@ -95,12 +95,12 @@ static int openfile(char *name, int flags, bool writethrough, bool force_share,
|
||||
opts = qdict_new();
|
||||
}
|
||||
if (qdict_haskey(opts, BDRV_OPT_FORCE_SHARE)
|
||||
&& !qdict_get_bool(opts, BDRV_OPT_FORCE_SHARE)) {
|
||||
&& strcmp(qdict_get_str(opts, BDRV_OPT_FORCE_SHARE), "on")) {
|
||||
error_report("-U conflicts with image options");
|
||||
qobject_unref(opts);
|
||||
return 1;
|
||||
}
|
||||
qdict_put_bool(opts, BDRV_OPT_FORCE_SHARE, true);
|
||||
qdict_put_str(opts, BDRV_OPT_FORCE_SHARE, "on");
|
||||
}
|
||||
qemuio_blk = blk_new_open(name, NULL, opts, flags, &local_err);
|
||||
if (!qemuio_blk) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user