summaryrefslogtreecommitdiff
path: root/block
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2018-01-24 22:55:57 +0000
committerPeter Maydell <peter.maydell@linaro.org>2018-01-24 22:55:57 +0000
commitf78b6f9b1161fb67f3ac54e73f7f37464cbff76f (patch)
tree732365f004c66eb981baff332bab69d2cde45bb8 /block
parent834a336eb911db8a8ca00e760ee6a85faca19414 (diff)
parent8c0c5e636e6b11eaf0556be31fceb68e0baff310 (diff)
downloadqemu-f78b6f9b1161fb67f3ac54e73f7f37464cbff76f.tar.gz
Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging
Block layer patches # gpg: Signature made Tue 23 Jan 2018 12:38: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: (29 commits) iotests: Disable some tests for compat=0.10 iotests: Split 177 into two parts for compat=0.10 iotests: Make 059 pass on machines with little RAM iotests: Filter compat-dependent info in 198 iotests: Make 191 work with qcow2 options iotests: Make 184 image-less iotests: Make 089 compatible with compat=0.10 iotests: Fix 067 for compat=0.10 iotests: Fix 059's reference output iotests: Fix 051 for compat=0.10 iotests: Fix 020 for vmdk iotests: Skip 103 for refcount_bits=1 iotests: Forbid 020 for non-file protocols iotests: Drop format-specific in _filter_img_info iotests: Fix _img_info for backslashes block/vmdk: Add blkdebug events block/qcow: Add blkdebug events qcow2: No persistent dirty bitmaps for compat=0.10 block/vmdk: Fix , instead of ; at end of line qemu-iotests: Fix locking issue in 102 ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'block')
-rw-r--r--block/qcow.c16
-rw-r--r--block/qcow2-bitmap.c10
-rw-r--r--block/qcow2-refcount.c70
-rw-r--r--block/qcow2.c14
-rw-r--r--block/vmdk.c18
5 files changed, 112 insertions, 16 deletions
diff --git a/block/qcow.c b/block/qcow.c
index 9569deeaf0..d552a6eba8 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -379,6 +379,7 @@ static int get_cluster_offset(BlockDriverState *bs,
/* update the L1 entry */
s->l1_table[l1_index] = l2_offset;
tmp = cpu_to_be64(l2_offset);
+ BLKDBG_EVENT(bs->file, BLKDBG_L1_UPDATE);
ret = bdrv_pwrite_sync(bs->file,
s->l1_table_offset + l1_index * sizeof(tmp),
&tmp, sizeof(tmp));
@@ -409,6 +410,7 @@ static int get_cluster_offset(BlockDriverState *bs,
}
}
l2_table = s->l2_cache + (min_index << s->l2_bits);
+ BLKDBG_EVENT(bs->file, BLKDBG_L2_LOAD);
if (new_l2_table) {
memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
ret = bdrv_pwrite_sync(bs->file, l2_offset, l2_table,
@@ -432,6 +434,7 @@ static int get_cluster_offset(BlockDriverState *bs,
((cluster_offset & QCOW_OFLAG_COMPRESSED) && allocate == 1)) {
if (!allocate)
return 0;
+ BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC);
/* allocate a new cluster */
if ((cluster_offset & QCOW_OFLAG_COMPRESSED) &&
(n_end - n_start) < s->cluster_sectors) {
@@ -447,6 +450,7 @@ static int get_cluster_offset(BlockDriverState *bs,
}
cluster_offset = QEMU_ALIGN_UP(cluster_offset, s->cluster_size);
/* write the cluster content */
+ BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
ret = bdrv_pwrite(bs->file, cluster_offset, s->cluster_cache,
s->cluster_size);
if (ret < 0) {
@@ -486,6 +490,7 @@ static int get_cluster_offset(BlockDriverState *bs,
NULL) < 0) {
return -EIO;
}
+ BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
ret = bdrv_pwrite(bs->file,
cluster_offset + i * 512,
s->cluster_data, 512);
@@ -503,6 +508,11 @@ static int get_cluster_offset(BlockDriverState *bs,
/* update L2 table */
tmp = cpu_to_be64(cluster_offset);
l2_table[l2_index] = tmp;
+ if (allocate == 2) {
+ BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE_COMPRESSED);
+ } else {
+ BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE);
+ }
ret = bdrv_pwrite_sync(bs->file, l2_offset + l2_index * sizeof(tmp),
&tmp, sizeof(tmp));
if (ret < 0) {
@@ -579,6 +589,7 @@ static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
if (s->cluster_cache_offset != coffset) {
csize = cluster_offset >> (63 - s->cluster_bits);
csize &= (s->cluster_size - 1);
+ BLKDBG_EVENT(bs->file, BLKDBG_READ_COMPRESSED);
ret = bdrv_pread(bs->file, coffset, s->cluster_data, csize);
if (ret != csize)
return -1;
@@ -635,6 +646,8 @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
hd_iov.iov_len = n * 512;
qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
qemu_co_mutex_unlock(&s->lock);
+ /* qcow2 emits this on bs->file instead of bs->backing */
+ BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
ret = bdrv_co_readv(bs->backing, sector_num, n, &hd_qiov);
qemu_co_mutex_lock(&s->lock);
if (ret < 0) {
@@ -661,6 +674,7 @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
hd_iov.iov_len = n * 512;
qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
qemu_co_mutex_unlock(&s->lock);
+ BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
ret = bdrv_co_readv(bs->file,
(cluster_offset >> 9) + index_in_cluster,
n, &hd_qiov);
@@ -754,6 +768,7 @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
hd_iov.iov_len = n * 512;
qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
qemu_co_mutex_unlock(&s->lock);
+ BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
ret = bdrv_co_writev(bs->file,
(cluster_offset >> 9) + index_in_cluster,
n, &hd_qiov);
@@ -1048,6 +1063,7 @@ qcow_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
.iov_len = out_len,
};
qemu_iovec_init_external(&hd_qiov, &iov, 1);
+ BLKDBG_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED);
ret = bdrv_co_pwritev(bs->file, cluster_offset, out_len, &hd_qiov, 0);
if (ret < 0) {
goto fail;
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
index f45e46cfbd..efa10c6663 100644
--- a/block/qcow2-bitmap.c
+++ b/block/qcow2-bitmap.c
@@ -1449,6 +1449,16 @@ bool qcow2_can_store_new_dirty_bitmap(BlockDriverState *bs,
bool found;
Qcow2BitmapList *bm_list;
+ if (s->qcow_version < 3) {
+ /* Without autoclear_features, we would always have to assume
+ * that a program without persistent dirty bitmap support has
+ * accessed this qcow2 file when opening it, and would thus
+ * have to drop all dirty bitmaps (defeating their purpose).
+ */
+ error_setg(errp, "Cannot store dirty bitmaps in qcow2 v2 files");
+ goto fail;
+ }
+
if (check_constraints_on_bitmap(bs, name, granularity, errp) != 0) {
goto fail;
}
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 3de1ab51ba..92701ab7af 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -1508,7 +1508,7 @@ enum {
static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
void **refcount_table,
int64_t *refcount_table_size, int64_t l2_offset,
- int flags)
+ int flags, BdrvCheckMode fix)
{
BDRVQcow2State *s = bs->opaque;
uint64_t *l2_table, l2_entry;
@@ -1579,6 +1579,57 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
next_contiguous_offset = offset + s->cluster_size;
}
+ /* Correct offsets are cluster aligned */
+ if (offset_into_cluster(s, offset)) {
+ if (qcow2_get_cluster_type(l2_entry) ==
+ QCOW2_CLUSTER_ZERO_ALLOC)
+ {
+ fprintf(stderr, "%s offset=%" PRIx64 ": Preallocated zero "
+ "cluster is not properly aligned; L2 entry "
+ "corrupted.\n",
+ fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR",
+ offset);
+ if (fix & BDRV_FIX_ERRORS) {
+ uint64_t l2e_offset =
+ l2_offset + (uint64_t)i * sizeof(uint64_t);
+
+ l2_entry = QCOW_OFLAG_ZERO;
+ l2_table[i] = cpu_to_be64(l2_entry);
+ ret = qcow2_pre_write_overlap_check(bs,
+ QCOW2_OL_ACTIVE_L2 | QCOW2_OL_INACTIVE_L2,
+ l2e_offset, sizeof(uint64_t));
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: Overlap check failed\n");
+ res->check_errors++;
+ /* Something is seriously wrong, so abort checking
+ * this L2 table */
+ goto fail;
+ }
+
+ ret = bdrv_pwrite_sync(bs->file, l2e_offset,
+ &l2_table[i], sizeof(uint64_t));
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: Failed to overwrite L2 "
+ "table entry: %s\n", strerror(-ret));
+ res->check_errors++;
+ /* Do not abort, continue checking the rest of this
+ * L2 table's entries */
+ } else {
+ res->corruptions_fixed++;
+ /* Skip marking the cluster as used
+ * (it is unused now) */
+ continue;
+ }
+ } else {
+ res->corruptions++;
+ }
+ } else {
+ fprintf(stderr, "ERROR offset=%" PRIx64 ": Data cluster is "
+ "not properly aligned; L2 entry corrupted.\n", offset);
+ res->corruptions++;
+ }
+ }
+
/* Mark cluster as used */
ret = qcow2_inc_refcounts_imrt(bs, res,
refcount_table, refcount_table_size,
@@ -1586,13 +1637,6 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
if (ret < 0) {
goto fail;
}
-
- /* Correct offsets are cluster aligned */
- if (offset_into_cluster(s, offset)) {
- fprintf(stderr, "ERROR offset=%" PRIx64 ": Cluster is not "
- "properly aligned; L2 entry corrupted.\n", offset);
- res->corruptions++;
- }
break;
}
@@ -1626,7 +1670,7 @@ static int check_refcounts_l1(BlockDriverState *bs,
void **refcount_table,
int64_t *refcount_table_size,
int64_t l1_table_offset, int l1_size,
- int flags)
+ int flags, BdrvCheckMode fix)
{
BDRVQcow2State *s = bs->opaque;
uint64_t *l1_table = NULL, l2_offset, l1_size2;
@@ -1681,7 +1725,8 @@ static int check_refcounts_l1(BlockDriverState *bs,
/* Process and check L2 entries */
ret = check_refcounts_l2(bs, res, refcount_table,
- refcount_table_size, l2_offset, flags);
+ refcount_table_size, l2_offset, flags,
+ fix);
if (ret < 0) {
goto fail;
}
@@ -1957,7 +2002,8 @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
/* current L1 table */
ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters,
- s->l1_table_offset, s->l1_size, CHECK_FRAG_INFO);
+ s->l1_table_offset, s->l1_size, CHECK_FRAG_INFO,
+ fix);
if (ret < 0) {
return ret;
}
@@ -1966,7 +2012,7 @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
for (i = 0; i < s->nb_snapshots; i++) {
sn = s->snapshots + i;
ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters,
- sn->l1_table_offset, sn->l1_size, 0);
+ sn->l1_table_offset, sn->l1_size, 0, fix);
if (ret < 0) {
return ret;
}
diff --git a/block/qcow2.c b/block/qcow2.c
index 4348b2c0c5..1f80961e1b 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -302,9 +302,17 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
}
if (!(s->autoclear_features & QCOW2_AUTOCLEAR_BITMAPS)) {
- warn_report("a program lacking bitmap support "
- "modified this file, so all bitmaps are now "
- "considered inconsistent");
+ if (s->qcow_version < 3) {
+ /* Let's be a bit more specific */
+ warn_report("This qcow2 v2 image contains bitmaps, but "
+ "they may have been modified by a program "
+ "without persistent bitmap support; so now "
+ "they must all be considered inconsistent");
+ } else {
+ warn_report("a program lacking bitmap support "
+ "modified this file, so all bitmaps are now "
+ "considered inconsistent");
+ }
error_printf("Some clusters may be leaked, "
"run 'qemu-img check -r' on the image "
"file to fix.");
diff --git a/block/vmdk.c b/block/vmdk.c
index c665bcc977..d71cec4f31 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -1075,6 +1075,8 @@ static int get_whole_cluster(BlockDriverState *bs,
/* Read backing data before skip range */
if (skip_start_bytes > 0) {
if (bs->backing) {
+ /* qcow2 emits this on bs->file instead of bs->backing */
+ BLKDBG_EVENT(extent->file, BLKDBG_COW_READ);
ret = bdrv_pread(bs->backing, offset, whole_grain,
skip_start_bytes);
if (ret < 0) {
@@ -1082,6 +1084,7 @@ static int get_whole_cluster(BlockDriverState *bs,
goto exit;
}
}
+ BLKDBG_EVENT(extent->file, BLKDBG_COW_WRITE);
ret = bdrv_pwrite(extent->file, cluster_offset, whole_grain,
skip_start_bytes);
if (ret < 0) {
@@ -1092,6 +1095,8 @@ static int get_whole_cluster(BlockDriverState *bs,
/* Read backing data after skip range */
if (skip_end_bytes < cluster_bytes) {
if (bs->backing) {
+ /* qcow2 emits this on bs->file instead of bs->backing */
+ BLKDBG_EVENT(extent->file, BLKDBG_COW_READ);
ret = bdrv_pread(bs->backing, offset + skip_end_bytes,
whole_grain + skip_end_bytes,
cluster_bytes - skip_end_bytes);
@@ -1100,6 +1105,7 @@ static int get_whole_cluster(BlockDriverState *bs,
goto exit;
}
}
+ BLKDBG_EVENT(extent->file, BLKDBG_COW_WRITE);
ret = bdrv_pwrite(extent->file, cluster_offset + skip_end_bytes,
whole_grain + skip_end_bytes,
cluster_bytes - skip_end_bytes);
@@ -1120,6 +1126,7 @@ static int vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data,
{
offset = cpu_to_le32(offset);
/* update L2 table */
+ BLKDBG_EVENT(extent->file, BLKDBG_L2_UPDATE);
if (bdrv_pwrite_sync(extent->file,
((int64_t)m_data->l2_offset * 512)
+ (m_data->l2_index * sizeof(offset)),
@@ -1218,6 +1225,7 @@ static int get_cluster_offset(BlockDriverState *bs,
}
}
l2_table = extent->l2_cache + (min_index * extent->l2_size);
+ BLKDBG_EVENT(extent->file, BLKDBG_L2_LOAD);
if (bdrv_pread(extent->file,
(int64_t)l2_offset * 512,
l2_table,
@@ -1393,12 +1401,16 @@ static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset,
.iov_len = n_bytes,
};
qemu_iovec_init_external(&local_qiov, &iov, 1);
+
+ BLKDBG_EVENT(extent->file, BLKDBG_WRITE_COMPRESSED);
} else {
qemu_iovec_init(&local_qiov, qiov->niov);
qemu_iovec_concat(&local_qiov, qiov, qiov_offset, n_bytes);
+
+ BLKDBG_EVENT(extent->file, BLKDBG_WRITE_AIO);
}
- write_offset = cluster_offset + offset_in_cluster,
+ write_offset = cluster_offset + offset_in_cluster;
ret = bdrv_co_pwritev(extent->file, write_offset, n_bytes,
&local_qiov, 0);
@@ -1437,6 +1449,7 @@ static int vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset,
if (!extent->compressed) {
+ BLKDBG_EVENT(extent->file, BLKDBG_READ_AIO);
ret = bdrv_co_preadv(extent->file,
cluster_offset + offset_in_cluster, bytes,
qiov, 0);
@@ -1450,6 +1463,7 @@ static int vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset,
buf_bytes = cluster_bytes * 2;
cluster_buf = g_malloc(buf_bytes);
uncomp_buf = g_malloc(cluster_bytes);
+ BLKDBG_EVENT(extent->file, BLKDBG_READ_COMPRESSED);
ret = bdrv_pread(extent->file,
cluster_offset,
cluster_buf, buf_bytes);
@@ -1527,6 +1541,8 @@ vmdk_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
qemu_iovec_reset(&local_qiov);
qemu_iovec_concat(&local_qiov, qiov, bytes_done, n_bytes);
+ /* qcow2 emits this on bs->file instead of bs->backing */
+ BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
ret = bdrv_co_preadv(bs->backing, offset, n_bytes,
&local_qiov, 0);
if (ret < 0) {