mirror of
https://github.com/xemu-project/xemu.git
synced 2024-11-28 14:00:44 +00:00
Block patches for 3.0-rc0:
- qcow2 metadata overlap protection for the persistent bitmap directory - Various bug fixes -----BEGIN PGP SIGNATURE----- iQEcBAABAgAGBQJbQ69uAAoJEPQH2wBh1c9A9gkH/0veRUeFS0BwPnE3+NKHw2tu 67RFyHi+HpwQf9nFjEeP9L2NqTQEnNMMZdpyB2DlLdEj1XCGgP1WCx6G46FI4erS jRGJufZA01b3Ud+kSR9LrzQFREaX/RslF1J27eMkv2O2FwFhJRPSH+UT/1WLoYJU 2AroQ4BMO0MoIGQ/O4OPH8e9Z62p6HpbJuLPg52PU1+uj8vvXbALHHCKBD0VIu8p mvj+5aRnoem0ICYomrPoaw5fe6N9CXy5V3Cj7hlSgVA/CyBjBFmq0cA2ZD4020SY 1Y6lOTm9PzBsEX4LnOLn2At1MzyPLERsTGee4zdn6r8g/0gUhNwfO7H2QV8NA5k= =0vHR -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/xanclic/tags/pull-block-2018-07-09' into staging Block patches for 3.0-rc0: - qcow2 metadata overlap protection for the persistent bitmap directory - Various bug fixes # gpg: Signature made Mon 09 Jul 2018 19:54:38 BST # 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 * remotes/xanclic/tags/pull-block-2018-07-09: qcow2: add overlap check for bitmap directory iotests: Add VMDK backing file correlation test vmdk: Fix possible segfault with non-VMDK backing raw: Drop superfluous semicolon qcow2: Drop unreachable break file-posix: Fix fd_open check in raw_co_copy_range_to qcow2: Drop unused cluster_data Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
6784273a0e
@ -2611,7 +2611,7 @@ static int coroutine_fn raw_co_copy_range_to(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
src_s = src->bs->opaque;
|
||||
if (fd_open(bs) < 0 || fd_open(bs) < 0) {
|
||||
if (fd_open(src->bs) < 0 || fd_open(dst->bs) < 0) {
|
||||
return -EIO;
|
||||
}
|
||||
return paio_submit_co_full(bs, src_s->fd, src_offset, s->fd, dst_offset,
|
||||
|
@ -775,7 +775,12 @@ static int bitmap_list_store(BlockDriverState *bs, Qcow2BitmapList *bm_list,
|
||||
}
|
||||
}
|
||||
|
||||
ret = qcow2_pre_write_overlap_check(bs, 0, dir_offset, dir_size);
|
||||
/* Actually, even in in-place case ignoring QCOW2_OL_BITMAP_DIRECTORY is not
|
||||
* necessary, because we drop QCOW2_AUTOCLEAR_BITMAPS when updating bitmap
|
||||
* directory in-place (actually, turn-off the extension), which is checked
|
||||
* in qcow2_check_metadata_overlap() */
|
||||
ret = qcow2_pre_write_overlap_check(
|
||||
bs, in_place ? QCOW2_OL_BITMAP_DIRECTORY : 0, dir_offset, dir_size);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
@ -2705,6 +2705,16 @@ int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset,
|
||||
}
|
||||
}
|
||||
|
||||
if ((chk & QCOW2_OL_BITMAP_DIRECTORY) &&
|
||||
(s->autoclear_features & QCOW2_AUTOCLEAR_BITMAPS))
|
||||
{
|
||||
if (overlaps_with(s->bitmap_directory_offset,
|
||||
s->bitmap_directory_size))
|
||||
{
|
||||
return QCOW2_OL_BITMAP_DIRECTORY;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -679,6 +679,11 @@ static QemuOptsList qcow2_runtime_opts = {
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "Check for unintended writes into an inactive L2 table",
|
||||
},
|
||||
{
|
||||
.name = QCOW2_OPT_OVERLAP_BITMAP_DIRECTORY,
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "Check for unintended writes into the bitmap directory",
|
||||
},
|
||||
{
|
||||
.name = QCOW2_OPT_CACHE_SIZE,
|
||||
.type = QEMU_OPT_SIZE,
|
||||
@ -712,14 +717,15 @@ static QemuOptsList qcow2_runtime_opts = {
|
||||
};
|
||||
|
||||
static const char *overlap_bool_option_names[QCOW2_OL_MAX_BITNR] = {
|
||||
[QCOW2_OL_MAIN_HEADER_BITNR] = QCOW2_OPT_OVERLAP_MAIN_HEADER,
|
||||
[QCOW2_OL_ACTIVE_L1_BITNR] = QCOW2_OPT_OVERLAP_ACTIVE_L1,
|
||||
[QCOW2_OL_ACTIVE_L2_BITNR] = QCOW2_OPT_OVERLAP_ACTIVE_L2,
|
||||
[QCOW2_OL_REFCOUNT_TABLE_BITNR] = QCOW2_OPT_OVERLAP_REFCOUNT_TABLE,
|
||||
[QCOW2_OL_REFCOUNT_BLOCK_BITNR] = QCOW2_OPT_OVERLAP_REFCOUNT_BLOCK,
|
||||
[QCOW2_OL_SNAPSHOT_TABLE_BITNR] = QCOW2_OPT_OVERLAP_SNAPSHOT_TABLE,
|
||||
[QCOW2_OL_INACTIVE_L1_BITNR] = QCOW2_OPT_OVERLAP_INACTIVE_L1,
|
||||
[QCOW2_OL_INACTIVE_L2_BITNR] = QCOW2_OPT_OVERLAP_INACTIVE_L2,
|
||||
[QCOW2_OL_MAIN_HEADER_BITNR] = QCOW2_OPT_OVERLAP_MAIN_HEADER,
|
||||
[QCOW2_OL_ACTIVE_L1_BITNR] = QCOW2_OPT_OVERLAP_ACTIVE_L1,
|
||||
[QCOW2_OL_ACTIVE_L2_BITNR] = QCOW2_OPT_OVERLAP_ACTIVE_L2,
|
||||
[QCOW2_OL_REFCOUNT_TABLE_BITNR] = QCOW2_OPT_OVERLAP_REFCOUNT_TABLE,
|
||||
[QCOW2_OL_REFCOUNT_BLOCK_BITNR] = QCOW2_OPT_OVERLAP_REFCOUNT_BLOCK,
|
||||
[QCOW2_OL_SNAPSHOT_TABLE_BITNR] = QCOW2_OPT_OVERLAP_SNAPSHOT_TABLE,
|
||||
[QCOW2_OL_INACTIVE_L1_BITNR] = QCOW2_OPT_OVERLAP_INACTIVE_L1,
|
||||
[QCOW2_OL_INACTIVE_L2_BITNR] = QCOW2_OPT_OVERLAP_INACTIVE_L2,
|
||||
[QCOW2_OL_BITMAP_DIRECTORY_BITNR] = QCOW2_OPT_OVERLAP_BITMAP_DIRECTORY,
|
||||
};
|
||||
|
||||
static void cache_clean_timer_cb(void *opaque)
|
||||
@ -3299,7 +3305,6 @@ qcow2_co_copy_range_from(BlockDriverState *bs,
|
||||
case QCOW2_CLUSTER_COMPRESSED:
|
||||
ret = -ENOTSUP;
|
||||
goto out;
|
||||
break;
|
||||
|
||||
case QCOW2_CLUSTER_NORMAL:
|
||||
child = bs->file;
|
||||
@ -3345,7 +3350,6 @@ qcow2_co_copy_range_to(BlockDriverState *bs,
|
||||
int ret;
|
||||
unsigned int cur_bytes; /* number of sectors in current iteration */
|
||||
uint64_t cluster_offset;
|
||||
uint8_t *cluster_data = NULL;
|
||||
QCowL2Meta *l2meta = NULL;
|
||||
|
||||
assert(!bs->encrypted);
|
||||
@ -3404,7 +3408,6 @@ fail:
|
||||
|
||||
qemu_co_mutex_unlock(&s->lock);
|
||||
|
||||
qemu_vfree(cluster_data);
|
||||
trace_qcow2_writev_done_req(qemu_coroutine_self(), ret);
|
||||
|
||||
return ret;
|
||||
|
@ -94,6 +94,7 @@
|
||||
#define QCOW2_OPT_OVERLAP_SNAPSHOT_TABLE "overlap-check.snapshot-table"
|
||||
#define QCOW2_OPT_OVERLAP_INACTIVE_L1 "overlap-check.inactive-l1"
|
||||
#define QCOW2_OPT_OVERLAP_INACTIVE_L2 "overlap-check.inactive-l2"
|
||||
#define QCOW2_OPT_OVERLAP_BITMAP_DIRECTORY "overlap-check.bitmap-directory"
|
||||
#define QCOW2_OPT_CACHE_SIZE "cache-size"
|
||||
#define QCOW2_OPT_L2_CACHE_SIZE "l2-cache-size"
|
||||
#define QCOW2_OPT_L2_CACHE_ENTRY_SIZE "l2-cache-entry-size"
|
||||
@ -400,34 +401,36 @@ typedef enum QCow2ClusterType {
|
||||
} QCow2ClusterType;
|
||||
|
||||
typedef enum QCow2MetadataOverlap {
|
||||
QCOW2_OL_MAIN_HEADER_BITNR = 0,
|
||||
QCOW2_OL_ACTIVE_L1_BITNR = 1,
|
||||
QCOW2_OL_ACTIVE_L2_BITNR = 2,
|
||||
QCOW2_OL_REFCOUNT_TABLE_BITNR = 3,
|
||||
QCOW2_OL_REFCOUNT_BLOCK_BITNR = 4,
|
||||
QCOW2_OL_SNAPSHOT_TABLE_BITNR = 5,
|
||||
QCOW2_OL_INACTIVE_L1_BITNR = 6,
|
||||
QCOW2_OL_INACTIVE_L2_BITNR = 7,
|
||||
QCOW2_OL_MAIN_HEADER_BITNR = 0,
|
||||
QCOW2_OL_ACTIVE_L1_BITNR = 1,
|
||||
QCOW2_OL_ACTIVE_L2_BITNR = 2,
|
||||
QCOW2_OL_REFCOUNT_TABLE_BITNR = 3,
|
||||
QCOW2_OL_REFCOUNT_BLOCK_BITNR = 4,
|
||||
QCOW2_OL_SNAPSHOT_TABLE_BITNR = 5,
|
||||
QCOW2_OL_INACTIVE_L1_BITNR = 6,
|
||||
QCOW2_OL_INACTIVE_L2_BITNR = 7,
|
||||
QCOW2_OL_BITMAP_DIRECTORY_BITNR = 8,
|
||||
|
||||
QCOW2_OL_MAX_BITNR = 8,
|
||||
QCOW2_OL_MAX_BITNR = 9,
|
||||
|
||||
QCOW2_OL_NONE = 0,
|
||||
QCOW2_OL_MAIN_HEADER = (1 << QCOW2_OL_MAIN_HEADER_BITNR),
|
||||
QCOW2_OL_ACTIVE_L1 = (1 << QCOW2_OL_ACTIVE_L1_BITNR),
|
||||
QCOW2_OL_ACTIVE_L2 = (1 << QCOW2_OL_ACTIVE_L2_BITNR),
|
||||
QCOW2_OL_REFCOUNT_TABLE = (1 << QCOW2_OL_REFCOUNT_TABLE_BITNR),
|
||||
QCOW2_OL_REFCOUNT_BLOCK = (1 << QCOW2_OL_REFCOUNT_BLOCK_BITNR),
|
||||
QCOW2_OL_SNAPSHOT_TABLE = (1 << QCOW2_OL_SNAPSHOT_TABLE_BITNR),
|
||||
QCOW2_OL_INACTIVE_L1 = (1 << QCOW2_OL_INACTIVE_L1_BITNR),
|
||||
QCOW2_OL_NONE = 0,
|
||||
QCOW2_OL_MAIN_HEADER = (1 << QCOW2_OL_MAIN_HEADER_BITNR),
|
||||
QCOW2_OL_ACTIVE_L1 = (1 << QCOW2_OL_ACTIVE_L1_BITNR),
|
||||
QCOW2_OL_ACTIVE_L2 = (1 << QCOW2_OL_ACTIVE_L2_BITNR),
|
||||
QCOW2_OL_REFCOUNT_TABLE = (1 << QCOW2_OL_REFCOUNT_TABLE_BITNR),
|
||||
QCOW2_OL_REFCOUNT_BLOCK = (1 << QCOW2_OL_REFCOUNT_BLOCK_BITNR),
|
||||
QCOW2_OL_SNAPSHOT_TABLE = (1 << QCOW2_OL_SNAPSHOT_TABLE_BITNR),
|
||||
QCOW2_OL_INACTIVE_L1 = (1 << QCOW2_OL_INACTIVE_L1_BITNR),
|
||||
/* NOTE: Checking overlaps with inactive L2 tables will result in bdrv
|
||||
* reads. */
|
||||
QCOW2_OL_INACTIVE_L2 = (1 << QCOW2_OL_INACTIVE_L2_BITNR),
|
||||
QCOW2_OL_INACTIVE_L2 = (1 << QCOW2_OL_INACTIVE_L2_BITNR),
|
||||
QCOW2_OL_BITMAP_DIRECTORY = (1 << QCOW2_OL_BITMAP_DIRECTORY_BITNR),
|
||||
} QCow2MetadataOverlap;
|
||||
|
||||
/* Perform all overlap checks which can be done in constant time */
|
||||
#define QCOW2_OL_CONSTANT \
|
||||
(QCOW2_OL_MAIN_HEADER | QCOW2_OL_ACTIVE_L1 | QCOW2_OL_REFCOUNT_TABLE | \
|
||||
QCOW2_OL_SNAPSHOT_TABLE)
|
||||
QCOW2_OL_SNAPSHOT_TABLE | QCOW2_OL_BITMAP_DIRECTORY)
|
||||
|
||||
/* Perform all overlap checks which don't require disk access */
|
||||
#define QCOW2_OL_CACHED \
|
||||
|
@ -177,7 +177,7 @@ static inline int raw_adjust_offset(BlockDriverState *bs, uint64_t *offset,
|
||||
/* There's not enough space for the write, or the read request is
|
||||
* out-of-range. Don't read/write anything to prevent leaking out of
|
||||
* the size specified in options. */
|
||||
return is_write ? -ENOSPC : -EINVAL;;
|
||||
return is_write ? -ENOSPC : -EINVAL;
|
||||
}
|
||||
|
||||
if (*offset > INT64_MAX - s->offset) {
|
||||
|
@ -333,6 +333,12 @@ static int vmdk_is_cid_valid(BlockDriverState *bs)
|
||||
if (!s->cid_checked && bs->backing) {
|
||||
BlockDriverState *p_bs = bs->backing->bs;
|
||||
|
||||
if (strcmp(p_bs->drv->format_name, "vmdk")) {
|
||||
/* Backing file is not in vmdk format, so it does not have
|
||||
* a CID, which makes the overlay's parent CID invalid */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vmdk_read_cid(p_bs, 0, &cur_pcid) != 0) {
|
||||
/* read failure: report as not valid */
|
||||
return 0;
|
||||
|
@ -2696,18 +2696,21 @@
|
||||
# @template: Specifies a template mode which can be adjusted using the other
|
||||
# flags, defaults to 'cached'
|
||||
#
|
||||
# @bitmap-directory: since 3.0
|
||||
#
|
||||
# Since: 2.9
|
||||
##
|
||||
{ 'struct': 'Qcow2OverlapCheckFlags',
|
||||
'data': { '*template': 'Qcow2OverlapCheckMode',
|
||||
'*main-header': 'bool',
|
||||
'*active-l1': 'bool',
|
||||
'*active-l2': 'bool',
|
||||
'*refcount-table': 'bool',
|
||||
'*refcount-block': 'bool',
|
||||
'*snapshot-table': 'bool',
|
||||
'*inactive-l1': 'bool',
|
||||
'*inactive-l2': 'bool' } }
|
||||
'data': { '*template': 'Qcow2OverlapCheckMode',
|
||||
'*main-header': 'bool',
|
||||
'*active-l1': 'bool',
|
||||
'*active-l2': 'bool',
|
||||
'*refcount-table': 'bool',
|
||||
'*refcount-block': 'bool',
|
||||
'*snapshot-table': 'bool',
|
||||
'*inactive-l1': 'bool',
|
||||
'*inactive-l2': 'bool',
|
||||
'*bitmap-directory': 'bool' } }
|
||||
|
||||
##
|
||||
# @Qcow2OverlapChecks:
|
||||
|
132
tests/qemu-iotests/225
Executable file
132
tests/qemu-iotests/225
Executable file
@ -0,0 +1,132 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Test vmdk backing file correlation
|
||||
#
|
||||
# Copyright (C) 2018 Red Hat, Inc.
|
||||
#
|
||||
# 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 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# 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/>.
|
||||
#
|
||||
|
||||
# creator
|
||||
owner=mreitz@redhat.com
|
||||
|
||||
seq=$(basename $0)
|
||||
echo "QA output created by $seq"
|
||||
|
||||
here=$PWD
|
||||
status=1 # failure is the default!
|
||||
|
||||
_cleanup()
|
||||
{
|
||||
_cleanup_test_img
|
||||
rm -f "$TEST_IMG.not_base"
|
||||
}
|
||||
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
# get standard environment, filters and checks
|
||||
. ./common.rc
|
||||
. ./common.filter
|
||||
. ./common.qemu
|
||||
|
||||
# This tests vmdk-specific low-level functionality
|
||||
_supported_fmt vmdk
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
_unsupported_imgopts "subformat=monolithicFlat" \
|
||||
"subformat=twoGbMaxExtentFlat" \
|
||||
"subformat=twoGbMaxExtentSparse"
|
||||
|
||||
TEST_IMG="$TEST_IMG.base" _make_test_img 1M
|
||||
TEST_IMG="$TEST_IMG.not_base" _make_test_img 1M
|
||||
_make_test_img -b "$TEST_IMG.base"
|
||||
|
||||
make_opts()
|
||||
{
|
||||
node_name=$1
|
||||
filename=$2
|
||||
backing=$3
|
||||
|
||||
if [ -z "$backing" ]; then
|
||||
backing="null"
|
||||
else
|
||||
backing="'$backing'"
|
||||
fi
|
||||
|
||||
echo "{ 'node-name': '$node_name',
|
||||
'driver': 'vmdk',
|
||||
'file': {
|
||||
'driver': 'file',
|
||||
'filename': '$filename'
|
||||
},
|
||||
'backing': $backing }"
|
||||
}
|
||||
|
||||
overlay_opts=$(make_opts overlay "$TEST_IMG" backing)
|
||||
base_opts=$(make_opts backing "$TEST_IMG.base")
|
||||
not_base_opts=$(make_opts backing "$TEST_IMG.not_base")
|
||||
|
||||
not_vmdk_opts="{ 'node-name': 'backing', 'driver': 'null-co' }"
|
||||
|
||||
echo
|
||||
echo '=== Testing fitting VMDK backing image ==='
|
||||
echo
|
||||
|
||||
qemu_comm_method=monitor \
|
||||
_launch_qemu -blockdev "$base_opts" -blockdev "$overlay_opts"
|
||||
|
||||
# Should not return an error
|
||||
_send_qemu_cmd $QEMU_HANDLE 'qemu-io overlay "read 0 512"' 'ops'
|
||||
|
||||
_cleanup_qemu
|
||||
|
||||
|
||||
echo
|
||||
echo '=== Testing unrelated VMDK backing image ==='
|
||||
echo
|
||||
|
||||
qemu_comm_method=monitor \
|
||||
_launch_qemu -blockdev "$not_base_opts" -blockdev "$overlay_opts"
|
||||
|
||||
# Should fail (gracefully)
|
||||
_send_qemu_cmd $QEMU_HANDLE 'qemu-io overlay "read 0 512"' 'failed'
|
||||
|
||||
_cleanup_qemu
|
||||
|
||||
|
||||
echo
|
||||
echo '=== Testing non-VMDK backing image ==='
|
||||
echo
|
||||
|
||||
# FIXME: This is the reason why we have to use two -blockdev
|
||||
# invocations. You can only fully override the backing file options
|
||||
# if you either specify a node reference (as done here) or the new
|
||||
# options contain file.filename (which in this case they do not).
|
||||
# In other cases, file.filename will be set to whatever the image
|
||||
# header of the overlay contains (which we do not want). I consider
|
||||
# this a FIXME because with -blockdev, you cannot specify "partial"
|
||||
# options, so setting file.filename but leaving the rest as specified
|
||||
# by the user does not make sense.
|
||||
qemu_comm_method=monitor \
|
||||
_launch_qemu -blockdev "$not_vmdk_opts" -blockdev "$overlay_opts"
|
||||
|
||||
# Should fail (gracefully)
|
||||
_send_qemu_cmd $QEMU_HANDLE 'qemu-io overlay "read 0 512"' 'failed'
|
||||
|
||||
_cleanup_qemu
|
||||
|
||||
|
||||
# success, all done
|
||||
echo "*** done"
|
||||
rm -f $seq.full
|
||||
status=0
|
24
tests/qemu-iotests/225.out
Normal file
24
tests/qemu-iotests/225.out
Normal file
@ -0,0 +1,24 @@
|
||||
QA output created by 225
|
||||
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=1048576
|
||||
Formatting 'TEST_DIR/t.IMGFMT.not_base', fmt=IMGFMT size=1048576
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT.base
|
||||
|
||||
=== Testing fitting VMDK backing image ===
|
||||
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
(qemu) qemu-io overlay "read 0 512"
|
||||
read 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
||||
=== Testing unrelated VMDK backing image ===
|
||||
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
(qemu) qemu-io overlay "read 0 512"
|
||||
read failed: Invalid argument
|
||||
|
||||
=== Testing non-VMDK backing image ===
|
||||
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
(qemu) qemu-io overlay "read 0 512"
|
||||
read failed: Invalid argument
|
||||
*** done
|
@ -222,3 +222,4 @@
|
||||
221 rw auto quick
|
||||
222 rw auto quick
|
||||
223 rw auto quick
|
||||
225 rw auto quick
|
||||
|
Loading…
Reference in New Issue
Block a user