1
The following changes since commit fb68096da3d35e64c88cd610c1fa42766c58e92a:
1
The following changes since commit 281f327487c9c9b1599f93c589a408bbf4a651b8:
2
2
3
Revert "tests: use memfd in vhost-user-test" (2018-02-13 09:51:52 +0000)
3
Merge remote-tracking branch 'remotes/vivier/tags/m68k-for-2.12-pull-request' into staging (2017-12-22 00:11:36 +0000)
4
4
5
are available in the git repository at:
5
are available in the git repository at:
6
6
7
git://repo.or.cz/qemu/kevin.git tags/for-upstream
7
git://repo.or.cz/qemu/kevin.git tags/for-upstream
8
8
9
for you to fetch changes up to 0a4dc980e6c935e9be745ce3ee1a4c71629ecd00:
9
for you to fetch changes up to 1a63a907507fbbcfaee3f622907ec244b7eabda8:
10
10
11
Merge remote-tracking branch 'mreitz/tags/pull-block-2018-02-13' into queue-block (2018-02-13 17:01:13 +0100)
11
block: Keep nodes drained between reopen_queue/multiple (2017-12-22 15:05:32 +0100)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block layer patches
14
Block layer patches
15
15
16
----------------------------------------------------------------
16
----------------------------------------------------------------
17
Alberto Garcia (40):
17
Doug Gale (1):
18
qcow2: Use g_try_realloc() in qcow2_expand_zero_clusters()
18
nvme: Add tracing
19
qcow2: Fix documentation of get_cluster_table()
20
qcow2: Add table size field to Qcow2Cache
21
qcow2: Remove BDS parameter from qcow2_cache_get_table_addr()
22
qcow2: Remove BDS parameter from qcow2_cache_get_table_idx()
23
qcow2: Remove BDS parameter from qcow2_cache_table_release()
24
qcow2: Remove BDS parameter from qcow2_cache_entry_mark_dirty()
25
qcow2: Remove BDS parameter from qcow2_cache_put()
26
qcow2: Remove BDS parameter from qcow2_cache_destroy()
27
qcow2: Remove BDS parameter from qcow2_cache_clean_unused()
28
qcow2: Remove BDS parameter from qcow2_cache_discard()
29
qcow2: Remove BDS parameter from qcow2_cache_is_table_offset()
30
qcow2: Add offset_to_l1_index()
31
qcow2: Add l2_slice_size field to BDRVQcow2State
32
qcow2: Add offset_to_l2_slice_index()
33
qcow2: Update l2_load() to support L2 slices
34
qcow2: Prepare l2_allocate() for adding L2 slice support
35
qcow2: Update l2_allocate() to support L2 slices
36
qcow2: Refactor get_cluster_table()
37
qcow2: Update get_cluster_table() to support L2 slices
38
qcow2: Update qcow2_get_cluster_offset() to support L2 slices
39
qcow2: Update qcow2_alloc_cluster_link_l2() to support L2 slices
40
qcow2: Update handle_copied() to support L2 slices
41
qcow2: Update handle_alloc() to support L2 slices
42
qcow2: Update discard_single_l2() to support L2 slices
43
qcow2: Update zero_single_l2() to support L2 slices
44
qcow2: Prepare qcow2_update_snapshot_refcount() for adding L2 slice support
45
qcow2: Update qcow2_update_snapshot_refcount() to support L2 slices
46
qcow2: Read refcount before L2 table in expand_zero_clusters_in_l1()
47
qcow2: Prepare expand_zero_clusters_in_l1() for adding L2 slice support
48
qcow2: Update expand_zero_clusters_in_l1() to support L2 slices
49
qcow2: Update qcow2_truncate() to support L2 slices
50
qcow2: Rename l2_table in qcow2_alloc_compressed_cluster_offset()
51
qcow2: Rename l2_table in count_contiguous_clusters()
52
qcow2: Rename l2_table in count_contiguous_clusters_unallocated()
53
qcow2: Rename l2_table in count_cow_clusters()
54
qcow2: Allow configuring the L2 slice size
55
iotests: Test valid values of l2-cache-entry-size
56
iotests: Test downgrading an image using a small L2 slice size
57
iotests: Add l2-cache-entry-size to iotest 137
58
19
59
Daniel P. Berrangé (1):
20
Edgar Kaziakhmedov (1):
60
qemu-io: fix EOF Ctrl-D handling in qemu-io readline code
21
qcow2: get rid of qcow2_backing_read1 routine
61
22
62
Fam Zheng (4):
23
Fam Zheng (2):
63
iotests: Fix CID for VMDK afl image
24
block: Open backing image in force share mode for size probe
64
qemu-img.texi: Clean up parameter list
25
block: Remove unused bdrv_requests_pending
65
qemu-img: Document --force-share / -U
66
docs: Document share-rw property more thoroughly
67
26
68
Kevin Wolf (1):
27
John Snow (1):
69
Merge remote-tracking branch 'mreitz/tags/pull-block-2018-02-13' into queue-block
28
iotests: fix 197 for vpc
70
29
71
Max Reitz (8):
30
Kevin Wolf (27):
72
iotests: Use virtio-blk in 155
31
block: Formats don't need CONSISTENT_READ with NO_IO
73
gluster: Move glfs_close() to create's clean-up
32
block: Make bdrv_drain_invoke() recursive
74
gluster: Pull truncation from qemu_gluster_create
33
block: Call .drain_begin only once in bdrv_drain_all_begin()
75
gluster: Query current size in do_truncate()
34
test-bdrv-drain: Test BlockDriver callbacks for drain
76
gluster: Add preallocated truncation
35
block: bdrv_drain_recurse(): Remove unused begin parameter
77
sheepdog: Make sd_prealloc() take a BDS
36
block: Don't wait for requests in bdrv_drain*_end()
78
sheepdog: Pass old and new size to sd_prealloc()
37
block: Unify order in drain functions
79
sheepdog: Allow fully preallocated truncation
38
block: Don't acquire AioContext in hmp_qemu_io()
39
block: Document that x-blockdev-change breaks quorum children list
40
block: Assert drain_all is only called from main AioContext
41
block: Make bdrv_drain() driver callbacks non-recursive
42
test-bdrv-drain: Test callback for bdrv_drain
43
test-bdrv-drain: Test bs->quiesce_counter
44
blockjob: Pause job on draining any job BDS
45
test-bdrv-drain: Test drain vs. block jobs
46
block: Don't block_job_pause_all() in bdrv_drain_all()
47
block: Nested drain_end must still call callbacks
48
test-bdrv-drain: Test nested drain sections
49
block: Don't notify parents in drain call chain
50
block: Add bdrv_subtree_drained_begin/end()
51
test-bdrv-drain: Tests for bdrv_subtree_drain
52
test-bdrv-drain: Test behaviour in coroutine context
53
test-bdrv-drain: Recursive draining with multiple parents
54
block: Allow graph changes in subtree drained section
55
test-bdrv-drain: Test graph changes in drained section
56
commit: Simplify reopen of base
57
block: Keep nodes drained between reopen_queue/multiple
80
58
81
Paolo Bonzini (1):
59
Thomas Huth (3):
82
block: early check for blockers on drive-mirror
60
block: Remove the obsolete -drive boot=on|off parameter
61
block: Remove the deprecated -hdachs option
62
block: Mention -drive cyls/heads/secs/trans/serial/addr in deprecation chapter
83
63
84
Vladimir Sementsov-Ogievskiy (1):
64
qapi/block-core.json | 4 +
85
block: maintain persistent disabled bitmaps
65
block/qcow2.h | 3 -
66
include/block/block.h | 15 +-
67
include/block/block_int.h | 6 +-
68
block.c | 75 ++++-
69
block/commit.c | 8 +-
70
block/io.c | 164 +++++++---
71
block/qcow2.c | 51 +--
72
block/replication.c | 6 +
73
blockdev.c | 11 -
74
blockjob.c | 22 +-
75
hmp.c | 6 -
76
hw/block/nvme.c | 349 +++++++++++++++++----
77
qemu-io-cmds.c | 3 +
78
tests/test-bdrv-drain.c | 651 +++++++++++++++++++++++++++++++++++++++
79
vl.c | 86 +-----
80
hw/block/trace-events | 93 ++++++
81
qemu-doc.texi | 29 +-
82
qemu-options.hx | 19 +-
83
tests/Makefile.include | 2 +
84
tests/qemu-iotests/197 | 4 +
85
tests/qemu-iotests/common.filter | 3 +-
86
22 files changed, 1294 insertions(+), 316 deletions(-)
87
create mode 100644 tests/test-bdrv-drain.c
86
88
87
qapi/block-core.json | 12 +-
88
block/qcow2.h | 33 +-
89
include/block/dirty-bitmap.h | 1 -
90
block/dirty-bitmap.c | 18 -
91
block/gluster.c | 116 +++---
92
block/qcow2-bitmap.c | 12 +-
93
block/qcow2-cache.c | 80 ++--
94
block/qcow2-cluster.c | 519 +++++++++++++------------
95
block/qcow2-refcount.c | 206 +++++-----
96
block/qcow2.c | 63 ++-
97
block/sheepdog.c | 56 ++-
98
blockdev.c | 15 +-
99
qemu-io.c | 27 +-
100
docs/qemu-block-drivers.texi | 10 +
101
qemu-doc.texi | 7 +
102
qemu-img.texi | 74 ++--
103
tests/qemu-iotests/059.out | 2 +-
104
tests/qemu-iotests/061 | 16 +
105
tests/qemu-iotests/061.out | 61 +++
106
tests/qemu-iotests/103 | 17 +
107
tests/qemu-iotests/103.out | 3 +
108
tests/qemu-iotests/137 | 5 +
109
tests/qemu-iotests/137.out | 2 +
110
tests/qemu-iotests/155 | 14 +-
111
tests/qemu-iotests/165 | 2 +-
112
tests/qemu-iotests/176 | 2 +-
113
tests/qemu-iotests/sample_images/afl9.vmdk.bz2 | Bin 178 -> 618 bytes
114
27 files changed, 816 insertions(+), 557 deletions(-)
115
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
Commit 1f4ad7d fixed 'qemu-img info' for raw images that are currently
2
in use as a mirror target. It is not enough for image formats, though,
3
as these still unconditionally request BLK_PERM_CONSISTENT_READ.
2
4
3
glfs_close() is a classical clean-up operation, as can be seen by the
5
As this permission is geared towards whether the guest-visible data is
4
fact that it is executed even if the truncation before it failed.
6
consistent, and has no impact on whether the metadata is sane, and
5
Also, moving it to clean-up makes it more clear that if it fails, we do
7
'qemu-img info' does not read guest-visible data (except for the raw
6
not want it to overwrite the current ret value if that signifies an
8
format), it makes sense to not require BLK_PERM_CONSISTENT_READ if there
7
error already.
9
is not going to be any guest I/O performed, regardless of image format.
8
10
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
Reviewed-by: Eric Blake <eblake@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
12
---
13
block/gluster.c | 10 ++++++----
13
block.c | 6 +++++-
14
1 file changed, 6 insertions(+), 4 deletions(-)
14
1 file changed, 5 insertions(+), 1 deletion(-)
15
15
16
diff --git a/block/gluster.c b/block/gluster.c
16
diff --git a/block.c b/block.c
17
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
18
--- a/block/gluster.c
18
--- a/block.c
19
+++ b/block/gluster.c
19
+++ b/block.c
20
@@ -XXX,XX +XXX,XX @@ static int qemu_gluster_create(const char *filename,
20
@@ -XXX,XX +XXX,XX @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
21
{
21
assert(role == &child_backing || role == &child_file);
22
BlockdevOptionsGluster *gconf;
22
23
struct glfs *glfs;
23
if (!backing) {
24
- struct glfs_fd *fd;
24
+ int flags = bdrv_reopen_get_flags(reopen_queue, bs);
25
+ struct glfs_fd *fd = NULL;
25
+
26
int ret = 0;
26
/* Apart from the modifications below, the same permissions are
27
PreallocMode prealloc;
27
* forwarded and left alone as for filters */
28
int64_t total_size = 0;
28
bdrv_filter_default_perms(bs, c, role, reopen_queue, perm, shared,
29
@@ -XXX,XX +XXX,XX @@ static int qemu_gluster_create(const char *filename,
29
@@ -XXX,XX +XXX,XX @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
30
break;
30
31
}
31
/* bs->file always needs to be consistent because of the metadata. We
32
32
* can never allow other users to resize or write to it. */
33
- if (glfs_close(fd) != 0) {
33
- perm |= BLK_PERM_CONSISTENT_READ;
34
- ret = -errno;
34
+ if (!(flags & BDRV_O_NO_IO)) {
35
- }
35
+ perm |= BLK_PERM_CONSISTENT_READ;
36
out:
37
+ if (fd) {
38
+ if (glfs_close(fd) != 0 && ret == 0) {
39
+ ret = -errno;
40
+ }
36
+ }
41
+ }
37
shared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE);
42
qapi_free_BlockdevOptionsGluster(gconf);
38
} else {
43
glfs_clear_preopened(glfs);
39
/* We want consistent read from backing files if the parent needs it.
44
return ret;
45
--
40
--
46
2.13.6
41
2.13.6
47
42
48
43
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: John Snow <jsnow@redhat.com>
2
2
3
qcow2_get_cluster_offset() checks how many contiguous bytes are
3
VPC has some difficulty creating geometries of particular size.
4
available at a given offset. The returned number of bytes is limited
4
However, we can indeed force it to use a literal one, so let's
5
by the amount that can be addressed without having to load more than
5
do that for the sake of test 197, which is testing some specific
6
one L2 table.
6
offsets.
7
7
8
Since we'll be loading L2 slices instead of full tables this patch
8
Signed-off-by: John Snow <jsnow@redhat.com>
9
changes the limit accordingly using the size of the L2 slice for the
9
Reviewed-by: Eric Blake <eblake@redhat.com>
10
calculations instead of the full table size.
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Reviewed-by: Lukáš Doktor <ldoktor@redhat.com>
13
---
14
tests/qemu-iotests/197 | 4 ++++
15
tests/qemu-iotests/common.filter | 3 ++-
16
2 files changed, 6 insertions(+), 1 deletion(-)
11
17
12
One consequence of this is that with small L2 slices operations such
18
diff --git a/tests/qemu-iotests/197 b/tests/qemu-iotests/197
13
as 'qemu-img map' will need to iterate in more steps because each
19
index XXXXXXX..XXXXXXX 100755
14
qcow2_get_cluster_offset() call will potentially return a smaller
20
--- a/tests/qemu-iotests/197
15
number. However the code is already prepared for that so this doesn't
21
+++ b/tests/qemu-iotests/197
16
break semantics.
22
@@ -XXX,XX +XXX,XX @@ echo '=== Copy-on-read ==='
17
23
echo
18
The l2_table variable is also renamed to l2_slice to reflect this, and
24
19
offset_to_l2_index() is replaced with offset_to_l2_slice_index().
25
# Prep the images
20
26
+# VPC rounds image sizes to a specific geometry, force a specific size.
21
Signed-off-by: Alberto Garcia <berto@igalia.com>
27
+if [ "$IMGFMT" = "vpc" ]; then
22
Reviewed-by: Eric Blake <eblake@redhat.com>
28
+ IMGOPTS=$(_optstr_add "$IMGOPTS" "force_size")
23
Reviewed-by: Max Reitz <mreitz@redhat.com>
29
+fi
24
Message-id: 6b602260acb33da56ed6af9611731cb7acd110eb.1517840877.git.berto@igalia.com
30
_make_test_img 4G
25
Signed-off-by: Max Reitz <mreitz@redhat.com>
31
$QEMU_IO -c "write -P 55 3G 1k" "$TEST_IMG" | _filter_qemu_io
26
---
32
IMGPROTO=file IMGFMT=qcow2 IMGOPTS= TEST_IMG_FILE="$TEST_WRAP" \
27
block/qcow2-cluster.c | 30 +++++++++++++++---------------
33
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
28
1 file changed, 15 insertions(+), 15 deletions(-)
29
30
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
31
index XXXXXXX..XXXXXXX 100644
34
index XXXXXXX..XXXXXXX 100644
32
--- a/block/qcow2-cluster.c
35
--- a/tests/qemu-iotests/common.filter
33
+++ b/block/qcow2-cluster.c
36
+++ b/tests/qemu-iotests/common.filter
34
@@ -XXX,XX +XXX,XX @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
37
@@ -XXX,XX +XXX,XX @@ _filter_img_create()
35
{
38
-e "s# log_size=[0-9]\\+##g" \
36
BDRVQcow2State *s = bs->opaque;
39
-e "s# refcount_bits=[0-9]\\+##g" \
37
unsigned int l2_index;
40
-e "s# key-secret=[a-zA-Z0-9]\\+##g" \
38
- uint64_t l1_index, l2_offset, *l2_table;
41
- -e "s# iter-time=[0-9]\\+##g"
39
- int l1_bits, c;
42
+ -e "s# iter-time=[0-9]\\+##g" \
40
+ uint64_t l1_index, l2_offset, *l2_slice;
43
+ -e "s# force_size=\\(on\\|off\\)##g"
41
+ int c;
42
unsigned int offset_in_cluster;
43
uint64_t bytes_available, bytes_needed, nb_clusters;
44
QCow2ClusterType type;
45
@@ -XXX,XX +XXX,XX @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
46
offset_in_cluster = offset_into_cluster(s, offset);
47
bytes_needed = (uint64_t) *bytes + offset_in_cluster;
48
49
- l1_bits = s->l2_bits + s->cluster_bits;
50
-
51
/* compute how many bytes there are between the start of the cluster
52
- * containing offset and the end of the l1 entry */
53
- bytes_available = (1ULL << l1_bits) - (offset & ((1ULL << l1_bits) - 1))
54
- + offset_in_cluster;
55
+ * containing offset and the end of the l2 slice that contains
56
+ * the entry pointing to it */
57
+ bytes_available =
58
+ ((uint64_t) (s->l2_slice_size - offset_to_l2_slice_index(s, offset)))
59
+ << s->cluster_bits;
60
61
if (bytes_needed > bytes_available) {
62
bytes_needed = bytes_available;
63
@@ -XXX,XX +XXX,XX @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
64
return -EIO;
65
}
66
67
- /* load the l2 table in memory */
68
+ /* load the l2 slice in memory */
69
70
- ret = l2_load(bs, offset, l2_offset, &l2_table);
71
+ ret = l2_load(bs, offset, l2_offset, &l2_slice);
72
if (ret < 0) {
73
return ret;
74
}
75
76
/* find the cluster offset for the given disk offset */
77
78
- l2_index = offset_to_l2_index(s, offset);
79
- *cluster_offset = be64_to_cpu(l2_table[l2_index]);
80
+ l2_index = offset_to_l2_slice_index(s, offset);
81
+ *cluster_offset = be64_to_cpu(l2_slice[l2_index]);
82
83
nb_clusters = size_to_clusters(s, bytes_needed);
84
/* bytes_needed <= *bytes + offset_in_cluster, both of which are unsigned
85
@@ -XXX,XX +XXX,XX @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
86
case QCOW2_CLUSTER_UNALLOCATED:
87
/* how many empty clusters ? */
88
c = count_contiguous_clusters_unallocated(nb_clusters,
89
- &l2_table[l2_index], type);
90
+ &l2_slice[l2_index], type);
91
*cluster_offset = 0;
92
break;
93
case QCOW2_CLUSTER_ZERO_ALLOC:
94
case QCOW2_CLUSTER_NORMAL:
95
/* how many allocated clusters ? */
96
c = count_contiguous_clusters(nb_clusters, s->cluster_size,
97
- &l2_table[l2_index], QCOW_OFLAG_ZERO);
98
+ &l2_slice[l2_index], QCOW_OFLAG_ZERO);
99
*cluster_offset &= L2E_OFFSET_MASK;
100
if (offset_into_cluster(s, *cluster_offset)) {
101
qcow2_signal_corruption(bs, true, -1, -1,
102
@@ -XXX,XX +XXX,XX @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
103
abort();
104
}
105
106
- qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
107
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
108
109
bytes_available = (int64_t)c * s->cluster_size;
110
111
@@ -XXX,XX +XXX,XX @@ out:
112
return type;
113
114
fail:
115
- qcow2_cache_put(s->l2_table_cache, (void **)&l2_table);
116
+ qcow2_cache_put(s->l2_table_cache, (void **)&l2_slice);
117
return ret;
118
}
44
}
119
45
46
_filter_img_info()
120
--
47
--
121
2.13.6
48
2.13.6
122
49
123
50
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
This change separates bdrv_drain_invoke(), which calls the BlockDriver
2
drain callbacks, from bdrv_drain_recurse(). Instead, the function
3
performs its own recursion now.
2
4
3
Now that the code is ready to handle L2 slices we can finally add an
5
One reason for this is that bdrv_drain_recurse() can be called multiple
4
option to allow configuring their size.
6
times by bdrv_drain_all_begin(), but the callbacks may only be called
7
once. The separation is necessary to fix this bug.
5
8
6
An L2 slice is the portion of an L2 table that is read by the qcow2
9
The other reason is that we intend to go to a model where we call all
7
cache. Until now the cache was always reading full L2 tables, and
10
driver callbacks first, and only then start polling. This is not fully
8
since the L2 table size is equal to the cluster size this was not very
11
achieved yet with this patch, as bdrv_drain_invoke() contains a
9
efficient with large clusters. Here's a more detailed explanation of
12
BDRV_POLL_WHILE() loop for the block driver callbacks, which can still
10
why it makes sense to have smaller cache entries in order to load L2
13
call callbacks for any unrelated event. It's a step in this direction
11
data:
14
anyway.
12
15
13
https://lists.gnu.org/archive/html/qemu-block/2017-09/msg00635.html
16
Cc: qemu-stable@nongnu.org
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
19
---
20
block/io.c | 14 +++++++++++---
21
1 file changed, 11 insertions(+), 3 deletions(-)
14
22
15
This patch introduces a new command-line option to the qcow2 driver
23
diff --git a/block/io.c b/block/io.c
16
named l2-cache-entry-size (cf. l2-cache-size). The cache entry size
17
has the same restrictions as the cluster size: it must be a power of
18
two and it has the same range of allowed values, with the additional
19
requirement that it must not be larger than the cluster size.
20
21
The L2 cache entry size (L2 slice size) remains equal to the cluster
22
size for now by default, so this feature must be explicitly enabled.
23
Although my tests show that 4KB slices consistently improve
24
performance and give the best results, let's wait and make more tests
25
with different cluster sizes before deciding on an optimal default.
26
27
Now that the cache entry size is not necessarily equal to the cluster
28
size we need to reflect that in the MIN_L2_CACHE_SIZE documentation.
29
That minimum value is a requirement of the COW algorithm: we need to
30
read two L2 slices (and not two L2 tables) in order to do COW, see
31
l2_allocate() for the actual code.
32
33
Signed-off-by: Alberto Garcia <berto@igalia.com>
34
Reviewed-by: Eric Blake <eblake@redhat.com>
35
Reviewed-by: Max Reitz <mreitz@redhat.com>
36
Message-id: c73e5611ff4a9ec5d20de68a6c289553a13d2354.1517840877.git.berto@igalia.com
37
Signed-off-by: Max Reitz <mreitz@redhat.com>
38
---
39
qapi/block-core.json | 6 ++++++
40
block/qcow2.h | 6 ++++--
41
block/qcow2-cache.c | 10 ++++++++--
42
block/qcow2.c | 34 +++++++++++++++++++++++++++-------
43
4 files changed, 45 insertions(+), 11 deletions(-)
44
45
diff --git a/qapi/block-core.json b/qapi/block-core.json
46
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
47
--- a/qapi/block-core.json
25
--- a/block/io.c
48
+++ b/qapi/block-core.json
26
+++ b/block/io.c
49
@@ -XXX,XX +XXX,XX @@
27
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_drain_invoke_entry(void *opaque)
50
# @l2-cache-size: the maximum size of the L2 table cache in
28
bdrv_wakeup(bs);
51
# bytes (since 2.2)
52
#
53
+# @l2-cache-entry-size: the size of each entry in the L2 cache in
54
+# bytes. It must be a power of two between 512
55
+# and the cluster size. The default value is
56
+# the cluster size (since 2.12)
57
+#
58
# @refcount-cache-size: the maximum size of the refcount block cache
59
# in bytes (since 2.2)
60
#
61
@@ -XXX,XX +XXX,XX @@
62
'*overlap-check': 'Qcow2OverlapChecks',
63
'*cache-size': 'int',
64
'*l2-cache-size': 'int',
65
+ '*l2-cache-entry-size': 'int',
66
'*refcount-cache-size': 'int',
67
'*cache-clean-interval': 'int',
68
'*encrypt': 'BlockdevQcow2Encryption' } }
69
diff --git a/block/qcow2.h b/block/qcow2.h
70
index XXXXXXX..XXXXXXX 100644
71
--- a/block/qcow2.h
72
+++ b/block/qcow2.h
73
@@ -XXX,XX +XXX,XX @@
74
#define MAX_CLUSTER_BITS 21
75
76
/* Must be at least 2 to cover COW */
77
-#define MIN_L2_CACHE_SIZE 2 /* clusters */
78
+#define MIN_L2_CACHE_SIZE 2 /* cache entries */
79
80
/* Must be at least 4 to cover all cases of refcount table growth */
81
#define MIN_REFCOUNT_CACHE_SIZE 4 /* clusters */
82
@@ -XXX,XX +XXX,XX @@
83
#define QCOW2_OPT_OVERLAP_INACTIVE_L2 "overlap-check.inactive-l2"
84
#define QCOW2_OPT_CACHE_SIZE "cache-size"
85
#define QCOW2_OPT_L2_CACHE_SIZE "l2-cache-size"
86
+#define QCOW2_OPT_L2_CACHE_ENTRY_SIZE "l2-cache-entry-size"
87
#define QCOW2_OPT_REFCOUNT_CACHE_SIZE "refcount-cache-size"
88
#define QCOW2_OPT_CACHE_CLEAN_INTERVAL "cache-clean-interval"
89
90
@@ -XXX,XX +XXX,XX @@ void qcow2_free_snapshots(BlockDriverState *bs);
91
int qcow2_read_snapshots(BlockDriverState *bs);
92
93
/* qcow2-cache.c functions */
94
-Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables);
95
+Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables,
96
+ unsigned table_size);
97
int qcow2_cache_destroy(Qcow2Cache *c);
98
99
void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table);
100
diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c
101
index XXXXXXX..XXXXXXX 100644
102
--- a/block/qcow2-cache.c
103
+++ b/block/qcow2-cache.c
104
@@ -XXX,XX +XXX,XX @@ void qcow2_cache_clean_unused(Qcow2Cache *c)
105
c->cache_clean_lru_counter = c->lru_counter;
106
}
29
}
107
30
108
-Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables)
31
+/* Recursively call BlockDriver.bdrv_co_drain_begin/end callbacks */
109
+Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables,
32
static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
110
+ unsigned table_size)
111
{
33
{
112
BDRVQcow2State *s = bs->opaque;
34
+ BdrvChild *child, *tmp;
113
Qcow2Cache *c;
35
BdrvCoDrainData data = { .bs = bs, .done = false, .begin = begin};
114
36
115
+ assert(num_tables > 0);
37
if (!bs->drv || (begin && !bs->drv->bdrv_co_drain_begin) ||
116
+ assert(is_power_of_2(table_size));
38
@@ -XXX,XX +XXX,XX @@ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
117
+ assert(table_size >= (1 << MIN_CLUSTER_BITS));
39
data.co = qemu_coroutine_create(bdrv_drain_invoke_entry, &data);
118
+ assert(table_size <= s->cluster_size);
40
bdrv_coroutine_enter(bs, data.co);
41
BDRV_POLL_WHILE(bs, !data.done);
119
+
42
+
120
c = g_new0(Qcow2Cache, 1);
43
+ QLIST_FOREACH_SAFE(child, &bs->children, next, tmp) {
121
c->size = num_tables;
44
+ bdrv_drain_invoke(child->bs, begin);
122
- c->table_size = s->cluster_size;
123
+ c->table_size = table_size;
124
c->entries = g_try_new0(Qcow2CachedTable, num_tables);
125
c->table_array = qemu_try_blockalign(bs->file->bs,
126
(size_t) num_tables * c->table_size);
127
diff --git a/block/qcow2.c b/block/qcow2.c
128
index XXXXXXX..XXXXXXX 100644
129
--- a/block/qcow2.c
130
+++ b/block/qcow2.c
131
@@ -XXX,XX +XXX,XX @@ static QemuOptsList qcow2_runtime_opts = {
132
.help = "Maximum L2 table cache size",
133
},
134
{
135
+ .name = QCOW2_OPT_L2_CACHE_ENTRY_SIZE,
136
+ .type = QEMU_OPT_SIZE,
137
+ .help = "Size of each entry in the L2 cache",
138
+ },
139
+ {
140
.name = QCOW2_OPT_REFCOUNT_CACHE_SIZE,
141
.type = QEMU_OPT_SIZE,
142
.help = "Maximum refcount block cache size",
143
@@ -XXX,XX +XXX,XX @@ static void qcow2_attach_aio_context(BlockDriverState *bs,
144
145
static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
146
uint64_t *l2_cache_size,
147
+ uint64_t *l2_cache_entry_size,
148
uint64_t *refcount_cache_size, Error **errp)
149
{
150
BDRVQcow2State *s = bs->opaque;
151
@@ -XXX,XX +XXX,XX @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
152
*refcount_cache_size = qemu_opt_get_size(opts,
153
QCOW2_OPT_REFCOUNT_CACHE_SIZE, 0);
154
155
+ *l2_cache_entry_size = qemu_opt_get_size(
156
+ opts, QCOW2_OPT_L2_CACHE_ENTRY_SIZE, s->cluster_size);
157
+
158
if (combined_cache_size_set) {
159
if (l2_cache_size_set && refcount_cache_size_set) {
160
error_setg(errp, QCOW2_OPT_CACHE_SIZE ", " QCOW2_OPT_L2_CACHE_SIZE
161
@@ -XXX,XX +XXX,XX @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
162
/ DEFAULT_L2_REFCOUNT_SIZE_RATIO;
163
}
164
}
165
+
166
+ if (*l2_cache_entry_size < (1 << MIN_CLUSTER_BITS) ||
167
+ *l2_cache_entry_size > s->cluster_size ||
168
+ !is_power_of_2(*l2_cache_entry_size)) {
169
+ error_setg(errp, "L2 cache entry size must be a power of two "
170
+ "between %d and the cluster size (%d)",
171
+ 1 << MIN_CLUSTER_BITS, s->cluster_size);
172
+ return;
173
+ }
45
+ }
174
}
46
}
175
47
176
typedef struct Qcow2ReopenState {
48
static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin)
177
@@ -XXX,XX +XXX,XX @@ static int qcow2_update_options_prepare(BlockDriverState *bs,
49
@@ -XXX,XX +XXX,XX @@ static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin)
178
QemuOpts *opts = NULL;
50
BdrvChild *child, *tmp;
179
const char *opt_overlap_check, *opt_overlap_check_template;
51
bool waited;
180
int overlap_check_template = 0;
52
181
- uint64_t l2_cache_size, refcount_cache_size;
53
- /* Ensure any pending metadata writes are submitted to bs->file. */
182
+ uint64_t l2_cache_size, l2_cache_entry_size, refcount_cache_size;
54
- bdrv_drain_invoke(bs, begin);
183
int i;
55
-
184
const char *encryptfmt;
56
/* Wait for drained requests to finish */
185
QDict *encryptopts = NULL;
57
waited = BDRV_POLL_WHILE(bs, atomic_read(&bs->in_flight) > 0);
186
@@ -XXX,XX +XXX,XX @@ static int qcow2_update_options_prepare(BlockDriverState *bs,
58
59
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs)
60
bdrv_parent_drained_begin(bs);
187
}
61
}
188
62
189
/* get L2 table/refcount block cache size from command line options */
63
+ bdrv_drain_invoke(bs, true);
190
- read_cache_sizes(bs, opts, &l2_cache_size, &refcount_cache_size,
64
bdrv_drain_recurse(bs, true);
191
- &local_err);
65
}
192
+ read_cache_sizes(bs, opts, &l2_cache_size, &l2_cache_entry_size,
66
193
+ &refcount_cache_size, &local_err);
67
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
194
if (local_err) {
195
error_propagate(errp, local_err);
196
ret = -EINVAL;
197
goto fail;
198
}
68
}
199
69
200
- l2_cache_size /= s->cluster_size;
70
bdrv_parent_drained_end(bs);
201
+ l2_cache_size /= l2_cache_entry_size;
71
+ bdrv_drain_invoke(bs, false);
202
if (l2_cache_size < MIN_L2_CACHE_SIZE) {
72
bdrv_drain_recurse(bs, false);
203
l2_cache_size = MIN_L2_CACHE_SIZE;
73
aio_enable_external(bdrv_get_aio_context(bs));
74
}
75
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
76
aio_context_acquire(aio_context);
77
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
78
if (aio_context == bdrv_get_aio_context(bs)) {
79
+ /* FIXME Calling this multiple times is wrong */
80
+ bdrv_drain_invoke(bs, true);
81
waited |= bdrv_drain_recurse(bs, true);
82
}
83
}
84
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
85
aio_context_acquire(aio_context);
86
aio_enable_external(aio_context);
87
bdrv_parent_drained_end(bs);
88
+ bdrv_drain_invoke(bs, false);
89
bdrv_drain_recurse(bs, false);
90
aio_context_release(aio_context);
204
}
91
}
205
@@ -XXX,XX +XXX,XX @@ static int qcow2_update_options_prepare(BlockDriverState *bs,
206
}
207
}
208
209
- r->l2_slice_size = s->cluster_size / sizeof(uint64_t);
210
- r->l2_table_cache = qcow2_cache_create(bs, l2_cache_size);
211
- r->refcount_block_cache = qcow2_cache_create(bs, refcount_cache_size);
212
+ r->l2_slice_size = l2_cache_entry_size / sizeof(uint64_t);
213
+ r->l2_table_cache = qcow2_cache_create(bs, l2_cache_size,
214
+ l2_cache_entry_size);
215
+ r->refcount_block_cache = qcow2_cache_create(bs, refcount_cache_size,
216
+ s->cluster_size);
217
if (r->l2_table_cache == NULL || r->refcount_block_cache == NULL) {
218
error_setg(errp, "Could not allocate metadata caches");
219
ret = -ENOMEM;
220
--
92
--
221
2.13.6
93
2.13.6
222
94
223
95
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
bdrv_drain_all_begin() used to call the .bdrv_co_drain_begin() driver
2
callback inside its polling loop. This means that how many times it got
3
called for each node depended on long it had to poll the event loop.
2
4
3
Adding support for L2 slices to expand_zero_clusters_in_l1() needs
5
This is obviously not right and results in nodes that stay drained even
4
(among other things) an extra loop that iterates over all slices of
6
after bdrv_drain_all_end(), which calls .bdrv_co_drain_begin() once per
5
each L2 table.
7
node.
6
8
7
Putting all changes in one patch would make it hard to read because
9
Fix bdrv_drain_all_begin() to call the callback only once, too.
8
all semantic changes would be mixed with pure indentation changes.
9
10
10
To make things easier this patch simply creates a new block and
11
Cc: qemu-stable@nongnu.org
11
changes the indentation of all lines of code inside it. Thus, all
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
modifications in this patch are cosmetic. There are no semantic
13
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
13
changes and no variables are renamed yet. The next patch will take
14
---
14
care of that.
15
block/io.c | 3 +--
16
1 file changed, 1 insertion(+), 2 deletions(-)
15
17
16
Signed-off-by: Alberto Garcia <berto@igalia.com>
18
diff --git a/block/io.c b/block/io.c
17
Reviewed-by: Eric Blake <eblake@redhat.com>
18
Reviewed-by: Max Reitz <mreitz@redhat.com>
19
Message-id: c2ae9f31ed5b6e591477ad4654448badd1c89d73.1517840877.git.berto@igalia.com
20
Signed-off-by: Max Reitz <mreitz@redhat.com>
21
---
22
block/qcow2-cluster.c | 187 ++++++++++++++++++++++++++------------------------
23
1 file changed, 96 insertions(+), 91 deletions(-)
24
25
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
26
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
27
--- a/block/qcow2-cluster.c
20
--- a/block/io.c
28
+++ b/block/qcow2-cluster.c
21
+++ b/block/io.c
29
@@ -XXX,XX +XXX,XX @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
22
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
30
goto fail;
23
aio_context_acquire(aio_context);
31
}
24
bdrv_parent_drained_begin(bs);
32
25
aio_disable_external(aio_context);
33
- if (is_active_l1) {
26
+ bdrv_drain_invoke(bs, true);
34
- /* get active L2 tables from cache */
27
aio_context_release(aio_context);
35
- ret = qcow2_cache_get(bs, s->l2_table_cache, l2_offset,
28
36
- (void **)&l2_table);
29
if (!g_slist_find(aio_ctxs, aio_context)) {
37
- } else {
30
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
38
- /* load inactive L2 tables from disk */
31
aio_context_acquire(aio_context);
39
- ret = bdrv_read(bs->file, l2_offset / BDRV_SECTOR_SIZE,
32
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
40
- (void *)l2_table, s->cluster_sectors);
33
if (aio_context == bdrv_get_aio_context(bs)) {
41
- }
34
- /* FIXME Calling this multiple times is wrong */
42
- if (ret < 0) {
35
- bdrv_drain_invoke(bs, true);
43
- goto fail;
36
waited |= bdrv_drain_recurse(bs, true);
44
- }
45
-
46
- for (j = 0; j < s->l2_size; j++) {
47
- uint64_t l2_entry = be64_to_cpu(l2_table[j]);
48
- int64_t offset = l2_entry & L2E_OFFSET_MASK;
49
- QCow2ClusterType cluster_type = qcow2_get_cluster_type(l2_entry);
50
-
51
- if (cluster_type != QCOW2_CLUSTER_ZERO_PLAIN &&
52
- cluster_type != QCOW2_CLUSTER_ZERO_ALLOC) {
53
- continue;
54
+ {
55
+ if (is_active_l1) {
56
+ /* get active L2 tables from cache */
57
+ ret = qcow2_cache_get(bs, s->l2_table_cache, l2_offset,
58
+ (void **)&l2_table);
59
+ } else {
60
+ /* load inactive L2 tables from disk */
61
+ ret = bdrv_read(bs->file, l2_offset / BDRV_SECTOR_SIZE,
62
+ (void *)l2_table, s->cluster_sectors);
63
+ }
64
+ if (ret < 0) {
65
+ goto fail;
66
}
67
68
- if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN) {
69
- if (!bs->backing) {
70
- /* not backed; therefore we can simply deallocate the
71
- * cluster */
72
- l2_table[j] = 0;
73
- l2_dirty = true;
74
+ for (j = 0; j < s->l2_size; j++) {
75
+ uint64_t l2_entry = be64_to_cpu(l2_table[j]);
76
+ int64_t offset = l2_entry & L2E_OFFSET_MASK;
77
+ QCow2ClusterType cluster_type =
78
+ qcow2_get_cluster_type(l2_entry);
79
+
80
+ if (cluster_type != QCOW2_CLUSTER_ZERO_PLAIN &&
81
+ cluster_type != QCOW2_CLUSTER_ZERO_ALLOC) {
82
continue;
83
}
84
85
- offset = qcow2_alloc_clusters(bs, s->cluster_size);
86
- if (offset < 0) {
87
- ret = offset;
88
- goto fail;
89
- }
90
+ if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN) {
91
+ if (!bs->backing) {
92
+ /* not backed; therefore we can simply deallocate the
93
+ * cluster */
94
+ l2_table[j] = 0;
95
+ l2_dirty = true;
96
+ continue;
97
+ }
98
+
99
+ offset = qcow2_alloc_clusters(bs, s->cluster_size);
100
+ if (offset < 0) {
101
+ ret = offset;
102
+ goto fail;
103
+ }
104
105
- if (l2_refcount > 1) {
106
- /* For shared L2 tables, set the refcount accordingly (it is
107
- * already 1 and needs to be l2_refcount) */
108
- ret = qcow2_update_cluster_refcount(bs,
109
- offset >> s->cluster_bits,
110
+ if (l2_refcount > 1) {
111
+ /* For shared L2 tables, set the refcount accordingly
112
+ * (it is already 1 and needs to be l2_refcount) */
113
+ ret = qcow2_update_cluster_refcount(
114
+ bs, offset >> s->cluster_bits,
115
refcount_diff(1, l2_refcount), false,
116
QCOW2_DISCARD_OTHER);
117
- if (ret < 0) {
118
- qcow2_free_clusters(bs, offset, s->cluster_size,
119
- QCOW2_DISCARD_OTHER);
120
- goto fail;
121
+ if (ret < 0) {
122
+ qcow2_free_clusters(bs, offset, s->cluster_size,
123
+ QCOW2_DISCARD_OTHER);
124
+ goto fail;
125
+ }
126
}
127
}
128
- }
129
130
- if (offset_into_cluster(s, offset)) {
131
- qcow2_signal_corruption(bs, true, -1, -1,
132
- "Cluster allocation offset "
133
- "%#" PRIx64 " unaligned (L2 offset: %#"
134
- PRIx64 ", L2 index: %#x)", offset,
135
- l2_offset, j);
136
- if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN) {
137
- qcow2_free_clusters(bs, offset, s->cluster_size,
138
- QCOW2_DISCARD_ALWAYS);
139
+ if (offset_into_cluster(s, offset)) {
140
+ qcow2_signal_corruption(
141
+ bs, true, -1, -1,
142
+ "Cluster allocation offset "
143
+ "%#" PRIx64 " unaligned (L2 offset: %#"
144
+ PRIx64 ", L2 index: %#x)", offset,
145
+ l2_offset, j);
146
+ if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN) {
147
+ qcow2_free_clusters(bs, offset, s->cluster_size,
148
+ QCOW2_DISCARD_ALWAYS);
149
+ }
150
+ ret = -EIO;
151
+ goto fail;
152
}
153
- ret = -EIO;
154
- goto fail;
155
- }
156
157
- ret = qcow2_pre_write_overlap_check(bs, 0, offset, s->cluster_size);
158
- if (ret < 0) {
159
- if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN) {
160
- qcow2_free_clusters(bs, offset, s->cluster_size,
161
- QCOW2_DISCARD_ALWAYS);
162
+ ret = qcow2_pre_write_overlap_check(bs, 0, offset,
163
+ s->cluster_size);
164
+ if (ret < 0) {
165
+ if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN) {
166
+ qcow2_free_clusters(bs, offset, s->cluster_size,
167
+ QCOW2_DISCARD_ALWAYS);
168
+ }
169
+ goto fail;
170
}
171
- goto fail;
172
- }
173
174
- ret = bdrv_pwrite_zeroes(bs->file, offset, s->cluster_size, 0);
175
- if (ret < 0) {
176
- if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN) {
177
- qcow2_free_clusters(bs, offset, s->cluster_size,
178
- QCOW2_DISCARD_ALWAYS);
179
+ ret = bdrv_pwrite_zeroes(bs->file, offset, s->cluster_size, 0);
180
+ if (ret < 0) {
181
+ if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN) {
182
+ qcow2_free_clusters(bs, offset, s->cluster_size,
183
+ QCOW2_DISCARD_ALWAYS);
184
+ }
185
+ goto fail;
186
}
187
- goto fail;
188
- }
189
190
- if (l2_refcount == 1) {
191
- l2_table[j] = cpu_to_be64(offset | QCOW_OFLAG_COPIED);
192
- } else {
193
- l2_table[j] = cpu_to_be64(offset);
194
+ if (l2_refcount == 1) {
195
+ l2_table[j] = cpu_to_be64(offset | QCOW_OFLAG_COPIED);
196
+ } else {
197
+ l2_table[j] = cpu_to_be64(offset);
198
+ }
199
+ l2_dirty = true;
200
}
201
- l2_dirty = true;
202
- }
203
204
- if (is_active_l1) {
205
- if (l2_dirty) {
206
- qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
207
- qcow2_cache_depends_on_flush(s->l2_table_cache);
208
- }
209
- qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
210
- } else {
211
- if (l2_dirty) {
212
- ret = qcow2_pre_write_overlap_check(bs,
213
- QCOW2_OL_INACTIVE_L2 | QCOW2_OL_ACTIVE_L2, l2_offset,
214
- s->cluster_size);
215
- if (ret < 0) {
216
- goto fail;
217
+ if (is_active_l1) {
218
+ if (l2_dirty) {
219
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
220
+ qcow2_cache_depends_on_flush(s->l2_table_cache);
221
}
222
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
223
+ } else {
224
+ if (l2_dirty) {
225
+ ret = qcow2_pre_write_overlap_check(
226
+ bs, QCOW2_OL_INACTIVE_L2 | QCOW2_OL_ACTIVE_L2,
227
+ l2_offset, s->cluster_size);
228
+ if (ret < 0) {
229
+ goto fail;
230
+ }
231
232
- ret = bdrv_write(bs->file, l2_offset / BDRV_SECTOR_SIZE,
233
- (void *)l2_table, s->cluster_sectors);
234
- if (ret < 0) {
235
- goto fail;
236
+ ret = bdrv_write(bs->file, l2_offset / BDRV_SECTOR_SIZE,
237
+ (void *)l2_table, s->cluster_sectors);
238
+ if (ret < 0) {
239
+ goto fail;
240
+ }
241
}
37
}
242
}
38
}
243
}
244
--
39
--
245
2.13.6
40
2.13.6
246
41
247
42
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
This adds a test case that the BlockDriver callbacks for drain are
2
called in bdrv_drained_all_begin/end(), and that both of them are called
3
exactly once.
2
4
3
Pull out the truncation code from the qemu_cluster_create() function so
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
we can later reuse it in qemu_gluster_truncate().
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
---
9
tests/test-bdrv-drain.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++
10
tests/Makefile.include | 2 +
11
2 files changed, 139 insertions(+)
12
create mode 100644 tests/test-bdrv-drain.c
5
13
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
7
Reviewed-by: Eric Blake <eblake@redhat.com>
15
new file mode 100644
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
index XXXXXXX..XXXXXXX
9
---
17
--- /dev/null
10
block/gluster.c | 74 +++++++++++++++++++++++++++++++--------------------------
18
+++ b/tests/test-bdrv-drain.c
11
1 file changed, 40 insertions(+), 34 deletions(-)
19
@@ -XXX,XX +XXX,XX @@
12
20
+/*
13
diff --git a/block/gluster.c b/block/gluster.c
21
+ * Block node draining tests
14
index XXXXXXX..XXXXXXX 100644
22
+ *
15
--- a/block/gluster.c
23
+ * Copyright (c) 2017 Kevin Wolf <kwolf@redhat.com>
16
+++ b/block/gluster.c
24
+ *
17
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qemu_gluster_co_pwrite_zeroes(BlockDriverState *bs,
25
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
18
}
26
+ * of this software and associated documentation files (the "Software"), to deal
19
#endif
27
+ * in the Software without restriction, including without limitation the rights
20
28
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
21
+static int qemu_gluster_do_truncate(struct glfs_fd *fd, int64_t offset,
29
+ * copies of the Software, and to permit persons to whom the Software is
22
+ PreallocMode prealloc, Error **errp)
30
+ * furnished to do so, subject to the following conditions:
31
+ *
32
+ * The above copyright notice and this permission notice shall be included in
33
+ * all copies or substantial portions of the Software.
34
+ *
35
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
36
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
38
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
39
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
40
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
41
+ * THE SOFTWARE.
42
+ */
43
+
44
+#include "qemu/osdep.h"
45
+#include "block/block.h"
46
+#include "sysemu/block-backend.h"
47
+#include "qapi/error.h"
48
+
49
+typedef struct BDRVTestState {
50
+ int drain_count;
51
+} BDRVTestState;
52
+
53
+static void coroutine_fn bdrv_test_co_drain_begin(BlockDriverState *bs)
23
+{
54
+{
24
+ switch (prealloc) {
55
+ BDRVTestState *s = bs->opaque;
25
+#ifdef CONFIG_GLUSTERFS_FALLOCATE
56
+ s->drain_count++;
26
+ case PREALLOC_MODE_FALLOC:
57
+}
27
+ if (glfs_fallocate(fd, 0, 0, offset)) {
58
+
28
+ error_setg_errno(errp, errno, "Could not preallocate data");
59
+static void coroutine_fn bdrv_test_co_drain_end(BlockDriverState *bs)
29
+ return -errno;
60
+{
30
+ }
61
+ BDRVTestState *s = bs->opaque;
31
+ break;
62
+ s->drain_count--;
32
+#endif /* CONFIG_GLUSTERFS_FALLOCATE */
63
+}
33
+#ifdef CONFIG_GLUSTERFS_ZEROFILL
64
+
34
+ case PREALLOC_MODE_FULL:
65
+static void bdrv_test_close(BlockDriverState *bs)
35
+ if (glfs_ftruncate(fd, offset)) {
66
+{
36
+ error_setg_errno(errp, errno, "Could not resize file");
67
+ BDRVTestState *s = bs->opaque;
37
+ return -errno;
68
+ g_assert_cmpint(s->drain_count, >, 0);
38
+ }
69
+}
39
+ if (glfs_zerofill(fd, 0, offset)) {
70
+
40
+ error_setg_errno(errp, errno, "Could not zerofill the new area");
71
+static int coroutine_fn bdrv_test_co_preadv(BlockDriverState *bs,
41
+ return -errno;
72
+ uint64_t offset, uint64_t bytes,
42
+ }
73
+ QEMUIOVector *qiov, int flags)
43
+ break;
74
+{
44
+#endif /* CONFIG_GLUSTERFS_ZEROFILL */
75
+ /* We want this request to stay until the polling loop in drain waits for
45
+ case PREALLOC_MODE_OFF:
76
+ * it to complete. We need to sleep a while as bdrv_drain_invoke() comes
46
+ if (glfs_ftruncate(fd, offset)) {
77
+ * first and polls its result, too, but it shouldn't accidentally complete
47
+ error_setg_errno(errp, errno, "Could not resize file");
78
+ * this request yet. */
48
+ return -errno;
79
+ qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 100000);
49
+ }
50
+ break;
51
+ default:
52
+ error_setg(errp, "Unsupported preallocation mode: %s",
53
+ PreallocMode_str(prealloc));
54
+ return -EINVAL;
55
+ }
56
+
80
+
57
+ return 0;
81
+ return 0;
58
+}
82
+}
59
+
83
+
60
static int qemu_gluster_create(const char *filename,
84
+static BlockDriver bdrv_test = {
61
QemuOpts *opts, Error **errp)
85
+ .format_name = "test",
62
{
86
+ .instance_size = sizeof(BDRVTestState),
63
@@ -XXX,XX +XXX,XX @@ static int qemu_gluster_create(const char *filename,
87
+
64
goto out;
88
+ .bdrv_close = bdrv_test_close,
65
}
89
+ .bdrv_co_preadv = bdrv_test_co_preadv,
66
90
+
67
- switch (prealloc) {
91
+ .bdrv_co_drain_begin = bdrv_test_co_drain_begin,
68
-#ifdef CONFIG_GLUSTERFS_FALLOCATE
92
+ .bdrv_co_drain_end = bdrv_test_co_drain_end,
69
- case PREALLOC_MODE_FALLOC:
93
+};
70
- if (glfs_fallocate(fd, 0, 0, total_size)) {
94
+
71
- error_setg(errp, "Could not preallocate data for the new file");
95
+static void aio_ret_cb(void *opaque, int ret)
72
- ret = -errno;
96
+{
73
- }
97
+ int *aio_ret = opaque;
74
- break;
98
+ *aio_ret = ret;
75
-#endif /* CONFIG_GLUSTERFS_FALLOCATE */
99
+}
76
-#ifdef CONFIG_GLUSTERFS_ZEROFILL
100
+
77
- case PREALLOC_MODE_FULL:
101
+static void test_drv_cb_drain_all(void)
78
- if (!glfs_ftruncate(fd, total_size)) {
102
+{
79
- if (glfs_zerofill(fd, 0, total_size)) {
103
+ BlockBackend *blk;
80
- error_setg(errp, "Could not zerofill the new file");
104
+ BlockDriverState *bs;
81
- ret = -errno;
105
+ BDRVTestState *s;
82
- }
106
+ BlockAIOCB *acb;
83
- } else {
107
+ int aio_ret;
84
- error_setg(errp, "Could not resize file");
108
+
85
- ret = -errno;
109
+ QEMUIOVector qiov;
86
- }
110
+ struct iovec iov = {
87
- break;
111
+ .iov_base = NULL,
88
-#endif /* CONFIG_GLUSTERFS_ZEROFILL */
112
+ .iov_len = 0,
89
- case PREALLOC_MODE_OFF:
113
+ };
90
- if (glfs_ftruncate(fd, total_size) != 0) {
114
+ qemu_iovec_init_external(&qiov, &iov, 1);
91
- ret = -errno;
115
+
92
- error_setg(errp, "Could not resize file");
116
+ blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
93
- }
117
+ bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR,
94
- break;
118
+ &error_abort);
95
- default:
119
+ s = bs->opaque;
96
- ret = -EINVAL;
120
+ blk_insert_bs(blk, bs, &error_abort);
97
- error_setg(errp, "Unsupported preallocation mode: %s",
121
+
98
- PreallocMode_str(prealloc));
122
+ /* Simple bdrv_drain_all_begin/end pair, check that CBs are called */
99
- break;
123
+ g_assert_cmpint(s->drain_count, ==, 0);
100
- }
124
+ bdrv_drain_all_begin();
101
+ ret = qemu_gluster_do_truncate(fd, total_size, prealloc, errp);
125
+ g_assert_cmpint(s->drain_count, ==, 1);
102
126
+ bdrv_drain_all_end();
103
out:
127
+ g_assert_cmpint(s->drain_count, ==, 0);
104
if (fd) {
128
+
129
+ /* Now do the same while a request is pending */
130
+ aio_ret = -EINPROGRESS;
131
+ acb = blk_aio_preadv(blk, 0, &qiov, 0, aio_ret_cb, &aio_ret);
132
+ g_assert(acb != NULL);
133
+ g_assert_cmpint(aio_ret, ==, -EINPROGRESS);
134
+
135
+ g_assert_cmpint(s->drain_count, ==, 0);
136
+ bdrv_drain_all_begin();
137
+ g_assert_cmpint(aio_ret, ==, 0);
138
+ g_assert_cmpint(s->drain_count, ==, 1);
139
+ bdrv_drain_all_end();
140
+ g_assert_cmpint(s->drain_count, ==, 0);
141
+
142
+ bdrv_unref(bs);
143
+ blk_unref(blk);
144
+}
145
+
146
+int main(int argc, char **argv)
147
+{
148
+ bdrv_init();
149
+ qemu_init_main_loop(&error_abort);
150
+
151
+ g_test_init(&argc, &argv, NULL);
152
+
153
+ g_test_add_func("/bdrv-drain/driver-cb/drain_all", test_drv_cb_drain_all);
154
+
155
+ return g_test_run();
156
+}
157
diff --git a/tests/Makefile.include b/tests/Makefile.include
158
index XXXXXXX..XXXXXXX 100644
159
--- a/tests/Makefile.include
160
+++ b/tests/Makefile.include
161
@@ -XXX,XX +XXX,XX @@ gcov-files-test-thread-pool-y = thread-pool.c
162
gcov-files-test-hbitmap-y = util/hbitmap.c
163
check-unit-y += tests/test-hbitmap$(EXESUF)
164
gcov-files-test-hbitmap-y = blockjob.c
165
+check-unit-y += tests/test-bdrv-drain$(EXESUF)
166
check-unit-y += tests/test-blockjob$(EXESUF)
167
check-unit-y += tests/test-blockjob-txn$(EXESUF)
168
check-unit-y += tests/test-x86-cpuid$(EXESUF)
169
@@ -XXX,XX +XXX,XX @@ tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(test-block-obj-y)
170
tests/test-aio$(EXESUF): tests/test-aio.o $(test-block-obj-y)
171
tests/test-aio-multithread$(EXESUF): tests/test-aio-multithread.o $(test-block-obj-y)
172
tests/test-throttle$(EXESUF): tests/test-throttle.o $(test-block-obj-y)
173
+tests/test-bdrv-drain$(EXESUF): tests/test-bdrv-drain.o $(test-block-obj-y) $(test-util-obj-y)
174
tests/test-blockjob$(EXESUF): tests/test-blockjob.o $(test-block-obj-y) $(test-util-obj-y)
175
tests/test-blockjob-txn$(EXESUF): tests/test-blockjob-txn.o $(test-block-obj-y) $(test-util-obj-y)
176
tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(test-block-obj-y)
105
--
177
--
106
2.13.6
178
2.13.6
107
179
108
180
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
Now that the bdrv_drain_invoke() calls are pulled up to the callers of
2
bdrv_drain_recurse(), the 'begin' parameter isn't needed any more.
2
3
3
This function was only using the BlockDriverState parameter to pass it
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
to qcow2_cache_get_table_idx(). This is no longer necessary so this
5
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
5
parameter can be removed.
6
---
7
block/io.c | 12 ++++++------
8
1 file changed, 6 insertions(+), 6 deletions(-)
6
9
7
Signed-off-by: Alberto Garcia <berto@igalia.com>
10
diff --git a/block/io.c b/block/io.c
8
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Message-id: 5c40516a91782b083c1428b7b6a41bb9e2679bfb.1517840876.git.berto@igalia.com
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
13
block/qcow2.h | 3 +--
14
block/qcow2-cache.c | 3 +--
15
block/qcow2-cluster.c | 12 ++++++------
16
block/qcow2-refcount.c | 14 ++++++--------
17
4 files changed, 14 insertions(+), 18 deletions(-)
18
19
diff --git a/block/qcow2.h b/block/qcow2.h
20
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
21
--- a/block/qcow2.h
12
--- a/block/io.c
22
+++ b/block/qcow2.h
13
+++ b/block/io.c
23
@@ -XXX,XX +XXX,XX @@ int qcow2_read_snapshots(BlockDriverState *bs);
14
@@ -XXX,XX +XXX,XX @@ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
24
Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables);
15
}
25
int qcow2_cache_destroy(BlockDriverState* bs, Qcow2Cache *c);
26
27
-void qcow2_cache_entry_mark_dirty(BlockDriverState *bs, Qcow2Cache *c,
28
- void *table);
29
+void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table);
30
int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c);
31
int qcow2_cache_write(BlockDriverState *bs, Qcow2Cache *c);
32
int qcow2_cache_set_dependency(BlockDriverState *bs, Qcow2Cache *c,
33
diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c
34
index XXXXXXX..XXXXXXX 100644
35
--- a/block/qcow2-cache.c
36
+++ b/block/qcow2-cache.c
37
@@ -XXX,XX +XXX,XX @@ void qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table)
38
assert(c->entries[i].ref >= 0);
39
}
16
}
40
17
41
-void qcow2_cache_entry_mark_dirty(BlockDriverState *bs, Qcow2Cache *c,
18
-static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin)
42
- void *table)
19
+static bool bdrv_drain_recurse(BlockDriverState *bs)
43
+void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table)
44
{
20
{
45
int i = qcow2_cache_get_table_idx(c, table);
21
BdrvChild *child, *tmp;
46
assert(c->entries[i].offset != 0);
22
bool waited;
47
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
23
@@ -XXX,XX +XXX,XX @@ static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin)
48
index XXXXXXX..XXXXXXX 100644
24
*/
49
--- a/block/qcow2-cluster.c
25
bdrv_ref(bs);
50
+++ b/block/qcow2-cluster.c
26
}
51
@@ -XXX,XX +XXX,XX @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
27
- waited |= bdrv_drain_recurse(bs, begin);
52
BLKDBG_EVENT(bs->file, BLKDBG_L2_ALLOC_WRITE);
28
+ waited |= bdrv_drain_recurse(bs);
53
29
if (in_main_loop) {
54
trace_qcow2_l2_allocate_write_l2(bs, l1_index);
30
bdrv_unref(bs);
55
- qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache, l2_table);
31
}
56
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
32
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs)
57
ret = qcow2_cache_flush(bs, s->l2_table_cache);
58
if (ret < 0) {
59
goto fail;
60
@@ -XXX,XX +XXX,XX @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
61
/* compressed clusters never have the copied flag */
62
63
BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE_COMPRESSED);
64
- qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache, l2_table);
65
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
66
l2_table[l2_index] = cpu_to_be64(cluster_offset);
67
qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
68
69
@@ -XXX,XX +XXX,XX @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
70
if (ret < 0) {
71
goto err;
72
}
33
}
73
- qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache, l2_table);
34
74
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
35
bdrv_drain_invoke(bs, true);
75
36
- bdrv_drain_recurse(bs, true);
76
assert(l2_index + m->nb_clusters <= s->l2_size);
37
+ bdrv_drain_recurse(bs);
77
for (i = 0; i < m->nb_clusters; i++) {
38
}
78
@@ -XXX,XX +XXX,XX @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
39
79
}
40
void bdrv_drained_end(BlockDriverState *bs)
80
41
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
81
/* First remove L2 entries */
42
82
- qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache, l2_table);
43
bdrv_parent_drained_end(bs);
83
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
44
bdrv_drain_invoke(bs, false);
84
if (!full_discard && s->qcow_version >= 3) {
45
- bdrv_drain_recurse(bs, false);
85
l2_table[l2_index + i] = cpu_to_be64(QCOW_OFLAG_ZERO);
46
+ bdrv_drain_recurse(bs);
86
} else {
47
aio_enable_external(bdrv_get_aio_context(bs));
87
@@ -XXX,XX +XXX,XX @@ static int zero_single_l2(BlockDriverState *bs, uint64_t offset,
48
}
88
continue;
49
89
}
50
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
90
51
aio_context_acquire(aio_context);
91
- qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache, l2_table);
52
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
92
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
53
if (aio_context == bdrv_get_aio_context(bs)) {
93
if (cluster_type == QCOW2_CLUSTER_COMPRESSED || unmap) {
54
- waited |= bdrv_drain_recurse(bs, true);
94
l2_table[l2_index + i] = cpu_to_be64(QCOW_OFLAG_ZERO);
55
+ waited |= bdrv_drain_recurse(bs);
95
qcow2_free_any_clusters(bs, old_offset, 1, QCOW2_DISCARD_REQUEST);
96
@@ -XXX,XX +XXX,XX @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
97
98
if (is_active_l1) {
99
if (l2_dirty) {
100
- qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache, l2_table);
101
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
102
qcow2_cache_depends_on_flush(s->l2_table_cache);
103
}
104
qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
105
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
106
index XXXXXXX..XXXXXXX 100644
107
--- a/block/qcow2-refcount.c
108
+++ b/block/qcow2-refcount.c
109
@@ -XXX,XX +XXX,XX @@ static int alloc_refcount_block(BlockDriverState *bs,
110
111
/* Now the new refcount block needs to be written to disk */
112
BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE);
113
- qcow2_cache_entry_mark_dirty(bs, s->refcount_block_cache, *refcount_block);
114
+ qcow2_cache_entry_mark_dirty(s->refcount_block_cache, *refcount_block);
115
ret = qcow2_cache_flush(bs, s->refcount_block_cache);
116
if (ret < 0) {
117
goto fail;
118
@@ -XXX,XX +XXX,XX @@ int64_t qcow2_refcount_area(BlockDriverState *bs, uint64_t start_offset,
119
goto fail;
120
}
121
memset(refblock_data, 0, s->cluster_size);
122
- qcow2_cache_entry_mark_dirty(bs, s->refcount_block_cache,
123
+ qcow2_cache_entry_mark_dirty(s->refcount_block_cache,
124
refblock_data);
125
126
new_table[i] = block_offset;
127
@@ -XXX,XX +XXX,XX @@ int64_t qcow2_refcount_area(BlockDriverState *bs, uint64_t start_offset,
128
s->set_refcount(refblock_data, j, 1);
129
}
130
131
- qcow2_cache_entry_mark_dirty(bs, s->refcount_block_cache,
132
+ qcow2_cache_entry_mark_dirty(s->refcount_block_cache,
133
refblock_data);
134
}
135
136
@@ -XXX,XX +XXX,XX @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
137
}
138
old_table_index = table_index;
139
140
- qcow2_cache_entry_mark_dirty(bs, s->refcount_block_cache,
141
- refcount_block);
142
+ qcow2_cache_entry_mark_dirty(s->refcount_block_cache, refcount_block);
143
144
/* we can update the count and save it */
145
block_index = cluster_index & (s->refcount_block_size - 1);
146
@@ -XXX,XX +XXX,XX @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
147
s->refcount_block_cache);
148
}
149
l2_table[j] = cpu_to_be64(entry);
150
- qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache,
151
- l2_table);
152
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
153
}
56
}
154
}
57
}
155
58
aio_context_release(aio_context);
156
@@ -XXX,XX +XXX,XX @@ static int qcow2_discard_refcount_block(BlockDriverState *bs,
59
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
60
aio_enable_external(aio_context);
61
bdrv_parent_drained_end(bs);
62
bdrv_drain_invoke(bs, false);
63
- bdrv_drain_recurse(bs, false);
64
+ bdrv_drain_recurse(bs);
65
aio_context_release(aio_context);
157
}
66
}
158
s->set_refcount(refblock, block_index, 0);
159
160
- qcow2_cache_entry_mark_dirty(bs, s->refcount_block_cache, refblock);
161
+ qcow2_cache_entry_mark_dirty(s->refcount_block_cache, refblock);
162
163
qcow2_cache_put(bs, s->refcount_block_cache, &refblock);
164
67
165
--
68
--
166
2.13.6
69
2.13.6
167
70
168
71
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
The device is drained, so there is no point in waiting for requests at
2
the end of the drained section. Remove the bdrv_drain_recurse() calls
3
there.
2
4
3
This function was only using the BlockDriverState parameter to pass it
5
The bdrv_drain_recurse() calls were introduced in commit 481cad48e5e
4
to qcow2_cache_get_table_addr(). This is no longer necessary so this
6
in order to call the .bdrv_co_drain_end() driver callback. This is now
5
parameter can be removed.
7
done by a separate bdrv_drain_invoke() call.
6
8
7
Signed-off-by: Alberto Garcia <berto@igalia.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
11
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Message-id: eb0ed90affcf302e5a954bafb5931b5215483d3a.1517840877.git.berto@igalia.com
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
12
---
13
block/qcow2.h | 3 +--
13
block/io.c | 2 --
14
block/qcow2-cache.c | 3 +--
14
1 file changed, 2 deletions(-)
15
block/qcow2-refcount.c | 6 +++---
16
3 files changed, 5 insertions(+), 7 deletions(-)
17
15
18
diff --git a/block/qcow2.h b/block/qcow2.h
16
diff --git a/block/io.c b/block/io.c
19
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
20
--- a/block/qcow2.h
18
--- a/block/io.c
21
+++ b/block/qcow2.h
19
+++ b/block/io.c
22
@@ -XXX,XX +XXX,XX @@ int qcow2_cache_get(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
20
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
23
int qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
21
24
void **table);
22
bdrv_parent_drained_end(bs);
25
void qcow2_cache_put(Qcow2Cache *c, void **table);
23
bdrv_drain_invoke(bs, false);
26
-void *qcow2_cache_is_table_offset(BlockDriverState *bs, Qcow2Cache *c,
24
- bdrv_drain_recurse(bs);
27
- uint64_t offset);
25
aio_enable_external(bdrv_get_aio_context(bs));
28
+void *qcow2_cache_is_table_offset(Qcow2Cache *c, uint64_t offset);
29
void qcow2_cache_discard(Qcow2Cache *c, void *table);
30
31
/* qcow2-bitmap.c functions */
32
diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c
33
index XXXXXXX..XXXXXXX 100644
34
--- a/block/qcow2-cache.c
35
+++ b/block/qcow2-cache.c
36
@@ -XXX,XX +XXX,XX @@ void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table)
37
c->entries[i].dirty = true;
38
}
26
}
39
27
40
-void *qcow2_cache_is_table_offset(BlockDriverState *bs, Qcow2Cache *c,
28
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
41
- uint64_t offset)
29
aio_enable_external(aio_context);
42
+void *qcow2_cache_is_table_offset(Qcow2Cache *c, uint64_t offset)
30
bdrv_parent_drained_end(bs);
43
{
31
bdrv_drain_invoke(bs, false);
44
int i;
32
- bdrv_drain_recurse(bs);
45
33
aio_context_release(aio_context);
46
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
47
index XXXXXXX..XXXXXXX 100644
48
--- a/block/qcow2-refcount.c
49
+++ b/block/qcow2-refcount.c
50
@@ -XXX,XX +XXX,XX @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
51
if (refcount == 0) {
52
void *table;
53
54
- table = qcow2_cache_is_table_offset(bs, s->refcount_block_cache,
55
+ table = qcow2_cache_is_table_offset(s->refcount_block_cache,
56
offset);
57
if (table != NULL) {
58
qcow2_cache_put(s->refcount_block_cache, &refcount_block);
59
qcow2_cache_discard(s->refcount_block_cache, table);
60
}
61
62
- table = qcow2_cache_is_table_offset(bs, s->l2_table_cache, offset);
63
+ table = qcow2_cache_is_table_offset(s->l2_table_cache, offset);
64
if (table != NULL) {
65
qcow2_cache_discard(s->l2_table_cache, table);
66
}
67
@@ -XXX,XX +XXX,XX @@ static int qcow2_discard_refcount_block(BlockDriverState *bs,
68
s->free_cluster_index = cluster_index;
69
}
34
}
70
35
71
- refblock = qcow2_cache_is_table_offset(bs, s->refcount_block_cache,
72
+ refblock = qcow2_cache_is_table_offset(s->refcount_block_cache,
73
discard_block_offs);
74
if (refblock) {
75
/* discard refblock from the cache if refblock is cached */
76
--
36
--
77
2.13.6
37
2.13.6
78
38
79
39
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
Drain requests are propagated to child nodes, parent nodes and directly
2
to the AioContext. The order in which this happened was different
3
between all combinations of drain/drain_all and begin/end.
2
4
3
This function doesn't need any changes to support L2 slices, but since
5
The correct order is to keep children only drained when their parents
4
it's now dealing with slices instead of full tables, the l2_table
6
are also drained. This means that at the start of a drained section, the
5
variable is renamed for clarity.
7
AioContext needs to be drained first, the parents second and only then
8
the children. The correct order for the end of a drained section is the
9
opposite.
6
10
7
Signed-off-by: Alberto Garcia <berto@igalia.com>
11
This patch changes the three other functions to follow the example of
8
Reviewed-by: Eric Blake <eblake@redhat.com>
12
bdrv_drained_begin(), which is the only one that got it right.
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
13
10
Message-id: 0c5d4b9bf163aa3b49ec19cc512a50d83563f2ad.1517840877.git.berto@igalia.com
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
12
---
16
---
13
block/qcow2-cluster.c | 16 ++++++++--------
17
block/io.c | 12 ++++++++----
14
1 file changed, 8 insertions(+), 8 deletions(-)
18
1 file changed, 8 insertions(+), 4 deletions(-)
15
19
16
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
20
diff --git a/block/io.c b/block/io.c
17
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
18
--- a/block/qcow2-cluster.c
22
--- a/block/io.c
19
+++ b/block/qcow2-cluster.c
23
+++ b/block/io.c
20
@@ -XXX,XX +XXX,XX @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
24
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs)
21
{
25
return;
22
BDRVQcow2State *s = bs->opaque;
23
int l2_index, ret;
24
- uint64_t *l2_table;
25
+ uint64_t *l2_slice;
26
int64_t cluster_offset;
27
int nb_csectors;
28
29
- ret = get_cluster_table(bs, offset, &l2_table, &l2_index);
30
+ ret = get_cluster_table(bs, offset, &l2_slice, &l2_index);
31
if (ret < 0) {
32
return 0;
33
}
26
}
34
27
35
/* Compression can't overwrite anything. Fail if the cluster was already
28
+ /* Stop things in parent-to-child order */
36
* allocated. */
29
if (atomic_fetch_inc(&bs->quiesce_counter) == 0) {
37
- cluster_offset = be64_to_cpu(l2_table[l2_index]);
30
aio_disable_external(bdrv_get_aio_context(bs));
38
+ cluster_offset = be64_to_cpu(l2_slice[l2_index]);
31
bdrv_parent_drained_begin(bs);
39
if (cluster_offset & L2E_OFFSET_MASK) {
32
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
40
- qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
33
return;
41
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
42
return 0;
43
}
34
}
44
35
45
cluster_offset = qcow2_alloc_bytes(bs, compressed_size);
36
- bdrv_parent_drained_end(bs);
46
if (cluster_offset < 0) {
37
+ /* Re-enable things in child-to-parent order */
47
- qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
38
bdrv_drain_invoke(bs, false);
48
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
39
+ bdrv_parent_drained_end(bs);
49
return 0;
40
aio_enable_external(bdrv_get_aio_context(bs));
41
}
42
43
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
44
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
45
AioContext *aio_context = bdrv_get_aio_context(bs);
46
47
+ /* Stop things in parent-to-child order */
48
aio_context_acquire(aio_context);
49
- bdrv_parent_drained_begin(bs);
50
aio_disable_external(aio_context);
51
+ bdrv_parent_drained_begin(bs);
52
bdrv_drain_invoke(bs, true);
53
aio_context_release(aio_context);
54
55
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
56
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
57
AioContext *aio_context = bdrv_get_aio_context(bs);
58
59
+ /* Re-enable things in child-to-parent order */
60
aio_context_acquire(aio_context);
61
- aio_enable_external(aio_context);
62
- bdrv_parent_drained_end(bs);
63
bdrv_drain_invoke(bs, false);
64
+ bdrv_parent_drained_end(bs);
65
+ aio_enable_external(aio_context);
66
aio_context_release(aio_context);
50
}
67
}
51
68
52
@@ -XXX,XX +XXX,XX @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
53
/* compressed clusters never have the copied flag */
54
55
BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE_COMPRESSED);
56
- qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
57
- l2_table[l2_index] = cpu_to_be64(cluster_offset);
58
- qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
59
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
60
+ l2_slice[l2_index] = cpu_to_be64(cluster_offset);
61
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
62
63
return cluster_offset;
64
}
65
--
69
--
66
2.13.6
70
2.13.6
67
71
68
72
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
Commit 15afd94a047 added code to acquire and release the AioContext in
2
qemuio_command(). This means that the lock is taken twice now in the
3
call path from hmp_qemu_io(). This causes BDRV_POLL_WHILE() to hang for
4
any requests issued to nodes in a non-mainloop AioContext.
2
5
3
expand_zero_clusters_in_l1() expands zero clusters as a necessary step
6
Dropping the first locking from hmp_qemu_io() fixes the problem.
4
to downgrade qcow2 images to a version that doesn't support metadata
5
zero clusters. This function takes an L1 table (which may or may not
6
be active) and iterates over all its L2 tables looking for zero
7
clusters.
8
7
9
Since we'll be loading L2 slices instead of full tables we need to add
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
an extra loop that iterates over all slices of each L2 table, and we
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
should also use the slice size when allocating the buffer used when
10
---
12
the L1 table is not active.
11
hmp.c | 6 ------
12
1 file changed, 6 deletions(-)
13
13
14
This function doesn't need any additional changes so apart from that
14
diff --git a/hmp.c b/hmp.c
15
this patch simply updates the variable name from l2_table to l2_slice.
16
17
Finally, and since we have to touch the bdrv_read() / bdrv_write()
18
calls anyway, this patch takes the opportunity to replace them with
19
the byte-based bdrv_pread() / bdrv_pwrite().
20
21
Signed-off-by: Alberto Garcia <berto@igalia.com>
22
Reviewed-by: Eric Blake <eblake@redhat.com>
23
Reviewed-by: Max Reitz <mreitz@redhat.com>
24
Message-id: 43590976f730501688096cff103f2923b72b0f32.1517840877.git.berto@igalia.com
25
Signed-off-by: Max Reitz <mreitz@redhat.com>
26
---
27
block/qcow2-cluster.c | 51 ++++++++++++++++++++++++++++-----------------------
28
1 file changed, 28 insertions(+), 23 deletions(-)
29
30
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
31
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
32
--- a/block/qcow2-cluster.c
16
--- a/hmp.c
33
+++ b/block/qcow2-cluster.c
17
+++ b/hmp.c
34
@@ -XXX,XX +XXX,XX @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
18
@@ -XXX,XX +XXX,XX @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict)
35
{
19
{
36
BDRVQcow2State *s = bs->opaque;
20
BlockBackend *blk;
37
bool is_active_l1 = (l1_table == s->l1_table);
21
BlockBackend *local_blk = NULL;
38
- uint64_t *l2_table = NULL;
22
- AioContext *aio_context;
39
+ uint64_t *l2_slice = NULL;
23
const char* device = qdict_get_str(qdict, "device");
40
+ unsigned slice, slice_size2, n_slices;
24
const char* command = qdict_get_str(qdict, "command");
41
int ret;
25
Error *err = NULL;
42
int i, j;
26
@@ -XXX,XX +XXX,XX @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict)
43
44
+ slice_size2 = s->l2_slice_size * sizeof(uint64_t);
45
+ n_slices = s->cluster_size / slice_size2;
46
+
47
if (!is_active_l1) {
48
/* inactive L2 tables require a buffer to be stored in when loading
49
* them from disk */
50
- l2_table = qemu_try_blockalign(bs->file->bs, s->cluster_size);
51
- if (l2_table == NULL) {
52
+ l2_slice = qemu_try_blockalign(bs->file->bs, slice_size2);
53
+ if (l2_slice == NULL) {
54
return -ENOMEM;
55
}
27
}
56
}
28
}
57
29
58
for (i = 0; i < l1_size; i++) {
30
- aio_context = blk_get_aio_context(blk);
59
uint64_t l2_offset = l1_table[i] & L1E_OFFSET_MASK;
31
- aio_context_acquire(aio_context);
60
- bool l2_dirty = false;
32
-
61
uint64_t l2_refcount;
33
/*
62
34
* Notably absent: Proper permission management. This is sad, but it seems
63
if (!l2_offset) {
35
* almost impossible to achieve without changing the semantics and thereby
64
@@ -XXX,XX +XXX,XX @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
36
@@ -XXX,XX +XXX,XX @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict)
65
goto fail;
37
*/
66
}
38
qemuio_command(blk, command);
67
39
68
- {
40
- aio_context_release(aio_context);
69
+ for (slice = 0; slice < n_slices; slice++) {
41
-
70
+ uint64_t slice_offset = l2_offset + slice * slice_size2;
71
+ bool l2_dirty = false;
72
if (is_active_l1) {
73
/* get active L2 tables from cache */
74
- ret = qcow2_cache_get(bs, s->l2_table_cache, l2_offset,
75
- (void **)&l2_table);
76
+ ret = qcow2_cache_get(bs, s->l2_table_cache, slice_offset,
77
+ (void **)&l2_slice);
78
} else {
79
/* load inactive L2 tables from disk */
80
- ret = bdrv_read(bs->file, l2_offset / BDRV_SECTOR_SIZE,
81
- (void *)l2_table, s->cluster_sectors);
82
+ ret = bdrv_pread(bs->file, slice_offset, l2_slice, slice_size2);
83
}
84
if (ret < 0) {
85
goto fail;
86
}
87
88
- for (j = 0; j < s->l2_size; j++) {
89
- uint64_t l2_entry = be64_to_cpu(l2_table[j]);
90
+ for (j = 0; j < s->l2_slice_size; j++) {
91
+ uint64_t l2_entry = be64_to_cpu(l2_slice[j]);
92
int64_t offset = l2_entry & L2E_OFFSET_MASK;
93
QCow2ClusterType cluster_type =
94
qcow2_get_cluster_type(l2_entry);
95
@@ -XXX,XX +XXX,XX @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
96
if (!bs->backing) {
97
/* not backed; therefore we can simply deallocate the
98
* cluster */
99
- l2_table[j] = 0;
100
+ l2_slice[j] = 0;
101
l2_dirty = true;
102
continue;
103
}
104
@@ -XXX,XX +XXX,XX @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
105
}
106
107
if (offset_into_cluster(s, offset)) {
108
+ int l2_index = slice * s->l2_slice_size + j;
109
qcow2_signal_corruption(
110
bs, true, -1, -1,
111
"Cluster allocation offset "
112
"%#" PRIx64 " unaligned (L2 offset: %#"
113
PRIx64 ", L2 index: %#x)", offset,
114
- l2_offset, j);
115
+ l2_offset, l2_index);
116
if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN) {
117
qcow2_free_clusters(bs, offset, s->cluster_size,
118
QCOW2_DISCARD_ALWAYS);
119
@@ -XXX,XX +XXX,XX @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
120
}
121
122
if (l2_refcount == 1) {
123
- l2_table[j] = cpu_to_be64(offset | QCOW_OFLAG_COPIED);
124
+ l2_slice[j] = cpu_to_be64(offset | QCOW_OFLAG_COPIED);
125
} else {
126
- l2_table[j] = cpu_to_be64(offset);
127
+ l2_slice[j] = cpu_to_be64(offset);
128
}
129
l2_dirty = true;
130
}
131
132
if (is_active_l1) {
133
if (l2_dirty) {
134
- qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
135
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
136
qcow2_cache_depends_on_flush(s->l2_table_cache);
137
}
138
- qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
139
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
140
} else {
141
if (l2_dirty) {
142
ret = qcow2_pre_write_overlap_check(
143
bs, QCOW2_OL_INACTIVE_L2 | QCOW2_OL_ACTIVE_L2,
144
- l2_offset, s->cluster_size);
145
+ slice_offset, slice_size2);
146
if (ret < 0) {
147
goto fail;
148
}
149
150
- ret = bdrv_write(bs->file, l2_offset / BDRV_SECTOR_SIZE,
151
- (void *)l2_table, s->cluster_sectors);
152
+ ret = bdrv_pwrite(bs->file, slice_offset,
153
+ l2_slice, slice_size2);
154
if (ret < 0) {
155
goto fail;
156
}
157
@@ -XXX,XX +XXX,XX @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
158
ret = 0;
159
160
fail:
42
fail:
161
- if (l2_table) {
43
blk_unref(local_blk);
162
+ if (l2_slice) {
44
hmp_handle_error(mon, &err);
163
if (!is_active_l1) {
164
- qemu_vfree(l2_table);
165
+ qemu_vfree(l2_slice);
166
} else {
167
- qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
168
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
169
}
170
}
171
return ret;
172
--
45
--
173
2.13.6
46
2.13.6
174
47
175
48
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Edgar Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com>
2
2
3
This function was never using the BlockDriverState parameter so it can
3
Since bdrv_co_preadv does all neccessary checks including
4
be safely removed.
4
reading after the end of the backing file, avoid duplication
5
of verification before bdrv_co_preadv call.
5
6
6
Signed-off-by: Alberto Garcia <berto@igalia.com>
7
Signed-off-by: Edgar Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com>
8
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Message-id: 49c74fe8b3aead9056e61a85b145ce787d06262b.1517840876.git.berto@igalia.com
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
11
---
12
block/qcow2.h | 2 +-
12
block/qcow2.h | 3 ---
13
block/qcow2-cache.c | 2 +-
13
block/qcow2.c | 51 ++++++++-------------------------------------------
14
block/qcow2.c | 16 ++++++++--------
14
2 files changed, 8 insertions(+), 46 deletions(-)
15
3 files changed, 10 insertions(+), 10 deletions(-)
16
15
17
diff --git a/block/qcow2.h b/block/qcow2.h
16
diff --git a/block/qcow2.h b/block/qcow2.h
18
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
19
--- a/block/qcow2.h
18
--- a/block/qcow2.h
20
+++ b/block/qcow2.h
19
+++ b/block/qcow2.h
21
@@ -XXX,XX +XXX,XX @@ int qcow2_read_snapshots(BlockDriverState *bs);
20
@@ -XXX,XX +XXX,XX @@ uint32_t offset_to_reftable_index(BDRVQcow2State *s, uint64_t offset)
22
23
/* qcow2-cache.c functions */
24
Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables);
25
-int qcow2_cache_destroy(BlockDriverState* bs, Qcow2Cache *c);
26
+int qcow2_cache_destroy(Qcow2Cache *c);
27
28
void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table);
29
int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c);
30
diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c
31
index XXXXXXX..XXXXXXX 100644
32
--- a/block/qcow2-cache.c
33
+++ b/block/qcow2-cache.c
34
@@ -XXX,XX +XXX,XX @@ Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables)
35
return c;
36
}
21
}
37
22
38
-int qcow2_cache_destroy(BlockDriverState *bs, Qcow2Cache *c)
23
/* qcow2.c functions */
39
+int qcow2_cache_destroy(Qcow2Cache *c)
24
-int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
40
{
25
- int64_t sector_num, int nb_sectors);
41
int i;
26
-
42
27
int64_t qcow2_refcount_metadata_size(int64_t clusters, size_t cluster_size,
28
int refcount_order, bool generous_increase,
29
uint64_t *refblock_count);
43
diff --git a/block/qcow2.c b/block/qcow2.c
30
diff --git a/block/qcow2.c b/block/qcow2.c
44
index XXXXXXX..XXXXXXX 100644
31
index XXXXXXX..XXXXXXX 100644
45
--- a/block/qcow2.c
32
--- a/block/qcow2.c
46
+++ b/block/qcow2.c
33
+++ b/block/qcow2.c
47
@@ -XXX,XX +XXX,XX @@ static void qcow2_update_options_commit(BlockDriverState *bs,
34
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn qcow2_co_get_block_status(BlockDriverState *bs,
48
int i;
35
return status;
49
36
}
50
if (s->l2_table_cache) {
37
51
- qcow2_cache_destroy(bs, s->l2_table_cache);
38
-/* handle reading after the end of the backing file */
52
+ qcow2_cache_destroy(s->l2_table_cache);
39
-int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
53
}
40
- int64_t offset, int bytes)
54
if (s->refcount_block_cache) {
41
-{
55
- qcow2_cache_destroy(bs, s->refcount_block_cache);
42
- uint64_t bs_size = bs->total_sectors * BDRV_SECTOR_SIZE;
56
+ qcow2_cache_destroy(s->refcount_block_cache);
43
- int n1;
57
}
44
-
58
s->l2_table_cache = r->l2_table_cache;
45
- if ((offset + bytes) <= bs_size) {
59
s->refcount_block_cache = r->refcount_block_cache;
46
- return bytes;
60
@@ -XXX,XX +XXX,XX @@ static void qcow2_update_options_abort(BlockDriverState *bs,
47
- }
61
Qcow2ReopenState *r)
48
-
49
- if (offset >= bs_size) {
50
- n1 = 0;
51
- } else {
52
- n1 = bs_size - offset;
53
- }
54
-
55
- qemu_iovec_memset(qiov, n1, 0, bytes - n1);
56
-
57
- return n1;
58
-}
59
-
60
static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
61
uint64_t bytes, QEMUIOVector *qiov,
62
int flags)
62
{
63
{
63
if (r->l2_table_cache) {
64
BDRVQcow2State *s = bs->opaque;
64
- qcow2_cache_destroy(bs, r->l2_table_cache);
65
- int offset_in_cluster, n1;
65
+ qcow2_cache_destroy(r->l2_table_cache);
66
+ int offset_in_cluster;
66
}
67
int ret;
67
if (r->refcount_block_cache) {
68
unsigned int cur_bytes; /* number of bytes in current iteration */
68
- qcow2_cache_destroy(bs, r->refcount_block_cache);
69
uint64_t cluster_offset = 0;
69
+ qcow2_cache_destroy(r->refcount_block_cache);
70
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
70
}
71
case QCOW2_CLUSTER_UNALLOCATED:
71
qapi_free_QCryptoBlockOpenOptions(r->crypto_opts);
72
72
}
73
if (bs->backing) {
73
@@ -XXX,XX +XXX,XX @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
74
- /* read from the base image */
74
s->l1_table = NULL;
75
- n1 = qcow2_backing_read1(bs->backing->bs, &hd_qiov,
75
cache_clean_timer_del(bs);
76
- offset, cur_bytes);
76
if (s->l2_table_cache) {
77
- if (n1 > 0) {
77
- qcow2_cache_destroy(bs, s->l2_table_cache);
78
- QEMUIOVector local_qiov;
78
+ qcow2_cache_destroy(s->l2_table_cache);
79
-
79
}
80
- qemu_iovec_init(&local_qiov, hd_qiov.niov);
80
if (s->refcount_block_cache) {
81
- qemu_iovec_concat(&local_qiov, &hd_qiov, 0, n1);
81
- qcow2_cache_destroy(bs, s->refcount_block_cache);
82
-
82
+ qcow2_cache_destroy(s->refcount_block_cache);
83
- BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
83
}
84
- qemu_co_mutex_unlock(&s->lock);
84
qcrypto_block_free(s->crypto);
85
- ret = bdrv_co_preadv(bs->backing, offset, n1,
85
qapi_free_QCryptoBlockOpenOptions(s->crypto_opts);
86
- &local_qiov, 0);
86
@@ -XXX,XX +XXX,XX @@ static void qcow2_close(BlockDriverState *bs)
87
- qemu_co_mutex_lock(&s->lock);
87
}
88
-
88
89
- qemu_iovec_destroy(&local_qiov);
89
cache_clean_timer_del(bs);
90
-
90
- qcow2_cache_destroy(bs, s->l2_table_cache);
91
- if (ret < 0) {
91
- qcow2_cache_destroy(bs, s->refcount_block_cache);
92
- goto fail;
92
+ qcow2_cache_destroy(s->l2_table_cache);
93
- }
93
+ qcow2_cache_destroy(s->refcount_block_cache);
94
+ BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
94
95
+ qemu_co_mutex_unlock(&s->lock);
95
qcrypto_block_free(s->crypto);
96
+ ret = bdrv_co_preadv(bs->backing, offset, cur_bytes,
96
s->crypto = NULL;
97
+ &hd_qiov, 0);
98
+ qemu_co_mutex_lock(&s->lock);
99
+ if (ret < 0) {
100
+ goto fail;
101
}
102
} else {
103
/* Note: in this case, no need to wait */
97
--
104
--
98
2.13.6
105
2.13.6
99
106
100
107
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
Removing a quorum child node with x-blockdev-change results in a quorum
2
driver state that cannot be recreated with create options because it
3
would require a list with gaps. This causes trouble in at least
4
.bdrv_refresh_filename().
2
5
3
To maintain load/store disabled bitmap there is new approach:
6
Document this problem so that we won't accidentally mark the command
7
stable without having addressed it.
4
8
5
- deprecate @autoload flag of block-dirty-bitmap-add, make it ignored
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
- store enabled bitmaps as "auto" to qcow2
10
Reviewed-by: Alberto Garcia <berto@igalia.com>
7
- store disabled bitmaps without "auto" flag to qcow2
8
- on qcow2 open load "auto" bitmaps as enabled and others
9
as disabled (except in_use bitmaps)
10
11
Also, adjust iotests 165 and 176 appropriately.
12
13
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
14
Message-id: 20180202160752.143796-1-vsementsov@virtuozzo.com
15
Signed-off-by: Max Reitz <mreitz@redhat.com>
16
---
11
---
17
qapi/block-core.json | 6 +++---
12
qapi/block-core.json | 4 ++++
18
block/qcow2.h | 2 +-
13
1 file changed, 4 insertions(+)
19
include/block/dirty-bitmap.h | 1 -
20
block/dirty-bitmap.c | 18 ------------------
21
block/qcow2-bitmap.c | 12 +++++++-----
22
block/qcow2.c | 2 +-
23
blockdev.c | 10 ++--------
24
qemu-doc.texi | 7 +++++++
25
tests/qemu-iotests/165 | 2 +-
26
tests/qemu-iotests/176 | 2 +-
27
10 files changed, 23 insertions(+), 39 deletions(-)
28
14
29
diff --git a/qapi/block-core.json b/qapi/block-core.json
15
diff --git a/qapi/block-core.json b/qapi/block-core.json
30
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
31
--- a/qapi/block-core.json
17
--- a/qapi/block-core.json
32
+++ b/qapi/block-core.json
18
+++ b/qapi/block-core.json
33
@@ -XXX,XX +XXX,XX @@
19
@@ -XXX,XX +XXX,XX @@
34
# Qcow2 disks support persistent bitmaps. Default is false for
20
# does not support all kinds of operations, all kinds of children, nor
35
# block-dirty-bitmap-add. (Since: 2.10)
21
# all block drivers.
36
#
22
#
37
-# @autoload: the bitmap will be automatically loaded when the image it is stored
23
+# FIXME Removing children from a quorum node means introducing gaps in the
38
-# in is opened. This flag may only be specified for persistent
24
+# child indices. This cannot be represented in the 'children' list of
39
-# bitmaps. Default is false for block-dirty-bitmap-add. (Since: 2.10)
25
+# BlockdevOptionsQuorum, as returned by .bdrv_refresh_filename().
40
+# @autoload: ignored and deprecated since 2.12.
26
+#
41
+# Currently, all dirty tracking bitmaps are loaded from Qcow2 on
27
# Warning: The data in a new quorum child MUST be consistent with that of
42
+# open.
28
# the rest of the array.
43
#
29
#
44
# Since: 2.4
45
##
46
diff --git a/block/qcow2.h b/block/qcow2.h
47
index XXXXXXX..XXXXXXX 100644
48
--- a/block/qcow2.h
49
+++ b/block/qcow2.h
50
@@ -XXX,XX +XXX,XX @@ void qcow2_cache_discard(BlockDriverState *bs, Qcow2Cache *c, void *table);
51
int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
52
void **refcount_table,
53
int64_t *refcount_table_size);
54
-bool qcow2_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp);
55
+bool qcow2_load_dirty_bitmaps(BlockDriverState *bs, Error **errp);
56
int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp);
57
void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp);
58
int qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp);
59
diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
60
index XXXXXXX..XXXXXXX 100644
61
--- a/include/block/dirty-bitmap.h
62
+++ b/include/block/dirty-bitmap.h
63
@@ -XXX,XX +XXX,XX @@ void bdrv_dirty_bitmap_deserialize_ones(BdrvDirtyBitmap *bitmap,
64
void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap);
65
66
void bdrv_dirty_bitmap_set_readonly(BdrvDirtyBitmap *bitmap, bool value);
67
-void bdrv_dirty_bitmap_set_autoload(BdrvDirtyBitmap *bitmap, bool autoload);
68
void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap,
69
bool persistent);
70
71
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
72
index XXXXXXX..XXXXXXX 100644
73
--- a/block/dirty-bitmap.c
74
+++ b/block/dirty-bitmap.c
75
@@ -XXX,XX +XXX,XX @@ struct BdrvDirtyBitmap {
76
Such operations must fail and both the image
77
and this bitmap must remain unchanged while
78
this flag is set. */
79
- bool autoload; /* For persistent bitmaps: bitmap must be
80
- autoloaded on image opening */
81
bool persistent; /* bitmap must be saved to owner disk image */
82
QLIST_ENTRY(BdrvDirtyBitmap) list;
83
};
84
@@ -XXX,XX +XXX,XX @@ void bdrv_dirty_bitmap_make_anon(BdrvDirtyBitmap *bitmap)
85
g_free(bitmap->name);
86
bitmap->name = NULL;
87
bitmap->persistent = false;
88
- bitmap->autoload = false;
89
}
90
91
/* Called with BQL taken. */
92
@@ -XXX,XX +XXX,XX @@ BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs,
93
bitmap->successor = NULL;
94
successor->persistent = bitmap->persistent;
95
bitmap->persistent = false;
96
- successor->autoload = bitmap->autoload;
97
- bitmap->autoload = false;
98
bdrv_release_dirty_bitmap(bs, bitmap);
99
100
return successor;
101
@@ -XXX,XX +XXX,XX @@ bool bdrv_has_readonly_bitmaps(BlockDriverState *bs)
102
}
103
104
/* Called with BQL taken. */
105
-void bdrv_dirty_bitmap_set_autoload(BdrvDirtyBitmap *bitmap, bool autoload)
106
-{
107
- qemu_mutex_lock(bitmap->mutex);
108
- bitmap->autoload = autoload;
109
- qemu_mutex_unlock(bitmap->mutex);
110
-}
111
-
112
-bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap)
113
-{
114
- return bitmap->autoload;
115
-}
116
-
117
-/* Called with BQL taken. */
118
void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap, bool persistent)
119
{
120
qemu_mutex_lock(bitmap->mutex);
121
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
122
index XXXXXXX..XXXXXXX 100644
123
--- a/block/qcow2-bitmap.c
124
+++ b/block/qcow2-bitmap.c
125
@@ -XXX,XX +XXX,XX @@ static void set_readonly_helper(gpointer bitmap, gpointer value)
126
bdrv_dirty_bitmap_set_readonly(bitmap, (bool)value);
127
}
128
129
-/* qcow2_load_autoloading_dirty_bitmaps()
130
+/* qcow2_load_dirty_bitmaps()
131
* Return value is a hint for caller: true means that the Qcow2 header was
132
* updated. (false doesn't mean that the header should be updated by the
133
* caller, it just means that updating was not needed or the image cannot be
134
* written to).
135
* On failure the function returns false.
136
*/
137
-bool qcow2_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp)
138
+bool qcow2_load_dirty_bitmaps(BlockDriverState *bs, Error **errp)
139
{
140
BDRVQcow2State *s = bs->opaque;
141
Qcow2BitmapList *bm_list;
142
@@ -XXX,XX +XXX,XX @@ bool qcow2_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp)
143
}
144
145
QSIMPLEQ_FOREACH(bm, bm_list, entry) {
146
- if ((bm->flags & BME_FLAG_AUTO) && !(bm->flags & BME_FLAG_IN_USE)) {
147
+ if (!(bm->flags & BME_FLAG_IN_USE)) {
148
BdrvDirtyBitmap *bitmap = load_bitmap(bs, bm, errp);
149
if (bitmap == NULL) {
150
goto fail;
151
}
152
153
+ if (!(bm->flags & BME_FLAG_AUTO)) {
154
+ bdrv_disable_dirty_bitmap(bitmap);
155
+ }
156
bdrv_dirty_bitmap_set_persistance(bitmap, true);
157
- bdrv_dirty_bitmap_set_autoload(bitmap, true);
158
bm->flags |= BME_FLAG_IN_USE;
159
created_dirty_bitmaps =
160
g_slist_append(created_dirty_bitmaps, bitmap);
161
@@ -XXX,XX +XXX,XX @@ void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp)
162
bm->table.size = 0;
163
QSIMPLEQ_INSERT_TAIL(&drop_tables, tb, entry);
164
}
165
- bm->flags = bdrv_dirty_bitmap_get_autoload(bitmap) ? BME_FLAG_AUTO : 0;
166
+ bm->flags = bdrv_dirty_bitmap_enabled(bitmap) ? BME_FLAG_AUTO : 0;
167
bm->granularity_bits = ctz32(bdrv_dirty_bitmap_granularity(bitmap));
168
bm->dirty_bitmap = bitmap;
169
}
170
diff --git a/block/qcow2.c b/block/qcow2.c
171
index XXXXXXX..XXXXXXX 100644
172
--- a/block/qcow2.c
173
+++ b/block/qcow2.c
174
@@ -XXX,XX +XXX,XX @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
175
s->autoclear_features &= QCOW2_AUTOCLEAR_MASK;
176
}
177
178
- if (qcow2_load_autoloading_dirty_bitmaps(bs, &local_err)) {
179
+ if (qcow2_load_dirty_bitmaps(bs, &local_err)) {
180
update_header = false;
181
}
182
if (local_err != NULL) {
183
diff --git a/blockdev.c b/blockdev.c
184
index XXXXXXX..XXXXXXX 100644
185
--- a/blockdev.c
186
+++ b/blockdev.c
187
@@ -XXX,XX +XXX,XX @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name,
188
if (!has_persistent) {
189
persistent = false;
190
}
191
- if (!has_autoload) {
192
- autoload = false;
193
- }
194
195
- if (has_autoload && !persistent) {
196
- error_setg(errp, "Autoload flag must be used only for persistent "
197
- "bitmaps");
198
- return;
199
+ if (has_autoload) {
200
+ warn_report("Autoload option is deprecated and its value is ignored");
201
}
202
203
if (persistent &&
204
@@ -XXX,XX +XXX,XX @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name,
205
}
206
207
bdrv_dirty_bitmap_set_persistance(bitmap, persistent);
208
- bdrv_dirty_bitmap_set_autoload(bitmap, autoload);
209
}
210
211
void qmp_block_dirty_bitmap_remove(const char *node, const char *name,
212
diff --git a/qemu-doc.texi b/qemu-doc.texi
213
index XXXXXXX..XXXXXXX 100644
214
--- a/qemu-doc.texi
215
+++ b/qemu-doc.texi
216
@@ -XXX,XX +XXX,XX @@ used and it will be removed with no replacement.
217
The ``convert -s snapshot_id_or_name'' argument is obsoleted
218
by the ``convert -l snapshot_param'' argument instead.
219
220
+@section QEMU Machine Protocol (QMP) commands
221
+
222
+@subsection block-dirty-bitmap-add "autoload" parameter (since 2.12.0)
223
+
224
+"autoload" parameter is now ignored. All bitmaps are automatically loaded
225
+from qcow2 images.
226
+
227
@section System emulator human monitor commands
228
229
@subsection host_net_add (since 2.10.0)
230
diff --git a/tests/qemu-iotests/165 b/tests/qemu-iotests/165
231
index XXXXXXX..XXXXXXX 100755
232
--- a/tests/qemu-iotests/165
233
+++ b/tests/qemu-iotests/165
234
@@ -XXX,XX +XXX,XX @@ class TestPersistentDirtyBitmap(iotests.QMPTestCase):
235
236
def qmpAddBitmap(self):
237
self.vm.qmp('block-dirty-bitmap-add', node='drive0',
238
- name='bitmap0', persistent=True, autoload=True)
239
+ name='bitmap0', persistent=True)
240
241
def test_persistent(self):
242
self.vm = self.mkVm()
243
diff --git a/tests/qemu-iotests/176 b/tests/qemu-iotests/176
244
index XXXXXXX..XXXXXXX 100755
245
--- a/tests/qemu-iotests/176
246
+++ b/tests/qemu-iotests/176
247
@@ -XXX,XX +XXX,XX @@ case $reason in
248
"file": { "driver": "file", "filename": "$TEST_IMG" } } }
249
{ "execute": "block-dirty-bitmap-add",
250
"arguments": { "node": "drive0", "name": "bitmap0",
251
- "persistent": true, "autoload": true } }
252
+ "persistent": true } }
253
{ "execute": "quit" }
254
EOF
255
    ;;
256
--
30
--
257
2.13.6
31
2.13.6
258
32
259
33
diff view generated by jsdifflib
1
From: Fam Zheng <famz@redhat.com>
1
From: Doug Gale <doug16k@gmail.com>
2
2
3
Split options out of the "@table @var" section and create a "@table
3
Add trace output for commands, errors, and undefined behavior.
4
@option", then use whitespaces and blank lines consistently.
4
Add guest error log output for undefined behavior.
5
Report invalid undefined accesses to MMIO.
6
Annotate unlikely error checks with unlikely.
5
7
6
Suggested-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Doug Gale <doug16k@gmail.com>
7
Signed-off-by: Fam Zheng <famz@redhat.com>
9
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Reviewed-by: Kashyap Chamarthy <kchamart@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
12
---
12
qemu-img.texi | 66 +++++++++++++++++++++++++++++++++++------------------------
13
hw/block/nvme.c | 349 ++++++++++++++++++++++++++++++++++++++++++--------
13
1 file changed, 39 insertions(+), 27 deletions(-)
14
hw/block/trace-events | 93 ++++++++++++++
15
2 files changed, 390 insertions(+), 52 deletions(-)
14
16
15
diff --git a/qemu-img.texi b/qemu-img.texi
17
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
16
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
17
--- a/qemu-img.texi
19
--- a/hw/block/nvme.c
18
+++ b/qemu-img.texi
20
+++ b/hw/block/nvme.c
19
@@ -XXX,XX +XXX,XX @@ The following commands are supported:
21
@@ -XXX,XX +XXX,XX @@
20
22
#include "qapi/visitor.h"
21
Command parameters:
23
#include "sysemu/block-backend.h"
22
@table @var
24
23
-@item filename
25
+#include "qemu/log.h"
24
- is a disk image filename
26
+#include "trace.h"
25
-
27
#include "nvme.h"
26
-@item --object @var{objectdef}
28
27
-
29
+#define NVME_GUEST_ERR(trace, fmt, ...) \
28
-is a QEMU user creatable object definition. See the @code{qemu(1)} manual
30
+ do { \
29
-page for a description of the object properties. The most common object
31
+ (trace_##trace)(__VA_ARGS__); \
30
-type is a @code{secret}, which is used to supply passwords and/or encryption
32
+ qemu_log_mask(LOG_GUEST_ERROR, #trace \
31
-keys.
33
+ " in %s: " fmt "\n", __func__, ## __VA_ARGS__); \
32
-
34
+ } while (0)
33
-@item --image-opts
35
+
34
-
36
static void nvme_process_sq(void *opaque);
35
-Indicates that the source @var{filename} parameter is to be interpreted as a
37
36
-full option string, not a plain filename. This parameter is mutually
38
static void nvme_addr_read(NvmeCtrl *n, hwaddr addr, void *buf, int size)
37
-exclusive with the @var{-f} parameter.
39
@@ -XXX,XX +XXX,XX @@ static void nvme_isr_notify(NvmeCtrl *n, NvmeCQueue *cq)
38
-
40
{
39
-@item --target-image-opts
41
if (cq->irq_enabled) {
40
42
if (msix_enabled(&(n->parent_obj))) {
41
-Indicates that the @var{output_filename} parameter(s) are to be interpreted as
43
+ trace_nvme_irq_msix(cq->vector);
42
-a full option string, not a plain filename. This parameter is mutually
44
msix_notify(&(n->parent_obj), cq->vector);
43
-exclusive with the @var{-O} parameters. It is currently required to also use
45
} else {
44
-the @var{-n} parameter to skip image creation. This restriction may be relaxed
46
+ trace_nvme_irq_pin();
45
-in a future release.
47
pci_irq_pulse(&n->parent_obj);
46
+@item filename
48
}
47
+is a disk image filename
49
+ } else {
48
50
+ trace_nvme_irq_masked();
49
@item fmt
51
}
50
is the disk image format. It is guessed automatically in most cases. See below
52
}
51
for a description of the supported disk formats.
53
52
54
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1,
53
-@item --backing-chain
55
trans_len = MIN(len, trans_len);
54
-will enumerate information about backing files in a disk image chain. Refer
56
int num_prps = (len >> n->page_bits) + 1;
55
-below for further description.
57
56
-
58
- if (!prp1) {
57
@item size
59
+ if (unlikely(!prp1)) {
58
is the disk image size in bytes. Optional suffixes @code{k} or @code{K}
60
+ trace_nvme_err_invalid_prp();
59
(kilobyte, 1024) @code{M} (megabyte, 1024k) and @code{G} (gigabyte, 1024M)
61
return NVME_INVALID_FIELD | NVME_DNR;
60
@@ -XXX,XX +XXX,XX @@ and T (terabyte, 1024G) are supported. @code{b} is ignored.
62
} else if (n->cmbsz && prp1 >= n->ctrl_mem.addr &&
61
is the destination disk image filename
63
prp1 < n->ctrl_mem.addr + int128_get64(n->ctrl_mem.size)) {
62
64
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1,
63
@item output_fmt
65
}
64
- is the destination format
66
len -= trans_len;
65
+is the destination format
67
if (len) {
66
+
68
- if (!prp2) {
67
@item options
69
+ if (unlikely(!prp2)) {
68
is a comma separated list of format specific options in a
70
+ trace_nvme_err_invalid_prp2_missing();
69
name=value format. Use @code{-o ?} for an overview of the options supported
71
goto unmap;
70
by the used format or see the format descriptions below for details.
72
}
71
+
73
if (len > n->page_size) {
72
@item snapshot_param
74
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1,
73
is param used for internal snapshot, format is
75
uint64_t prp_ent = le64_to_cpu(prp_list[i]);
74
'snapshot.id=[ID],snapshot.name=[NAME]' or '[ID_OR_NAME]'
76
75
+
77
if (i == n->max_prp_ents - 1 && len > n->page_size) {
76
@item snapshot_id_or_name
78
- if (!prp_ent || prp_ent & (n->page_size - 1)) {
77
is deprecated, use snapshot_param instead
79
+ if (unlikely(!prp_ent || prp_ent & (n->page_size - 1))) {
78
80
+ trace_nvme_err_invalid_prplist_ent(prp_ent);
79
+@end table
81
goto unmap;
80
+
82
}
81
+@table @option
83
82
+
84
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1,
83
+@item --object @var{objectdef}
85
prp_ent = le64_to_cpu(prp_list[i]);
84
+is a QEMU user creatable object definition. See the @code{qemu(1)} manual
86
}
85
+page for a description of the object properties. The most common object
87
86
+type is a @code{secret}, which is used to supply passwords and/or encryption
88
- if (!prp_ent || prp_ent & (n->page_size - 1)) {
87
+keys.
89
+ if (unlikely(!prp_ent || prp_ent & (n->page_size - 1))) {
88
+
90
+ trace_nvme_err_invalid_prplist_ent(prp_ent);
89
+@item --image-opts
91
goto unmap;
90
+Indicates that the source @var{filename} parameter is to be interpreted as a
92
}
91
+full option string, not a plain filename. This parameter is mutually
93
92
+exclusive with the @var{-f} parameter.
94
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1,
93
+
95
i++;
94
+@item --target-image-opts
96
}
95
+Indicates that the @var{output_filename} parameter(s) are to be interpreted as
97
} else {
96
+a full option string, not a plain filename. This parameter is mutually
98
- if (prp2 & (n->page_size - 1)) {
97
+exclusive with the @var{-O} parameters. It is currently required to also use
99
+ if (unlikely(prp2 & (n->page_size - 1))) {
98
+the @var{-n} parameter to skip image creation. This restriction may be relaxed
100
+ trace_nvme_err_invalid_prp2_align(prp2);
99
+in a future release.
101
goto unmap;
100
+
102
}
101
+@item --backing-chain
103
if (qsg->nsg) {
102
+will enumerate information about backing files in a disk image chain. Refer
104
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_dma_read_prp(NvmeCtrl *n, uint8_t *ptr, uint32_t len,
103
+below for further description.
105
QEMUIOVector iov;
104
+
106
uint16_t status = NVME_SUCCESS;
105
@item -c
107
106
indicates that target image must be compressed (qcow format only)
108
+ trace_nvme_dma_read(prp1, prp2);
107
+
109
+
108
@item -h
110
if (nvme_map_prp(&qsg, &iov, prp1, prp2, len, n)) {
109
with or without a command shows help and lists the supported formats
111
return NVME_INVALID_FIELD | NVME_DNR;
110
+
112
}
111
@item -p
113
if (qsg.nsg > 0) {
112
display progress bar (compare, convert and rebase commands only).
114
- if (dma_buf_read(ptr, len, &qsg)) {
113
If the @var{-p} option is not used for a command that supports it, the
115
+ if (unlikely(dma_buf_read(ptr, len, &qsg))) {
114
progress is reported when the process receives a @code{SIGUSR1} or
116
+ trace_nvme_err_invalid_dma();
115
@code{SIGINFO} signal.
117
status = NVME_INVALID_FIELD | NVME_DNR;
116
+
118
}
117
@item -q
119
qemu_sglist_destroy(&qsg);
118
Quiet mode - do not print any output (except errors). There's no progress bar
120
} else {
119
in case both @var{-q} and @var{-p} options are used.
121
- if (qemu_iovec_to_buf(&iov, 0, ptr, len) != len) {
120
+
122
+ if (unlikely(qemu_iovec_to_buf(&iov, 0, ptr, len) != len)) {
121
@item -S @var{size}
123
+ trace_nvme_err_invalid_dma();
122
indicates the consecutive number of bytes that must contain only zeros
124
status = NVME_INVALID_FIELD | NVME_DNR;
123
for qemu-img to create a sparse image during conversion. This value is rounded
125
}
124
down to the nearest 512 bytes. You may use the common size suffixes like
126
qemu_iovec_destroy(&iov);
125
@code{k} for kilobytes.
127
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_write_zeros(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
126
+
128
uint64_t aio_slba = slba << (data_shift - BDRV_SECTOR_BITS);
127
@item -t @var{cache}
129
uint32_t aio_nlb = nlb << (data_shift - BDRV_SECTOR_BITS);
128
specifies the cache mode that should be used with the (destination) file. See
130
129
the documentation of the emulator's @code{-drive cache=...} option for allowed
131
- if (slba + nlb > ns->id_ns.nsze) {
130
values.
132
+ if (unlikely(slba + nlb > ns->id_ns.nsze)) {
131
+
133
+ trace_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze);
132
@item -T @var{src_cache}
134
return NVME_LBA_RANGE | NVME_DNR;
133
specifies the cache mode that should be used with the source file(s). See
135
}
134
the documentation of the emulator's @code{-drive cache=...} option for allowed
136
135
values.
137
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_rw(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
136
+
138
int is_write = rw->opcode == NVME_CMD_WRITE ? 1 : 0;
137
@end table
139
enum BlockAcctType acct = is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ;
138
140
139
Parameters to snapshot subcommand:
141
- if ((slba + nlb) > ns->id_ns.nsze) {
142
+ trace_nvme_rw(is_write ? "write" : "read", nlb, data_size, slba);
143
+
144
+ if (unlikely((slba + nlb) > ns->id_ns.nsze)) {
145
block_acct_invalid(blk_get_stats(n->conf.blk), acct);
146
+ trace_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze);
147
return NVME_LBA_RANGE | NVME_DNR;
148
}
149
150
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
151
NvmeNamespace *ns;
152
uint32_t nsid = le32_to_cpu(cmd->nsid);
153
154
- if (nsid == 0 || nsid > n->num_namespaces) {
155
+ if (unlikely(nsid == 0 || nsid > n->num_namespaces)) {
156
+ trace_nvme_err_invalid_ns(nsid, n->num_namespaces);
157
return NVME_INVALID_NSID | NVME_DNR;
158
}
159
160
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
161
case NVME_CMD_READ:
162
return nvme_rw(n, ns, cmd, req);
163
default:
164
+ trace_nvme_err_invalid_opc(cmd->opcode);
165
return NVME_INVALID_OPCODE | NVME_DNR;
166
}
167
}
168
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_del_sq(NvmeCtrl *n, NvmeCmd *cmd)
169
NvmeCQueue *cq;
170
uint16_t qid = le16_to_cpu(c->qid);
171
172
- if (!qid || nvme_check_sqid(n, qid)) {
173
+ if (unlikely(!qid || nvme_check_sqid(n, qid))) {
174
+ trace_nvme_err_invalid_del_sq(qid);
175
return NVME_INVALID_QID | NVME_DNR;
176
}
177
178
+ trace_nvme_del_sq(qid);
179
+
180
sq = n->sq[qid];
181
while (!QTAILQ_EMPTY(&sq->out_req_list)) {
182
req = QTAILQ_FIRST(&sq->out_req_list);
183
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_create_sq(NvmeCtrl *n, NvmeCmd *cmd)
184
uint16_t qflags = le16_to_cpu(c->sq_flags);
185
uint64_t prp1 = le64_to_cpu(c->prp1);
186
187
- if (!cqid || nvme_check_cqid(n, cqid)) {
188
+ trace_nvme_create_sq(prp1, sqid, cqid, qsize, qflags);
189
+
190
+ if (unlikely(!cqid || nvme_check_cqid(n, cqid))) {
191
+ trace_nvme_err_invalid_create_sq_cqid(cqid);
192
return NVME_INVALID_CQID | NVME_DNR;
193
}
194
- if (!sqid || !nvme_check_sqid(n, sqid)) {
195
+ if (unlikely(!sqid || !nvme_check_sqid(n, sqid))) {
196
+ trace_nvme_err_invalid_create_sq_sqid(sqid);
197
return NVME_INVALID_QID | NVME_DNR;
198
}
199
- if (!qsize || qsize > NVME_CAP_MQES(n->bar.cap)) {
200
+ if (unlikely(!qsize || qsize > NVME_CAP_MQES(n->bar.cap))) {
201
+ trace_nvme_err_invalid_create_sq_size(qsize);
202
return NVME_MAX_QSIZE_EXCEEDED | NVME_DNR;
203
}
204
- if (!prp1 || prp1 & (n->page_size - 1)) {
205
+ if (unlikely(!prp1 || prp1 & (n->page_size - 1))) {
206
+ trace_nvme_err_invalid_create_sq_addr(prp1);
207
return NVME_INVALID_FIELD | NVME_DNR;
208
}
209
- if (!(NVME_SQ_FLAGS_PC(qflags))) {
210
+ if (unlikely(!(NVME_SQ_FLAGS_PC(qflags)))) {
211
+ trace_nvme_err_invalid_create_sq_qflags(NVME_SQ_FLAGS_PC(qflags));
212
return NVME_INVALID_FIELD | NVME_DNR;
213
}
214
sq = g_malloc0(sizeof(*sq));
215
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_del_cq(NvmeCtrl *n, NvmeCmd *cmd)
216
NvmeCQueue *cq;
217
uint16_t qid = le16_to_cpu(c->qid);
218
219
- if (!qid || nvme_check_cqid(n, qid)) {
220
+ if (unlikely(!qid || nvme_check_cqid(n, qid))) {
221
+ trace_nvme_err_invalid_del_cq_cqid(qid);
222
return NVME_INVALID_CQID | NVME_DNR;
223
}
224
225
cq = n->cq[qid];
226
- if (!QTAILQ_EMPTY(&cq->sq_list)) {
227
+ if (unlikely(!QTAILQ_EMPTY(&cq->sq_list))) {
228
+ trace_nvme_err_invalid_del_cq_notempty(qid);
229
return NVME_INVALID_QUEUE_DEL;
230
}
231
+ trace_nvme_del_cq(qid);
232
nvme_free_cq(cq, n);
233
return NVME_SUCCESS;
234
}
235
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_create_cq(NvmeCtrl *n, NvmeCmd *cmd)
236
uint16_t qflags = le16_to_cpu(c->cq_flags);
237
uint64_t prp1 = le64_to_cpu(c->prp1);
238
239
- if (!cqid || !nvme_check_cqid(n, cqid)) {
240
+ trace_nvme_create_cq(prp1, cqid, vector, qsize, qflags,
241
+ NVME_CQ_FLAGS_IEN(qflags) != 0);
242
+
243
+ if (unlikely(!cqid || !nvme_check_cqid(n, cqid))) {
244
+ trace_nvme_err_invalid_create_cq_cqid(cqid);
245
return NVME_INVALID_CQID | NVME_DNR;
246
}
247
- if (!qsize || qsize > NVME_CAP_MQES(n->bar.cap)) {
248
+ if (unlikely(!qsize || qsize > NVME_CAP_MQES(n->bar.cap))) {
249
+ trace_nvme_err_invalid_create_cq_size(qsize);
250
return NVME_MAX_QSIZE_EXCEEDED | NVME_DNR;
251
}
252
- if (!prp1) {
253
+ if (unlikely(!prp1)) {
254
+ trace_nvme_err_invalid_create_cq_addr(prp1);
255
return NVME_INVALID_FIELD | NVME_DNR;
256
}
257
- if (vector > n->num_queues) {
258
+ if (unlikely(vector > n->num_queues)) {
259
+ trace_nvme_err_invalid_create_cq_vector(vector);
260
return NVME_INVALID_IRQ_VECTOR | NVME_DNR;
261
}
262
- if (!(NVME_CQ_FLAGS_PC(qflags))) {
263
+ if (unlikely(!(NVME_CQ_FLAGS_PC(qflags)))) {
264
+ trace_nvme_err_invalid_create_cq_qflags(NVME_CQ_FLAGS_PC(qflags));
265
return NVME_INVALID_FIELD | NVME_DNR;
266
}
267
268
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_identify_ctrl(NvmeCtrl *n, NvmeIdentify *c)
269
uint64_t prp1 = le64_to_cpu(c->prp1);
270
uint64_t prp2 = le64_to_cpu(c->prp2);
271
272
+ trace_nvme_identify_ctrl();
273
+
274
return nvme_dma_read_prp(n, (uint8_t *)&n->id_ctrl, sizeof(n->id_ctrl),
275
prp1, prp2);
276
}
277
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_identify_ns(NvmeCtrl *n, NvmeIdentify *c)
278
uint64_t prp1 = le64_to_cpu(c->prp1);
279
uint64_t prp2 = le64_to_cpu(c->prp2);
280
281
- if (nsid == 0 || nsid > n->num_namespaces) {
282
+ trace_nvme_identify_ns(nsid);
283
+
284
+ if (unlikely(nsid == 0 || nsid > n->num_namespaces)) {
285
+ trace_nvme_err_invalid_ns(nsid, n->num_namespaces);
286
return NVME_INVALID_NSID | NVME_DNR;
287
}
288
289
ns = &n->namespaces[nsid - 1];
290
+
291
return nvme_dma_read_prp(n, (uint8_t *)&ns->id_ns, sizeof(ns->id_ns),
292
prp1, prp2);
293
}
294
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeIdentify *c)
295
uint16_t ret;
296
int i, j = 0;
297
298
+ trace_nvme_identify_nslist(min_nsid);
299
+
300
list = g_malloc0(data_len);
301
for (i = 0; i < n->num_namespaces; i++) {
302
if (i < min_nsid) {
303
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_identify(NvmeCtrl *n, NvmeCmd *cmd)
304
case 0x02:
305
return nvme_identify_nslist(n, c);
306
default:
307
+ trace_nvme_err_invalid_identify_cns(le32_to_cpu(c->cns));
308
return NVME_INVALID_FIELD | NVME_DNR;
309
}
310
}
311
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
312
switch (dw10) {
313
case NVME_VOLATILE_WRITE_CACHE:
314
result = blk_enable_write_cache(n->conf.blk);
315
+ trace_nvme_getfeat_vwcache(result ? "enabled" : "disabled");
316
break;
317
case NVME_NUMBER_OF_QUEUES:
318
result = cpu_to_le32((n->num_queues - 2) | ((n->num_queues - 2) << 16));
319
+ trace_nvme_getfeat_numq(result);
320
break;
321
default:
322
+ trace_nvme_err_invalid_getfeat(dw10);
323
return NVME_INVALID_FIELD | NVME_DNR;
324
}
325
326
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
327
blk_set_enable_write_cache(n->conf.blk, dw11 & 1);
328
break;
329
case NVME_NUMBER_OF_QUEUES:
330
+ trace_nvme_setfeat_numq((dw11 & 0xFFFF) + 1,
331
+ ((dw11 >> 16) & 0xFFFF) + 1,
332
+ n->num_queues - 1, n->num_queues - 1);
333
req->cqe.result =
334
cpu_to_le32((n->num_queues - 2) | ((n->num_queues - 2) << 16));
335
break;
336
default:
337
+ trace_nvme_err_invalid_setfeat(dw10);
338
return NVME_INVALID_FIELD | NVME_DNR;
339
}
340
return NVME_SUCCESS;
341
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
342
case NVME_ADM_CMD_GET_FEATURES:
343
return nvme_get_feature(n, cmd, req);
344
default:
345
+ trace_nvme_err_invalid_admin_opc(cmd->opcode);
346
return NVME_INVALID_OPCODE | NVME_DNR;
347
}
348
}
349
@@ -XXX,XX +XXX,XX @@ static int nvme_start_ctrl(NvmeCtrl *n)
350
uint32_t page_bits = NVME_CC_MPS(n->bar.cc) + 12;
351
uint32_t page_size = 1 << page_bits;
352
353
- if (n->cq[0] || n->sq[0] || !n->bar.asq || !n->bar.acq ||
354
- n->bar.asq & (page_size - 1) || n->bar.acq & (page_size - 1) ||
355
- NVME_CC_MPS(n->bar.cc) < NVME_CAP_MPSMIN(n->bar.cap) ||
356
- NVME_CC_MPS(n->bar.cc) > NVME_CAP_MPSMAX(n->bar.cap) ||
357
- NVME_CC_IOCQES(n->bar.cc) < NVME_CTRL_CQES_MIN(n->id_ctrl.cqes) ||
358
- NVME_CC_IOCQES(n->bar.cc) > NVME_CTRL_CQES_MAX(n->id_ctrl.cqes) ||
359
- NVME_CC_IOSQES(n->bar.cc) < NVME_CTRL_SQES_MIN(n->id_ctrl.sqes) ||
360
- NVME_CC_IOSQES(n->bar.cc) > NVME_CTRL_SQES_MAX(n->id_ctrl.sqes) ||
361
- !NVME_AQA_ASQS(n->bar.aqa) || !NVME_AQA_ACQS(n->bar.aqa)) {
362
+ if (unlikely(n->cq[0])) {
363
+ trace_nvme_err_startfail_cq();
364
+ return -1;
365
+ }
366
+ if (unlikely(n->sq[0])) {
367
+ trace_nvme_err_startfail_sq();
368
+ return -1;
369
+ }
370
+ if (unlikely(!n->bar.asq)) {
371
+ trace_nvme_err_startfail_nbarasq();
372
+ return -1;
373
+ }
374
+ if (unlikely(!n->bar.acq)) {
375
+ trace_nvme_err_startfail_nbaracq();
376
+ return -1;
377
+ }
378
+ if (unlikely(n->bar.asq & (page_size - 1))) {
379
+ trace_nvme_err_startfail_asq_misaligned(n->bar.asq);
380
+ return -1;
381
+ }
382
+ if (unlikely(n->bar.acq & (page_size - 1))) {
383
+ trace_nvme_err_startfail_acq_misaligned(n->bar.acq);
384
+ return -1;
385
+ }
386
+ if (unlikely(NVME_CC_MPS(n->bar.cc) <
387
+ NVME_CAP_MPSMIN(n->bar.cap))) {
388
+ trace_nvme_err_startfail_page_too_small(
389
+ NVME_CC_MPS(n->bar.cc),
390
+ NVME_CAP_MPSMIN(n->bar.cap));
391
+ return -1;
392
+ }
393
+ if (unlikely(NVME_CC_MPS(n->bar.cc) >
394
+ NVME_CAP_MPSMAX(n->bar.cap))) {
395
+ trace_nvme_err_startfail_page_too_large(
396
+ NVME_CC_MPS(n->bar.cc),
397
+ NVME_CAP_MPSMAX(n->bar.cap));
398
+ return -1;
399
+ }
400
+ if (unlikely(NVME_CC_IOCQES(n->bar.cc) <
401
+ NVME_CTRL_CQES_MIN(n->id_ctrl.cqes))) {
402
+ trace_nvme_err_startfail_cqent_too_small(
403
+ NVME_CC_IOCQES(n->bar.cc),
404
+ NVME_CTRL_CQES_MIN(n->bar.cap));
405
+ return -1;
406
+ }
407
+ if (unlikely(NVME_CC_IOCQES(n->bar.cc) >
408
+ NVME_CTRL_CQES_MAX(n->id_ctrl.cqes))) {
409
+ trace_nvme_err_startfail_cqent_too_large(
410
+ NVME_CC_IOCQES(n->bar.cc),
411
+ NVME_CTRL_CQES_MAX(n->bar.cap));
412
+ return -1;
413
+ }
414
+ if (unlikely(NVME_CC_IOSQES(n->bar.cc) <
415
+ NVME_CTRL_SQES_MIN(n->id_ctrl.sqes))) {
416
+ trace_nvme_err_startfail_sqent_too_small(
417
+ NVME_CC_IOSQES(n->bar.cc),
418
+ NVME_CTRL_SQES_MIN(n->bar.cap));
419
+ return -1;
420
+ }
421
+ if (unlikely(NVME_CC_IOSQES(n->bar.cc) >
422
+ NVME_CTRL_SQES_MAX(n->id_ctrl.sqes))) {
423
+ trace_nvme_err_startfail_sqent_too_large(
424
+ NVME_CC_IOSQES(n->bar.cc),
425
+ NVME_CTRL_SQES_MAX(n->bar.cap));
426
+ return -1;
427
+ }
428
+ if (unlikely(!NVME_AQA_ASQS(n->bar.aqa))) {
429
+ trace_nvme_err_startfail_asqent_sz_zero();
430
+ return -1;
431
+ }
432
+ if (unlikely(!NVME_AQA_ACQS(n->bar.aqa))) {
433
+ trace_nvme_err_startfail_acqent_sz_zero();
434
return -1;
435
}
436
437
@@ -XXX,XX +XXX,XX @@ static int nvme_start_ctrl(NvmeCtrl *n)
438
static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data,
439
unsigned size)
440
{
441
+ if (unlikely(offset & (sizeof(uint32_t) - 1))) {
442
+ NVME_GUEST_ERR(nvme_ub_mmiowr_misaligned32,
443
+ "MMIO write not 32-bit aligned,"
444
+ " offset=0x%"PRIx64"", offset);
445
+ /* should be ignored, fall through for now */
446
+ }
447
+
448
+ if (unlikely(size < sizeof(uint32_t))) {
449
+ NVME_GUEST_ERR(nvme_ub_mmiowr_toosmall,
450
+ "MMIO write smaller than 32-bits,"
451
+ " offset=0x%"PRIx64", size=%u",
452
+ offset, size);
453
+ /* should be ignored, fall through for now */
454
+ }
455
+
456
switch (offset) {
457
- case 0xc:
458
+ case 0xc: /* INTMS */
459
+ if (unlikely(msix_enabled(&(n->parent_obj)))) {
460
+ NVME_GUEST_ERR(nvme_ub_mmiowr_intmask_with_msix,
461
+ "undefined access to interrupt mask set"
462
+ " when MSI-X is enabled");
463
+ /* should be ignored, fall through for now */
464
+ }
465
n->bar.intms |= data & 0xffffffff;
466
n->bar.intmc = n->bar.intms;
467
+ trace_nvme_mmio_intm_set(data & 0xffffffff,
468
+ n->bar.intmc);
469
break;
470
- case 0x10:
471
+ case 0x10: /* INTMC */
472
+ if (unlikely(msix_enabled(&(n->parent_obj)))) {
473
+ NVME_GUEST_ERR(nvme_ub_mmiowr_intmask_with_msix,
474
+ "undefined access to interrupt mask clr"
475
+ " when MSI-X is enabled");
476
+ /* should be ignored, fall through for now */
477
+ }
478
n->bar.intms &= ~(data & 0xffffffff);
479
n->bar.intmc = n->bar.intms;
480
+ trace_nvme_mmio_intm_clr(data & 0xffffffff,
481
+ n->bar.intmc);
482
break;
483
- case 0x14:
484
+ case 0x14: /* CC */
485
+ trace_nvme_mmio_cfg(data & 0xffffffff);
486
/* Windows first sends data, then sends enable bit */
487
if (!NVME_CC_EN(data) && !NVME_CC_EN(n->bar.cc) &&
488
!NVME_CC_SHN(data) && !NVME_CC_SHN(n->bar.cc))
489
@@ -XXX,XX +XXX,XX @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data,
490
491
if (NVME_CC_EN(data) && !NVME_CC_EN(n->bar.cc)) {
492
n->bar.cc = data;
493
- if (nvme_start_ctrl(n)) {
494
+ if (unlikely(nvme_start_ctrl(n))) {
495
+ trace_nvme_err_startfail();
496
n->bar.csts = NVME_CSTS_FAILED;
497
} else {
498
+ trace_nvme_mmio_start_success();
499
n->bar.csts = NVME_CSTS_READY;
500
}
501
} else if (!NVME_CC_EN(data) && NVME_CC_EN(n->bar.cc)) {
502
+ trace_nvme_mmio_stopped();
503
nvme_clear_ctrl(n);
504
n->bar.csts &= ~NVME_CSTS_READY;
505
}
506
if (NVME_CC_SHN(data) && !(NVME_CC_SHN(n->bar.cc))) {
507
- nvme_clear_ctrl(n);
508
- n->bar.cc = data;
509
- n->bar.csts |= NVME_CSTS_SHST_COMPLETE;
510
+ trace_nvme_mmio_shutdown_set();
511
+ nvme_clear_ctrl(n);
512
+ n->bar.cc = data;
513
+ n->bar.csts |= NVME_CSTS_SHST_COMPLETE;
514
} else if (!NVME_CC_SHN(data) && NVME_CC_SHN(n->bar.cc)) {
515
- n->bar.csts &= ~NVME_CSTS_SHST_COMPLETE;
516
- n->bar.cc = data;
517
+ trace_nvme_mmio_shutdown_cleared();
518
+ n->bar.csts &= ~NVME_CSTS_SHST_COMPLETE;
519
+ n->bar.cc = data;
520
+ }
521
+ break;
522
+ case 0x1C: /* CSTS */
523
+ if (data & (1 << 4)) {
524
+ NVME_GUEST_ERR(nvme_ub_mmiowr_ssreset_w1c_unsupported,
525
+ "attempted to W1C CSTS.NSSRO"
526
+ " but CAP.NSSRS is zero (not supported)");
527
+ } else if (data != 0) {
528
+ NVME_GUEST_ERR(nvme_ub_mmiowr_ro_csts,
529
+ "attempted to set a read only bit"
530
+ " of controller status");
531
+ }
532
+ break;
533
+ case 0x20: /* NSSR */
534
+ if (data == 0x4E564D65) {
535
+ trace_nvme_ub_mmiowr_ssreset_unsupported();
536
+ } else {
537
+ /* The spec says that writes of other values have no effect */
538
+ return;
539
}
540
break;
541
- case 0x24:
542
+ case 0x24: /* AQA */
543
n->bar.aqa = data & 0xffffffff;
544
+ trace_nvme_mmio_aqattr(data & 0xffffffff);
545
break;
546
- case 0x28:
547
+ case 0x28: /* ASQ */
548
n->bar.asq = data;
549
+ trace_nvme_mmio_asqaddr(data);
550
break;
551
- case 0x2c:
552
+ case 0x2c: /* ASQ hi */
553
n->bar.asq |= data << 32;
554
+ trace_nvme_mmio_asqaddr_hi(data, n->bar.asq);
555
break;
556
- case 0x30:
557
+ case 0x30: /* ACQ */
558
+ trace_nvme_mmio_acqaddr(data);
559
n->bar.acq = data;
560
break;
561
- case 0x34:
562
+ case 0x34: /* ACQ hi */
563
n->bar.acq |= data << 32;
564
+ trace_nvme_mmio_acqaddr_hi(data, n->bar.acq);
565
break;
566
+ case 0x38: /* CMBLOC */
567
+ NVME_GUEST_ERR(nvme_ub_mmiowr_cmbloc_reserved,
568
+ "invalid write to reserved CMBLOC"
569
+ " when CMBSZ is zero, ignored");
570
+ return;
571
+ case 0x3C: /* CMBSZ */
572
+ NVME_GUEST_ERR(nvme_ub_mmiowr_cmbsz_readonly,
573
+ "invalid write to read only CMBSZ, ignored");
574
+ return;
575
default:
576
+ NVME_GUEST_ERR(nvme_ub_mmiowr_invalid,
577
+ "invalid MMIO write,"
578
+ " offset=0x%"PRIx64", data=%"PRIx64"",
579
+ offset, data);
580
break;
581
}
582
}
583
@@ -XXX,XX +XXX,XX @@ static uint64_t nvme_mmio_read(void *opaque, hwaddr addr, unsigned size)
584
uint8_t *ptr = (uint8_t *)&n->bar;
585
uint64_t val = 0;
586
587
+ if (unlikely(addr & (sizeof(uint32_t) - 1))) {
588
+ NVME_GUEST_ERR(nvme_ub_mmiord_misaligned32,
589
+ "MMIO read not 32-bit aligned,"
590
+ " offset=0x%"PRIx64"", addr);
591
+ /* should RAZ, fall through for now */
592
+ } else if (unlikely(size < sizeof(uint32_t))) {
593
+ NVME_GUEST_ERR(nvme_ub_mmiord_toosmall,
594
+ "MMIO read smaller than 32-bits,"
595
+ " offset=0x%"PRIx64"", addr);
596
+ /* should RAZ, fall through for now */
597
+ }
598
+
599
if (addr < sizeof(n->bar)) {
600
memcpy(&val, ptr + addr, size);
601
+ } else {
602
+ NVME_GUEST_ERR(nvme_ub_mmiord_invalid_ofs,
603
+ "MMIO read beyond last register,"
604
+ " offset=0x%"PRIx64", returning 0", addr);
605
}
606
+
607
return val;
608
}
609
610
@@ -XXX,XX +XXX,XX @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val)
611
{
612
uint32_t qid;
613
614
- if (addr & ((1 << 2) - 1)) {
615
+ if (unlikely(addr & ((1 << 2) - 1))) {
616
+ NVME_GUEST_ERR(nvme_ub_db_wr_misaligned,
617
+ "doorbell write not 32-bit aligned,"
618
+ " offset=0x%"PRIx64", ignoring", addr);
619
return;
620
}
621
622
if (((addr - 0x1000) >> 2) & 1) {
623
+ /* Completion queue doorbell write */
624
+
625
uint16_t new_head = val & 0xffff;
626
int start_sqs;
627
NvmeCQueue *cq;
628
629
qid = (addr - (0x1000 + (1 << 2))) >> 3;
630
- if (nvme_check_cqid(n, qid)) {
631
+ if (unlikely(nvme_check_cqid(n, qid))) {
632
+ NVME_GUEST_ERR(nvme_ub_db_wr_invalid_cq,
633
+ "completion queue doorbell write"
634
+ " for nonexistent queue,"
635
+ " sqid=%"PRIu32", ignoring", qid);
636
return;
637
}
638
639
cq = n->cq[qid];
640
- if (new_head >= cq->size) {
641
+ if (unlikely(new_head >= cq->size)) {
642
+ NVME_GUEST_ERR(nvme_ub_db_wr_invalid_cqhead,
643
+ "completion queue doorbell write value"
644
+ " beyond queue size, sqid=%"PRIu32","
645
+ " new_head=%"PRIu16", ignoring",
646
+ qid, new_head);
647
return;
648
}
649
650
@@ -XXX,XX +XXX,XX @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val)
651
nvme_isr_notify(n, cq);
652
}
653
} else {
654
+ /* Submission queue doorbell write */
655
+
656
uint16_t new_tail = val & 0xffff;
657
NvmeSQueue *sq;
658
659
qid = (addr - 0x1000) >> 3;
660
- if (nvme_check_sqid(n, qid)) {
661
+ if (unlikely(nvme_check_sqid(n, qid))) {
662
+ NVME_GUEST_ERR(nvme_ub_db_wr_invalid_sq,
663
+ "submission queue doorbell write"
664
+ " for nonexistent queue,"
665
+ " sqid=%"PRIu32", ignoring", qid);
666
return;
667
}
668
669
sq = n->sq[qid];
670
- if (new_tail >= sq->size) {
671
+ if (unlikely(new_tail >= sq->size)) {
672
+ NVME_GUEST_ERR(nvme_ub_db_wr_invalid_sqtail,
673
+ "submission queue doorbell write value"
674
+ " beyond queue size, sqid=%"PRIu32","
675
+ " new_tail=%"PRIu16", ignoring",
676
+ qid, new_tail);
677
return;
678
}
679
680
diff --git a/hw/block/trace-events b/hw/block/trace-events
681
index XXXXXXX..XXXXXXX 100644
682
--- a/hw/block/trace-events
683
+++ b/hw/block/trace-events
684
@@ -XXX,XX +XXX,XX @@ virtio_blk_submit_multireq(void *vdev, void *mrb, int start, int num_reqs, uint6
685
hd_geometry_lchs_guess(void *blk, int cyls, int heads, int secs) "blk %p LCHS %d %d %d"
686
hd_geometry_guess(void *blk, uint32_t cyls, uint32_t heads, uint32_t secs, int trans) "blk %p CHS %u %u %u trans %d"
687
688
+# hw/block/nvme.c
689
+# nvme traces for successful events
690
+nvme_irq_msix(uint32_t vector) "raising MSI-X IRQ vector %u"
691
+nvme_irq_pin(void) "pulsing IRQ pin"
692
+nvme_irq_masked(void) "IRQ is masked"
693
+nvme_dma_read(uint64_t prp1, uint64_t prp2) "DMA read, prp1=0x%"PRIx64" prp2=0x%"PRIx64""
694
+nvme_rw(char const *verb, uint32_t blk_count, uint64_t byte_count, uint64_t lba) "%s %"PRIu32" blocks (%"PRIu64" bytes) from LBA %"PRIu64""
695
+nvme_create_sq(uint64_t addr, uint16_t sqid, uint16_t cqid, uint16_t qsize, uint16_t qflags) "create submission queue, addr=0x%"PRIx64", sqid=%"PRIu16", cqid=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16""
696
+nvme_create_cq(uint64_t addr, uint16_t cqid, uint16_t vector, uint16_t size, uint16_t qflags, int ien) "create completion queue, addr=0x%"PRIx64", cqid=%"PRIu16", vector=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16", ien=%d"
697
+nvme_del_sq(uint16_t qid) "deleting submission queue sqid=%"PRIu16""
698
+nvme_del_cq(uint16_t cqid) "deleted completion queue, sqid=%"PRIu16""
699
+nvme_identify_ctrl(void) "identify controller"
700
+nvme_identify_ns(uint16_t ns) "identify namespace, nsid=%"PRIu16""
701
+nvme_identify_nslist(uint16_t ns) "identify namespace list, nsid=%"PRIu16""
702
+nvme_getfeat_vwcache(char const* result) "get feature volatile write cache, result=%s"
703
+nvme_getfeat_numq(int result) "get feature number of queues, result=%d"
704
+nvme_setfeat_numq(int reqcq, int reqsq, int gotcq, int gotsq) "requested cq_count=%d sq_count=%d, responding with cq_count=%d sq_count=%d"
705
+nvme_mmio_intm_set(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask set, data=0x%"PRIx64", new_mask=0x%"PRIx64""
706
+nvme_mmio_intm_clr(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask clr, data=0x%"PRIx64", new_mask=0x%"PRIx64""
707
+nvme_mmio_cfg(uint64_t data) "wrote MMIO, config controller config=0x%"PRIx64""
708
+nvme_mmio_aqattr(uint64_t data) "wrote MMIO, admin queue attributes=0x%"PRIx64""
709
+nvme_mmio_asqaddr(uint64_t data) "wrote MMIO, admin submission queue address=0x%"PRIx64""
710
+nvme_mmio_acqaddr(uint64_t data) "wrote MMIO, admin completion queue address=0x%"PRIx64""
711
+nvme_mmio_asqaddr_hi(uint64_t data, uint64_t new_addr) "wrote MMIO, admin submission queue high half=0x%"PRIx64", new_address=0x%"PRIx64""
712
+nvme_mmio_acqaddr_hi(uint64_t data, uint64_t new_addr) "wrote MMIO, admin completion queue high half=0x%"PRIx64", new_address=0x%"PRIx64""
713
+nvme_mmio_start_success(void) "setting controller enable bit succeeded"
714
+nvme_mmio_stopped(void) "cleared controller enable bit"
715
+nvme_mmio_shutdown_set(void) "shutdown bit set"
716
+nvme_mmio_shutdown_cleared(void) "shutdown bit cleared"
717
+
718
+# nvme traces for error conditions
719
+nvme_err_invalid_dma(void) "PRP/SGL is too small for transfer size"
720
+nvme_err_invalid_prplist_ent(uint64_t prplist) "PRP list entry is null or not page aligned: 0x%"PRIx64""
721
+nvme_err_invalid_prp2_align(uint64_t prp2) "PRP2 is not page aligned: 0x%"PRIx64""
722
+nvme_err_invalid_prp2_missing(void) "PRP2 is null and more data to be transferred"
723
+nvme_err_invalid_field(void) "invalid field"
724
+nvme_err_invalid_prp(void) "invalid PRP"
725
+nvme_err_invalid_sgl(void) "invalid SGL"
726
+nvme_err_invalid_ns(uint32_t ns, uint32_t limit) "invalid namespace %u not within 1-%u"
727
+nvme_err_invalid_opc(uint8_t opc) "invalid opcode 0x%"PRIx8""
728
+nvme_err_invalid_admin_opc(uint8_t opc) "invalid admin opcode 0x%"PRIx8""
729
+nvme_err_invalid_lba_range(uint64_t start, uint64_t len, uint64_t limit) "Invalid LBA start=%"PRIu64" len=%"PRIu64" limit=%"PRIu64""
730
+nvme_err_invalid_del_sq(uint16_t qid) "invalid submission queue deletion, sid=%"PRIu16""
731
+nvme_err_invalid_create_sq_cqid(uint16_t cqid) "failed creating submission queue, invalid cqid=%"PRIu16""
732
+nvme_err_invalid_create_sq_sqid(uint16_t sqid) "failed creating submission queue, invalid sqid=%"PRIu16""
733
+nvme_err_invalid_create_sq_size(uint16_t qsize) "failed creating submission queue, invalid qsize=%"PRIu16""
734
+nvme_err_invalid_create_sq_addr(uint64_t addr) "failed creating submission queue, addr=0x%"PRIx64""
735
+nvme_err_invalid_create_sq_qflags(uint16_t qflags) "failed creating submission queue, qflags=%"PRIu16""
736
+nvme_err_invalid_del_cq_cqid(uint16_t cqid) "failed deleting completion queue, cqid=%"PRIu16""
737
+nvme_err_invalid_del_cq_notempty(uint16_t cqid) "failed deleting completion queue, it is not empty, cqid=%"PRIu16""
738
+nvme_err_invalid_create_cq_cqid(uint16_t cqid) "failed creating completion queue, cqid=%"PRIu16""
739
+nvme_err_invalid_create_cq_size(uint16_t size) "failed creating completion queue, size=%"PRIu16""
740
+nvme_err_invalid_create_cq_addr(uint64_t addr) "failed creating completion queue, addr=0x%"PRIx64""
741
+nvme_err_invalid_create_cq_vector(uint16_t vector) "failed creating completion queue, vector=%"PRIu16""
742
+nvme_err_invalid_create_cq_qflags(uint16_t qflags) "failed creating completion queue, qflags=%"PRIu16""
743
+nvme_err_invalid_identify_cns(uint16_t cns) "identify, invalid cns=0x%"PRIx16""
744
+nvme_err_invalid_getfeat(int dw10) "invalid get features, dw10=0x%"PRIx32""
745
+nvme_err_invalid_setfeat(uint32_t dw10) "invalid set features, dw10=0x%"PRIx32""
746
+nvme_err_startfail_cq(void) "nvme_start_ctrl failed because there are non-admin completion queues"
747
+nvme_err_startfail_sq(void) "nvme_start_ctrl failed because there are non-admin submission queues"
748
+nvme_err_startfail_nbarasq(void) "nvme_start_ctrl failed because the admin submission queue address is null"
749
+nvme_err_startfail_nbaracq(void) "nvme_start_ctrl failed because the admin completion queue address is null"
750
+nvme_err_startfail_asq_misaligned(uint64_t addr) "nvme_start_ctrl failed because the admin submission queue address is misaligned: 0x%"PRIx64""
751
+nvme_err_startfail_acq_misaligned(uint64_t addr) "nvme_start_ctrl failed because the admin completion queue address is misaligned: 0x%"PRIx64""
752
+nvme_err_startfail_page_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the page size is too small: log2size=%u, min=%u"
753
+nvme_err_startfail_page_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the page size is too large: log2size=%u, max=%u"
754
+nvme_err_startfail_cqent_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the completion queue entry size is too small: log2size=%u, min=%u"
755
+nvme_err_startfail_cqent_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the completion queue entry size is too large: log2size=%u, max=%u"
756
+nvme_err_startfail_sqent_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the submission queue entry size is too small: log2size=%u, min=%u"
757
+nvme_err_startfail_sqent_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the submission queue entry size is too large: log2size=%u, max=%u"
758
+nvme_err_startfail_asqent_sz_zero(void) "nvme_start_ctrl failed because the admin submission queue size is zero"
759
+nvme_err_startfail_acqent_sz_zero(void) "nvme_start_ctrl failed because the admin completion queue size is zero"
760
+nvme_err_startfail(void) "setting controller enable bit failed"
761
+
762
+# Traces for undefined behavior
763
+nvme_ub_mmiowr_misaligned32(uint64_t offset) "MMIO write not 32-bit aligned, offset=0x%"PRIx64""
764
+nvme_ub_mmiowr_toosmall(uint64_t offset, unsigned size) "MMIO write smaller than 32 bits, offset=0x%"PRIx64", size=%u"
765
+nvme_ub_mmiowr_intmask_with_msix(void) "undefined access to interrupt mask set when MSI-X is enabled"
766
+nvme_ub_mmiowr_ro_csts(void) "attempted to set a read only bit of controller status"
767
+nvme_ub_mmiowr_ssreset_w1c_unsupported(void) "attempted to W1C CSTS.NSSRO but CAP.NSSRS is zero (not supported)"
768
+nvme_ub_mmiowr_ssreset_unsupported(void) "attempted NVM subsystem reset but CAP.NSSRS is zero (not supported)"
769
+nvme_ub_mmiowr_cmbloc_reserved(void) "invalid write to reserved CMBLOC when CMBSZ is zero, ignored"
770
+nvme_ub_mmiowr_cmbsz_readonly(void) "invalid write to read only CMBSZ, ignored"
771
+nvme_ub_mmiowr_invalid(uint64_t offset, uint64_t data) "invalid MMIO write, offset=0x%"PRIx64", data=0x%"PRIx64""
772
+nvme_ub_mmiord_misaligned32(uint64_t offset) "MMIO read not 32-bit aligned, offset=0x%"PRIx64""
773
+nvme_ub_mmiord_toosmall(uint64_t offset) "MMIO read smaller than 32-bits, offset=0x%"PRIx64""
774
+nvme_ub_mmiord_invalid_ofs(uint64_t offset) "MMIO read beyond last register, offset=0x%"PRIx64", returning 0"
775
+nvme_ub_db_wr_misaligned(uint64_t offset) "doorbell write not 32-bit aligned, offset=0x%"PRIx64", ignoring"
776
+nvme_ub_db_wr_invalid_cq(uint32_t qid) "completion queue doorbell write for nonexistent queue, cqid=%"PRIu32", ignoring"
777
+nvme_ub_db_wr_invalid_cqhead(uint32_t qid, uint16_t new_head) "completion queue doorbell write value beyond queue size, cqid=%"PRIu32", new_head=%"PRIu16", ignoring"
778
+nvme_ub_db_wr_invalid_sq(uint32_t qid) "submission queue doorbell write for nonexistent queue, sqid=%"PRIu32", ignoring"
779
+nvme_ub_db_wr_invalid_sqtail(uint32_t qid, uint16_t new_tail) "submission queue doorbell write value beyond queue size, sqid=%"PRIu32", new_head=%"PRIu16", ignoring"
780
+
781
# hw/block/xen_disk.c
782
xen_disk_alloc(char *name) "%s"
783
xen_disk_init(char *name) "%s"
140
--
784
--
141
2.13.6
785
2.13.6
142
786
143
787
diff view generated by jsdifflib
1
From: Fam Zheng <famz@redhat.com>
1
From: Fam Zheng <famz@redhat.com>
2
2
3
This reverts commit 76bf133c4 which updated the reference output, and
3
Management tools create overlays of running guests with qemu-img:
4
fixed the reference image, because the code path we want to exercise is
5
actually the invalid image size.
6
4
7
The descriptor block in the image, which includes the CID to verify, has been
5
$ qemu-img create -b /image/in/use.qcow2 -f qcow2 /overlay/image.qcow2
8
invalid since the reference image was added. Since commit 9877860e7bd we report
9
this error earlier than the "file too large", so 059.out mismatches.
10
6
11
The binary change is generated along the operations of:
7
but this doesn't work anymore due to image locking:
12
8
13
$ bunzip2 afl9.vmdk.bz2
9
qemu-img: /overlay/image.qcow2: Failed to get shared "write" lock
14
$ qemu-img create -f vmdk fix.vmdk 1G
10
Is another process using the image?
15
$ dd if=afl9.vmdk of=fix.vmdk bs=512 count=1 conv=notrunc
11
Could not open backing image to determine size.
16
$ mv fix.vmdk afl9.vmdk
12
Use the force share option to allow this use case again.
17
$ bzip2 afl9.vmdk
18
13
14
Cc: qemu-stable@nongnu.org
19
Signed-off-by: Fam Zheng <famz@redhat.com>
15
Signed-off-by: Fam Zheng <famz@redhat.com>
20
Reviewed-by: Eric Blake <eblake@redhat.com>
16
Reviewed-by: Eric Blake <eblake@redhat.com>
21
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
22
---
18
---
23
tests/qemu-iotests/059.out | 2 +-
19
block.c | 3 ++-
24
tests/qemu-iotests/sample_images/afl9.vmdk.bz2 | Bin 178 -> 618 bytes
20
1 file changed, 2 insertions(+), 1 deletion(-)
25
2 files changed, 1 insertion(+), 1 deletion(-)
26
21
27
diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out
22
diff --git a/block.c b/block.c
28
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
29
--- a/tests/qemu-iotests/059.out
24
--- a/block.c
30
+++ b/tests/qemu-iotests/059.out
25
+++ b/block.c
31
@@ -XXX,XX +XXX,XX @@ Offset Length Mapped to File
26
@@ -XXX,XX +XXX,XX @@ void bdrv_img_create(const char *filename, const char *fmt,
32
0x140000000 0x10000 0x50000 TEST_DIR/t-s003.vmdk
27
back_flags = flags;
33
28
back_flags &= ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);
34
=== Testing afl image with a very large capacity ===
29
35
-qemu-img: Could not open 'TEST_DIR/afl9.IMGFMT': Could not open 'TEST_DIR/afl9.IMGFMT': Invalid argument
30
+ backing_options = qdict_new();
36
+qemu-img: Can't get image size 'TEST_DIR/afl9.IMGFMT': File too large
31
if (backing_fmt) {
37
*** done
32
- backing_options = qdict_new();
38
diff --git a/tests/qemu-iotests/sample_images/afl9.vmdk.bz2 b/tests/qemu-iotests/sample_images/afl9.vmdk.bz2
33
qdict_put_str(backing_options, "driver", backing_fmt);
39
index XXXXXXX..XXXXXXX 100644
34
}
40
GIT binary patch
35
+ qdict_put_bool(backing_options, BDRV_OPT_FORCE_SHARE, true);
41
literal 618
36
42
zcmV-w0+szjT4*^jL0KkKSvgW7ssIN3|NsBH-Q9UpfAhclU70`s-*NE~5QvC~h=_=Y
37
bs = bdrv_open(full_backing, NULL, backing_options, back_flags,
43
zh>D2n*q*=vygR634445h35k;?00h9835kMW00004$iPepVE{Bqk)uhJ^wfGLr=)3s
38
&local_err);
44
zhM5CR88jLh7)B;cA*K)*6GmuECPU3o4NWG5O#pg>Ak#xY8Z^<M8Z>CrMt}oD38Ns$
45
z02n}M0LdjZ&}cLPqd+nPKmn$j0iXe(02%-d27nnJriN-uE+X&cz@Bj4BBfd|yV!NB
46
zwqkL}nW3AI5x^jp=t%^F1pxqp)v#n#)j$zcm1xqv(!$2d*5%vF{5RPWnOV8-^tE<(
47
zU~%&}Y0uNu*9Wt=yS^8PkC&gPueZO%IG;aD{l#sG`<Af;l1Pnwpi9I75FkQ`LLhd8
48
z6(9f*2s+N5=%bwp80ddrD6>m4Ho*fsHXdM<jtl*zKvRiTx7Ugy1|Nl<Ns!z;1dvhy
49
z=`SDHh~{u|1ZodC(_lzezQ)I*Kv2z|PZ@!SJjlVzwGdx2iu#W}dI{t+T&dDWT^LPy
50
zg3NouEM=V~7GvZQS1CXy676F6mJXWGgW!KTr+E$OspGYCjWmuwa^<Bc>_(-i7fPIW
51
zA+~n9iy_f)g8B2RILhd%F)dZ5f?7pFLw)@;Ncl<JE}gvMrfh{elT#3gLjY6r8xY4O
52
z)UO#pv=WYptukn<DuoMH2ip%k?V^k!rjQirK^RC<Brw>3Bz9<|!xm0F{45K+gg8#n
53
z4FNAJ!<X|3Vq+lyV4=xZ;>AN0<K=%c4A2ruB!4rGvWm!KFrvd4PyfZ-kxmpO4pfM$
54
EfLnqQYXATM
55
56
literal 178
57
zcmV;j08RfwT4*^jL0KkKS>A08g#Z9x|HJ$H)ZJi0004xF0SE*D03g5s00IDLSQelF
58
ziVX^$pfWNUJrmRhn2k52pQ;Rs0EQC;(S%|!m`2~BZ@b++;etskRJUVl!Kt)wu7?VN
59
zl;%JdqX2?TgsNVJP?87M*MvL1qQnBkCES&?0@MeaN-bL4;bDzxmMm|da4fuh!=#fu
60
g@i9R@5z!av{9tA<GGr!3hi~HUNT&)C8_l7xpl%OKQ2+n{
61
62
--
39
--
63
2.13.6
40
2.13.6
64
41
65
42
diff view generated by jsdifflib
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
From: Thomas Huth <thuth@redhat.com>
2
2
3
Even if an op blocker is present for BLOCK_OP_TYPE_MIRROR_SOURCE,
3
It's not working anymore since QEMU v1.3.0 - time to remove it now.
4
it is checked a bit late and the result is that the target is
5
created even if drive-mirror subsequently fails. Add an early
6
check to avoid this.
7
4
8
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
5
Signed-off-by: Thomas Huth <thuth@redhat.com>
9
Reviewed-by: Fam Zheng <famz@redhat.com>
6
Reviewed-by: John Snow <jsnow@redhat.com>
10
Reviewed-by: Alberto Garcia <berto@igalia.com>
7
Reviewed-by: Markus Armbruster <armbru@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
9
---
13
blockdev.c | 5 +++++
10
blockdev.c | 11 -----------
14
1 file changed, 5 insertions(+)
11
qemu-doc.texi | 6 ------
12
2 files changed, 17 deletions(-)
15
13
16
diff --git a/blockdev.c b/blockdev.c
14
diff --git a/blockdev.c b/blockdev.c
17
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
18
--- a/blockdev.c
16
--- a/blockdev.c
19
+++ b/blockdev.c
17
+++ b/blockdev.c
20
@@ -XXX,XX +XXX,XX @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
18
@@ -XXX,XX +XXX,XX @@ QemuOptsList qemu_legacy_drive_opts = {
21
return;
19
.type = QEMU_OPT_STRING,
20
.help = "chs translation (auto, lba, none)",
21
},{
22
- .name = "boot",
23
- .type = QEMU_OPT_BOOL,
24
- .help = "(deprecated, ignored)",
25
- },{
26
.name = "addr",
27
.type = QEMU_OPT_STRING,
28
.help = "pci address (virtio only)",
29
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
30
goto fail;
22
}
31
}
23
32
24
+ /* Early check to avoid creating target */
33
- /* Deprecated option boot=[on|off] */
25
+ if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_MIRROR_SOURCE, errp)) {
34
- if (qemu_opt_get(legacy_opts, "boot") != NULL) {
26
+ return;
35
- fprintf(stderr, "qemu-kvm: boot=on|off is deprecated and will be "
27
+ }
36
- "ignored. Future versions will reject this parameter. Please "
28
+
37
- "update your scripts.\n");
29
aio_context = bdrv_get_aio_context(bs);
38
- }
30
aio_context_acquire(aio_context);
39
-
31
40
/* Other deprecated options */
41
if (!qtest_enabled()) {
42
for (i = 0; i < ARRAY_SIZE(deprecated); i++) {
43
diff --git a/qemu-doc.texi b/qemu-doc.texi
44
index XXXXXXX..XXXXXXX 100644
45
--- a/qemu-doc.texi
46
+++ b/qemu-doc.texi
47
@@ -XXX,XX +XXX,XX @@ deprecated.
48
49
@section System emulator command line arguments
50
51
-@subsection -drive boot=on|off (since 1.3.0)
52
-
53
-The ``boot=on|off'' option to the ``-drive'' argument is
54
-ignored. Applications should use the ``bootindex=N'' parameter
55
-to set an absolute ordering between devices instead.
56
-
57
@subsection -tdf (since 1.3.0)
58
59
The ``-tdf'' argument is ignored. The behaviour implemented
32
--
60
--
33
2.13.6
61
2.13.6
34
62
35
63
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Thomas Huth <thuth@redhat.com>
2
2
3
g_realloc() aborts the program if it fails to allocate the required
3
It's been marked as deprecated since QEMU v2.10.0, and so far nobody
4
amount of memory. We want to detect that scenario and return an error
4
complained that we should keep it, so let's remove this legacy option
5
instead, so let's use g_try_realloc().
5
now to simplify the code quite a bit.
6
6
7
Signed-off-by: Alberto Garcia <berto@igalia.com>
7
Signed-off-by: Thomas Huth <thuth@redhat.com>
8
Reviewed-by: John Snow <jsnow@redhat.com>
9
Reviewed-by: Markus Armbruster <armbru@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
11
---
10
block/qcow2-cluster.c | 10 +++++++++-
12
vl.c | 86 ++-------------------------------------------------------
11
1 file changed, 9 insertions(+), 1 deletion(-)
13
qemu-doc.texi | 8 ------
12
14
qemu-options.hx | 19 ++-----------
13
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
15
3 files changed, 4 insertions(+), 109 deletions(-)
16
17
diff --git a/vl.c b/vl.c
14
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
15
--- a/block/qcow2-cluster.c
19
--- a/vl.c
16
+++ b/block/qcow2-cluster.c
20
+++ b/vl.c
17
@@ -XXX,XX +XXX,XX @@ int qcow2_expand_zero_clusters(BlockDriverState *bs,
21
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp)
18
int l1_sectors = DIV_ROUND_UP(s->snapshots[i].l1_size *
22
const char *boot_order = NULL;
19
sizeof(uint64_t), BDRV_SECTOR_SIZE);
23
const char *boot_once = NULL;
20
24
DisplayState *ds;
21
- l1_table = g_realloc(l1_table, l1_sectors * BDRV_SECTOR_SIZE);
25
- int cyls, heads, secs, translation;
22
+ uint64_t *new_l1_table =
26
QemuOpts *opts, *machine_opts;
23
+ g_try_realloc(l1_table, l1_sectors * BDRV_SECTOR_SIZE);
27
- QemuOpts *hda_opts = NULL, *icount_opts = NULL, *accel_opts = NULL;
24
+
28
+ QemuOpts *icount_opts = NULL, *accel_opts = NULL;
25
+ if (!new_l1_table) {
29
QemuOptsList *olist;
26
+ ret = -ENOMEM;
30
int optind;
27
+ goto fail;
31
const char *optarg;
28
+ }
32
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp)
29
+
33
30
+ l1_table = new_l1_table;
34
cpu_model = NULL;
31
35
snapshot = 0;
32
ret = bdrv_read(bs->file,
36
- cyls = heads = secs = 0;
33
s->snapshots[i].l1_table_offset / BDRV_SECTOR_SIZE,
37
- translation = BIOS_ATA_TRANSLATION_AUTO;
38
39
nb_nics = 0;
40
41
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp)
42
if (optind >= argc)
43
break;
44
if (argv[optind][0] != '-') {
45
- hda_opts = drive_add(IF_DEFAULT, 0, argv[optind++], HD_OPTS);
46
+ drive_add(IF_DEFAULT, 0, argv[optind++], HD_OPTS);
47
} else {
48
const QEMUOption *popt;
49
50
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp)
51
cpu_model = optarg;
52
break;
53
case QEMU_OPTION_hda:
54
- {
55
- char buf[256];
56
- if (cyls == 0)
57
- snprintf(buf, sizeof(buf), "%s", HD_OPTS);
58
- else
59
- snprintf(buf, sizeof(buf),
60
- "%s,cyls=%d,heads=%d,secs=%d%s",
61
- HD_OPTS , cyls, heads, secs,
62
- translation == BIOS_ATA_TRANSLATION_LBA ?
63
- ",trans=lba" :
64
- translation == BIOS_ATA_TRANSLATION_NONE ?
65
- ",trans=none" : "");
66
- drive_add(IF_DEFAULT, 0, optarg, buf);
67
- break;
68
- }
69
case QEMU_OPTION_hdb:
70
case QEMU_OPTION_hdc:
71
case QEMU_OPTION_hdd:
72
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp)
73
case QEMU_OPTION_snapshot:
74
snapshot = 1;
75
break;
76
- case QEMU_OPTION_hdachs:
77
- {
78
- const char *p;
79
- p = optarg;
80
- cyls = strtol(p, (char **)&p, 0);
81
- if (cyls < 1 || cyls > 16383)
82
- goto chs_fail;
83
- if (*p != ',')
84
- goto chs_fail;
85
- p++;
86
- heads = strtol(p, (char **)&p, 0);
87
- if (heads < 1 || heads > 16)
88
- goto chs_fail;
89
- if (*p != ',')
90
- goto chs_fail;
91
- p++;
92
- secs = strtol(p, (char **)&p, 0);
93
- if (secs < 1 || secs > 63)
94
- goto chs_fail;
95
- if (*p == ',') {
96
- p++;
97
- if (!strcmp(p, "large")) {
98
- translation = BIOS_ATA_TRANSLATION_LARGE;
99
- } else if (!strcmp(p, "rechs")) {
100
- translation = BIOS_ATA_TRANSLATION_RECHS;
101
- } else if (!strcmp(p, "none")) {
102
- translation = BIOS_ATA_TRANSLATION_NONE;
103
- } else if (!strcmp(p, "lba")) {
104
- translation = BIOS_ATA_TRANSLATION_LBA;
105
- } else if (!strcmp(p, "auto")) {
106
- translation = BIOS_ATA_TRANSLATION_AUTO;
107
- } else {
108
- goto chs_fail;
109
- }
110
- } else if (*p != '\0') {
111
- chs_fail:
112
- error_report("invalid physical CHS format");
113
- exit(1);
114
- }
115
- if (hda_opts != NULL) {
116
- qemu_opt_set_number(hda_opts, "cyls", cyls,
117
- &error_abort);
118
- qemu_opt_set_number(hda_opts, "heads", heads,
119
- &error_abort);
120
- qemu_opt_set_number(hda_opts, "secs", secs,
121
- &error_abort);
122
- if (translation == BIOS_ATA_TRANSLATION_LARGE) {
123
- qemu_opt_set(hda_opts, "trans", "large",
124
- &error_abort);
125
- } else if (translation == BIOS_ATA_TRANSLATION_RECHS) {
126
- qemu_opt_set(hda_opts, "trans", "rechs",
127
- &error_abort);
128
- } else if (translation == BIOS_ATA_TRANSLATION_LBA) {
129
- qemu_opt_set(hda_opts, "trans", "lba",
130
- &error_abort);
131
- } else if (translation == BIOS_ATA_TRANSLATION_NONE) {
132
- qemu_opt_set(hda_opts, "trans", "none",
133
- &error_abort);
134
- }
135
- }
136
- }
137
- error_report("'-hdachs' is deprecated, please use '-device"
138
- " ide-hd,cyls=c,heads=h,secs=s,...' instead");
139
- break;
140
case QEMU_OPTION_numa:
141
opts = qemu_opts_parse_noisily(qemu_find_opts("numa"),
142
optarg, true);
143
diff --git a/qemu-doc.texi b/qemu-doc.texi
144
index XXXXXXX..XXXXXXX 100644
145
--- a/qemu-doc.texi
146
+++ b/qemu-doc.texi
147
@@ -XXX,XX +XXX,XX @@ The ``--net dump'' argument is now replaced with the
148
``-object filter-dump'' argument which works in combination
149
with the modern ``-netdev`` backends instead.
150
151
-@subsection -hdachs (since 2.10.0)
152
-
153
-The ``-hdachs'' argument is now a synonym for setting
154
-the ``cyls'', ``heads'', ``secs'', and ``trans'' properties
155
-on the ``ide-hd'' device using the ``-device'' argument.
156
-The new syntax allows different settings to be provided
157
-per disk.
158
-
159
@subsection -usbdevice (since 2.10.0)
160
161
The ``-usbdevice DEV'' argument is now a synonym for setting
162
diff --git a/qemu-options.hx b/qemu-options.hx
163
index XXXXXXX..XXXXXXX 100644
164
--- a/qemu-options.hx
165
+++ b/qemu-options.hx
166
@@ -XXX,XX +XXX,XX @@ of available connectors of a given interface type.
167
@item media=@var{media}
168
This option defines the type of the media: disk or cdrom.
169
@item cyls=@var{c},heads=@var{h},secs=@var{s}[,trans=@var{t}]
170
-These options have the same definition as they have in @option{-hdachs}.
171
-These parameters are deprecated, use the corresponding parameters
172
+Force disk physical geometry and the optional BIOS translation (trans=none or
173
+lba). These parameters are deprecated, use the corresponding parameters
174
of @code{-device} instead.
175
@item snapshot=@var{snapshot}
176
@var{snapshot} is "on" or "off" and controls snapshot mode for the given drive
177
@@ -XXX,XX +XXX,XX @@ the raw disk image you use is not written back. You can however force
178
the write back by pressing @key{C-a s} (@pxref{disk_images}).
179
ETEXI
180
181
-DEF("hdachs", HAS_ARG, QEMU_OPTION_hdachs, \
182
- "-hdachs c,h,s[,t]\n" \
183
- " force hard disk 0 physical geometry and the optional BIOS\n" \
184
- " translation (t=none or lba) (usually QEMU can guess them)\n",
185
- QEMU_ARCH_ALL)
186
-STEXI
187
-@item -hdachs @var{c},@var{h},@var{s},[,@var{t}]
188
-@findex -hdachs
189
-Force hard disk 0 physical geometry (1 <= @var{c} <= 16383, 1 <=
190
-@var{h} <= 16, 1 <= @var{s} <= 63) and optionally force the BIOS
191
-translation mode (@var{t}=none, lba or auto). Usually QEMU can guess
192
-all those parameters. This option is deprecated, please use
193
-@code{-device ide-hd,cyls=c,heads=h,secs=s,...} instead.
194
-ETEXI
195
-
196
DEF("fsdev", HAS_ARG, QEMU_OPTION_fsdev,
197
"-fsdev fsdriver,id=id[,path=path,][security_model={mapped-xattr|mapped-file|passthrough|none}]\n"
198
" [,writeout=immediate][,readonly][,socket=socket|sock_fd=sock_fd][,fmode=fmode][,dmode=dmode]\n"
34
--
199
--
35
2.13.6
200
2.13.6
36
201
37
202
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
From: Thomas Huth <thuth@redhat.com>
2
2
3
Only a few select machine types support floppy drives and there is
3
Looks like we forgot to announce the deprecation of these options in
4
actually nothing preventing us from using virtio here, so let's do it.
4
the corresponding chapter of the qemu-doc text, so let's do that now.
5
5
6
Reported-by: Christian Borntraeger <borntraeger@de.ibm.com>
6
Signed-off-by: Thomas Huth <thuth@redhat.com>
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
Reviewed-by: John Snow <jsnow@redhat.com>
8
Tested-by: Christian Borntraeger <borntraeger@de.ibm.com>
8
Reviewed-by: Markus Armbruster <armbru@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
10
---
11
tests/qemu-iotests/155 | 14 +++++++++-----
11
qemu-doc.texi | 15 +++++++++++++++
12
1 file changed, 9 insertions(+), 5 deletions(-)
12
1 file changed, 15 insertions(+)
13
13
14
diff --git a/tests/qemu-iotests/155 b/tests/qemu-iotests/155
14
diff --git a/qemu-doc.texi b/qemu-doc.texi
15
index XXXXXXX..XXXXXXX 100755
15
index XXXXXXX..XXXXXXX 100644
16
--- a/tests/qemu-iotests/155
16
--- a/qemu-doc.texi
17
+++ b/tests/qemu-iotests/155
17
+++ b/qemu-doc.texi
18
@@ -XXX,XX +XXX,XX @@ class BaseClass(iotests.QMPTestCase):
18
@@ -XXX,XX +XXX,XX @@ longer be directly supported in QEMU.
19
'file': {'driver': 'file',
19
The ``-drive if=scsi'' argument is replaced by the the
20
'filename': source_img}}
20
``-device BUS-TYPE'' argument combined with ``-drive if=none''.
21
self.vm.add_blockdev(self.qmp_to_opts(blockdev))
21
22
- self.vm.add_device('floppy,id=qdev0,drive=source')
22
+@subsection -drive cyls=...,heads=...,secs=...,trans=... (since 2.10.0)
23
+ self.vm.add_device('virtio-blk,id=qdev0,drive=source')
23
+
24
self.vm.launch()
24
+The drive geometry arguments are replaced by the the geometry arguments
25
25
+that can be specified with the ``-device'' parameter.
26
self.assertIntactSourceBackingChain()
26
+
27
@@ -XXX,XX +XXX,XX @@ class MirrorBaseClass(BaseClass):
27
+@subsection -drive serial=... (since 2.10.0)
28
def testFull(self):
28
+
29
self.runMirror('full')
29
+The drive serial argument is replaced by the the serial argument
30
30
+that can be specified with the ``-device'' parameter.
31
- node = self.findBlockNode('target', 'qdev0')
31
+
32
+ node = self.findBlockNode('target',
32
+@subsection -drive addr=... (since 2.10.0)
33
+ '/machine/peripheral/qdev0/virtio-backend')
33
+
34
self.assertCorrectBackingImage(node, None)
34
+The drive addr argument is replaced by the the addr argument
35
self.assertIntactSourceBackingChain()
35
+that can be specified with the ``-device'' parameter.
36
36
+
37
def testTop(self):
37
@subsection -net dump (since 2.10.0)
38
self.runMirror('top')
38
39
39
The ``--net dump'' argument is now replaced with the
40
- node = self.findBlockNode('target', 'qdev0')
41
+ node = self.findBlockNode('target',
42
+ '/machine/peripheral/qdev0/virtio-backend')
43
self.assertCorrectBackingImage(node, back2_img)
44
self.assertIntactSourceBackingChain()
45
46
def testNone(self):
47
self.runMirror('none')
48
49
- node = self.findBlockNode('target', 'qdev0')
50
+ node = self.findBlockNode('target',
51
+ '/machine/peripheral/qdev0/virtio-backend')
52
self.assertCorrectBackingImage(node, source_img)
53
self.assertIntactSourceBackingChain()
54
55
@@ -XXX,XX +XXX,XX @@ class TestCommit(BaseClass):
56
57
self.vm.event_wait('BLOCK_JOB_COMPLETED')
58
59
- node = self.findBlockNode(None, 'qdev0')
60
+ node = self.findBlockNode(None,
61
+ '/machine/peripheral/qdev0/virtio-backend')
62
self.assert_qmp(node, 'image' + '/backing-image' * 0 + '/filename',
63
back1_img)
64
self.assert_qmp(node, 'image' + '/backing-image' * 1 + '/filename',
65
--
40
--
66
2.13.6
41
2.13.6
67
42
68
43
diff view generated by jsdifflib
1
From: Fam Zheng <famz@redhat.com>
1
From: Fam Zheng <famz@redhat.com>
2
2
3
Signed-off-by: Fam Zheng <famz@redhat.com>
3
Signed-off-by: Fam Zheng <famz@redhat.com>
4
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
5
Reviewed-by: Kashyap Chamarthy <kchamart@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
5
---
8
qemu-img.texi | 8 ++++++++
6
include/block/block_int.h | 1 -
9
1 file changed, 8 insertions(+)
7
block/io.c | 18 ------------------
8
2 files changed, 19 deletions(-)
10
9
11
diff --git a/qemu-img.texi b/qemu-img.texi
10
diff --git a/include/block/block_int.h b/include/block/block_int.h
12
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
13
--- a/qemu-img.texi
12
--- a/include/block/block_int.h
14
+++ b/qemu-img.texi
13
+++ b/include/block/block_int.h
15
@@ -XXX,XX +XXX,XX @@ exclusive with the @var{-O} parameters. It is currently required to also use
14
@@ -XXX,XX +XXX,XX @@ bool blk_dev_is_tray_open(BlockBackend *blk);
16
the @var{-n} parameter to skip image creation. This restriction may be relaxed
15
bool blk_dev_is_medium_locked(BlockBackend *blk);
17
in a future release.
16
18
17
void bdrv_set_dirty(BlockDriverState *bs, int64_t offset, int64_t bytes);
19
+@item --force-share (-U)
18
-bool bdrv_requests_pending(BlockDriverState *bs);
20
+If specified, @code{qemu-img} will open the image in shared mode, allowing
19
21
+other QEMU processes to open it in write mode. For example, this can be used to
20
void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out);
22
+get the image information (with 'info' subcommand) when the image is used by a
21
void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in);
23
+running guest. Note that this could produce inconsistent results because of
22
diff --git a/block/io.c b/block/io.c
24
+concurrent metadata changes, etc. This option is only allowed when opening
23
index XXXXXXX..XXXXXXX 100644
25
+images in read-only mode.
24
--- a/block/io.c
26
+
25
+++ b/block/io.c
27
@item --backing-chain
26
@@ -XXX,XX +XXX,XX @@ void bdrv_disable_copy_on_read(BlockDriverState *bs)
28
will enumerate information about backing files in a disk image chain. Refer
27
assert(old >= 1);
29
below for further description.
28
}
29
30
-/* Check if any requests are in-flight (including throttled requests) */
31
-bool bdrv_requests_pending(BlockDriverState *bs)
32
-{
33
- BdrvChild *child;
34
-
35
- if (atomic_read(&bs->in_flight)) {
36
- return true;
37
- }
38
-
39
- QLIST_FOREACH(child, &bs->children, next) {
40
- if (bdrv_requests_pending(child->bs)) {
41
- return true;
42
- }
43
- }
44
-
45
- return false;
46
-}
47
-
48
typedef struct {
49
Coroutine *co;
50
BlockDriverState *bs;
30
--
51
--
31
2.13.6
52
2.13.6
32
53
33
54
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Reviewed-by: Fam Zheng <famz@redhat.com>
3
---
4
block/io.c | 6 ++++++
5
1 file changed, 6 insertions(+)
2
6
3
This test tries reopening a qcow2 image with valid and invalid
7
diff --git a/block/io.c b/block/io.c
4
options. This patch adds l2-cache-entry-size to the set.
5
6
Signed-off-by: Alberto Garcia <berto@igalia.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Message-id: 3d3b7d2dbfc020deaef60fb58739b0801eb9517c.1517840877.git.berto@igalia.com
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
12
tests/qemu-iotests/137 | 5 +++++
13
tests/qemu-iotests/137.out | 2 ++
14
2 files changed, 7 insertions(+)
15
16
diff --git a/tests/qemu-iotests/137 b/tests/qemu-iotests/137
17
index XXXXXXX..XXXXXXX 100755
18
--- a/tests/qemu-iotests/137
19
+++ b/tests/qemu-iotests/137
20
@@ -XXX,XX +XXX,XX @@ $QEMU_IO \
21
-c "reopen -o overlap-check.inactive-l2=off" \
22
-c "reopen -o cache-size=1M" \
23
-c "reopen -o l2-cache-size=512k" \
24
+ -c "reopen -o l2-cache-entry-size=512" \
25
+ -c "reopen -o l2-cache-entry-size=4k" \
26
+ -c "reopen -o l2-cache-entry-size=64k" \
27
-c "reopen -o refcount-cache-size=128k" \
28
-c "reopen -o cache-clean-interval=5" \
29
-c "reopen -o cache-clean-interval=0" \
30
@@ -XXX,XX +XXX,XX @@ $QEMU_IO \
31
-c "reopen -o cache-size=1M,l2-cache-size=2M" \
32
-c "reopen -o cache-size=1M,refcount-cache-size=2M" \
33
-c "reopen -o l2-cache-size=256T" \
34
+ -c "reopen -o l2-cache-entry-size=33k" \
35
+ -c "reopen -o l2-cache-entry-size=128k" \
36
-c "reopen -o refcount-cache-size=256T" \
37
-c "reopen -o overlap-check=constant,overlap-check.template=all" \
38
-c "reopen -o overlap-check=blubb" \
39
diff --git a/tests/qemu-iotests/137.out b/tests/qemu-iotests/137.out
40
index XXXXXXX..XXXXXXX 100644
8
index XXXXXXX..XXXXXXX 100644
41
--- a/tests/qemu-iotests/137.out
9
--- a/block/io.c
42
+++ b/tests/qemu-iotests/137.out
10
+++ b/block/io.c
43
@@ -XXX,XX +XXX,XX @@ cache-size, l2-cache-size and refcount-cache-size may not be set the same time
11
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
44
l2-cache-size may not exceed cache-size
12
BdrvNextIterator it;
45
refcount-cache-size may not exceed cache-size
13
GSList *aio_ctxs = NULL, *ctx;
46
L2 cache size too big
14
47
+L2 cache entry size must be a power of two between 512 and the cluster size (65536)
15
+ /* BDRV_POLL_WHILE() for a node can only be called from its own I/O thread
48
+L2 cache entry size must be a power of two between 512 and the cluster size (65536)
16
+ * or the main loop AioContext. We potentially use BDRV_POLL_WHILE() on
49
L2 cache size too big
17
+ * nodes in several different AioContexts, so make sure we're in the main
50
Conflicting values for qcow2 options 'overlap-check' ('constant') and 'overlap-check.template' ('all')
18
+ * context. */
51
Unsupported value 'blubb' for qcow2 option 'overlap-check'. Allowed are any of the following: none, constant, cached, all
19
+ assert(qemu_get_current_aio_context() == qemu_get_aio_context());
20
+
21
block_job_pause_all();
22
23
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
52
--
24
--
53
2.13.6
25
2.13.6
54
26
55
27
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
bdrv_drained_begin() doesn't increase bs->quiesce_counter recursively
2
and also doesn't notify other parent nodes of children, which both means
3
that the child nodes are not actually drained, and bdrv_drained_begin()
4
is providing useful functionality only on a single node.
2
5
3
This function was only using the BlockDriverState parameter to get the
6
To keep things consistent, we also shouldn't call the block driver
4
cache table size (since it was equal to the cluster size). This is no
7
callbacks recursively.
5
longer necessary so this parameter can be removed.
6
8
7
Signed-off-by: Alberto Garcia <berto@igalia.com>
9
A proper recursive drain version that provides an actually working
8
Reviewed-by: Eric Blake <eblake@redhat.com>
10
drained section for child nodes will be introduced later.
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
11
10
Message-id: 7c1b262344375d52544525f85bbbf0548d5ba575.1517840876.git.berto@igalia.com
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
Reviewed-by: Fam Zheng <famz@redhat.com>
12
---
14
---
13
block/qcow2-cache.c | 9 ++++-----
15
block/io.c | 16 +++++++++-------
14
1 file changed, 4 insertions(+), 5 deletions(-)
16
1 file changed, 9 insertions(+), 7 deletions(-)
15
17
16
diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c
18
diff --git a/block/io.c b/block/io.c
17
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
18
--- a/block/qcow2-cache.c
20
--- a/block/io.c
19
+++ b/block/qcow2-cache.c
21
+++ b/block/io.c
20
@@ -XXX,XX +XXX,XX @@ static inline const char *qcow2_cache_get_name(BDRVQcow2State *s, Qcow2Cache *c)
22
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_drain_invoke_entry(void *opaque)
23
}
24
25
/* Recursively call BlockDriver.bdrv_co_drain_begin/end callbacks */
26
-static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
27
+static void bdrv_drain_invoke(BlockDriverState *bs, bool begin, bool recursive)
28
{
29
BdrvChild *child, *tmp;
30
BdrvCoDrainData data = { .bs = bs, .done = false, .begin = begin};
31
@@ -XXX,XX +XXX,XX @@ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
32
bdrv_coroutine_enter(bs, data.co);
33
BDRV_POLL_WHILE(bs, !data.done);
34
35
- QLIST_FOREACH_SAFE(child, &bs->children, next, tmp) {
36
- bdrv_drain_invoke(child->bs, begin);
37
+ if (recursive) {
38
+ QLIST_FOREACH_SAFE(child, &bs->children, next, tmp) {
39
+ bdrv_drain_invoke(child->bs, begin, true);
40
+ }
21
}
41
}
22
}
42
}
23
43
24
-static void qcow2_cache_table_release(BlockDriverState *bs, Qcow2Cache *c,
44
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs)
25
- int i, int num_tables)
45
bdrv_parent_drained_begin(bs);
26
+static void qcow2_cache_table_release(Qcow2Cache *c, int i, int num_tables)
27
{
28
/* Using MADV_DONTNEED to discard memory is a Linux-specific feature */
29
#ifdef CONFIG_LINUX
30
@@ -XXX,XX +XXX,XX @@ void qcow2_cache_clean_unused(BlockDriverState *bs, Qcow2Cache *c)
31
}
32
33
if (to_clean > 0) {
34
- qcow2_cache_table_release(bs, c, i - to_clean, to_clean);
35
+ qcow2_cache_table_release(c, i - to_clean, to_clean);
36
}
37
}
46
}
38
47
39
@@ -XXX,XX +XXX,XX @@ int qcow2_cache_empty(BlockDriverState *bs, Qcow2Cache *c)
48
- bdrv_drain_invoke(bs, true);
40
c->entries[i].lru_counter = 0;
49
+ bdrv_drain_invoke(bs, true, false);
50
bdrv_drain_recurse(bs);
51
}
52
53
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
41
}
54
}
42
55
43
- qcow2_cache_table_release(bs, c, 0, c->size);
56
/* Re-enable things in child-to-parent order */
44
+ qcow2_cache_table_release(c, 0, c->size);
57
- bdrv_drain_invoke(bs, false);
45
58
+ bdrv_drain_invoke(bs, false, false);
46
c->lru_counter = 0;
59
bdrv_parent_drained_end(bs);
47
60
aio_enable_external(bdrv_get_aio_context(bs));
48
@@ -XXX,XX +XXX,XX @@ void qcow2_cache_discard(BlockDriverState *bs, Qcow2Cache *c, void *table)
49
c->entries[i].lru_counter = 0;
50
c->entries[i].dirty = false;
51
52
- qcow2_cache_table_release(bs, c, i, 1);
53
+ qcow2_cache_table_release(c, i, 1);
54
}
61
}
62
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
63
aio_context_acquire(aio_context);
64
aio_disable_external(aio_context);
65
bdrv_parent_drained_begin(bs);
66
- bdrv_drain_invoke(bs, true);
67
+ bdrv_drain_invoke(bs, true, true);
68
aio_context_release(aio_context);
69
70
if (!g_slist_find(aio_ctxs, aio_context)) {
71
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
72
73
/* Re-enable things in child-to-parent order */
74
aio_context_acquire(aio_context);
75
- bdrv_drain_invoke(bs, false);
76
+ bdrv_drain_invoke(bs, false, true);
77
bdrv_parent_drained_end(bs);
78
aio_enable_external(aio_context);
79
aio_context_release(aio_context);
55
--
80
--
56
2.13.6
81
2.13.6
57
82
58
83
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
The existing test is for bdrv_drain_all_begin/end() only. Generalise the
2
test case so that it can be run for the other variants as well. At the
3
moment this is only bdrv_drain_begin/end(), but in a while, we'll add
4
another one.
2
5
3
Similar to offset_to_l2_index(), this function takes a guest offset
6
Also, add a backing file to the test node to test whether the operations
4
and returns the index in the L2 slice that contains its L2 entry.
7
work recursively.
5
8
6
An L2 slice has currently the same size as an L2 table (one cluster),
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
so both functions return the same value for now.
10
---
11
tests/test-bdrv-drain.c | 69 ++++++++++++++++++++++++++++++++++++++++++++-----
12
1 file changed, 62 insertions(+), 7 deletions(-)
8
13
9
Signed-off-by: Alberto Garcia <berto@igalia.com>
14
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
10
Reviewed-by: Eric Blake <eblake@redhat.com>
11
Reviewed-by: Max Reitz <mreitz@redhat.com>
12
Message-id: a1c45c5c5a76146dd1712d8d1e7b409ad539c718.1517840877.git.berto@igalia.com
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
---
15
block/qcow2.h | 5 +++++
16
1 file changed, 5 insertions(+)
17
18
diff --git a/block/qcow2.h b/block/qcow2.h
19
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
20
--- a/block/qcow2.h
16
--- a/tests/test-bdrv-drain.c
21
+++ b/block/qcow2.h
17
+++ b/tests/test-bdrv-drain.c
22
@@ -XXX,XX +XXX,XX @@ static inline int offset_to_l2_index(BDRVQcow2State *s, int64_t offset)
18
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_test = {
23
return (offset >> s->cluster_bits) & (s->l2_size - 1);
19
20
.bdrv_co_drain_begin = bdrv_test_co_drain_begin,
21
.bdrv_co_drain_end = bdrv_test_co_drain_end,
22
+
23
+ .bdrv_child_perm = bdrv_format_default_perms,
24
};
25
26
static void aio_ret_cb(void *opaque, int ret)
27
@@ -XXX,XX +XXX,XX @@ static void aio_ret_cb(void *opaque, int ret)
28
*aio_ret = ret;
24
}
29
}
25
30
26
+static inline int offset_to_l2_slice_index(BDRVQcow2State *s, int64_t offset)
31
-static void test_drv_cb_drain_all(void)
32
+enum drain_type {
33
+ BDRV_DRAIN_ALL,
34
+ BDRV_DRAIN,
35
+};
36
+
37
+static void do_drain_begin(enum drain_type drain_type, BlockDriverState *bs)
27
+{
38
+{
28
+ return (offset >> s->cluster_bits) & (s->l2_slice_size - 1);
39
+ switch (drain_type) {
40
+ case BDRV_DRAIN_ALL: bdrv_drain_all_begin(); break;
41
+ case BDRV_DRAIN: bdrv_drained_begin(bs); break;
42
+ default: g_assert_not_reached();
43
+ }
29
+}
44
+}
30
+
45
+
31
static inline int64_t align_offset(int64_t offset, int n)
46
+static void do_drain_end(enum drain_type drain_type, BlockDriverState *bs)
47
+{
48
+ switch (drain_type) {
49
+ case BDRV_DRAIN_ALL: bdrv_drain_all_end(); break;
50
+ case BDRV_DRAIN: bdrv_drained_end(bs); break;
51
+ default: g_assert_not_reached();
52
+ }
53
+}
54
+
55
+static void test_drv_cb_common(enum drain_type drain_type, bool recursive)
32
{
56
{
33
offset = (offset + n - 1) & ~(n - 1);
57
BlockBackend *blk;
58
- BlockDriverState *bs;
59
- BDRVTestState *s;
60
+ BlockDriverState *bs, *backing;
61
+ BDRVTestState *s, *backing_s;
62
BlockAIOCB *acb;
63
int aio_ret;
64
65
@@ -XXX,XX +XXX,XX @@ static void test_drv_cb_drain_all(void)
66
s = bs->opaque;
67
blk_insert_bs(blk, bs, &error_abort);
68
69
+ backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort);
70
+ backing_s = backing->opaque;
71
+ bdrv_set_backing_hd(bs, backing, &error_abort);
72
+
73
/* Simple bdrv_drain_all_begin/end pair, check that CBs are called */
74
g_assert_cmpint(s->drain_count, ==, 0);
75
- bdrv_drain_all_begin();
76
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
77
+
78
+ do_drain_begin(drain_type, bs);
79
+
80
g_assert_cmpint(s->drain_count, ==, 1);
81
- bdrv_drain_all_end();
82
+ g_assert_cmpint(backing_s->drain_count, ==, !!recursive);
83
+
84
+ do_drain_end(drain_type, bs);
85
+
86
g_assert_cmpint(s->drain_count, ==, 0);
87
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
88
89
/* Now do the same while a request is pending */
90
aio_ret = -EINPROGRESS;
91
@@ -XXX,XX +XXX,XX @@ static void test_drv_cb_drain_all(void)
92
g_assert_cmpint(aio_ret, ==, -EINPROGRESS);
93
94
g_assert_cmpint(s->drain_count, ==, 0);
95
- bdrv_drain_all_begin();
96
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
97
+
98
+ do_drain_begin(drain_type, bs);
99
+
100
g_assert_cmpint(aio_ret, ==, 0);
101
g_assert_cmpint(s->drain_count, ==, 1);
102
- bdrv_drain_all_end();
103
+ g_assert_cmpint(backing_s->drain_count, ==, !!recursive);
104
+
105
+ do_drain_end(drain_type, bs);
106
+
107
g_assert_cmpint(s->drain_count, ==, 0);
108
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
109
110
+ bdrv_unref(backing);
111
bdrv_unref(bs);
112
blk_unref(blk);
113
}
114
115
+static void test_drv_cb_drain_all(void)
116
+{
117
+ test_drv_cb_common(BDRV_DRAIN_ALL, true);
118
+}
119
+
120
+static void test_drv_cb_drain(void)
121
+{
122
+ test_drv_cb_common(BDRV_DRAIN, false);
123
+}
124
+
125
int main(int argc, char **argv)
126
{
127
bdrv_init();
128
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
129
g_test_init(&argc, &argv, NULL);
130
131
g_test_add_func("/bdrv-drain/driver-cb/drain_all", test_drv_cb_drain_all);
132
+ g_test_add_func("/bdrv-drain/driver-cb/drain", test_drv_cb_drain);
133
134
return g_test_run();
135
}
34
--
136
--
35
2.13.6
137
2.13.6
36
138
37
139
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
This is currently only working correctly for bdrv_drain(), not for
2
bdrv_drain_all(). Leave a comment for the drain_all case, we'll address
3
it later.
2
4
3
This function was only using the BlockDriverState parameter to pass it
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
to qcow2_cache_table_release(). This is no longer necessary so this
6
---
5
parameter can be removed.
7
tests/test-bdrv-drain.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
8
1 file changed, 45 insertions(+)
6
9
7
Signed-off-by: Alberto Garcia <berto@igalia.com>
10
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
8
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Message-id: b74f17591af52f201de0ea3a3b2dd0a81932334d.1517840876.git.berto@igalia.com
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
13
block/qcow2.h | 2 +-
14
block/qcow2-cache.c | 2 +-
15
block/qcow2.c | 4 ++--
16
3 files changed, 4 insertions(+), 4 deletions(-)
17
18
diff --git a/block/qcow2.h b/block/qcow2.h
19
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
20
--- a/block/qcow2.h
12
--- a/tests/test-bdrv-drain.c
21
+++ b/block/qcow2.h
13
+++ b/tests/test-bdrv-drain.c
22
@@ -XXX,XX +XXX,XX @@ int qcow2_cache_set_dependency(BlockDriverState *bs, Qcow2Cache *c,
14
@@ -XXX,XX +XXX,XX @@ static void test_drv_cb_drain(void)
23
Qcow2Cache *dependency);
15
test_drv_cb_common(BDRV_DRAIN, false);
24
void qcow2_cache_depends_on_flush(Qcow2Cache *c);
25
26
-void qcow2_cache_clean_unused(BlockDriverState *bs, Qcow2Cache *c);
27
+void qcow2_cache_clean_unused(Qcow2Cache *c);
28
int qcow2_cache_empty(BlockDriverState *bs, Qcow2Cache *c);
29
30
int qcow2_cache_get(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
31
diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c
32
index XXXXXXX..XXXXXXX 100644
33
--- a/block/qcow2-cache.c
34
+++ b/block/qcow2-cache.c
35
@@ -XXX,XX +XXX,XX @@ static inline bool can_clean_entry(Qcow2Cache *c, int i)
36
t->lru_counter <= c->cache_clean_lru_counter;
37
}
16
}
38
17
39
-void qcow2_cache_clean_unused(BlockDriverState *bs, Qcow2Cache *c)
18
+static void test_quiesce_common(enum drain_type drain_type, bool recursive)
40
+void qcow2_cache_clean_unused(Qcow2Cache *c)
19
+{
20
+ BlockBackend *blk;
21
+ BlockDriverState *bs, *backing;
22
+
23
+ blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
24
+ bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR,
25
+ &error_abort);
26
+ blk_insert_bs(blk, bs, &error_abort);
27
+
28
+ backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort);
29
+ bdrv_set_backing_hd(bs, backing, &error_abort);
30
+
31
+ g_assert_cmpint(bs->quiesce_counter, ==, 0);
32
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
33
+
34
+ do_drain_begin(drain_type, bs);
35
+
36
+ g_assert_cmpint(bs->quiesce_counter, ==, 1);
37
+ g_assert_cmpint(backing->quiesce_counter, ==, !!recursive);
38
+
39
+ do_drain_end(drain_type, bs);
40
+
41
+ g_assert_cmpint(bs->quiesce_counter, ==, 0);
42
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
43
+
44
+ bdrv_unref(backing);
45
+ bdrv_unref(bs);
46
+ blk_unref(blk);
47
+}
48
+
49
+static void test_quiesce_drain_all(void)
50
+{
51
+ // XXX drain_all doesn't quiesce
52
+ //test_quiesce_common(BDRV_DRAIN_ALL, true);
53
+}
54
+
55
+static void test_quiesce_drain(void)
56
+{
57
+ test_quiesce_common(BDRV_DRAIN, false);
58
+}
59
+
60
int main(int argc, char **argv)
41
{
61
{
42
int i = 0;
62
bdrv_init();
43
while (i < c->size) {
63
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
44
diff --git a/block/qcow2.c b/block/qcow2.c
64
g_test_add_func("/bdrv-drain/driver-cb/drain_all", test_drv_cb_drain_all);
45
index XXXXXXX..XXXXXXX 100644
65
g_test_add_func("/bdrv-drain/driver-cb/drain", test_drv_cb_drain);
46
--- a/block/qcow2.c
66
47
+++ b/block/qcow2.c
67
+ g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all);
48
@@ -XXX,XX +XXX,XX @@ static void cache_clean_timer_cb(void *opaque)
68
+ g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain);
49
{
69
+
50
BlockDriverState *bs = opaque;
70
return g_test_run();
51
BDRVQcow2State *s = bs->opaque;
52
- qcow2_cache_clean_unused(bs, s->l2_table_cache);
53
- qcow2_cache_clean_unused(bs, s->refcount_block_cache);
54
+ qcow2_cache_clean_unused(s->l2_table_cache);
55
+ qcow2_cache_clean_unused(s->refcount_block_cache);
56
timer_mod(s->cache_clean_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
57
(int64_t) s->cache_clean_interval * 1000);
58
}
71
}
59
--
72
--
60
2.13.6
73
2.13.6
61
74
62
75
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
Block jobs already paused themselves when their main BlockBackend
2
entered a drained section. This is not good enough: We also want to
3
pause a block job and may not submit new requests if, for example, the
4
mirror target node should be drained.
2
5
3
The table size in the qcow2 cache is currently equal to the cluster
6
This implements .drained_begin/end callbacks in child_job in order to
4
size. This doesn't allow us to use the cache memory efficiently,
7
consider all block nodes related to the job, and removes the
5
particularly with large cluster sizes, so we need to be able to have
8
BlockBackend callbacks which are unnecessary now because the root of the
6
smaller cache tables that are independent from the cluster size. This
9
job main BlockBackend is always referenced with a child_job, too.
7
patch adds a new field to Qcow2Cache that we can use instead of the
8
cluster size.
9
10
10
The current table size is still being initialized to the cluster size,
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
so there are no semantic changes yet, but this patch will allow us to
12
---
12
prepare the rest of the code and simplify a few function calls.
13
blockjob.c | 22 +++++++++-------------
14
1 file changed, 9 insertions(+), 13 deletions(-)
13
15
14
Signed-off-by: Alberto Garcia <berto@igalia.com>
16
diff --git a/blockjob.c b/blockjob.c
15
Reviewed-by: Eric Blake <eblake@redhat.com>
16
Reviewed-by: Max Reitz <mreitz@redhat.com>
17
Message-id: 67a1bf9e55f417005c567bead95a018dc34bc687.1517840876.git.berto@igalia.com
18
Signed-off-by: Max Reitz <mreitz@redhat.com>
19
---
20
block/qcow2-cache.c | 29 ++++++++++++++---------------
21
1 file changed, 14 insertions(+), 15 deletions(-)
22
23
diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c
24
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
25
--- a/block/qcow2-cache.c
18
--- a/blockjob.c
26
+++ b/block/qcow2-cache.c
19
+++ b/blockjob.c
27
@@ -XXX,XX +XXX,XX @@ struct Qcow2Cache {
20
@@ -XXX,XX +XXX,XX @@ static char *child_job_get_parent_desc(BdrvChild *c)
28
Qcow2CachedTable *entries;
21
job->id);
29
struct Qcow2Cache *depends;
22
}
30
int size;
23
31
+ int table_size;
24
-static const BdrvChildRole child_job = {
32
bool depends_on_flush;
25
- .get_parent_desc = child_job_get_parent_desc,
33
void *table_array;
26
- .stay_at_node = true,
34
uint64_t lru_counter;
27
-};
35
@@ -XXX,XX +XXX,XX @@ struct Qcow2Cache {
28
-
36
static inline void *qcow2_cache_get_table_addr(BlockDriverState *bs,
29
-static void block_job_drained_begin(void *opaque)
37
Qcow2Cache *c, int table)
30
+static void child_job_drained_begin(BdrvChild *c)
38
{
31
{
39
- BDRVQcow2State *s = bs->opaque;
32
- BlockJob *job = opaque;
40
- return (uint8_t *) c->table_array + (size_t) table * s->cluster_size;
33
+ BlockJob *job = c->opaque;
41
+ return (uint8_t *) c->table_array + (size_t) table * c->table_size;
34
block_job_pause(job);
42
}
35
}
43
36
44
static inline int qcow2_cache_get_table_idx(BlockDriverState *bs,
37
-static void block_job_drained_end(void *opaque)
45
Qcow2Cache *c, void *table)
38
+static void child_job_drained_end(BdrvChild *c)
46
{
39
{
47
- BDRVQcow2State *s = bs->opaque;
40
- BlockJob *job = opaque;
48
ptrdiff_t table_offset = (uint8_t *) table - (uint8_t *) c->table_array;
41
+ BlockJob *job = c->opaque;
49
- int idx = table_offset / s->cluster_size;
42
block_job_resume(job);
50
- assert(idx >= 0 && idx < c->size && table_offset % s->cluster_size == 0);
51
+ int idx = table_offset / c->table_size;
52
+ assert(idx >= 0 && idx < c->size && table_offset % c->table_size == 0);
53
return idx;
54
}
43
}
55
44
56
@@ -XXX,XX +XXX,XX @@ static void qcow2_cache_table_release(BlockDriverState *bs, Qcow2Cache *c,
45
-static const BlockDevOps block_job_dev_ops = {
57
{
46
- .drained_begin = block_job_drained_begin,
58
/* Using MADV_DONTNEED to discard memory is a Linux-specific feature */
47
- .drained_end = block_job_drained_end,
59
#ifdef CONFIG_LINUX
48
+static const BdrvChildRole child_job = {
60
- BDRVQcow2State *s = bs->opaque;
49
+ .get_parent_desc = child_job_get_parent_desc,
61
void *t = qcow2_cache_get_table_addr(bs, c, i);
50
+ .drained_begin = child_job_drained_begin,
62
int align = getpagesize();
51
+ .drained_end = child_job_drained_end,
63
- size_t mem_size = (size_t) s->cluster_size * num_tables;
52
+ .stay_at_node = true,
64
+ size_t mem_size = (size_t) c->table_size * num_tables;
53
};
65
size_t offset = QEMU_ALIGN_UP((uintptr_t) t, align) - (uintptr_t) t;
54
66
size_t length = QEMU_ALIGN_DOWN(mem_size - offset, align);
55
void block_job_remove_all_bdrv(BlockJob *job)
67
if (mem_size > offset && length > 0) {
56
@@ -XXX,XX +XXX,XX @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
68
@@ -XXX,XX +XXX,XX @@ Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables)
57
block_job_add_bdrv(job, "main node", bs, 0, BLK_PERM_ALL, &error_abort);
69
58
bs->job = job;
70
c = g_new0(Qcow2Cache, 1);
59
71
c->size = num_tables;
60
- blk_set_dev_ops(blk, &block_job_dev_ops, job);
72
+ c->table_size = s->cluster_size;
61
bdrv_op_unblock(bs, BLOCK_OP_TYPE_DATAPLANE, job->blocker);
73
c->entries = g_try_new0(Qcow2CachedTable, num_tables);
62
74
c->table_array = qemu_try_blockalign(bs->file->bs,
63
QLIST_INSERT_HEAD(&block_jobs, job, job_list);
75
- (size_t) num_tables * s->cluster_size);
76
+ (size_t) num_tables * c->table_size);
77
78
if (!c->entries || !c->table_array) {
79
qemu_vfree(c->table_array);
80
@@ -XXX,XX +XXX,XX @@ static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i)
81
82
if (c == s->refcount_block_cache) {
83
ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_REFCOUNT_BLOCK,
84
- c->entries[i].offset, s->cluster_size);
85
+ c->entries[i].offset, c->table_size);
86
} else if (c == s->l2_table_cache) {
87
ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L2,
88
- c->entries[i].offset, s->cluster_size);
89
+ c->entries[i].offset, c->table_size);
90
} else {
91
ret = qcow2_pre_write_overlap_check(bs, 0,
92
- c->entries[i].offset, s->cluster_size);
93
+ c->entries[i].offset, c->table_size);
94
}
95
96
if (ret < 0) {
97
@@ -XXX,XX +XXX,XX @@ static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i)
98
}
99
100
ret = bdrv_pwrite(bs->file, c->entries[i].offset,
101
- qcow2_cache_get_table_addr(bs, c, i), s->cluster_size);
102
+ qcow2_cache_get_table_addr(bs, c, i), c->table_size);
103
if (ret < 0) {
104
return ret;
105
}
106
@@ -XXX,XX +XXX,XX @@ static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
107
trace_qcow2_cache_get(qemu_coroutine_self(), c == s->l2_table_cache,
108
offset, read_from_disk);
109
110
- if (offset_into_cluster(s, offset)) {
111
+ if (!QEMU_IS_ALIGNED(offset, c->table_size)) {
112
qcow2_signal_corruption(bs, true, -1, -1, "Cannot get entry from %s "
113
"cache: Offset %#" PRIx64 " is unaligned",
114
qcow2_cache_get_name(s, c), offset);
115
@@ -XXX,XX +XXX,XX @@ static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
116
}
117
118
/* Check if the table is already cached */
119
- i = lookup_index = (offset / s->cluster_size * 4) % c->size;
120
+ i = lookup_index = (offset / c->table_size * 4) % c->size;
121
do {
122
const Qcow2CachedTable *t = &c->entries[i];
123
if (t->offset == offset) {
124
@@ -XXX,XX +XXX,XX @@ static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
125
126
ret = bdrv_pread(bs->file, offset,
127
qcow2_cache_get_table_addr(bs, c, i),
128
- s->cluster_size);
129
+ c->table_size);
130
if (ret < 0) {
131
return ret;
132
}
133
--
64
--
134
2.13.6
65
2.13.6
135
66
136
67
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
Block jobs must be paused if any of the involved nodes are drained.
2
2
3
Instead of expecting the current size to be 0, query it and allocate
4
only the area [current_size, offset) if preallocation is requested.
5
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
4
---
10
block/gluster.c | 21 +++++++++++++++++++--
5
tests/test-bdrv-drain.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++
11
1 file changed, 19 insertions(+), 2 deletions(-)
6
1 file changed, 121 insertions(+)
12
7
13
diff --git a/block/gluster.c b/block/gluster.c
8
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
14
index XXXXXXX..XXXXXXX 100644
9
index XXXXXXX..XXXXXXX 100644
15
--- a/block/gluster.c
10
--- a/tests/test-bdrv-drain.c
16
+++ b/block/gluster.c
11
+++ b/tests/test-bdrv-drain.c
17
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qemu_gluster_co_pwrite_zeroes(BlockDriverState *bs,
12
@@ -XXX,XX +XXX,XX @@
18
static int qemu_gluster_do_truncate(struct glfs_fd *fd, int64_t offset,
13
19
PreallocMode prealloc, Error **errp)
14
#include "qemu/osdep.h"
20
{
15
#include "block/block.h"
21
+ int64_t current_length;
16
+#include "block/blockjob_int.h"
17
#include "sysemu/block-backend.h"
18
#include "qapi/error.h"
19
20
@@ -XXX,XX +XXX,XX @@ static void test_quiesce_drain(void)
21
test_quiesce_common(BDRV_DRAIN, false);
22
}
23
22
+
24
+
23
+ current_length = glfs_lseek(fd, 0, SEEK_END);
25
+typedef struct TestBlockJob {
24
+ if (current_length < 0) {
26
+ BlockJob common;
25
+ error_setg_errno(errp, errno, "Failed to determine current size");
27
+ bool should_complete;
26
+ return -errno;
28
+} TestBlockJob;
29
+
30
+static void test_job_completed(BlockJob *job, void *opaque)
31
+{
32
+ block_job_completed(job, 0);
33
+}
34
+
35
+static void coroutine_fn test_job_start(void *opaque)
36
+{
37
+ TestBlockJob *s = opaque;
38
+
39
+ while (!s->should_complete) {
40
+ block_job_sleep_ns(&s->common, 100000);
27
+ }
41
+ }
28
+
42
+
29
+ if (current_length > offset && prealloc != PREALLOC_MODE_OFF) {
43
+ block_job_defer_to_main_loop(&s->common, test_job_completed, NULL);
30
+ error_setg(errp, "Cannot use preallocation for shrinking files");
44
+}
31
+ return -ENOTSUP;
45
+
46
+static void test_job_complete(BlockJob *job, Error **errp)
47
+{
48
+ TestBlockJob *s = container_of(job, TestBlockJob, common);
49
+ s->should_complete = true;
50
+}
51
+
52
+BlockJobDriver test_job_driver = {
53
+ .instance_size = sizeof(TestBlockJob),
54
+ .start = test_job_start,
55
+ .complete = test_job_complete,
56
+};
57
+
58
+static void test_blockjob_common(enum drain_type drain_type)
59
+{
60
+ BlockBackend *blk_src, *blk_target;
61
+ BlockDriverState *src, *target;
62
+ BlockJob *job;
63
+ int ret;
64
+
65
+ src = bdrv_new_open_driver(&bdrv_test, "source", BDRV_O_RDWR,
66
+ &error_abort);
67
+ blk_src = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
68
+ blk_insert_bs(blk_src, src, &error_abort);
69
+
70
+ target = bdrv_new_open_driver(&bdrv_test, "target", BDRV_O_RDWR,
71
+ &error_abort);
72
+ blk_target = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
73
+ blk_insert_bs(blk_target, target, &error_abort);
74
+
75
+ job = block_job_create("job0", &test_job_driver, src, 0, BLK_PERM_ALL, 0,
76
+ 0, NULL, NULL, &error_abort);
77
+ block_job_add_bdrv(job, "target", target, 0, BLK_PERM_ALL, &error_abort);
78
+ block_job_start(job);
79
+
80
+ g_assert_cmpint(job->pause_count, ==, 0);
81
+ g_assert_false(job->paused);
82
+ g_assert_false(job->busy); /* We're in block_job_sleep_ns() */
83
+
84
+ do_drain_begin(drain_type, src);
85
+
86
+ if (drain_type == BDRV_DRAIN_ALL) {
87
+ /* bdrv_drain_all() drains both src and target, and involves an
88
+ * additional block_job_pause_all() */
89
+ g_assert_cmpint(job->pause_count, ==, 3);
90
+ } else {
91
+ g_assert_cmpint(job->pause_count, ==, 1);
32
+ }
92
+ }
93
+ /* XXX We don't wait until the job is actually paused. Is this okay? */
94
+ /* g_assert_true(job->paused); */
95
+ g_assert_false(job->busy); /* The job is paused */
33
+
96
+
34
+ if (current_length == offset) {
97
+ do_drain_end(drain_type, src);
35
+ return 0;
98
+
99
+ g_assert_cmpint(job->pause_count, ==, 0);
100
+ g_assert_false(job->paused);
101
+ g_assert_false(job->busy); /* We're in block_job_sleep_ns() */
102
+
103
+ do_drain_begin(drain_type, target);
104
+
105
+ if (drain_type == BDRV_DRAIN_ALL) {
106
+ /* bdrv_drain_all() drains both src and target, and involves an
107
+ * additional block_job_pause_all() */
108
+ g_assert_cmpint(job->pause_count, ==, 3);
109
+ } else {
110
+ g_assert_cmpint(job->pause_count, ==, 1);
36
+ }
111
+ }
112
+ /* XXX We don't wait until the job is actually paused. Is this okay? */
113
+ /* g_assert_true(job->paused); */
114
+ g_assert_false(job->busy); /* The job is paused */
37
+
115
+
38
switch (prealloc) {
116
+ do_drain_end(drain_type, target);
39
#ifdef CONFIG_GLUSTERFS_FALLOCATE
117
+
40
case PREALLOC_MODE_FALLOC:
118
+ g_assert_cmpint(job->pause_count, ==, 0);
41
- if (glfs_fallocate(fd, 0, 0, offset)) {
119
+ g_assert_false(job->paused);
42
+ if (glfs_fallocate(fd, 0, current_length, offset - current_length)) {
120
+ g_assert_false(job->busy); /* We're in block_job_sleep_ns() */
43
error_setg_errno(errp, errno, "Could not preallocate data");
121
+
44
return -errno;
122
+ ret = block_job_complete_sync(job, &error_abort);
45
}
123
+ g_assert_cmpint(ret, ==, 0);
46
@@ -XXX,XX +XXX,XX @@ static int qemu_gluster_do_truncate(struct glfs_fd *fd, int64_t offset,
124
+
47
error_setg_errno(errp, errno, "Could not resize file");
125
+ blk_unref(blk_src);
48
return -errno;
126
+ blk_unref(blk_target);
49
}
127
+ bdrv_unref(src);
50
- if (glfs_zerofill(fd, 0, offset)) {
128
+ bdrv_unref(target);
51
+ if (glfs_zerofill(fd, current_length, offset - current_length)) {
129
+}
52
error_setg_errno(errp, errno, "Could not zerofill the new area");
130
+
53
return -errno;
131
+static void test_blockjob_drain_all(void)
54
}
132
+{
133
+ test_blockjob_common(BDRV_DRAIN_ALL);
134
+}
135
+
136
+static void test_blockjob_drain(void)
137
+{
138
+ test_blockjob_common(BDRV_DRAIN);
139
+}
140
+
141
int main(int argc, char **argv)
142
{
143
bdrv_init();
144
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
145
g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all);
146
g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain);
147
148
+ g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all);
149
+ g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain);
150
+
151
return g_test_run();
152
}
55
--
153
--
56
2.13.6
154
2.13.6
57
155
58
156
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
Block jobs are already paused using the BdrvChildRole drain callbacks,
2
so we don't need an additional block_job_pause_all() call.
2
3
3
sd_prealloc() will now preallocate the area [old_size, new_size). As
4
before, it rounds to buf_size and may thus overshoot and preallocate
5
areas that were not requested to be preallocated. For image creation,
6
this is no change in behavior. For truncation, this is in accordance
7
with the documentation for preallocated truncation.
8
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
Reviewed-by: Eric Blake <eblake@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
5
---
13
block/sheepdog.c | 16 +++++-----------
6
block/io.c | 4 ----
14
1 file changed, 5 insertions(+), 11 deletions(-)
7
tests/test-bdrv-drain.c | 10 ++++------
8
2 files changed, 4 insertions(+), 10 deletions(-)
15
9
16
diff --git a/block/sheepdog.c b/block/sheepdog.c
10
diff --git a/block/io.c b/block/io.c
17
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
18
--- a/block/sheepdog.c
12
--- a/block/io.c
19
+++ b/block/sheepdog.c
13
+++ b/block/io.c
20
@@ -XXX,XX +XXX,XX @@ static int do_sd_create(BDRVSheepdogState *s, uint32_t *vdi_id, int snapshot,
14
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
21
return 0;
15
* context. */
16
assert(qemu_get_current_aio_context() == qemu_get_aio_context());
17
18
- block_job_pause_all();
19
-
20
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
21
AioContext *aio_context = bdrv_get_aio_context(bs);
22
23
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
24
aio_enable_external(aio_context);
25
aio_context_release(aio_context);
26
}
27
-
28
- block_job_resume_all();
22
}
29
}
23
30
24
-static int sd_prealloc(BlockDriverState *bs, Error **errp)
31
void bdrv_drain_all(void)
25
+static int sd_prealloc(BlockDriverState *bs, int64_t old_size, int64_t new_size,
32
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
26
+ Error **errp)
33
index XXXXXXX..XXXXXXX 100644
27
{
34
--- a/tests/test-bdrv-drain.c
28
BlockBackend *blk = NULL;
35
+++ b/tests/test-bdrv-drain.c
29
BDRVSheepdogState *base = bs->opaque;
36
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common(enum drain_type drain_type)
30
unsigned long buf_size;
37
do_drain_begin(drain_type, src);
31
uint32_t idx, max_idx;
38
32
uint32_t object_size;
39
if (drain_type == BDRV_DRAIN_ALL) {
33
- int64_t vdi_size;
40
- /* bdrv_drain_all() drains both src and target, and involves an
34
void *buf = NULL;
41
- * additional block_job_pause_all() */
35
int ret;
42
- g_assert_cmpint(job->pause_count, ==, 3);
36
43
+ /* bdrv_drain_all() drains both src and target */
37
@@ -XXX,XX +XXX,XX @@ static int sd_prealloc(BlockDriverState *bs, Error **errp)
44
+ g_assert_cmpint(job->pause_count, ==, 2);
38
45
} else {
39
blk_set_allow_write_beyond_eof(blk, true);
46
g_assert_cmpint(job->pause_count, ==, 1);
40
47
}
41
- vdi_size = blk_getlength(blk);
48
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common(enum drain_type drain_type)
42
- if (vdi_size < 0) {
49
do_drain_begin(drain_type, target);
43
- ret = vdi_size;
50
44
- goto out;
51
if (drain_type == BDRV_DRAIN_ALL) {
45
- }
52
- /* bdrv_drain_all() drains both src and target, and involves an
46
-
53
- * additional block_job_pause_all() */
47
object_size = (UINT32_C(1) << base->inode.block_size_shift);
54
- g_assert_cmpint(job->pause_count, ==, 3);
48
buf_size = MIN(object_size, SD_DATA_OBJ_SIZE);
55
+ /* bdrv_drain_all() drains both src and target */
49
buf = g_malloc0(buf_size);
56
+ g_assert_cmpint(job->pause_count, ==, 2);
50
57
} else {
51
- max_idx = DIV_ROUND_UP(vdi_size, buf_size);
58
g_assert_cmpint(job->pause_count, ==, 1);
52
+ max_idx = DIV_ROUND_UP(new_size, buf_size);
53
54
- for (idx = 0; idx < max_idx; idx++) {
55
+ for (idx = old_size / buf_size; idx < max_idx; idx++) {
56
/*
57
* The created image can be a cloned image, so we need to read
58
* a data from the source image.
59
@@ -XXX,XX +XXX,XX @@ static int sd_create(const char *filename, QemuOpts *opts,
60
goto out;
61
}
62
63
- ret = sd_prealloc(bs, errp);
64
+ ret = sd_prealloc(bs, 0, s->inode.vdi_size, errp);
65
66
bdrv_unref(bs);
67
}
59
}
68
--
60
--
69
2.13.6
61
2.13.6
70
62
71
63
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
bdrv_do_drained_begin() restricts the call of parent callbacks and
2
aio_disable_external() to the outermost drain section, but the block
3
driver callbacks are always called. bdrv_do_drained_end() must match
4
this behaviour, otherwise nodes stay drained even if begin/end calls
5
were balanced.
2
6
3
This function doesn't need any changes to support L2 slices, but since
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
it's now dealing with slices intead of full tables, the l2_table
8
---
5
variable is renamed for clarity.
9
block/io.c | 12 +++++++-----
10
1 file changed, 7 insertions(+), 5 deletions(-)
6
11
7
Signed-off-by: Alberto Garcia <berto@igalia.com>
12
diff --git a/block/io.c b/block/io.c
8
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Message-id: 812b0c3505bb1687e51285dccf1a94f0cecb1f74.1517840877.git.berto@igalia.com
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
13
block/qcow2-cluster.c | 8 ++++----
14
1 file changed, 4 insertions(+), 4 deletions(-)
15
16
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
17
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
18
--- a/block/qcow2-cluster.c
14
--- a/block/io.c
19
+++ b/block/qcow2-cluster.c
15
+++ b/block/io.c
20
@@ -XXX,XX +XXX,XX @@ fail:
16
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs)
17
18
void bdrv_drained_end(BlockDriverState *bs)
19
{
20
+ int old_quiesce_counter;
21
+
22
if (qemu_in_coroutine()) {
23
bdrv_co_yield_to_drain(bs, false);
24
return;
25
}
26
assert(bs->quiesce_counter > 0);
27
- if (atomic_fetch_dec(&bs->quiesce_counter) > 1) {
28
- return;
29
- }
30
+ old_quiesce_counter = atomic_fetch_dec(&bs->quiesce_counter);
31
32
/* Re-enable things in child-to-parent order */
33
bdrv_drain_invoke(bs, false, false);
34
- bdrv_parent_drained_end(bs);
35
- aio_enable_external(bdrv_get_aio_context(bs));
36
+ if (old_quiesce_counter == 1) {
37
+ bdrv_parent_drained_end(bs);
38
+ aio_enable_external(bdrv_get_aio_context(bs));
39
+ }
21
}
40
}
22
41
23
/*
42
/*
24
- * Checks how many clusters in a given L2 table are contiguous in the image
25
+ * Checks how many clusters in a given L2 slice are contiguous in the image
26
* file. As soon as one of the flags in the bitmask stop_flags changes compared
27
* to the first cluster, the search is stopped and the cluster is not counted
28
* as contiguous. (This allows it, for example, to stop at the first compressed
29
* cluster which may require a different handling)
30
*/
31
static int count_contiguous_clusters(int nb_clusters, int cluster_size,
32
- uint64_t *l2_table, uint64_t stop_flags)
33
+ uint64_t *l2_slice, uint64_t stop_flags)
34
{
35
int i;
36
QCow2ClusterType first_cluster_type;
37
uint64_t mask = stop_flags | L2E_OFFSET_MASK | QCOW_OFLAG_COMPRESSED;
38
- uint64_t first_entry = be64_to_cpu(l2_table[0]);
39
+ uint64_t first_entry = be64_to_cpu(l2_slice[0]);
40
uint64_t offset = first_entry & mask;
41
42
if (!offset) {
43
@@ -XXX,XX +XXX,XX @@ static int count_contiguous_clusters(int nb_clusters, int cluster_size,
44
first_cluster_type == QCOW2_CLUSTER_ZERO_ALLOC);
45
46
for (i = 0; i < nb_clusters; i++) {
47
- uint64_t l2_entry = be64_to_cpu(l2_table[i]) & mask;
48
+ uint64_t l2_entry = be64_to_cpu(l2_slice[i]) & mask;
49
if (offset + (uint64_t) i * cluster_size != l2_entry) {
50
break;
51
}
52
--
43
--
53
2.13.6
44
2.13.6
54
45
55
46
diff view generated by jsdifflib
1
From: "Daniel P. Berrange" <berrange@redhat.com>
2
3
qemu-io puts the TTY into non-canonical mode, which means no EOF processing is
4
done and thus getchar() will never return the EOF constant. Instead we have to
5
query the TTY attributes to determine the configured EOF character (usually
6
Ctrl-D / 0x4), and then explicitly check for that value. This fixes the
7
regression that prevented Ctrl-D from triggering an exit of qemu-io that has
8
existed since readline was first added in
9
10
commit 0cf17e181798063c3824c8200ba46f25f54faa1a
11
Author: Stefan Hajnoczi <stefanha@redhat.com>
12
Date: Thu Nov 14 11:54:17 2013 +0100
13
14
qemu-io: use readline.c
15
16
It also ensures that a newline is printed when exiting, to complete the
17
line output by the "qemu-io> " prompt.
18
19
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
20
Reviewed-by: Eric Blake <eblake@redhat.com>
21
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
22
---
2
---
23
qemu-io.c | 27 ++++++++++++++++++++++++++-
3
tests/test-bdrv-drain.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++
24
1 file changed, 26 insertions(+), 1 deletion(-)
4
1 file changed, 57 insertions(+)
25
5
26
diff --git a/qemu-io.c b/qemu-io.c
6
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
27
index XXXXXXX..XXXXXXX 100644
7
index XXXXXXX..XXXXXXX 100644
28
--- a/qemu-io.c
8
--- a/tests/test-bdrv-drain.c
29
+++ b/qemu-io.c
9
+++ b/tests/test-bdrv-drain.c
30
@@ -XXX,XX +XXX,XX @@
10
@@ -XXX,XX +XXX,XX @@ static void aio_ret_cb(void *opaque, int ret)
31
#include "qemu/osdep.h"
11
enum drain_type {
32
#include <getopt.h>
12
BDRV_DRAIN_ALL,
33
#include <libgen.h>
13
BDRV_DRAIN,
34
+#ifndef _WIN32
14
+ DRAIN_TYPE_MAX,
35
+#include <termios.h>
15
};
36
+#endif
16
37
17
static void do_drain_begin(enum drain_type drain_type, BlockDriverState *bs)
38
#include "qapi/error.h"
18
@@ -XXX,XX +XXX,XX @@ static void test_quiesce_drain(void)
39
#include "qemu-io.h"
19
test_quiesce_common(BDRV_DRAIN, false);
40
@@ -XXX,XX +XXX,XX @@ static bool imageOpts;
20
}
41
21
42
static ReadLineState *readline_state;
22
+static void test_nested(void)
43
23
+{
44
+static int ttyEOF;
24
+ BlockBackend *blk;
25
+ BlockDriverState *bs, *backing;
26
+ BDRVTestState *s, *backing_s;
27
+ enum drain_type outer, inner;
45
+
28
+
46
+static int get_eof_char(void)
29
+ blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
47
+{
30
+ bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR,
48
+#ifdef _WIN32
31
+ &error_abort);
49
+ return 0x4; /* Ctrl-D */
32
+ s = bs->opaque;
50
+#else
33
+ blk_insert_bs(blk, bs, &error_abort);
51
+ struct termios tty;
34
+
52
+ if (tcgetattr(STDIN_FILENO, &tty) != 0) {
35
+ backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort);
53
+ if (errno == ENOTTY) {
36
+ backing_s = backing->opaque;
54
+ return 0x0; /* just expect read() == 0 */
37
+ bdrv_set_backing_hd(bs, backing, &error_abort);
55
+ } else {
38
+
56
+ return 0x4; /* Ctrl-D */
39
+ for (outer = 0; outer < DRAIN_TYPE_MAX; outer++) {
40
+ for (inner = 0; inner < DRAIN_TYPE_MAX; inner++) {
41
+ /* XXX bdrv_drain_all() doesn't increase the quiesce_counter */
42
+ int bs_quiesce = (outer != BDRV_DRAIN_ALL) +
43
+ (inner != BDRV_DRAIN_ALL);
44
+ int backing_quiesce = 0;
45
+ int backing_cb_cnt = (outer != BDRV_DRAIN) +
46
+ (inner != BDRV_DRAIN);
47
+
48
+ g_assert_cmpint(bs->quiesce_counter, ==, 0);
49
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
50
+ g_assert_cmpint(s->drain_count, ==, 0);
51
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
52
+
53
+ do_drain_begin(outer, bs);
54
+ do_drain_begin(inner, bs);
55
+
56
+ g_assert_cmpint(bs->quiesce_counter, ==, bs_quiesce);
57
+ g_assert_cmpint(backing->quiesce_counter, ==, backing_quiesce);
58
+ g_assert_cmpint(s->drain_count, ==, 2);
59
+ g_assert_cmpint(backing_s->drain_count, ==, backing_cb_cnt);
60
+
61
+ do_drain_end(inner, bs);
62
+ do_drain_end(outer, bs);
63
+
64
+ g_assert_cmpint(bs->quiesce_counter, ==, 0);
65
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
66
+ g_assert_cmpint(s->drain_count, ==, 0);
67
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
57
+ }
68
+ }
58
+ }
69
+ }
59
+
70
+
60
+ return tty.c_cc[VEOF];
71
+ bdrv_unref(backing);
61
+#endif
72
+ bdrv_unref(bs);
73
+ blk_unref(blk);
62
+}
74
+}
63
+
75
+
64
static int close_f(BlockBackend *blk, int argc, char **argv)
76
65
{
77
typedef struct TestBlockJob {
66
blk_unref(qemuio_blk);
78
BlockJob common;
67
@@ -XXX,XX +XXX,XX @@ static char *fetchline_readline(void)
68
readline_start(readline_state, get_prompt(), 0, readline_func, &line);
69
while (!line) {
70
int ch = getchar();
71
- if (ch == EOF) {
72
+ if (ttyEOF != 0x0 && ch == ttyEOF) {
73
+ printf("\n");
74
break;
75
}
76
readline_handle_byte(readline_state, ch);
77
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
79
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
78
qemuio_add_command(&close_cmd);
80
g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all);
79
81
g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain);
80
if (isatty(STDIN_FILENO)) {
82
81
+ ttyEOF = get_eof_char();
83
+ g_test_add_func("/bdrv-drain/nested", test_nested);
82
readline_state = readline_init(readline_printf_func,
84
+
83
readline_flush_func,
85
g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all);
84
NULL,
86
g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain);
87
85
--
88
--
86
2.13.6
89
2.13.6
87
90
88
91
diff view generated by jsdifflib
1
From: Fam Zheng <famz@redhat.com>
1
This is in preparation for subtree drains, i.e. drained sections that
2
2
affect not only a single node, but recursively all child nodes, too.
3
Suggested-by: Stefan Hajnoczi <stefanha@redhat.com>
3
4
Signed-off-by: Fam Zheng <famz@redhat.com>
4
Calling the parent callbacks for drain is pointless when we just came
5
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
5
from that parent node recursively and leads to multiple increases of
6
Reviewed-by: Kashyap Chamarthy <kchamart@redhat.com>
6
bs->quiesce_counter in a single drain call. Don't do it.
7
8
In order for this to work correctly, the parent callback must be called
9
for every bdrv_drain_begin/end() call, not only for the outermost one:
10
11
If we have a node N with two parents A and B, recursive draining of A
12
should cause the quiesce_counter of B to increase because its child N is
13
drained independently of B. If now B is recursively drained, too, A must
14
increase its quiesce_counter because N is drained independently of A
15
only now, even if N is going from quiesce_counter 1 to 2.
16
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
18
---
9
docs/qemu-block-drivers.texi | 10 ++++++++++
19
include/block/block.h | 4 ++--
10
1 file changed, 10 insertions(+)
20
block.c | 13 +++++++++----
11
21
block/io.c | 47 ++++++++++++++++++++++++++++++++++-------------
12
diff --git a/docs/qemu-block-drivers.texi b/docs/qemu-block-drivers.texi
22
3 files changed, 45 insertions(+), 19 deletions(-)
23
24
diff --git a/include/block/block.h b/include/block/block.h
13
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
14
--- a/docs/qemu-block-drivers.texi
26
--- a/include/block/block.h
15
+++ b/docs/qemu-block-drivers.texi
27
+++ b/include/block/block.h
16
@@ -XXX,XX +XXX,XX @@ QEMU transparently handles lock handover during shared storage migration. For
28
@@ -XXX,XX +XXX,XX @@ void bdrv_io_unplug(BlockDriverState *bs);
17
shared virtual disk images between multiple VMs, the "share-rw" device option
29
* Begin a quiesced section of all users of @bs. This is part of
18
should be used.
30
* bdrv_drained_begin.
19
31
*/
20
+By default, the guest has exclusive write access to its disk image. If the
32
-void bdrv_parent_drained_begin(BlockDriverState *bs);
21
+guest can safely share the disk image with other writers the @code{-device
33
+void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore);
22
+...,share-rw=on} parameter can be used. This is only safe if the guest is
34
23
+running software, such as a cluster file system, that coordinates disk accesses
35
/**
24
+to avoid corruption.
36
* bdrv_parent_drained_end:
37
@@ -XXX,XX +XXX,XX @@ void bdrv_parent_drained_begin(BlockDriverState *bs);
38
* End a quiesced section of all users of @bs. This is part of
39
* bdrv_drained_end.
40
*/
41
-void bdrv_parent_drained_end(BlockDriverState *bs);
42
+void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore);
43
44
/**
45
* bdrv_drained_begin:
46
diff --git a/block.c b/block.c
47
index XXXXXXX..XXXXXXX 100644
48
--- a/block.c
49
+++ b/block.c
50
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child,
51
BlockDriverState *new_bs)
52
{
53
BlockDriverState *old_bs = child->bs;
54
+ int i;
55
56
if (old_bs && new_bs) {
57
assert(bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs));
58
}
59
if (old_bs) {
60
if (old_bs->quiesce_counter && child->role->drained_end) {
61
- child->role->drained_end(child);
62
+ for (i = 0; i < old_bs->quiesce_counter; i++) {
63
+ child->role->drained_end(child);
64
+ }
65
}
66
if (child->role->detach) {
67
child->role->detach(child);
68
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child,
69
if (new_bs) {
70
QLIST_INSERT_HEAD(&new_bs->parents, child, next_parent);
71
if (new_bs->quiesce_counter && child->role->drained_begin) {
72
- child->role->drained_begin(child);
73
+ for (i = 0; i < new_bs->quiesce_counter; i++) {
74
+ child->role->drained_begin(child);
75
+ }
76
}
77
78
if (child->role->attach) {
79
@@ -XXX,XX +XXX,XX @@ void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
80
AioContext *ctx = bdrv_get_aio_context(bs);
81
82
aio_disable_external(ctx);
83
- bdrv_parent_drained_begin(bs);
84
+ bdrv_parent_drained_begin(bs, NULL);
85
bdrv_drain(bs); /* ensure there are no in-flight requests */
86
87
while (aio_poll(ctx, false)) {
88
@@ -XXX,XX +XXX,XX @@ void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
89
*/
90
aio_context_acquire(new_context);
91
bdrv_attach_aio_context(bs, new_context);
92
- bdrv_parent_drained_end(bs);
93
+ bdrv_parent_drained_end(bs, NULL);
94
aio_enable_external(ctx);
95
aio_context_release(new_context);
96
}
97
diff --git a/block/io.c b/block/io.c
98
index XXXXXXX..XXXXXXX 100644
99
--- a/block/io.c
100
+++ b/block/io.c
101
@@ -XXX,XX +XXX,XX @@
102
static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
103
int64_t offset, int bytes, BdrvRequestFlags flags);
104
105
-void bdrv_parent_drained_begin(BlockDriverState *bs)
106
+void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore)
107
{
108
BdrvChild *c, *next;
109
110
QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) {
111
+ if (c == ignore) {
112
+ continue;
113
+ }
114
if (c->role->drained_begin) {
115
c->role->drained_begin(c);
116
}
117
}
118
}
119
120
-void bdrv_parent_drained_end(BlockDriverState *bs)
121
+void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore)
122
{
123
BdrvChild *c, *next;
124
125
QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) {
126
+ if (c == ignore) {
127
+ continue;
128
+ }
129
if (c->role->drained_end) {
130
c->role->drained_end(c);
131
}
132
@@ -XXX,XX +XXX,XX @@ typedef struct {
133
BlockDriverState *bs;
134
bool done;
135
bool begin;
136
+ BdrvChild *parent;
137
} BdrvCoDrainData;
138
139
static void coroutine_fn bdrv_drain_invoke_entry(void *opaque)
140
@@ -XXX,XX +XXX,XX @@ static bool bdrv_drain_recurse(BlockDriverState *bs)
141
return waited;
142
}
143
144
+static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent);
145
+static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent);
25
+
146
+
26
+Note that share-rw=on only declares the guest's ability to share the disk.
147
static void bdrv_co_drain_bh_cb(void *opaque)
27
+Some QEMU features, such as image file formats, require exclusive write access
148
{
28
+to the disk image and this is unaffected by the share-rw=on option.
149
BdrvCoDrainData *data = opaque;
150
@@ -XXX,XX +XXX,XX @@ static void bdrv_co_drain_bh_cb(void *opaque)
151
152
bdrv_dec_in_flight(bs);
153
if (data->begin) {
154
- bdrv_drained_begin(bs);
155
+ bdrv_do_drained_begin(bs, data->parent);
156
} else {
157
- bdrv_drained_end(bs);
158
+ bdrv_do_drained_end(bs, data->parent);
159
}
160
161
data->done = true;
162
@@ -XXX,XX +XXX,XX @@ static void bdrv_co_drain_bh_cb(void *opaque)
163
}
164
165
static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
166
- bool begin)
167
+ bool begin, BdrvChild *parent)
168
{
169
BdrvCoDrainData data;
170
171
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
172
.bs = bs,
173
.done = false,
174
.begin = begin,
175
+ .parent = parent,
176
};
177
bdrv_inc_in_flight(bs);
178
aio_bh_schedule_oneshot(bdrv_get_aio_context(bs),
179
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
180
assert(data.done);
181
}
182
183
-void bdrv_drained_begin(BlockDriverState *bs)
184
+static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent)
185
{
186
if (qemu_in_coroutine()) {
187
- bdrv_co_yield_to_drain(bs, true);
188
+ bdrv_co_yield_to_drain(bs, true, parent);
189
return;
190
}
191
192
/* Stop things in parent-to-child order */
193
if (atomic_fetch_inc(&bs->quiesce_counter) == 0) {
194
aio_disable_external(bdrv_get_aio_context(bs));
195
- bdrv_parent_drained_begin(bs);
196
}
197
198
+ bdrv_parent_drained_begin(bs, parent);
199
bdrv_drain_invoke(bs, true, false);
200
bdrv_drain_recurse(bs);
201
}
202
203
-void bdrv_drained_end(BlockDriverState *bs)
204
+void bdrv_drained_begin(BlockDriverState *bs)
205
+{
206
+ bdrv_do_drained_begin(bs, NULL);
207
+}
29
+
208
+
30
Alternatively, locking can be fully disabled by "locking=off" block device
209
+static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent)
31
option. In the command line, the option is usually in the form of
210
{
32
"file.locking=off" as the protocol driver is normally placed as a "file" child
211
int old_quiesce_counter;
212
213
if (qemu_in_coroutine()) {
214
- bdrv_co_yield_to_drain(bs, false);
215
+ bdrv_co_yield_to_drain(bs, false, parent);
216
return;
217
}
218
assert(bs->quiesce_counter > 0);
219
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
220
221
/* Re-enable things in child-to-parent order */
222
bdrv_drain_invoke(bs, false, false);
223
+ bdrv_parent_drained_end(bs, parent);
224
if (old_quiesce_counter == 1) {
225
- bdrv_parent_drained_end(bs);
226
aio_enable_external(bdrv_get_aio_context(bs));
227
}
228
}
229
230
+void bdrv_drained_end(BlockDriverState *bs)
231
+{
232
+ bdrv_do_drained_end(bs, NULL);
233
+}
234
+
235
/*
236
* Wait for pending requests to complete on a single BlockDriverState subtree,
237
* and suspend block driver's internal I/O until next request arrives.
238
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
239
/* Stop things in parent-to-child order */
240
aio_context_acquire(aio_context);
241
aio_disable_external(aio_context);
242
- bdrv_parent_drained_begin(bs);
243
+ bdrv_parent_drained_begin(bs, NULL);
244
bdrv_drain_invoke(bs, true, true);
245
aio_context_release(aio_context);
246
247
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
248
/* Re-enable things in child-to-parent order */
249
aio_context_acquire(aio_context);
250
bdrv_drain_invoke(bs, false, true);
251
- bdrv_parent_drained_end(bs);
252
+ bdrv_parent_drained_end(bs, NULL);
253
aio_enable_external(aio_context);
254
aio_context_release(aio_context);
255
}
33
--
256
--
34
2.13.6
257
2.13.6
35
258
36
259
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
bdrv_drained_begin() waits for the completion of requests in the whole
2
subtree, but it only actually keeps its immediate bs parameter quiesced
3
until bdrv_drained_end().
2
4
3
Signed-off-by: Max Reitz <mreitz@redhat.com>
5
Add a version that keeps the whole subtree drained. As of this commit,
4
Reviewed-by: Eric Blake <eblake@redhat.com>
6
graph changes cannot be allowed during a subtree drained section, but
7
this will be fixed soon.
8
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
10
---
7
block/sheepdog.c | 15 ++++++++++++---
11
include/block/block.h | 13 +++++++++++++
8
1 file changed, 12 insertions(+), 3 deletions(-)
12
block/io.c | 54 ++++++++++++++++++++++++++++++++++++++++-----------
13
2 files changed, 56 insertions(+), 11 deletions(-)
9
14
10
diff --git a/block/sheepdog.c b/block/sheepdog.c
15
diff --git a/include/block/block.h b/include/block/block.h
11
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
12
--- a/block/sheepdog.c
17
--- a/include/block/block.h
13
+++ b/block/sheepdog.c
18
+++ b/include/block/block.h
14
@@ -XXX,XX +XXX,XX @@ static int sd_truncate(BlockDriverState *bs, int64_t offset,
19
@@ -XXX,XX +XXX,XX @@ void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore);
15
int ret, fd;
20
void bdrv_drained_begin(BlockDriverState *bs);
16
unsigned int datalen;
21
17
uint64_t max_vdi_size;
22
/**
18
+ int64_t old_size = s->inode.vdi_size;
23
+ * Like bdrv_drained_begin, but recursively begins a quiesced section for
19
24
+ * exclusive access to all child nodes as well.
20
- if (prealloc != PREALLOC_MODE_OFF) {
25
+ *
21
+ if (prealloc != PREALLOC_MODE_OFF && prealloc != PREALLOC_MODE_FULL) {
26
+ * Graph changes are not allowed during a subtree drain section.
22
error_setg(errp, "Unsupported preallocation mode '%s'",
27
+ */
23
PreallocMode_str(prealloc));
28
+void bdrv_subtree_drained_begin(BlockDriverState *bs);
24
return -ENOTSUP;
29
+
30
+/**
31
* bdrv_drained_end:
32
*
33
* End a quiescent section started by bdrv_drained_begin().
34
*/
35
void bdrv_drained_end(BlockDriverState *bs);
36
37
+/**
38
+ * End a quiescent section started by bdrv_subtree_drained_begin().
39
+ */
40
+void bdrv_subtree_drained_end(BlockDriverState *bs);
41
+
42
void bdrv_add_child(BlockDriverState *parent, BlockDriverState *child,
43
Error **errp);
44
void bdrv_del_child(BlockDriverState *parent, BdrvChild *child, Error **errp);
45
diff --git a/block/io.c b/block/io.c
46
index XXXXXXX..XXXXXXX 100644
47
--- a/block/io.c
48
+++ b/block/io.c
49
@@ -XXX,XX +XXX,XX @@ typedef struct {
50
BlockDriverState *bs;
51
bool done;
52
bool begin;
53
+ bool recursive;
54
BdrvChild *parent;
55
} BdrvCoDrainData;
56
57
@@ -XXX,XX +XXX,XX @@ static bool bdrv_drain_recurse(BlockDriverState *bs)
58
return waited;
59
}
60
61
-static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent);
62
-static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent);
63
+static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
64
+ BdrvChild *parent);
65
+static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
66
+ BdrvChild *parent);
67
68
static void bdrv_co_drain_bh_cb(void *opaque)
69
{
70
@@ -XXX,XX +XXX,XX @@ static void bdrv_co_drain_bh_cb(void *opaque)
71
72
bdrv_dec_in_flight(bs);
73
if (data->begin) {
74
- bdrv_do_drained_begin(bs, data->parent);
75
+ bdrv_do_drained_begin(bs, data->recursive, data->parent);
76
} else {
77
- bdrv_do_drained_end(bs, data->parent);
78
+ bdrv_do_drained_end(bs, data->recursive, data->parent);
25
}
79
}
26
80
27
max_vdi_size = (UINT64_C(1) << s->inode.block_size_shift) * MAX_DATA_OBJS;
81
data->done = true;
28
- if (offset < s->inode.vdi_size) {
82
@@ -XXX,XX +XXX,XX @@ static void bdrv_co_drain_bh_cb(void *opaque)
29
+ if (offset < old_size) {
83
}
30
error_setg(errp, "shrinking is not supported");
84
31
return -EINVAL;
85
static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
32
} else if (offset > max_vdi_size) {
86
- bool begin, BdrvChild *parent)
33
@@ -XXX,XX +XXX,XX @@ static int sd_truncate(BlockDriverState *bs, int64_t offset,
87
+ bool begin, bool recursive,
34
88
+ BdrvChild *parent)
35
if (ret < 0) {
89
{
36
error_setg_errno(errp, -ret, "failed to update an inode");
90
BdrvCoDrainData data;
37
+ return ret;
91
92
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
93
.bs = bs,
94
.done = false,
95
.begin = begin,
96
+ .recursive = recursive,
97
.parent = parent,
98
};
99
bdrv_inc_in_flight(bs);
100
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
101
assert(data.done);
102
}
103
104
-static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent)
105
+static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
106
+ BdrvChild *parent)
107
{
108
+ BdrvChild *child, *next;
109
+
110
if (qemu_in_coroutine()) {
111
- bdrv_co_yield_to_drain(bs, true, parent);
112
+ bdrv_co_yield_to_drain(bs, true, recursive, parent);
113
return;
38
}
114
}
39
115
40
- return ret;
116
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent)
41
+ if (prealloc == PREALLOC_MODE_FULL) {
117
bdrv_parent_drained_begin(bs, parent);
42
+ ret = sd_prealloc(bs, old_size, offset, errp);
118
bdrv_drain_invoke(bs, true, false);
43
+ if (ret < 0) {
119
bdrv_drain_recurse(bs);
44
+ return ret;
120
+
121
+ if (recursive) {
122
+ QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
123
+ bdrv_do_drained_begin(child->bs, true, child);
45
+ }
124
+ }
46
+ }
125
+ }
126
}
127
128
void bdrv_drained_begin(BlockDriverState *bs)
129
{
130
- bdrv_do_drained_begin(bs, NULL);
131
+ bdrv_do_drained_begin(bs, false, NULL);
132
+}
47
+
133
+
48
+ return 0;
134
+void bdrv_subtree_drained_begin(BlockDriverState *bs)
135
+{
136
+ bdrv_do_drained_begin(bs, true, NULL);
49
}
137
}
138
139
-static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent)
140
+static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
141
+ BdrvChild *parent)
142
{
143
+ BdrvChild *child, *next;
144
int old_quiesce_counter;
145
146
if (qemu_in_coroutine()) {
147
- bdrv_co_yield_to_drain(bs, false, parent);
148
+ bdrv_co_yield_to_drain(bs, false, recursive, parent);
149
return;
150
}
151
assert(bs->quiesce_counter > 0);
152
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent)
153
if (old_quiesce_counter == 1) {
154
aio_enable_external(bdrv_get_aio_context(bs));
155
}
156
+
157
+ if (recursive) {
158
+ QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
159
+ bdrv_do_drained_end(child->bs, true, child);
160
+ }
161
+ }
162
}
163
164
void bdrv_drained_end(BlockDriverState *bs)
165
{
166
- bdrv_do_drained_end(bs, NULL);
167
+ bdrv_do_drained_end(bs, false, NULL);
168
+}
169
+
170
+void bdrv_subtree_drained_end(BlockDriverState *bs)
171
+{
172
+ bdrv_do_drained_end(bs, true, NULL);
173
}
50
174
51
/*
175
/*
52
--
176
--
53
2.13.6
177
2.13.6
54
178
55
179
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
Add a subtree drain version to the existing test cases.
2
2
3
By using qemu_do_cluster_truncate() in qemu_cluster_truncate(), we now
4
automatically have preallocated truncation.
5
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
4
---
10
block/gluster.c | 17 +----------------
5
tests/test-bdrv-drain.c | 27 ++++++++++++++++++++++++++-
11
1 file changed, 1 insertion(+), 16 deletions(-)
6
1 file changed, 26 insertions(+), 1 deletion(-)
12
7
13
diff --git a/block/gluster.c b/block/gluster.c
8
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
14
index XXXXXXX..XXXXXXX 100644
9
index XXXXXXX..XXXXXXX 100644
15
--- a/block/gluster.c
10
--- a/tests/test-bdrv-drain.c
16
+++ b/block/gluster.c
11
+++ b/tests/test-bdrv-drain.c
17
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qemu_gluster_co_rw(BlockDriverState *bs,
12
@@ -XXX,XX +XXX,XX @@ static void aio_ret_cb(void *opaque, int ret)
18
static int qemu_gluster_truncate(BlockDriverState *bs, int64_t offset,
13
enum drain_type {
19
PreallocMode prealloc, Error **errp)
14
BDRV_DRAIN_ALL,
15
BDRV_DRAIN,
16
+ BDRV_SUBTREE_DRAIN,
17
DRAIN_TYPE_MAX,
18
};
19
20
@@ -XXX,XX +XXX,XX @@ static void do_drain_begin(enum drain_type drain_type, BlockDriverState *bs)
21
switch (drain_type) {
22
case BDRV_DRAIN_ALL: bdrv_drain_all_begin(); break;
23
case BDRV_DRAIN: bdrv_drained_begin(bs); break;
24
+ case BDRV_SUBTREE_DRAIN: bdrv_subtree_drained_begin(bs); break;
25
default: g_assert_not_reached();
26
}
27
}
28
@@ -XXX,XX +XXX,XX @@ static void do_drain_end(enum drain_type drain_type, BlockDriverState *bs)
29
switch (drain_type) {
30
case BDRV_DRAIN_ALL: bdrv_drain_all_end(); break;
31
case BDRV_DRAIN: bdrv_drained_end(bs); break;
32
+ case BDRV_SUBTREE_DRAIN: bdrv_subtree_drained_end(bs); break;
33
default: g_assert_not_reached();
34
}
35
}
36
@@ -XXX,XX +XXX,XX @@ static void test_drv_cb_drain(void)
37
test_drv_cb_common(BDRV_DRAIN, false);
38
}
39
40
+static void test_drv_cb_drain_subtree(void)
41
+{
42
+ test_drv_cb_common(BDRV_SUBTREE_DRAIN, true);
43
+}
44
+
45
static void test_quiesce_common(enum drain_type drain_type, bool recursive)
20
{
46
{
21
- int ret;
47
BlockBackend *blk;
22
BDRVGlusterState *s = bs->opaque;
48
@@ -XXX,XX +XXX,XX @@ static void test_quiesce_drain(void)
23
-
49
test_quiesce_common(BDRV_DRAIN, false);
24
- if (prealloc != PREALLOC_MODE_OFF) {
25
- error_setg(errp, "Unsupported preallocation mode '%s'",
26
- PreallocMode_str(prealloc));
27
- return -ENOTSUP;
28
- }
29
-
30
- ret = glfs_ftruncate(s->fd, offset);
31
- if (ret < 0) {
32
- ret = -errno;
33
- error_setg_errno(errp, -ret, "Failed to truncate file");
34
- return ret;
35
- }
36
-
37
- return 0;
38
+ return qemu_gluster_do_truncate(s->fd, offset, prealloc, errp);
39
}
50
}
40
51
41
static coroutine_fn int qemu_gluster_co_readv(BlockDriverState *bs,
52
+static void test_quiesce_drain_subtree(void)
53
+{
54
+ test_quiesce_common(BDRV_SUBTREE_DRAIN, true);
55
+}
56
+
57
static void test_nested(void)
58
{
59
BlockBackend *blk;
60
@@ -XXX,XX +XXX,XX @@ static void test_nested(void)
61
/* XXX bdrv_drain_all() doesn't increase the quiesce_counter */
62
int bs_quiesce = (outer != BDRV_DRAIN_ALL) +
63
(inner != BDRV_DRAIN_ALL);
64
- int backing_quiesce = 0;
65
+ int backing_quiesce = (outer == BDRV_SUBTREE_DRAIN) +
66
+ (inner == BDRV_SUBTREE_DRAIN);
67
int backing_cb_cnt = (outer != BDRV_DRAIN) +
68
(inner != BDRV_DRAIN);
69
70
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_drain(void)
71
test_blockjob_common(BDRV_DRAIN);
72
}
73
74
+static void test_blockjob_drain_subtree(void)
75
+{
76
+ test_blockjob_common(BDRV_SUBTREE_DRAIN);
77
+}
78
+
79
int main(int argc, char **argv)
80
{
81
bdrv_init();
82
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
83
84
g_test_add_func("/bdrv-drain/driver-cb/drain_all", test_drv_cb_drain_all);
85
g_test_add_func("/bdrv-drain/driver-cb/drain", test_drv_cb_drain);
86
+ g_test_add_func("/bdrv-drain/driver-cb/drain_subtree",
87
+ test_drv_cb_drain_subtree);
88
89
g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all);
90
g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain);
91
+ g_test_add_func("/bdrv-drain/quiesce/drain_subtree",
92
+ test_quiesce_drain_subtree);
93
94
g_test_add_func("/bdrv-drain/nested", test_nested);
95
96
g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all);
97
g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain);
98
+ g_test_add_func("/bdrv-drain/blockjob/drain_subtree",
99
+ test_blockjob_drain_subtree);
100
101
return g_test_run();
102
}
42
--
103
--
43
2.13.6
104
2.13.6
44
105
45
106
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
If bdrv_do_drained_begin/end() are called in coroutine context, they
2
first use a BH to get out of the coroutine context. Call some existing
3
tests again from a coroutine to cover this code path.
2
4
3
The l2-cache-entry-size setting can only contain values that are
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
powers of two between 512 and the cluster size.
6
---
7
tests/test-bdrv-drain.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++
8
1 file changed, 59 insertions(+)
5
9
6
Signed-off-by: Alberto Garcia <berto@igalia.com>
10
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
7
Reviewed-by: Eric Blake <eblake@redhat.com>
11
index XXXXXXX..XXXXXXX 100644
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
12
--- a/tests/test-bdrv-drain.c
9
Message-id: bd3547b670b8d0af11480c760991a22bcae5b48c.1517840877.git.berto@igalia.com
13
+++ b/tests/test-bdrv-drain.c
10
[mreitz: Changed non-power-of-two test value from 300 to 4242]
14
@@ -XXX,XX +XXX,XX @@ static void aio_ret_cb(void *opaque, int ret)
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
*aio_ret = ret;
12
---
16
}
13
tests/qemu-iotests/103 | 17 +++++++++++++++++
17
14
tests/qemu-iotests/103.out | 3 +++
18
+typedef struct CallInCoroutineData {
15
2 files changed, 20 insertions(+)
19
+ void (*entry)(void);
16
20
+ bool done;
17
diff --git a/tests/qemu-iotests/103 b/tests/qemu-iotests/103
21
+} CallInCoroutineData;
18
index XXXXXXX..XXXXXXX 100755
19
--- a/tests/qemu-iotests/103
20
+++ b/tests/qemu-iotests/103
21
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c "open -o cache-size=1M,refcount-cache-size=2M $TEST_IMG" 2>&1 \
22
$QEMU_IO -c "open -o cache-size=0,l2-cache-size=0,refcount-cache-size=0 $TEST_IMG" \
23
2>&1 | _filter_testdir | _filter_imgfmt
24
25
+# Invalid cache entry sizes
26
+$QEMU_IO -c "open -o l2-cache-entry-size=256 $TEST_IMG" \
27
+ 2>&1 | _filter_testdir | _filter_imgfmt
28
+$QEMU_IO -c "open -o l2-cache-entry-size=4242 $TEST_IMG" \
29
+ 2>&1 | _filter_testdir | _filter_imgfmt
30
+$QEMU_IO -c "open -o l2-cache-entry-size=128k $TEST_IMG" \
31
+ 2>&1 | _filter_testdir | _filter_imgfmt
32
+
22
+
33
echo
23
+static coroutine_fn void call_in_coroutine_entry(void *opaque)
34
echo '=== Testing valid option combinations ==='
24
+{
35
echo
25
+ CallInCoroutineData *data = opaque;
36
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c "open -o l2-cache-size=1M,refcount-cache-size=0.25M $TEST_IMG" \
26
+
37
-c 'read -P 42 0 64k' \
27
+ data->entry();
38
| _filter_qemu_io
28
+ data->done = true;
39
29
+}
40
+# Valid cache entry sizes
30
+
41
+$QEMU_IO -c "open -o l2-cache-entry-size=512 $TEST_IMG" \
31
+static void call_in_coroutine(void (*entry)(void))
42
+ 2>&1 | _filter_testdir | _filter_imgfmt
32
+{
43
+$QEMU_IO -c "open -o l2-cache-entry-size=16k $TEST_IMG" \
33
+ Coroutine *co;
44
+ 2>&1 | _filter_testdir | _filter_imgfmt
34
+ CallInCoroutineData data = {
45
+$QEMU_IO -c "open -o l2-cache-entry-size=64k $TEST_IMG" \
35
+ .entry = entry,
46
+ 2>&1 | _filter_testdir | _filter_imgfmt
36
+ .done = false,
37
+ };
38
+
39
+ co = qemu_coroutine_create(call_in_coroutine_entry, &data);
40
+ qemu_coroutine_enter(co);
41
+ while (!data.done) {
42
+ aio_poll(qemu_get_aio_context(), true);
43
+ }
44
+}
45
+
46
enum drain_type {
47
BDRV_DRAIN_ALL,
48
BDRV_DRAIN,
49
@@ -XXX,XX +XXX,XX @@ static void test_drv_cb_drain_subtree(void)
50
test_drv_cb_common(BDRV_SUBTREE_DRAIN, true);
51
}
52
53
+static void test_drv_cb_co_drain(void)
54
+{
55
+ call_in_coroutine(test_drv_cb_drain);
56
+}
57
+
58
+static void test_drv_cb_co_drain_subtree(void)
59
+{
60
+ call_in_coroutine(test_drv_cb_drain_subtree);
61
+}
62
+
63
static void test_quiesce_common(enum drain_type drain_type, bool recursive)
64
{
65
BlockBackend *blk;
66
@@ -XXX,XX +XXX,XX @@ static void test_quiesce_drain_subtree(void)
67
test_quiesce_common(BDRV_SUBTREE_DRAIN, true);
68
}
69
70
+static void test_quiesce_co_drain(void)
71
+{
72
+ call_in_coroutine(test_quiesce_drain);
73
+}
74
+
75
+static void test_quiesce_co_drain_subtree(void)
76
+{
77
+ call_in_coroutine(test_quiesce_drain_subtree);
78
+}
79
+
80
static void test_nested(void)
81
{
82
BlockBackend *blk;
83
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
84
g_test_add_func("/bdrv-drain/driver-cb/drain_subtree",
85
test_drv_cb_drain_subtree);
86
87
+ // XXX bdrv_drain_all() doesn't work in coroutine context
88
+ g_test_add_func("/bdrv-drain/driver-cb/co/drain", test_drv_cb_co_drain);
89
+ g_test_add_func("/bdrv-drain/driver-cb/co/drain_subtree",
90
+ test_drv_cb_co_drain_subtree);
47
+
91
+
48
+
92
+
49
echo
93
g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all);
50
echo '=== Testing minimal L2 cache and COW ==='
94
g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain);
51
echo
95
g_test_add_func("/bdrv-drain/quiesce/drain_subtree",
52
diff --git a/tests/qemu-iotests/103.out b/tests/qemu-iotests/103.out
96
test_quiesce_drain_subtree);
53
index XXXXXXX..XXXXXXX 100644
97
54
--- a/tests/qemu-iotests/103.out
98
+ // XXX bdrv_drain_all() doesn't work in coroutine context
55
+++ b/tests/qemu-iotests/103.out
99
+ g_test_add_func("/bdrv-drain/quiesce/co/drain", test_quiesce_co_drain);
56
@@ -XXX,XX +XXX,XX @@ can't open device TEST_DIR/t.IMGFMT: cache-size, l2-cache-size and refcount-cach
100
+ g_test_add_func("/bdrv-drain/quiesce/co/drain_subtree",
57
can't open device TEST_DIR/t.IMGFMT: l2-cache-size may not exceed cache-size
101
+ test_quiesce_co_drain_subtree);
58
can't open device TEST_DIR/t.IMGFMT: refcount-cache-size may not exceed cache-size
102
+
59
can't open device TEST_DIR/t.IMGFMT: cache-size, l2-cache-size and refcount-cache-size may not be set the same time
103
g_test_add_func("/bdrv-drain/nested", test_nested);
60
+can't open device TEST_DIR/t.IMGFMT: L2 cache entry size must be a power of two between 512 and the cluster size (65536)
104
61
+can't open device TEST_DIR/t.IMGFMT: L2 cache entry size must be a power of two between 512 and the cluster size (65536)
105
g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all);
62
+can't open device TEST_DIR/t.IMGFMT: L2 cache entry size must be a power of two between 512 and the cluster size (65536)
63
64
=== Testing valid option combinations ===
65
66
--
106
--
67
2.13.6
107
2.13.6
68
108
69
109
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
Test that drain sections are correctly propagated through the graph.
2
2
3
Similar to offset_to_l2_index(), this function returns the index in
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
the L1 table for a given guest offset. This is only used in a couple
4
---
5
of places and it's not a particularly complex calculation, but it
5
tests/test-bdrv-drain.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++
6
makes the code a bit more readable.
6
1 file changed, 74 insertions(+)
7
7
8
Although in the qcow2_get_cluster_offset() case the old code was
8
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
9
taking advantage of the l1_bits variable, we're going to get rid of
10
the other uses of l1_bits in a later patch anyway, so it doesn't make
11
sense to keep it just for this.
12
13
Signed-off-by: Alberto Garcia <berto@igalia.com>
14
Reviewed-by: Eric Blake <eblake@redhat.com>
15
Reviewed-by: Max Reitz <mreitz@redhat.com>
16
Message-id: a5f626fed526b7459a0425fad06d823d18df8522.1517840877.git.berto@igalia.com
17
Signed-off-by: Max Reitz <mreitz@redhat.com>
18
---
19
block/qcow2.h | 5 +++++
20
block/qcow2-cluster.c | 4 ++--
21
2 files changed, 7 insertions(+), 2 deletions(-)
22
23
diff --git a/block/qcow2.h b/block/qcow2.h
24
index XXXXXXX..XXXXXXX 100644
9
index XXXXXXX..XXXXXXX 100644
25
--- a/block/qcow2.h
10
--- a/tests/test-bdrv-drain.c
26
+++ b/block/qcow2.h
11
+++ b/tests/test-bdrv-drain.c
27
@@ -XXX,XX +XXX,XX @@ static inline int64_t size_to_l1(BDRVQcow2State *s, int64_t size)
12
@@ -XXX,XX +XXX,XX @@ static void test_nested(void)
28
return (size + (1ULL << shift) - 1) >> shift;
13
blk_unref(blk);
29
}
14
}
30
15
31
+static inline int offset_to_l1_index(BDRVQcow2State *s, uint64_t offset)
16
+static void test_multiparent(void)
32
+{
17
+{
33
+ return offset >> (s->l2_bits + s->cluster_bits);
18
+ BlockBackend *blk_a, *blk_b;
19
+ BlockDriverState *bs_a, *bs_b, *backing;
20
+ BDRVTestState *a_s, *b_s, *backing_s;
21
+
22
+ blk_a = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
23
+ bs_a = bdrv_new_open_driver(&bdrv_test, "test-node-a", BDRV_O_RDWR,
24
+ &error_abort);
25
+ a_s = bs_a->opaque;
26
+ blk_insert_bs(blk_a, bs_a, &error_abort);
27
+
28
+ blk_b = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
29
+ bs_b = bdrv_new_open_driver(&bdrv_test, "test-node-b", BDRV_O_RDWR,
30
+ &error_abort);
31
+ b_s = bs_b->opaque;
32
+ blk_insert_bs(blk_b, bs_b, &error_abort);
33
+
34
+ backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort);
35
+ backing_s = backing->opaque;
36
+ bdrv_set_backing_hd(bs_a, backing, &error_abort);
37
+ bdrv_set_backing_hd(bs_b, backing, &error_abort);
38
+
39
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 0);
40
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 0);
41
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
42
+ g_assert_cmpint(a_s->drain_count, ==, 0);
43
+ g_assert_cmpint(b_s->drain_count, ==, 0);
44
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
45
+
46
+ do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a);
47
+
48
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 1);
49
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 1);
50
+ g_assert_cmpint(backing->quiesce_counter, ==, 1);
51
+ g_assert_cmpint(a_s->drain_count, ==, 1);
52
+ g_assert_cmpint(b_s->drain_count, ==, 1);
53
+ g_assert_cmpint(backing_s->drain_count, ==, 1);
54
+
55
+ do_drain_begin(BDRV_SUBTREE_DRAIN, bs_b);
56
+
57
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 2);
58
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 2);
59
+ g_assert_cmpint(backing->quiesce_counter, ==, 2);
60
+ g_assert_cmpint(a_s->drain_count, ==, 2);
61
+ g_assert_cmpint(b_s->drain_count, ==, 2);
62
+ g_assert_cmpint(backing_s->drain_count, ==, 2);
63
+
64
+ do_drain_end(BDRV_SUBTREE_DRAIN, bs_b);
65
+
66
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 1);
67
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 1);
68
+ g_assert_cmpint(backing->quiesce_counter, ==, 1);
69
+ g_assert_cmpint(a_s->drain_count, ==, 1);
70
+ g_assert_cmpint(b_s->drain_count, ==, 1);
71
+ g_assert_cmpint(backing_s->drain_count, ==, 1);
72
+
73
+ do_drain_end(BDRV_SUBTREE_DRAIN, bs_a);
74
+
75
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 0);
76
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 0);
77
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
78
+ g_assert_cmpint(a_s->drain_count, ==, 0);
79
+ g_assert_cmpint(b_s->drain_count, ==, 0);
80
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
81
+
82
+ bdrv_unref(backing);
83
+ bdrv_unref(bs_a);
84
+ bdrv_unref(bs_b);
85
+ blk_unref(blk_a);
86
+ blk_unref(blk_b);
34
+}
87
+}
35
+
88
+
36
static inline int offset_to_l2_index(BDRVQcow2State *s, int64_t offset)
89
37
{
90
typedef struct TestBlockJob {
38
return (offset >> s->cluster_bits) & (s->l2_size - 1);
91
BlockJob common;
39
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
92
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
40
index XXXXXXX..XXXXXXX 100644
93
test_quiesce_co_drain_subtree);
41
--- a/block/qcow2-cluster.c
94
42
+++ b/block/qcow2-cluster.c
95
g_test_add_func("/bdrv-drain/nested", test_nested);
43
@@ -XXX,XX +XXX,XX @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
96
+ g_test_add_func("/bdrv-drain/multiparent", test_multiparent);
44
97
45
/* seek to the l2 offset in the l1 table */
98
g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all);
46
99
g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain);
47
- l1_index = offset >> l1_bits;
48
+ l1_index = offset_to_l1_index(s, offset);
49
if (l1_index >= s->l1_size) {
50
type = QCOW2_CLUSTER_UNALLOCATED;
51
goto out;
52
@@ -XXX,XX +XXX,XX @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
53
54
/* seek to the l2 offset in the l1 table */
55
56
- l1_index = offset >> (s->l2_bits + s->cluster_bits);
57
+ l1_index = offset_to_l1_index(s, offset);
58
if (l1_index >= s->l1_size) {
59
ret = qcow2_grow_l1_table(bs, l1_index + 1, false);
60
if (ret < 0) {
61
--
100
--
62
2.13.6
101
2.13.6
63
102
64
103
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
We need to remember how many of the drain sections in which a node is
2
2
were recursive (i.e. subtree drain rather than node drain), so that they
3
discard_single_l2() limits the number of clusters to be discarded
3
can be correctly applied when children are added or removed during the
4
to the amount that fits inside an L2 table. Since we'll be loading
4
drained section.
5
L2 slices instead of full tables we need to update that limit. The
5
6
function is renamed to discard_in_l2_slice() for clarity.
6
With this change, it is safe to modify the graph even inside a
7
7
bdrv_subtree_drained_begin/end() section.
8
Apart from that, this function doesn't need any additional changes, so
8
9
this patch simply updates the variable name from l2_table to l2_slice.
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
11
Signed-off-by: Alberto Garcia <berto@igalia.com>
12
Message-id: 1cb44a5b68be5334cb01b97a3db3a3c5a43396e5.1517840877.git.berto@igalia.com
13
Reviewed-by: Eric Blake <eblake@redhat.com>
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
---
10
---
16
block/qcow2-cluster.c | 32 ++++++++++++++++----------------
11
include/block/block.h | 2 --
17
1 file changed, 16 insertions(+), 16 deletions(-)
12
include/block/block_int.h | 5 +++++
18
13
block.c | 32 +++++++++++++++++++++++++++++---
19
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
14
block/io.c | 28 ++++++++++++++++++++++++----
20
index XXXXXXX..XXXXXXX 100644
15
4 files changed, 58 insertions(+), 9 deletions(-)
21
--- a/block/qcow2-cluster.c
16
22
+++ b/block/qcow2-cluster.c
17
diff --git a/include/block/block.h b/include/block/block.h
23
@@ -XXX,XX +XXX,XX @@ int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
18
index XXXXXXX..XXXXXXX 100644
19
--- a/include/block/block.h
20
+++ b/include/block/block.h
21
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs);
22
/**
23
* Like bdrv_drained_begin, but recursively begins a quiesced section for
24
* exclusive access to all child nodes as well.
25
- *
26
- * Graph changes are not allowed during a subtree drain section.
27
*/
28
void bdrv_subtree_drained_begin(BlockDriverState *bs);
29
30
diff --git a/include/block/block_int.h b/include/block/block_int.h
31
index XXXXXXX..XXXXXXX 100644
32
--- a/include/block/block_int.h
33
+++ b/include/block/block_int.h
34
@@ -XXX,XX +XXX,XX @@ struct BlockDriverState {
35
36
/* Accessed with atomic ops. */
37
int quiesce_counter;
38
+ int recursive_quiesce_counter;
39
+
40
unsigned int write_gen; /* Current data generation */
41
42
/* Protected by reqs_lock. */
43
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwritev(BdrvChild *child,
44
int64_t offset, unsigned int bytes, QEMUIOVector *qiov,
45
BdrvRequestFlags flags);
46
47
+void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent);
48
+void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent);
49
+
50
int get_tmp_filename(char *filename, int size);
51
BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size,
52
const char *filename);
53
diff --git a/block.c b/block.c
54
index XXXXXXX..XXXXXXX 100644
55
--- a/block.c
56
+++ b/block.c
57
@@ -XXX,XX +XXX,XX @@ static void bdrv_child_cb_drained_end(BdrvChild *child)
58
bdrv_drained_end(bs);
59
}
60
61
+static void bdrv_child_cb_attach(BdrvChild *child)
62
+{
63
+ BlockDriverState *bs = child->opaque;
64
+ bdrv_apply_subtree_drain(child, bs);
65
+}
66
+
67
+static void bdrv_child_cb_detach(BdrvChild *child)
68
+{
69
+ BlockDriverState *bs = child->opaque;
70
+ bdrv_unapply_subtree_drain(child, bs);
71
+}
72
+
73
static int bdrv_child_cb_inactivate(BdrvChild *child)
74
{
75
BlockDriverState *bs = child->opaque;
76
@@ -XXX,XX +XXX,XX @@ const BdrvChildRole child_file = {
77
.inherit_options = bdrv_inherited_options,
78
.drained_begin = bdrv_child_cb_drained_begin,
79
.drained_end = bdrv_child_cb_drained_end,
80
+ .attach = bdrv_child_cb_attach,
81
+ .detach = bdrv_child_cb_detach,
82
.inactivate = bdrv_child_cb_inactivate,
83
};
84
85
@@ -XXX,XX +XXX,XX @@ const BdrvChildRole child_format = {
86
.inherit_options = bdrv_inherited_fmt_options,
87
.drained_begin = bdrv_child_cb_drained_begin,
88
.drained_end = bdrv_child_cb_drained_end,
89
+ .attach = bdrv_child_cb_attach,
90
+ .detach = bdrv_child_cb_detach,
91
.inactivate = bdrv_child_cb_inactivate,
92
};
93
94
@@ -XXX,XX +XXX,XX @@ static void bdrv_backing_attach(BdrvChild *c)
95
parent->backing_blocker);
96
bdrv_op_unblock(backing_hd, BLOCK_OP_TYPE_BACKUP_TARGET,
97
parent->backing_blocker);
98
+
99
+ bdrv_child_cb_attach(c);
100
}
101
102
static void bdrv_backing_detach(BdrvChild *c)
103
@@ -XXX,XX +XXX,XX @@ static void bdrv_backing_detach(BdrvChild *c)
104
bdrv_op_unblock_all(c->bs, parent->backing_blocker);
105
error_free(parent->backing_blocker);
106
parent->backing_blocker = NULL;
107
+
108
+ bdrv_child_cb_detach(c);
109
}
24
110
25
/*
111
/*
26
* This discards as many clusters of nb_clusters as possible at once (i.e.
112
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child,
27
- * all clusters in the same L2 table) and returns the number of discarded
113
assert(bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs));
28
+ * all clusters in the same L2 slice) and returns the number of discarded
114
}
29
* clusters.
115
if (old_bs) {
30
*/
116
+ /* Detach first so that the recursive drain sections coming from @child
31
-static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
117
+ * are already gone and we only end the drain sections that came from
32
- uint64_t nb_clusters, enum qcow2_discard_type type,
118
+ * elsewhere. */
33
- bool full_discard)
119
+ if (child->role->detach) {
34
+static int discard_in_l2_slice(BlockDriverState *bs, uint64_t offset,
120
+ child->role->detach(child);
35
+ uint64_t nb_clusters,
121
+ }
36
+ enum qcow2_discard_type type, bool full_discard)
122
if (old_bs->quiesce_counter && child->role->drained_end) {
123
for (i = 0; i < old_bs->quiesce_counter; i++) {
124
child->role->drained_end(child);
125
}
126
}
127
- if (child->role->detach) {
128
- child->role->detach(child);
129
- }
130
QLIST_REMOVE(child, next_parent);
131
}
132
133
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child,
134
}
135
}
136
137
+ /* Attach only after starting new drained sections, so that recursive
138
+ * drain sections coming from @child don't get an extra .drained_begin
139
+ * callback. */
140
if (child->role->attach) {
141
child->role->attach(child);
142
}
143
diff --git a/block/io.c b/block/io.c
144
index XXXXXXX..XXXXXXX 100644
145
--- a/block/io.c
146
+++ b/block/io.c
147
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
148
assert(data.done);
149
}
150
151
-static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
152
- BdrvChild *parent)
153
+void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
154
+ BdrvChild *parent)
37
{
155
{
38
BDRVQcow2State *s = bs->opaque;
156
BdrvChild *child, *next;
39
- uint64_t *l2_table;
157
40
+ uint64_t *l2_slice;
158
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
41
int l2_index;
159
bdrv_drain_recurse(bs);
42
int ret;
160
43
int i;
161
if (recursive) {
44
162
+ bs->recursive_quiesce_counter++;
45
- ret = get_cluster_table(bs, offset, &l2_table, &l2_index);
163
QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
46
+ ret = get_cluster_table(bs, offset, &l2_slice, &l2_index);
164
bdrv_do_drained_begin(child->bs, true, child);
47
if (ret < 0) {
165
}
48
return ret;
166
@@ -XXX,XX +XXX,XX @@ void bdrv_subtree_drained_begin(BlockDriverState *bs)
167
bdrv_do_drained_begin(bs, true, NULL);
168
}
169
170
-static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
171
- BdrvChild *parent)
172
+void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
173
+ BdrvChild *parent)
174
{
175
BdrvChild *child, *next;
176
int old_quiesce_counter;
177
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
49
}
178
}
50
179
51
- /* Limit nb_clusters to one L2 table */
180
if (recursive) {
52
- nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
181
+ bs->recursive_quiesce_counter--;
53
+ /* Limit nb_clusters to one L2 slice */
182
QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
54
+ nb_clusters = MIN(nb_clusters, s->l2_slice_size - l2_index);
183
bdrv_do_drained_end(child->bs, true, child);
55
assert(nb_clusters <= INT_MAX);
184
}
56
185
@@ -XXX,XX +XXX,XX @@ void bdrv_subtree_drained_end(BlockDriverState *bs)
57
for (i = 0; i < nb_clusters; i++) {
186
bdrv_do_drained_end(bs, true, NULL);
58
uint64_t old_l2_entry;
187
}
59
188
60
- old_l2_entry = be64_to_cpu(l2_table[l2_index + i]);
189
+void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent)
61
+ old_l2_entry = be64_to_cpu(l2_slice[l2_index + i]);
190
+{
62
191
+ int i;
63
/*
192
+
64
* If full_discard is false, make sure that a discarded area reads back
193
+ for (i = 0; i < new_parent->recursive_quiesce_counter; i++) {
65
@@ -XXX,XX +XXX,XX @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
194
+ bdrv_do_drained_begin(child->bs, true, child);
66
}
195
+ }
67
196
+}
68
/* First remove L2 entries */
197
+
69
- qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
198
+void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent)
70
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
199
+{
71
if (!full_discard && s->qcow_version >= 3) {
200
+ int i;
72
- l2_table[l2_index + i] = cpu_to_be64(QCOW_OFLAG_ZERO);
201
+
73
+ l2_slice[l2_index + i] = cpu_to_be64(QCOW_OFLAG_ZERO);
202
+ for (i = 0; i < old_parent->recursive_quiesce_counter; i++) {
74
} else {
203
+ bdrv_do_drained_end(child->bs, true, child);
75
- l2_table[l2_index + i] = cpu_to_be64(0);
204
+ }
76
+ l2_slice[l2_index + i] = cpu_to_be64(0);
205
+}
77
}
206
+
78
207
/*
79
/* Then decrease the refcount */
208
* Wait for pending requests to complete on a single BlockDriverState subtree,
80
qcow2_free_any_clusters(bs, old_l2_entry, 1, type);
209
* and suspend block driver's internal I/O until next request arrives.
81
}
82
83
- qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
84
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
85
86
return nb_clusters;
87
}
88
@@ -XXX,XX +XXX,XX @@ int qcow2_cluster_discard(BlockDriverState *bs, uint64_t offset,
89
90
s->cache_discards = true;
91
92
- /* Each L2 table is handled by its own loop iteration */
93
+ /* Each L2 slice is handled by its own loop iteration */
94
while (nb_clusters > 0) {
95
- cleared = discard_single_l2(bs, offset, nb_clusters, type,
96
- full_discard);
97
+ cleared = discard_in_l2_slice(bs, offset, nb_clusters, type,
98
+ full_discard);
99
if (cleared < 0) {
100
ret = cleared;
101
goto fail;
102
--
210
--
103
2.13.6
211
2.13.6
104
212
105
213
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
2
3
We want to use this function in sd_truncate() later on, so taking a
4
filename is not exactly ideal.
5
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
2
---
10
block/sheepdog.c | 29 +++++++++++++++++++++--------
3
tests/test-bdrv-drain.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++
11
1 file changed, 21 insertions(+), 8 deletions(-)
4
1 file changed, 80 insertions(+)
12
5
13
diff --git a/block/sheepdog.c b/block/sheepdog.c
6
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
14
index XXXXXXX..XXXXXXX 100644
7
index XXXXXXX..XXXXXXX 100644
15
--- a/block/sheepdog.c
8
--- a/tests/test-bdrv-drain.c
16
+++ b/block/sheepdog.c
9
+++ b/tests/test-bdrv-drain.c
17
@@ -XXX,XX +XXX,XX @@ static int do_sd_create(BDRVSheepdogState *s, uint32_t *vdi_id, int snapshot,
10
@@ -XXX,XX +XXX,XX @@ static void test_multiparent(void)
18
return 0;
11
blk_unref(blk_b);
19
}
12
}
20
13
21
-static int sd_prealloc(const char *filename, Error **errp)
14
+static void test_graph_change(void)
22
+static int sd_prealloc(BlockDriverState *bs, Error **errp)
15
+{
23
{
16
+ BlockBackend *blk_a, *blk_b;
24
BlockBackend *blk = NULL;
17
+ BlockDriverState *bs_a, *bs_b, *backing;
25
- BDRVSheepdogState *base = NULL;
18
+ BDRVTestState *a_s, *b_s, *backing_s;
26
+ BDRVSheepdogState *base = bs->opaque;
27
unsigned long buf_size;
28
uint32_t idx, max_idx;
29
uint32_t object_size;
30
@@ -XXX,XX +XXX,XX @@ static int sd_prealloc(const char *filename, Error **errp)
31
void *buf = NULL;
32
int ret;
33
34
- blk = blk_new_open(filename, NULL, NULL,
35
- BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp);
36
- if (blk == NULL) {
37
- ret = -EIO;
38
+ blk = blk_new(BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | BLK_PERM_RESIZE,
39
+ BLK_PERM_ALL);
40
+
19
+
41
+ ret = blk_insert_bs(blk, bs, errp);
20
+ blk_a = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
42
+ if (ret < 0) {
21
+ bs_a = bdrv_new_open_driver(&bdrv_test, "test-node-a", BDRV_O_RDWR,
43
goto out_with_err_set;
22
+ &error_abort);
44
}
23
+ a_s = bs_a->opaque;
45
24
+ blk_insert_bs(blk_a, bs_a, &error_abort);
46
@@ -XXX,XX +XXX,XX @@ static int sd_prealloc(const char *filename, Error **errp)
47
goto out;
48
}
49
50
- base = blk_bs(blk)->opaque;
51
object_size = (UINT32_C(1) << base->inode.block_size_shift);
52
buf_size = MIN(object_size, SD_DATA_OBJ_SIZE);
53
buf = g_malloc0(buf_size);
54
@@ -XXX,XX +XXX,XX @@ static int sd_create(const char *filename, QemuOpts *opts,
55
}
56
57
if (prealloc) {
58
- ret = sd_prealloc(filename, errp);
59
+ BlockDriverState *bs;
60
+ QDict *opts;
61
+
25
+
62
+ opts = qdict_new();
26
+ blk_b = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
63
+ qdict_put_str(opts, "driver", "sheepdog");
27
+ bs_b = bdrv_new_open_driver(&bdrv_test, "test-node-b", BDRV_O_RDWR,
64
+ bs = bdrv_open(filename, NULL, opts, BDRV_O_PROTOCOL | BDRV_O_RDWR,
28
+ &error_abort);
65
+ errp);
29
+ b_s = bs_b->opaque;
66
+ if (!bs) {
30
+ blk_insert_bs(blk_b, bs_b, &error_abort);
67
+ goto out;
68
+ }
69
+
31
+
70
+ ret = sd_prealloc(bs, errp);
32
+ backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort);
33
+ backing_s = backing->opaque;
34
+ bdrv_set_backing_hd(bs_a, backing, &error_abort);
71
+
35
+
72
+ bdrv_unref(bs);
36
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 0);
73
}
37
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 0);
74
out:
38
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
75
g_free(backing_file);
39
+ g_assert_cmpint(a_s->drain_count, ==, 0);
40
+ g_assert_cmpint(b_s->drain_count, ==, 0);
41
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
42
+
43
+ do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a);
44
+ do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a);
45
+ do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a);
46
+ do_drain_begin(BDRV_SUBTREE_DRAIN, bs_b);
47
+ do_drain_begin(BDRV_SUBTREE_DRAIN, bs_b);
48
+
49
+ bdrv_set_backing_hd(bs_b, backing, &error_abort);
50
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 5);
51
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 5);
52
+ g_assert_cmpint(backing->quiesce_counter, ==, 5);
53
+ g_assert_cmpint(a_s->drain_count, ==, 5);
54
+ g_assert_cmpint(b_s->drain_count, ==, 5);
55
+ g_assert_cmpint(backing_s->drain_count, ==, 5);
56
+
57
+ bdrv_set_backing_hd(bs_b, NULL, &error_abort);
58
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 3);
59
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 2);
60
+ g_assert_cmpint(backing->quiesce_counter, ==, 3);
61
+ g_assert_cmpint(a_s->drain_count, ==, 3);
62
+ g_assert_cmpint(b_s->drain_count, ==, 2);
63
+ g_assert_cmpint(backing_s->drain_count, ==, 3);
64
+
65
+ bdrv_set_backing_hd(bs_b, backing, &error_abort);
66
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 5);
67
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 5);
68
+ g_assert_cmpint(backing->quiesce_counter, ==, 5);
69
+ g_assert_cmpint(a_s->drain_count, ==, 5);
70
+ g_assert_cmpint(b_s->drain_count, ==, 5);
71
+ g_assert_cmpint(backing_s->drain_count, ==, 5);
72
+
73
+ do_drain_end(BDRV_SUBTREE_DRAIN, bs_b);
74
+ do_drain_end(BDRV_SUBTREE_DRAIN, bs_b);
75
+ do_drain_end(BDRV_SUBTREE_DRAIN, bs_a);
76
+ do_drain_end(BDRV_SUBTREE_DRAIN, bs_a);
77
+ do_drain_end(BDRV_SUBTREE_DRAIN, bs_a);
78
+
79
+ g_assert_cmpint(bs_a->quiesce_counter, ==, 0);
80
+ g_assert_cmpint(bs_b->quiesce_counter, ==, 0);
81
+ g_assert_cmpint(backing->quiesce_counter, ==, 0);
82
+ g_assert_cmpint(a_s->drain_count, ==, 0);
83
+ g_assert_cmpint(b_s->drain_count, ==, 0);
84
+ g_assert_cmpint(backing_s->drain_count, ==, 0);
85
+
86
+ bdrv_unref(backing);
87
+ bdrv_unref(bs_a);
88
+ bdrv_unref(bs_b);
89
+ blk_unref(blk_a);
90
+ blk_unref(blk_b);
91
+}
92
+
93
94
typedef struct TestBlockJob {
95
BlockJob common;
96
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
97
98
g_test_add_func("/bdrv-drain/nested", test_nested);
99
g_test_add_func("/bdrv-drain/multiparent", test_multiparent);
100
+ g_test_add_func("/bdrv-drain/graph-change", test_graph_change);
101
102
g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all);
103
g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain);
76
--
104
--
77
2.13.6
105
2.13.6
78
106
79
107
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
This function has not been returning the offset of the L2 table since
4
commit 3948d1d4876065160583e79533bf604481063833
5
6
Signed-off-by: Alberto Garcia <berto@igalia.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Message-id: b498733b6706a859a03678d74ecbd26aeba129aa.1517840876.git.berto@igalia.com
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
12
block/qcow2-cluster.c | 3 +--
13
1 file changed, 1 insertion(+), 2 deletions(-)
14
15
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/block/qcow2-cluster.c
18
+++ b/block/qcow2-cluster.c
19
@@ -XXX,XX +XXX,XX @@ fail:
20
* for a given disk offset, load (and allocate if needed)
21
* the l2 table.
22
*
23
- * the l2 table offset in the qcow2 file and the cluster index
24
- * in the l2 table are given to the caller.
25
+ * the cluster index in the l2 table is given to the caller.
26
*
27
* Returns 0 on success, -errno in failure case
28
*/
29
--
30
2.13.6
31
32
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
This function was only using the BlockDriverState parameter to get the
4
cache table size (since it was equal to the cluster size). This is no
5
longer necessary so this parameter can be removed.
6
7
Signed-off-by: Alberto Garcia <berto@igalia.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Message-id: e1f943a9e89e1deb876f45de1bb22419ccdb6ad3.1517840876.git.berto@igalia.com
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
13
block/qcow2-cache.c | 13 ++++++-------
14
1 file changed, 6 insertions(+), 7 deletions(-)
15
16
diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/block/qcow2-cache.c
19
+++ b/block/qcow2-cache.c
20
@@ -XXX,XX +XXX,XX @@ struct Qcow2Cache {
21
uint64_t cache_clean_lru_counter;
22
};
23
24
-static inline void *qcow2_cache_get_table_addr(BlockDriverState *bs,
25
- Qcow2Cache *c, int table)
26
+static inline void *qcow2_cache_get_table_addr(Qcow2Cache *c, int table)
27
{
28
return (uint8_t *) c->table_array + (size_t) table * c->table_size;
29
}
30
@@ -XXX,XX +XXX,XX @@ static void qcow2_cache_table_release(BlockDriverState *bs, Qcow2Cache *c,
31
{
32
/* Using MADV_DONTNEED to discard memory is a Linux-specific feature */
33
#ifdef CONFIG_LINUX
34
- void *t = qcow2_cache_get_table_addr(bs, c, i);
35
+ void *t = qcow2_cache_get_table_addr(c, i);
36
int align = getpagesize();
37
size_t mem_size = (size_t) c->table_size * num_tables;
38
size_t offset = QEMU_ALIGN_UP((uintptr_t) t, align) - (uintptr_t) t;
39
@@ -XXX,XX +XXX,XX @@ static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i)
40
}
41
42
ret = bdrv_pwrite(bs->file, c->entries[i].offset,
43
- qcow2_cache_get_table_addr(bs, c, i), c->table_size);
44
+ qcow2_cache_get_table_addr(c, i), c->table_size);
45
if (ret < 0) {
46
return ret;
47
}
48
@@ -XXX,XX +XXX,XX @@ static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
49
}
50
51
ret = bdrv_pread(bs->file, offset,
52
- qcow2_cache_get_table_addr(bs, c, i),
53
+ qcow2_cache_get_table_addr(c, i),
54
c->table_size);
55
if (ret < 0) {
56
return ret;
57
@@ -XXX,XX +XXX,XX @@ static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
58
/* And return the right table */
59
found:
60
c->entries[i].ref++;
61
- *table = qcow2_cache_get_table_addr(bs, c, i);
62
+ *table = qcow2_cache_get_table_addr(c, i);
63
64
trace_qcow2_cache_get_done(qemu_coroutine_self(),
65
c == s->l2_table_cache, i);
66
@@ -XXX,XX +XXX,XX @@ void *qcow2_cache_is_table_offset(BlockDriverState *bs, Qcow2Cache *c,
67
68
for (i = 0; i < c->size; i++) {
69
if (c->entries[i].offset == offset) {
70
- return qcow2_cache_get_table_addr(bs, c, i);
71
+ return qcow2_cache_get_table_addr(c, i);
72
}
73
}
74
return NULL;
75
--
76
2.13.6
77
78
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
This function was only using the BlockDriverState parameter to get the
4
cache table size (since it was equal to the cluster size). This is no
5
longer necessary so this parameter can be removed.
6
7
Signed-off-by: Alberto Garcia <berto@igalia.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Message-id: da3575d47c9a181a2cfd4715e53dd84a2c651017.1517840876.git.berto@igalia.com
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
13
block/qcow2-cache.c | 9 ++++-----
14
1 file changed, 4 insertions(+), 5 deletions(-)
15
16
diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/block/qcow2-cache.c
19
+++ b/block/qcow2-cache.c
20
@@ -XXX,XX +XXX,XX @@ static inline void *qcow2_cache_get_table_addr(Qcow2Cache *c, int table)
21
return (uint8_t *) c->table_array + (size_t) table * c->table_size;
22
}
23
24
-static inline int qcow2_cache_get_table_idx(BlockDriverState *bs,
25
- Qcow2Cache *c, void *table)
26
+static inline int qcow2_cache_get_table_idx(Qcow2Cache *c, void *table)
27
{
28
ptrdiff_t table_offset = (uint8_t *) table - (uint8_t *) c->table_array;
29
int idx = table_offset / c->table_size;
30
@@ -XXX,XX +XXX,XX @@ int qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
31
32
void qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table)
33
{
34
- int i = qcow2_cache_get_table_idx(bs, c, *table);
35
+ int i = qcow2_cache_get_table_idx(c, *table);
36
37
c->entries[i].ref--;
38
*table = NULL;
39
@@ -XXX,XX +XXX,XX @@ void qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table)
40
void qcow2_cache_entry_mark_dirty(BlockDriverState *bs, Qcow2Cache *c,
41
void *table)
42
{
43
- int i = qcow2_cache_get_table_idx(bs, c, table);
44
+ int i = qcow2_cache_get_table_idx(c, table);
45
assert(c->entries[i].offset != 0);
46
c->entries[i].dirty = true;
47
}
48
@@ -XXX,XX +XXX,XX @@ void *qcow2_cache_is_table_offset(BlockDriverState *bs, Qcow2Cache *c,
49
50
void qcow2_cache_discard(BlockDriverState *bs, Qcow2Cache *c, void *table)
51
{
52
- int i = qcow2_cache_get_table_idx(bs, c, table);
53
+ int i = qcow2_cache_get_table_idx(c, table);
54
55
assert(c->entries[i].ref == 0);
56
57
--
58
2.13.6
59
60
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
Since commit bde70715, base is the only node that is reopened in
2
commit_start(). This means that the code, which still involves an
3
explicit BlockReopenQueue, can now be simplified by using bdrv_reopen().
2
4
3
zero_single_l2() limits the number of clusters to be zeroed to the
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
amount that fits inside an L2 table. Since we'll be loading L2 slices
6
Reviewed-by: Fam Zheng <famz@redhat.com>
5
instead of full tables we need to update that limit. The function is
7
---
6
renamed to zero_in_l2_slice() for clarity.
8
block/commit.c | 8 +-------
9
1 file changed, 1 insertion(+), 7 deletions(-)
7
10
8
Apart from that, this function doesn't need any additional changes, so
11
diff --git a/block/commit.c b/block/commit.c
9
this patch simply updates the variable name from l2_table to l2_slice.
10
11
Signed-off-by: Alberto Garcia <berto@igalia.com>
12
Message-id: ebc16e7e79fa6969d8975ef487d679794de4fbcc.1517840877.git.berto@igalia.com
13
Reviewed-by: Eric Blake <eblake@redhat.com>
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
---
16
block/qcow2-cluster.c | 28 ++++++++++++++--------------
17
1 file changed, 14 insertions(+), 14 deletions(-)
18
19
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
20
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
21
--- a/block/qcow2-cluster.c
13
--- a/block/commit.c
22
+++ b/block/qcow2-cluster.c
14
+++ b/block/commit.c
23
@@ -XXX,XX +XXX,XX @@ fail:
15
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
24
16
const char *filter_node_name, Error **errp)
25
/*
26
* This zeroes as many clusters of nb_clusters as possible at once (i.e.
27
- * all clusters in the same L2 table) and returns the number of zeroed
28
+ * all clusters in the same L2 slice) and returns the number of zeroed
29
* clusters.
30
*/
31
-static int zero_single_l2(BlockDriverState *bs, uint64_t offset,
32
- uint64_t nb_clusters, int flags)
33
+static int zero_in_l2_slice(BlockDriverState *bs, uint64_t offset,
34
+ uint64_t nb_clusters, int flags)
35
{
17
{
36
BDRVQcow2State *s = bs->opaque;
18
CommitBlockJob *s;
37
- uint64_t *l2_table;
19
- BlockReopenQueue *reopen_queue = NULL;
38
+ uint64_t *l2_slice;
20
int orig_base_flags;
39
int l2_index;
21
BlockDriverState *iter;
40
int ret;
22
BlockDriverState *commit_top_bs = NULL;
41
int i;
23
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
42
bool unmap = !!(flags & BDRV_REQ_MAY_UNMAP);
24
/* convert base to r/w, if necessary */
43
25
orig_base_flags = bdrv_get_flags(base);
44
- ret = get_cluster_table(bs, offset, &l2_table, &l2_index);
26
if (!(orig_base_flags & BDRV_O_RDWR)) {
45
+ ret = get_cluster_table(bs, offset, &l2_slice, &l2_index);
27
- reopen_queue = bdrv_reopen_queue(reopen_queue, base, NULL,
46
if (ret < 0) {
28
- orig_base_flags | BDRV_O_RDWR);
47
return ret;
29
- }
48
}
30
-
49
31
- if (reopen_queue) {
50
- /* Limit nb_clusters to one L2 table */
32
- bdrv_reopen_multiple(bdrv_get_aio_context(bs), reopen_queue, &local_err);
51
- nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
33
+ bdrv_reopen(base, orig_base_flags | BDRV_O_RDWR, &local_err);
52
+ /* Limit nb_clusters to one L2 slice */
34
if (local_err != NULL) {
53
+ nb_clusters = MIN(nb_clusters, s->l2_slice_size - l2_index);
35
error_propagate(errp, local_err);
54
assert(nb_clusters <= INT_MAX);
55
56
for (i = 0; i < nb_clusters; i++) {
57
uint64_t old_offset;
58
QCow2ClusterType cluster_type;
59
60
- old_offset = be64_to_cpu(l2_table[l2_index + i]);
61
+ old_offset = be64_to_cpu(l2_slice[l2_index + i]);
62
63
/*
64
* Minimize L2 changes if the cluster already reads back as
65
@@ -XXX,XX +XXX,XX @@ static int zero_single_l2(BlockDriverState *bs, uint64_t offset,
66
continue;
67
}
68
69
- qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
70
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
71
if (cluster_type == QCOW2_CLUSTER_COMPRESSED || unmap) {
72
- l2_table[l2_index + i] = cpu_to_be64(QCOW_OFLAG_ZERO);
73
+ l2_slice[l2_index + i] = cpu_to_be64(QCOW_OFLAG_ZERO);
74
qcow2_free_any_clusters(bs, old_offset, 1, QCOW2_DISCARD_REQUEST);
75
} else {
76
- l2_table[l2_index + i] |= cpu_to_be64(QCOW_OFLAG_ZERO);
77
+ l2_slice[l2_index + i] |= cpu_to_be64(QCOW_OFLAG_ZERO);
78
}
79
}
80
81
- qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
82
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
83
84
return nb_clusters;
85
}
86
@@ -XXX,XX +XXX,XX @@ int qcow2_cluster_zeroize(BlockDriverState *bs, uint64_t offset,
87
return -ENOTSUP;
88
}
89
90
- /* Each L2 table is handled by its own loop iteration */
91
+ /* Each L2 slice is handled by its own loop iteration */
92
nb_clusters = size_to_clusters(s, bytes);
93
94
s->cache_discards = true;
95
96
while (nb_clusters > 0) {
97
- cleared = zero_single_l2(bs, offset, nb_clusters, flags);
98
+ cleared = zero_in_l2_slice(bs, offset, nb_clusters, flags);
99
if (cleared < 0) {
100
ret = cleared;
101
goto fail;
36
goto fail;
102
--
37
--
103
2.13.6
38
2.13.6
104
39
105
40
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
The bdrv_reopen*() implementation doesn't like it if the graph is
2
changed between queuing nodes for reopen and actually reopening them
3
(one of the reasons is that queuing can be recursive).
2
4
3
This function was only using the BlockDriverState parameter to pass it
5
So instead of draining the device only in bdrv_reopen_multiple(),
4
to qcow2_cache_get_table_idx(). This is no longer necessary so this
6
require that callers already drained all affected nodes, and assert this
5
parameter can be removed.
7
in bdrv_reopen_queue().
6
8
7
Signed-off-by: Alberto Garcia <berto@igalia.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Reviewed-by: Fam Zheng <famz@redhat.com>
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Message-id: 6f98155489054a457563da77cdad1a66ebb3e896.1517840876.git.berto@igalia.com
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
11
---
13
block/qcow2.h | 2 +-
12
block.c | 23 ++++++++++++++++-------
14
block/qcow2-cache.c | 2 +-
13
block/replication.c | 6 ++++++
15
block/qcow2-cluster.c | 28 ++++++++++++++--------------
14
qemu-io-cmds.c | 3 +++
16
block/qcow2-refcount.c | 30 +++++++++++++++---------------
15
3 files changed, 25 insertions(+), 7 deletions(-)
17
4 files changed, 31 insertions(+), 31 deletions(-)
18
16
19
diff --git a/block/qcow2.h b/block/qcow2.h
17
diff --git a/block.c b/block.c
20
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
21
--- a/block/qcow2.h
19
--- a/block.c
22
+++ b/block/qcow2.h
20
+++ b/block.c
23
@@ -XXX,XX +XXX,XX @@ int qcow2_cache_get(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
21
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_open(const char *filename, const char *reference,
24
void **table);
22
* returns a pointer to bs_queue, which is either the newly allocated
25
int qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
23
* bs_queue, or the existing bs_queue being used.
26
void **table);
24
*
27
-void qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table);
25
+ * bs must be drained between bdrv_reopen_queue() and bdrv_reopen_multiple().
28
+void qcow2_cache_put(Qcow2Cache *c, void **table);
26
*/
29
void *qcow2_cache_is_table_offset(BlockDriverState *bs, Qcow2Cache *c,
27
static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
30
uint64_t offset);
28
BlockDriverState *bs,
31
void qcow2_cache_discard(BlockDriverState *bs, Qcow2Cache *c, void *table);
29
@@ -XXX,XX +XXX,XX @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
32
diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c
30
BdrvChild *child;
33
index XXXXXXX..XXXXXXX 100644
31
QDict *old_options, *explicit_options;
34
--- a/block/qcow2-cache.c
32
35
+++ b/block/qcow2-cache.c
33
+ /* Make sure that the caller remembered to use a drained section. This is
36
@@ -XXX,XX +XXX,XX @@ int qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
34
+ * important to avoid graph changes between the recursive queuing here and
37
return qcow2_cache_do_get(bs, c, offset, table, false);
35
+ * bdrv_reopen_multiple(). */
38
}
36
+ assert(bs->quiesce_counter > 0);
39
37
+
40
-void qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table)
38
if (bs_queue == NULL) {
41
+void qcow2_cache_put(Qcow2Cache *c, void **table)
39
bs_queue = g_new0(BlockReopenQueue, 1);
40
QSIMPLEQ_INIT(bs_queue);
41
@@ -XXX,XX +XXX,XX @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
42
* If all devices prepare successfully, then the changes are committed
43
* to all devices.
44
*
45
+ * All affected nodes must be drained between bdrv_reopen_queue() and
46
+ * bdrv_reopen_multiple().
47
*/
48
int bdrv_reopen_multiple(AioContext *ctx, BlockReopenQueue *bs_queue, Error **errp)
42
{
49
{
43
int i = qcow2_cache_get_table_idx(c, *table);
50
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_multiple(AioContext *ctx, BlockReopenQueue *bs_queue, Error **er
44
51
45
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
52
assert(bs_queue != NULL);
46
index XXXXXXX..XXXXXXX 100644
53
47
--- a/block/qcow2-cluster.c
54
- aio_context_release(ctx);
48
+++ b/block/qcow2-cluster.c
55
- bdrv_drain_all_begin();
49
@@ -XXX,XX +XXX,XX @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
56
- aio_context_acquire(ctx);
50
57
-
51
memcpy(l2_table, old_table, s->cluster_size);
58
QSIMPLEQ_FOREACH(bs_entry, bs_queue, entry) {
52
59
+ assert(bs_entry->state.bs->quiesce_counter > 0);
53
- qcow2_cache_put(bs, s->l2_table_cache, (void **) &old_table);
60
if (bdrv_reopen_prepare(&bs_entry->state, bs_queue, &local_err)) {
54
+ qcow2_cache_put(s->l2_table_cache, (void **) &old_table);
61
error_propagate(errp, local_err);
62
goto cleanup;
63
@@ -XXX,XX +XXX,XX @@ cleanup:
55
}
64
}
56
65
g_free(bs_queue);
57
/* write the l2 table to the file */
66
58
@@ -XXX,XX +XXX,XX @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
67
- bdrv_drain_all_end();
59
fail:
68
-
60
trace_qcow2_l2_allocate_done(bs, l1_index, ret);
61
if (l2_table != NULL) {
62
- qcow2_cache_put(bs, s->l2_table_cache, (void**) table);
63
+ qcow2_cache_put(s->l2_table_cache, (void **) table);
64
}
65
s->l1_table[l1_index] = old_l2_offset;
66
if (l2_offset > 0) {
67
@@ -XXX,XX +XXX,XX @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
68
abort();
69
}
70
71
- qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
72
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
73
74
bytes_available = (int64_t)c * s->cluster_size;
75
76
@@ -XXX,XX +XXX,XX @@ out:
77
return type;
78
79
fail:
80
- qcow2_cache_put(bs, s->l2_table_cache, (void **)&l2_table);
81
+ qcow2_cache_put(s->l2_table_cache, (void **)&l2_table);
82
return ret;
69
return ret;
83
}
70
}
84
71
85
@@ -XXX,XX +XXX,XX @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
72
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen(BlockDriverState *bs, int bdrv_flags, Error **errp)
86
* allocated. */
73
{
87
cluster_offset = be64_to_cpu(l2_table[l2_index]);
74
int ret = -1;
88
if (cluster_offset & L2E_OFFSET_MASK) {
75
Error *local_err = NULL;
89
- qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
76
- BlockReopenQueue *queue = bdrv_reopen_queue(NULL, bs, NULL, bdrv_flags);
90
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
77
+ BlockReopenQueue *queue;
91
return 0;
78
79
+ bdrv_subtree_drained_begin(bs);
80
+
81
+ queue = bdrv_reopen_queue(NULL, bs, NULL, bdrv_flags);
82
ret = bdrv_reopen_multiple(bdrv_get_aio_context(bs), queue, &local_err);
83
if (local_err != NULL) {
84
error_propagate(errp, local_err);
92
}
85
}
93
86
+
94
cluster_offset = qcow2_alloc_bytes(bs, compressed_size);
87
+ bdrv_subtree_drained_end(bs);
95
if (cluster_offset < 0) {
88
+
96
- qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
97
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
98
return 0;
99
}
100
101
@@ -XXX,XX +XXX,XX @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
102
BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE_COMPRESSED);
103
qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
104
l2_table[l2_index] = cpu_to_be64(cluster_offset);
105
- qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
106
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
107
108
return cluster_offset;
109
}
110
@@ -XXX,XX +XXX,XX @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
111
}
112
113
114
- qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
115
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
116
117
/*
118
* If this was a COW, we need to decrease the refcount of the old cluster.
119
@@ -XXX,XX +XXX,XX @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset,
120
121
/* Cleanup */
122
out:
123
- qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
124
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
125
126
/* Only return a host offset if we actually made progress. Otherwise we
127
* would make requirements for handle_alloc() that it can't fulfill */
128
@@ -XXX,XX +XXX,XX @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
129
keep_old_clusters = true;
130
}
131
132
- qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
133
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
134
135
if (!alloc_cluster_offset) {
136
/* Allocate, if necessary at a given offset in the image file */
137
@@ -XXX,XX +XXX,XX @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
138
qcow2_free_any_clusters(bs, old_l2_entry, 1, type);
139
}
140
141
- qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
142
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
143
144
return nb_clusters;
145
}
146
@@ -XXX,XX +XXX,XX @@ static int zero_single_l2(BlockDriverState *bs, uint64_t offset,
147
}
148
}
149
150
- qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
151
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
152
153
return nb_clusters;
154
}
155
@@ -XXX,XX +XXX,XX @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
156
qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
157
qcow2_cache_depends_on_flush(s->l2_table_cache);
158
}
159
- qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
160
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
161
} else {
162
if (l2_dirty) {
163
ret = qcow2_pre_write_overlap_check(bs,
164
@@ -XXX,XX +XXX,XX @@ fail:
165
if (!is_active_l1) {
166
qemu_vfree(l2_table);
167
} else {
168
- qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
169
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
170
}
171
}
172
return ret;
173
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
174
index XXXXXXX..XXXXXXX 100644
175
--- a/block/qcow2-refcount.c
176
+++ b/block/qcow2-refcount.c
177
@@ -XXX,XX +XXX,XX @@ int qcow2_get_refcount(BlockDriverState *bs, int64_t cluster_index,
178
block_index = cluster_index & (s->refcount_block_size - 1);
179
*refcount = s->get_refcount(refcount_block, block_index);
180
181
- qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block);
182
+ qcow2_cache_put(s->refcount_block_cache, &refcount_block);
183
184
return 0;
185
}
186
@@ -XXX,XX +XXX,XX @@ static int alloc_refcount_block(BlockDriverState *bs,
187
return -EAGAIN;
188
}
189
190
- qcow2_cache_put(bs, s->refcount_block_cache, refcount_block);
191
+ qcow2_cache_put(s->refcount_block_cache, refcount_block);
192
193
/*
194
* If we come here, we need to grow the refcount table. Again, a new
195
@@ -XXX,XX +XXX,XX @@ static int alloc_refcount_block(BlockDriverState *bs,
196
197
fail:
198
if (*refcount_block != NULL) {
199
- qcow2_cache_put(bs, s->refcount_block_cache, refcount_block);
200
+ qcow2_cache_put(s->refcount_block_cache, refcount_block);
201
}
202
return ret;
89
return ret;
203
}
90
}
204
@@ -XXX,XX +XXX,XX @@ int64_t qcow2_refcount_area(BlockDriverState *bs, uint64_t start_offset,
91
205
refblock_data);
92
diff --git a/block/replication.c b/block/replication.c
206
}
93
index XXXXXXX..XXXXXXX 100644
207
94
--- a/block/replication.c
208
- qcow2_cache_put(bs, s->refcount_block_cache, &refblock_data);
95
+++ b/block/replication.c
209
+ qcow2_cache_put(s->refcount_block_cache, &refblock_data);
96
@@ -XXX,XX +XXX,XX @@ static void reopen_backing_file(BlockDriverState *bs, bool writable,
97
new_secondary_flags = s->orig_secondary_flags;
210
}
98
}
211
99
212
assert(block_offset == table_offset);
100
+ bdrv_subtree_drained_begin(s->hidden_disk->bs);
213
@@ -XXX,XX +XXX,XX @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
101
+ bdrv_subtree_drained_begin(s->secondary_disk->bs);
214
/* Load the refcount block and allocate it if needed */
102
+
215
if (table_index != old_table_index) {
103
if (orig_hidden_flags != new_hidden_flags) {
216
if (refcount_block) {
104
reopen_queue = bdrv_reopen_queue(reopen_queue, s->hidden_disk->bs, NULL,
217
- qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block);
105
new_hidden_flags);
218
+ qcow2_cache_put(s->refcount_block_cache, &refcount_block);
106
@@ -XXX,XX +XXX,XX @@ static void reopen_backing_file(BlockDriverState *bs, bool writable,
219
}
107
reopen_queue, &local_err);
220
ret = alloc_refcount_block(bs, cluster_index, &refcount_block);
108
error_propagate(errp, local_err);
221
if (ret < 0) {
222
@@ -XXX,XX +XXX,XX @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
223
table = qcow2_cache_is_table_offset(bs, s->refcount_block_cache,
224
offset);
225
if (table != NULL) {
226
- qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block);
227
+ qcow2_cache_put(s->refcount_block_cache, &refcount_block);
228
qcow2_cache_discard(bs, s->refcount_block_cache, table);
229
}
230
231
@@ -XXX,XX +XXX,XX @@ fail:
232
233
/* Write last changed block to disk */
234
if (refcount_block) {
235
- qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block);
236
+ qcow2_cache_put(s->refcount_block_cache, &refcount_block);
237
}
109
}
238
110
+
239
/*
111
+ bdrv_subtree_drained_end(s->hidden_disk->bs);
240
@@ -XXX,XX +XXX,XX @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
112
+ bdrv_subtree_drained_end(s->secondary_disk->bs);
241
}
113
}
242
}
114
243
115
static void backup_job_cleanup(BlockDriverState *bs)
244
- qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
116
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
245
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
117
index XXXXXXX..XXXXXXX 100644
246
118
--- a/qemu-io-cmds.c
247
if (addend != 0) {
119
+++ b/qemu-io-cmds.c
248
ret = qcow2_update_cluster_refcount(bs, l2_offset >>
120
@@ -XXX,XX +XXX,XX @@ static int reopen_f(BlockBackend *blk, int argc, char **argv)
249
@@ -XXX,XX +XXX,XX @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
121
opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : NULL;
250
ret = bdrv_flush(bs);
122
qemu_opts_reset(&reopen_opts);
251
fail:
123
252
if (l2_table) {
124
+ bdrv_subtree_drained_begin(bs);
253
- qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
125
brq = bdrv_reopen_queue(NULL, bs, opts, flags);
254
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
126
bdrv_reopen_multiple(bdrv_get_aio_context(bs), brq, &local_err);
255
}
127
+ bdrv_subtree_drained_end(bs);
256
128
+
257
s->cache_discards = false;
129
if (local_err) {
258
@@ -XXX,XX +XXX,XX @@ static int walk_over_reftable(BlockDriverState *bs, uint64_t **new_reftable,
130
error_report_err(local_err);
259
new_reftable_size, new_refblock,
131
} else {
260
new_refblock_empty, allocated, errp);
261
if (ret < 0) {
262
- qcow2_cache_put(bs, s->refcount_block_cache, &refblock);
263
+ qcow2_cache_put(s->refcount_block_cache, &refblock);
264
return ret;
265
}
266
267
@@ -XXX,XX +XXX,XX @@ static int walk_over_reftable(BlockDriverState *bs, uint64_t **new_reftable,
268
if (new_refcount_bits < 64 && refcount >> new_refcount_bits) {
269
uint64_t offset;
270
271
- qcow2_cache_put(bs, s->refcount_block_cache, &refblock);
272
+ qcow2_cache_put(s->refcount_block_cache, &refblock);
273
274
offset = ((reftable_index << s->refcount_block_bits)
275
+ refblock_index) << s->cluster_bits;
276
@@ -XXX,XX +XXX,XX @@ static int walk_over_reftable(BlockDriverState *bs, uint64_t **new_reftable,
277
new_refblock_empty = new_refblock_empty && refcount == 0;
278
}
279
280
- qcow2_cache_put(bs, s->refcount_block_cache, &refblock);
281
+ qcow2_cache_put(s->refcount_block_cache, &refblock);
282
} else {
283
/* No refblock means every refcount is 0 */
284
for (refblock_index = 0; refblock_index < s->refcount_block_size;
285
@@ -XXX,XX +XXX,XX @@ static int qcow2_discard_refcount_block(BlockDriverState *bs,
286
offset_to_reftable_index(s, discard_block_offs),
287
discard_block_offs,
288
s->get_refcount(refblock, block_index));
289
- qcow2_cache_put(bs, s->refcount_block_cache, &refblock);
290
+ qcow2_cache_put(s->refcount_block_cache, &refblock);
291
return -EINVAL;
292
}
293
s->set_refcount(refblock, block_index, 0);
294
295
qcow2_cache_entry_mark_dirty(s->refcount_block_cache, refblock);
296
297
- qcow2_cache_put(bs, s->refcount_block_cache, &refblock);
298
+ qcow2_cache_put(s->refcount_block_cache, &refblock);
299
300
if (cluster_index < s->free_cluster_index) {
301
s->free_cluster_index = cluster_index;
302
@@ -XXX,XX +XXX,XX @@ int qcow2_shrink_reftable(BlockDriverState *bs)
303
} else {
304
unused_block = buffer_is_zero(refblock, s->cluster_size);
305
}
306
- qcow2_cache_put(bs, s->refcount_block_cache, &refblock);
307
+ qcow2_cache_put(s->refcount_block_cache, &refblock);
308
309
reftable_tmp[i] = unused_block ? 0 : cpu_to_be64(s->refcount_table[i]);
310
}
311
--
132
--
312
2.13.6
133
2.13.6
313
134
314
135
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
This function was only using the BlockDriverState parameter to pass it
4
to qcow2_cache_get_table_idx() and qcow2_cache_table_release(). This
5
is no longer necessary so this parameter can be removed.
6
7
Signed-off-by: Alberto Garcia <berto@igalia.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Message-id: 9724f7e38e763ad3be32627c6b7fe8df9edb1476.1517840877.git.berto@igalia.com
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
13
block/qcow2.h | 2 +-
14
block/qcow2-cache.c | 2 +-
15
block/qcow2-refcount.c | 6 +++---
16
3 files changed, 5 insertions(+), 5 deletions(-)
17
18
diff --git a/block/qcow2.h b/block/qcow2.h
19
index XXXXXXX..XXXXXXX 100644
20
--- a/block/qcow2.h
21
+++ b/block/qcow2.h
22
@@ -XXX,XX +XXX,XX @@ int qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
23
void qcow2_cache_put(Qcow2Cache *c, void **table);
24
void *qcow2_cache_is_table_offset(BlockDriverState *bs, Qcow2Cache *c,
25
uint64_t offset);
26
-void qcow2_cache_discard(BlockDriverState *bs, Qcow2Cache *c, void *table);
27
+void qcow2_cache_discard(Qcow2Cache *c, void *table);
28
29
/* qcow2-bitmap.c functions */
30
int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
31
diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c
32
index XXXXXXX..XXXXXXX 100644
33
--- a/block/qcow2-cache.c
34
+++ b/block/qcow2-cache.c
35
@@ -XXX,XX +XXX,XX @@ void *qcow2_cache_is_table_offset(BlockDriverState *bs, Qcow2Cache *c,
36
return NULL;
37
}
38
39
-void qcow2_cache_discard(BlockDriverState *bs, Qcow2Cache *c, void *table)
40
+void qcow2_cache_discard(Qcow2Cache *c, void *table)
41
{
42
int i = qcow2_cache_get_table_idx(c, table);
43
44
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
45
index XXXXXXX..XXXXXXX 100644
46
--- a/block/qcow2-refcount.c
47
+++ b/block/qcow2-refcount.c
48
@@ -XXX,XX +XXX,XX @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
49
offset);
50
if (table != NULL) {
51
qcow2_cache_put(s->refcount_block_cache, &refcount_block);
52
- qcow2_cache_discard(bs, s->refcount_block_cache, table);
53
+ qcow2_cache_discard(s->refcount_block_cache, table);
54
}
55
56
table = qcow2_cache_is_table_offset(bs, s->l2_table_cache, offset);
57
if (table != NULL) {
58
- qcow2_cache_discard(bs, s->l2_table_cache, table);
59
+ qcow2_cache_discard(s->l2_table_cache, table);
60
}
61
62
if (s->discard_passthrough[type]) {
63
@@ -XXX,XX +XXX,XX @@ static int qcow2_discard_refcount_block(BlockDriverState *bs,
64
discard_block_offs);
65
if (refblock) {
66
/* discard refblock from the cache if refblock is cached */
67
- qcow2_cache_discard(bs, s->refcount_block_cache, refblock);
68
+ qcow2_cache_discard(s->refcount_block_cache, refblock);
69
}
70
update_refcount_discard(bs, discard_block_offs, s->cluster_size);
71
72
--
73
2.13.6
74
75
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
The BDRVQcow2State structure contains an l2_size field, which stores
4
the number of 64-bit entries in an L2 table.
5
6
For efficiency reasons we want to be able to load slices instead of
7
full L2 tables, so we need to know how many entries an L2 slice can
8
hold.
9
10
An L2 slice is the portion of an L2 table that is loaded by the qcow2
11
cache. At the moment that cache can only load complete tables,
12
therefore an L2 slice has the same size as an L2 table (one cluster)
13
and l2_size == l2_slice_size.
14
15
Later we'll allow smaller slices, but until then we have to use this
16
new l2_slice_size field to make the rest of the code ready for that.
17
18
Signed-off-by: Alberto Garcia <berto@igalia.com>
19
Reviewed-by: Eric Blake <eblake@redhat.com>
20
Reviewed-by: Max Reitz <mreitz@redhat.com>
21
Message-id: adb048595f9fb5dfb110c802a8b3c3be3b937f37.1517840877.git.berto@igalia.com
22
Signed-off-by: Max Reitz <mreitz@redhat.com>
23
---
24
block/qcow2.h | 1 +
25
block/qcow2.c | 3 +++
26
2 files changed, 4 insertions(+)
27
28
diff --git a/block/qcow2.h b/block/qcow2.h
29
index XXXXXXX..XXXXXXX 100644
30
--- a/block/qcow2.h
31
+++ b/block/qcow2.h
32
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVQcow2State {
33
int cluster_bits;
34
int cluster_size;
35
int cluster_sectors;
36
+ int l2_slice_size;
37
int l2_bits;
38
int l2_size;
39
int l1_size;
40
diff --git a/block/qcow2.c b/block/qcow2.c
41
index XXXXXXX..XXXXXXX 100644
42
--- a/block/qcow2.c
43
+++ b/block/qcow2.c
44
@@ -XXX,XX +XXX,XX @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
45
typedef struct Qcow2ReopenState {
46
Qcow2Cache *l2_table_cache;
47
Qcow2Cache *refcount_block_cache;
48
+ int l2_slice_size; /* Number of entries in a slice of the L2 table */
49
bool use_lazy_refcounts;
50
int overlap_check;
51
bool discard_passthrough[QCOW2_DISCARD_MAX];
52
@@ -XXX,XX +XXX,XX @@ static int qcow2_update_options_prepare(BlockDriverState *bs,
53
}
54
}
55
56
+ r->l2_slice_size = s->cluster_size / sizeof(uint64_t);
57
r->l2_table_cache = qcow2_cache_create(bs, l2_cache_size);
58
r->refcount_block_cache = qcow2_cache_create(bs, refcount_cache_size);
59
if (r->l2_table_cache == NULL || r->refcount_block_cache == NULL) {
60
@@ -XXX,XX +XXX,XX @@ static void qcow2_update_options_commit(BlockDriverState *bs,
61
}
62
s->l2_table_cache = r->l2_table_cache;
63
s->refcount_block_cache = r->refcount_block_cache;
64
+ s->l2_slice_size = r->l2_slice_size;
65
66
s->overlap_check = r->overlap_check;
67
s->use_lazy_refcounts = r->use_lazy_refcounts;
68
--
69
2.13.6
70
71
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
Each entry in the qcow2 L2 cache stores a full L2 table (which uses a
4
complete cluster in the qcow2 image). A cluster is usually too large
5
to be used efficiently as the size for a cache entry, so we want to
6
decouple both values by allowing smaller cache entries. Therefore the
7
qcow2 L2 cache will no longer return full L2 tables but slices
8
instead.
9
10
This patch updates l2_load() so it can handle L2 slices correctly.
11
Apart from the offset of the L2 table (which we already had) we also
12
need the guest offset in order to calculate which one of the slices
13
we need.
14
15
An L2 slice has currently the same size as an L2 table (one cluster),
16
so for now this function will load exactly the same data as before.
17
18
This patch also removes a stale comment about the return value being
19
a pointer to the L2 table. This function returns an error code since
20
55c17e9821c474d5fcdebdc82ed2fc096777d611.
21
22
Signed-off-by: Alberto Garcia <berto@igalia.com>
23
Reviewed-by: Eric Blake <eblake@redhat.com>
24
Reviewed-by: Max Reitz <mreitz@redhat.com>
25
Message-id: b830aa1fc5b6f8e3cb331d006853fe22facca847.1517840877.git.berto@igalia.com
26
Signed-off-by: Max Reitz <mreitz@redhat.com>
27
---
28
block/qcow2-cluster.c | 28 +++++++++++++++++-----------
29
1 file changed, 17 insertions(+), 11 deletions(-)
30
31
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
32
index XXXXXXX..XXXXXXX 100644
33
--- a/block/qcow2-cluster.c
34
+++ b/block/qcow2-cluster.c
35
@@ -XXX,XX +XXX,XX @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
36
/*
37
* l2_load
38
*
39
- * Loads a L2 table into memory. If the table is in the cache, the cache
40
- * is used; otherwise the L2 table is loaded from the image file.
41
+ * @bs: The BlockDriverState
42
+ * @offset: A guest offset, used to calculate what slice of the L2
43
+ * table to load.
44
+ * @l2_offset: Offset to the L2 table in the image file.
45
+ * @l2_slice: Location to store the pointer to the L2 slice.
46
*
47
- * Returns a pointer to the L2 table on success, or NULL if the read from
48
- * the image file failed.
49
+ * Loads a L2 slice into memory (L2 slices are the parts of L2 tables
50
+ * that are loaded by the qcow2 cache). If the slice is in the cache,
51
+ * the cache is used; otherwise the L2 slice is loaded from the image
52
+ * file.
53
*/
54
-
55
-static int l2_load(BlockDriverState *bs, uint64_t l2_offset,
56
- uint64_t **l2_table)
57
+static int l2_load(BlockDriverState *bs, uint64_t offset,
58
+ uint64_t l2_offset, uint64_t **l2_slice)
59
{
60
BDRVQcow2State *s = bs->opaque;
61
+ int start_of_slice = sizeof(uint64_t) *
62
+ (offset_to_l2_index(s, offset) - offset_to_l2_slice_index(s, offset));
63
64
- return qcow2_cache_get(bs, s->l2_table_cache, l2_offset,
65
- (void **)l2_table);
66
+ return qcow2_cache_get(bs, s->l2_table_cache, l2_offset + start_of_slice,
67
+ (void **)l2_slice);
68
}
69
70
/*
71
@@ -XXX,XX +XXX,XX @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
72
73
/* load the l2 table in memory */
74
75
- ret = l2_load(bs, l2_offset, &l2_table);
76
+ ret = l2_load(bs, offset, l2_offset, &l2_table);
77
if (ret < 0) {
78
return ret;
79
}
80
@@ -XXX,XX +XXX,XX @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
81
82
if (s->l1_table[l1_index] & QCOW_OFLAG_COPIED) {
83
/* load the l2 table in memory */
84
- ret = l2_load(bs, l2_offset, &l2_table);
85
+ ret = l2_load(bs, offset, l2_offset, &l2_table);
86
if (ret < 0) {
87
return ret;
88
}
89
--
90
2.13.6
91
92
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
Adding support for L2 slices to l2_allocate() needs (among other
4
things) an extra loop that iterates over all slices of a new L2 table.
5
6
Putting all changes in one patch would make it hard to read because
7
all semantic changes would be mixed with pure indentation changes.
8
9
To make things easier this patch simply creates a new block and
10
changes the indentation of all lines of code inside it. Thus, all
11
modifications in this patch are cosmetic. There are no semantic
12
changes and no variables are renamed yet. The next patch will take
13
care of that.
14
15
Signed-off-by: Alberto Garcia <berto@igalia.com>
16
Reviewed-by: Eric Blake <eblake@redhat.com>
17
Reviewed-by: Max Reitz <mreitz@redhat.com>
18
Message-id: d0d7dca8520db304524f52f49d8157595a707a35.1517840877.git.berto@igalia.com
19
Signed-off-by: Max Reitz <mreitz@redhat.com>
20
---
21
block/qcow2-cluster.c | 53 ++++++++++++++++++++++++++++-----------------------
22
1 file changed, 29 insertions(+), 24 deletions(-)
23
24
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
25
index XXXXXXX..XXXXXXX 100644
26
--- a/block/qcow2-cluster.c
27
+++ b/block/qcow2-cluster.c
28
@@ -XXX,XX +XXX,XX @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
29
/* allocate a new entry in the l2 cache */
30
31
trace_qcow2_l2_allocate_get_empty(bs, l1_index);
32
- ret = qcow2_cache_get_empty(bs, s->l2_table_cache, l2_offset, (void**) table);
33
- if (ret < 0) {
34
- goto fail;
35
- }
36
+ {
37
+ ret = qcow2_cache_get_empty(bs, s->l2_table_cache,
38
+ l2_offset,
39
+ (void **) table);
40
+ if (ret < 0) {
41
+ goto fail;
42
+ }
43
44
- l2_table = *table;
45
+ l2_table = *table;
46
47
- if ((old_l2_offset & L1E_OFFSET_MASK) == 0) {
48
- /* if there was no old l2 table, clear the new table */
49
- memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
50
- } else {
51
- uint64_t* old_table;
52
+ if ((old_l2_offset & L1E_OFFSET_MASK) == 0) {
53
+ /* if there was no old l2 table, clear the new table */
54
+ memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
55
+ } else {
56
+ uint64_t *old_table;
57
58
- /* if there was an old l2 table, read it from the disk */
59
- BLKDBG_EVENT(bs->file, BLKDBG_L2_ALLOC_COW_READ);
60
- ret = qcow2_cache_get(bs, s->l2_table_cache,
61
- old_l2_offset & L1E_OFFSET_MASK,
62
- (void**) &old_table);
63
- if (ret < 0) {
64
- goto fail;
65
+ /* if there was an old l2 table, read it from the disk */
66
+ BLKDBG_EVENT(bs->file, BLKDBG_L2_ALLOC_COW_READ);
67
+ ret = qcow2_cache_get(bs, s->l2_table_cache,
68
+ old_l2_offset & L1E_OFFSET_MASK,
69
+ (void **) &old_table);
70
+ if (ret < 0) {
71
+ goto fail;
72
+ }
73
+
74
+ memcpy(l2_table, old_table, s->cluster_size);
75
+
76
+ qcow2_cache_put(s->l2_table_cache, (void **) &old_table);
77
}
78
79
- memcpy(l2_table, old_table, s->cluster_size);
80
+ /* write the l2 table to the file */
81
+ BLKDBG_EVENT(bs->file, BLKDBG_L2_ALLOC_WRITE);
82
83
- qcow2_cache_put(s->l2_table_cache, (void **) &old_table);
84
+ trace_qcow2_l2_allocate_write_l2(bs, l1_index);
85
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
86
}
87
88
- /* write the l2 table to the file */
89
- BLKDBG_EVENT(bs->file, BLKDBG_L2_ALLOC_WRITE);
90
-
91
- trace_qcow2_l2_allocate_write_l2(bs, l1_index);
92
- qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
93
ret = qcow2_cache_flush(bs, s->l2_table_cache);
94
if (ret < 0) {
95
goto fail;
96
--
97
2.13.6
98
99
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
This patch updates l2_allocate() to support the qcow2 cache returning
4
L2 slices instead of full L2 tables.
5
6
The old code simply gets an L2 table from the cache and initializes it
7
with zeroes or with the contents of an existing table. With a cache
8
that returns slices instead of tables the idea remains the same, but
9
the code must now iterate over all the slices that are contained in an
10
L2 table.
11
12
Since now we're operating with slices the function can no longer
13
return the newly-allocated table, so it's up to the caller to retrieve
14
the appropriate L2 slice after calling l2_allocate() (note that with
15
this patch the caller is still loading full L2 tables, but we'll deal
16
with that in a separate patch).
17
18
Signed-off-by: Alberto Garcia <berto@igalia.com>
19
Reviewed-by: Eric Blake <eblake@redhat.com>
20
Message-id: 20fc0415bf0e011e29f6487ec86eb06a11f37445.1517840877.git.berto@igalia.com
21
Reviewed-by: Max Reitz <mreitz@redhat.com>
22
Signed-off-by: Max Reitz <mreitz@redhat.com>
23
---
24
block/qcow2-cluster.c | 56 +++++++++++++++++++++++++++++++--------------------
25
1 file changed, 34 insertions(+), 22 deletions(-)
26
27
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
28
index XXXXXXX..XXXXXXX 100644
29
--- a/block/qcow2-cluster.c
30
+++ b/block/qcow2-cluster.c
31
@@ -XXX,XX +XXX,XX @@ int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index)
32
*
33
*/
34
35
-static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
36
+static int l2_allocate(BlockDriverState *bs, int l1_index)
37
{
38
BDRVQcow2State *s = bs->opaque;
39
uint64_t old_l2_offset;
40
- uint64_t *l2_table = NULL;
41
+ uint64_t *l2_slice = NULL;
42
+ unsigned slice, slice_size2, n_slices;
43
int64_t l2_offset;
44
int ret;
45
46
@@ -XXX,XX +XXX,XX @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
47
48
/* allocate a new entry in the l2 cache */
49
50
+ slice_size2 = s->l2_slice_size * sizeof(uint64_t);
51
+ n_slices = s->cluster_size / slice_size2;
52
+
53
trace_qcow2_l2_allocate_get_empty(bs, l1_index);
54
- {
55
+ for (slice = 0; slice < n_slices; slice++) {
56
ret = qcow2_cache_get_empty(bs, s->l2_table_cache,
57
- l2_offset,
58
- (void **) table);
59
+ l2_offset + slice * slice_size2,
60
+ (void **) &l2_slice);
61
if (ret < 0) {
62
goto fail;
63
}
64
65
- l2_table = *table;
66
-
67
if ((old_l2_offset & L1E_OFFSET_MASK) == 0) {
68
- /* if there was no old l2 table, clear the new table */
69
- memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
70
+ /* if there was no old l2 table, clear the new slice */
71
+ memset(l2_slice, 0, slice_size2);
72
} else {
73
- uint64_t *old_table;
74
+ uint64_t *old_slice;
75
+ uint64_t old_l2_slice_offset =
76
+ (old_l2_offset & L1E_OFFSET_MASK) + slice * slice_size2;
77
78
- /* if there was an old l2 table, read it from the disk */
79
+ /* if there was an old l2 table, read a slice from the disk */
80
BLKDBG_EVENT(bs->file, BLKDBG_L2_ALLOC_COW_READ);
81
- ret = qcow2_cache_get(bs, s->l2_table_cache,
82
- old_l2_offset & L1E_OFFSET_MASK,
83
- (void **) &old_table);
84
+ ret = qcow2_cache_get(bs, s->l2_table_cache, old_l2_slice_offset,
85
+ (void **) &old_slice);
86
if (ret < 0) {
87
goto fail;
88
}
89
90
- memcpy(l2_table, old_table, s->cluster_size);
91
+ memcpy(l2_slice, old_slice, slice_size2);
92
93
- qcow2_cache_put(s->l2_table_cache, (void **) &old_table);
94
+ qcow2_cache_put(s->l2_table_cache, (void **) &old_slice);
95
}
96
97
- /* write the l2 table to the file */
98
+ /* write the l2 slice to the file */
99
BLKDBG_EVENT(bs->file, BLKDBG_L2_ALLOC_WRITE);
100
101
trace_qcow2_l2_allocate_write_l2(bs, l1_index);
102
- qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
103
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
104
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
105
}
106
107
ret = qcow2_cache_flush(bs, s->l2_table_cache);
108
@@ -XXX,XX +XXX,XX @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
109
goto fail;
110
}
111
112
- *table = l2_table;
113
trace_qcow2_l2_allocate_done(bs, l1_index, 0);
114
return 0;
115
116
fail:
117
trace_qcow2_l2_allocate_done(bs, l1_index, ret);
118
- if (l2_table != NULL) {
119
- qcow2_cache_put(s->l2_table_cache, (void **) table);
120
+ if (l2_slice != NULL) {
121
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
122
}
123
s->l1_table[l1_index] = old_l2_offset;
124
if (l2_offset > 0) {
125
@@ -XXX,XX +XXX,XX @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
126
}
127
} else {
128
/* First allocate a new L2 table (and do COW if needed) */
129
- ret = l2_allocate(bs, l1_index, &l2_table);
130
+ ret = l2_allocate(bs, l1_index);
131
if (ret < 0) {
132
return ret;
133
}
134
@@ -XXX,XX +XXX,XX @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
135
qcow2_free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t),
136
QCOW2_DISCARD_OTHER);
137
}
138
+
139
+ /* Get the offset of the newly-allocated l2 table */
140
+ l2_offset = s->l1_table[l1_index] & L1E_OFFSET_MASK;
141
+ assert(offset_into_cluster(s, l2_offset) == 0);
142
+ /* Load the l2 table in memory */
143
+ ret = l2_load(bs, offset, l2_offset, &l2_table);
144
+ if (ret < 0) {
145
+ return ret;
146
+ }
147
}
148
149
/* find the cluster offset for the given disk offset */
150
--
151
2.13.6
152
153
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
After the previous patch we're now always using l2_load() in
4
get_cluster_table() regardless of whether a new L2 table has to be
5
allocated or not.
6
7
This patch refactors that part of the code to use one single l2_load()
8
call.
9
10
Signed-off-by: Alberto Garcia <berto@igalia.com>
11
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Reviewed-by: Max Reitz <mreitz@redhat.com>
13
Message-id: ce31758c4a1fadccea7a6ccb93951eb01d95fd4c.1517840877.git.berto@igalia.com
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
---
16
block/qcow2-cluster.c | 21 +++++++--------------
17
1 file changed, 7 insertions(+), 14 deletions(-)
18
19
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/block/qcow2-cluster.c
22
+++ b/block/qcow2-cluster.c
23
@@ -XXX,XX +XXX,XX @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
24
return -EIO;
25
}
26
27
- /* seek the l2 table of the given l2 offset */
28
-
29
- if (s->l1_table[l1_index] & QCOW_OFLAG_COPIED) {
30
- /* load the l2 table in memory */
31
- ret = l2_load(bs, offset, l2_offset, &l2_table);
32
- if (ret < 0) {
33
- return ret;
34
- }
35
- } else {
36
+ if (!(s->l1_table[l1_index] & QCOW_OFLAG_COPIED)) {
37
/* First allocate a new L2 table (and do COW if needed) */
38
ret = l2_allocate(bs, l1_index);
39
if (ret < 0) {
40
@@ -XXX,XX +XXX,XX @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
41
/* Get the offset of the newly-allocated l2 table */
42
l2_offset = s->l1_table[l1_index] & L1E_OFFSET_MASK;
43
assert(offset_into_cluster(s, l2_offset) == 0);
44
- /* Load the l2 table in memory */
45
- ret = l2_load(bs, offset, l2_offset, &l2_table);
46
- if (ret < 0) {
47
- return ret;
48
- }
49
+ }
50
+
51
+ /* load the l2 table in memory */
52
+ ret = l2_load(bs, offset, l2_offset, &l2_table);
53
+ if (ret < 0) {
54
+ return ret;
55
}
56
57
/* find the cluster offset for the given disk offset */
58
--
59
2.13.6
60
61
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
This patch updates get_cluster_table() to return L2 slices instead of
4
full L2 tables.
5
6
The code itself needs almost no changes, it only needs to call
7
offset_to_l2_slice_index() instead of offset_to_l2_index(). This patch
8
also renames all the relevant variables and the documentation.
9
10
Signed-off-by: Alberto Garcia <berto@igalia.com>
11
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Reviewed-by: Max Reitz <mreitz@redhat.com>
13
Message-id: 64cf064c0021ba315d3f3032da0f95db1b615f33.1517840877.git.berto@igalia.com
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
---
16
block/qcow2-cluster.c | 16 ++++++++--------
17
1 file changed, 8 insertions(+), 8 deletions(-)
18
19
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/block/qcow2-cluster.c
22
+++ b/block/qcow2-cluster.c
23
@@ -XXX,XX +XXX,XX @@ fail:
24
* get_cluster_table
25
*
26
* for a given disk offset, load (and allocate if needed)
27
- * the l2 table.
28
+ * the appropriate slice of its l2 table.
29
*
30
- * the cluster index in the l2 table is given to the caller.
31
+ * the cluster index in the l2 slice is given to the caller.
32
*
33
* Returns 0 on success, -errno in failure case
34
*/
35
static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
36
- uint64_t **new_l2_table,
37
+ uint64_t **new_l2_slice,
38
int *new_l2_index)
39
{
40
BDRVQcow2State *s = bs->opaque;
41
unsigned int l2_index;
42
uint64_t l1_index, l2_offset;
43
- uint64_t *l2_table = NULL;
44
+ uint64_t *l2_slice = NULL;
45
int ret;
46
47
/* seek to the l2 offset in the l1 table */
48
@@ -XXX,XX +XXX,XX @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
49
assert(offset_into_cluster(s, l2_offset) == 0);
50
}
51
52
- /* load the l2 table in memory */
53
- ret = l2_load(bs, offset, l2_offset, &l2_table);
54
+ /* load the l2 slice in memory */
55
+ ret = l2_load(bs, offset, l2_offset, &l2_slice);
56
if (ret < 0) {
57
return ret;
58
}
59
60
/* find the cluster offset for the given disk offset */
61
62
- l2_index = offset_to_l2_index(s, offset);
63
+ l2_index = offset_to_l2_slice_index(s, offset);
64
65
- *new_l2_table = l2_table;
66
+ *new_l2_slice = l2_slice;
67
*new_l2_index = l2_index;
68
69
return 0;
70
--
71
2.13.6
72
73
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
There's a loop in this function that iterates over the L2 entries in a
4
table, so now we need to assert that it remains within the limits of
5
an L2 slice.
6
7
Apart from that, this function doesn't need any additional changes, so
8
this patch simply updates the variable name from l2_table to l2_slice.
9
10
Signed-off-by: Alberto Garcia <berto@igalia.com>
11
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Reviewed-by: Max Reitz <mreitz@redhat.com>
13
Message-id: f9846a1c2efc51938e877e2a25852d9ab14797ff.1517840877.git.berto@igalia.com
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
---
16
block/qcow2-cluster.c | 16 ++++++++--------
17
1 file changed, 8 insertions(+), 8 deletions(-)
18
19
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/block/qcow2-cluster.c
22
+++ b/block/qcow2-cluster.c
23
@@ -XXX,XX +XXX,XX @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
24
{
25
BDRVQcow2State *s = bs->opaque;
26
int i, j = 0, l2_index, ret;
27
- uint64_t *old_cluster, *l2_table;
28
+ uint64_t *old_cluster, *l2_slice;
29
uint64_t cluster_offset = m->alloc_offset;
30
31
trace_qcow2_cluster_link_l2(qemu_coroutine_self(), m->nb_clusters);
32
@@ -XXX,XX +XXX,XX @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
33
s->refcount_block_cache);
34
}
35
36
- ret = get_cluster_table(bs, m->offset, &l2_table, &l2_index);
37
+ ret = get_cluster_table(bs, m->offset, &l2_slice, &l2_index);
38
if (ret < 0) {
39
goto err;
40
}
41
- qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
42
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
43
44
- assert(l2_index + m->nb_clusters <= s->l2_size);
45
+ assert(l2_index + m->nb_clusters <= s->l2_slice_size);
46
for (i = 0; i < m->nb_clusters; i++) {
47
/* if two concurrent writes happen to the same unallocated cluster
48
* each write allocates separate cluster and writes data concurrently.
49
@@ -XXX,XX +XXX,XX @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
50
* cluster the second one has to do RMW (which is done above by
51
* perform_cow()), update l2 table with its cluster pointer and free
52
* old cluster. This is what this loop does */
53
- if (l2_table[l2_index + i] != 0) {
54
- old_cluster[j++] = l2_table[l2_index + i];
55
+ if (l2_slice[l2_index + i] != 0) {
56
+ old_cluster[j++] = l2_slice[l2_index + i];
57
}
58
59
- l2_table[l2_index + i] = cpu_to_be64((cluster_offset +
60
+ l2_slice[l2_index + i] = cpu_to_be64((cluster_offset +
61
(i << s->cluster_bits)) | QCOW_OFLAG_COPIED);
62
}
63
64
65
- qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
66
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
67
68
/*
69
* If this was a COW, we need to decrease the refcount of the old cluster.
70
--
71
2.13.6
72
73
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
handle_copied() loads an L2 table and limits the number of checked
4
clusters to the amount that fits inside that table. Since we'll be
5
loading L2 slices instead of full tables we need to update that limit.
6
7
Apart from that, this function doesn't need any additional changes, so
8
this patch simply updates the variable name from l2_table to l2_slice.
9
10
Signed-off-by: Alberto Garcia <berto@igalia.com>
11
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Reviewed-by: Max Reitz <mreitz@redhat.com>
13
Message-id: 541ac001a7d6b86bab2392554bee53c2b312148c.1517840877.git.berto@igalia.com
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
---
16
block/qcow2-cluster.c | 16 ++++++++--------
17
1 file changed, 8 insertions(+), 8 deletions(-)
18
19
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/block/qcow2-cluster.c
22
+++ b/block/qcow2-cluster.c
23
@@ -XXX,XX +XXX,XX @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset,
24
BDRVQcow2State *s = bs->opaque;
25
int l2_index;
26
uint64_t cluster_offset;
27
- uint64_t *l2_table;
28
+ uint64_t *l2_slice;
29
uint64_t nb_clusters;
30
unsigned int keep_clusters;
31
int ret;
32
@@ -XXX,XX +XXX,XX @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset,
33
== offset_into_cluster(s, *host_offset));
34
35
/*
36
- * Calculate the number of clusters to look for. We stop at L2 table
37
+ * Calculate the number of clusters to look for. We stop at L2 slice
38
* boundaries to keep things simple.
39
*/
40
nb_clusters =
41
size_to_clusters(s, offset_into_cluster(s, guest_offset) + *bytes);
42
43
- l2_index = offset_to_l2_index(s, guest_offset);
44
- nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
45
+ l2_index = offset_to_l2_slice_index(s, guest_offset);
46
+ nb_clusters = MIN(nb_clusters, s->l2_slice_size - l2_index);
47
assert(nb_clusters <= INT_MAX);
48
49
/* Find L2 entry for the first involved cluster */
50
- ret = get_cluster_table(bs, guest_offset, &l2_table, &l2_index);
51
+ ret = get_cluster_table(bs, guest_offset, &l2_slice, &l2_index);
52
if (ret < 0) {
53
return ret;
54
}
55
56
- cluster_offset = be64_to_cpu(l2_table[l2_index]);
57
+ cluster_offset = be64_to_cpu(l2_slice[l2_index]);
58
59
/* Check how many clusters are already allocated and don't need COW */
60
if (qcow2_get_cluster_type(cluster_offset) == QCOW2_CLUSTER_NORMAL
61
@@ -XXX,XX +XXX,XX @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset,
62
/* We keep all QCOW_OFLAG_COPIED clusters */
63
keep_clusters =
64
count_contiguous_clusters(nb_clusters, s->cluster_size,
65
- &l2_table[l2_index],
66
+ &l2_slice[l2_index],
67
QCOW_OFLAG_COPIED | QCOW_OFLAG_ZERO);
68
assert(keep_clusters <= nb_clusters);
69
70
@@ -XXX,XX +XXX,XX @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset,
71
72
/* Cleanup */
73
out:
74
- qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
75
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
76
77
/* Only return a host offset if we actually made progress. Otherwise we
78
* would make requirements for handle_alloc() that it can't fulfill */
79
--
80
2.13.6
81
82
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
handle_alloc() loads an L2 table and limits the number of checked
4
clusters to the amount that fits inside that table. Since we'll be
5
loading L2 slices instead of full tables we need to update that limit.
6
7
Apart from that, this function doesn't need any additional changes, so
8
this patch simply updates the variable name from l2_table to l2_slice.
9
10
Signed-off-by: Alberto Garcia <berto@igalia.com>
11
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Reviewed-by: Max Reitz <mreitz@redhat.com>
13
Message-id: b243299c7136f7014c5af51665431ddbf5e99afd.1517840877.git.berto@igalia.com
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
---
16
block/qcow2-cluster.c | 18 +++++++++---------
17
1 file changed, 9 insertions(+), 9 deletions(-)
18
19
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/block/qcow2-cluster.c
22
+++ b/block/qcow2-cluster.c
23
@@ -XXX,XX +XXX,XX @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
24
{
25
BDRVQcow2State *s = bs->opaque;
26
int l2_index;
27
- uint64_t *l2_table;
28
+ uint64_t *l2_slice;
29
uint64_t entry;
30
uint64_t nb_clusters;
31
int ret;
32
@@ -XXX,XX +XXX,XX @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
33
assert(*bytes > 0);
34
35
/*
36
- * Calculate the number of clusters to look for. We stop at L2 table
37
+ * Calculate the number of clusters to look for. We stop at L2 slice
38
* boundaries to keep things simple.
39
*/
40
nb_clusters =
41
size_to_clusters(s, offset_into_cluster(s, guest_offset) + *bytes);
42
43
- l2_index = offset_to_l2_index(s, guest_offset);
44
- nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
45
+ l2_index = offset_to_l2_slice_index(s, guest_offset);
46
+ nb_clusters = MIN(nb_clusters, s->l2_slice_size - l2_index);
47
assert(nb_clusters <= INT_MAX);
48
49
/* Find L2 entry for the first involved cluster */
50
- ret = get_cluster_table(bs, guest_offset, &l2_table, &l2_index);
51
+ ret = get_cluster_table(bs, guest_offset, &l2_slice, &l2_index);
52
if (ret < 0) {
53
return ret;
54
}
55
56
- entry = be64_to_cpu(l2_table[l2_index]);
57
+ entry = be64_to_cpu(l2_slice[l2_index]);
58
59
/* For the moment, overwrite compressed clusters one by one */
60
if (entry & QCOW_OFLAG_COMPRESSED) {
61
nb_clusters = 1;
62
} else {
63
- nb_clusters = count_cow_clusters(s, nb_clusters, l2_table, l2_index);
64
+ nb_clusters = count_cow_clusters(s, nb_clusters, l2_slice, l2_index);
65
}
66
67
/* This function is only called when there were no non-COW clusters, so if
68
@@ -XXX,XX +XXX,XX @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
69
* nb_clusters already to a range of COW clusters */
70
preallocated_nb_clusters =
71
count_contiguous_clusters(nb_clusters, s->cluster_size,
72
- &l2_table[l2_index], QCOW_OFLAG_COPIED);
73
+ &l2_slice[l2_index], QCOW_OFLAG_COPIED);
74
assert(preallocated_nb_clusters > 0);
75
76
nb_clusters = preallocated_nb_clusters;
77
@@ -XXX,XX +XXX,XX @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
78
keep_old_clusters = true;
79
}
80
81
- qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
82
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
83
84
if (!alloc_cluster_offset) {
85
/* Allocate, if necessary at a given offset in the image file */
86
--
87
2.13.6
88
89
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
Adding support for L2 slices to qcow2_update_snapshot_refcount() needs
4
(among other things) an extra loop that iterates over all slices of
5
each L2 table.
6
7
Putting all changes in one patch would make it hard to read because
8
all semantic changes would be mixed with pure indentation changes.
9
10
To make things easier this patch simply creates a new block and
11
changes the indentation of all lines of code inside it. Thus, all
12
modifications in this patch are cosmetic. There are no semantic
13
changes and no variables are renamed yet. The next patch will take
14
care of that.
15
16
Signed-off-by: Alberto Garcia <berto@igalia.com>
17
Reviewed-by: Eric Blake <eblake@redhat.com>
18
Reviewed-by: Max Reitz <mreitz@redhat.com>
19
Message-id: 8ffaa5e55bd51121f80e498f4045b64902a94293.1517840877.git.berto@igalia.com
20
Signed-off-by: Max Reitz <mreitz@redhat.com>
21
---
22
block/qcow2-refcount.c | 144 +++++++++++++++++++++++++------------------------
23
1 file changed, 75 insertions(+), 69 deletions(-)
24
25
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
26
index XXXXXXX..XXXXXXX 100644
27
--- a/block/qcow2-refcount.c
28
+++ b/block/qcow2-refcount.c
29
@@ -XXX,XX +XXX,XX @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
30
goto fail;
31
}
32
33
- ret = qcow2_cache_get(bs, s->l2_table_cache, l2_offset,
34
- (void**) &l2_table);
35
- if (ret < 0) {
36
- goto fail;
37
- }
38
+ {
39
+ ret = qcow2_cache_get(bs, s->l2_table_cache,
40
+ l2_offset,
41
+ (void **) &l2_table);
42
+ if (ret < 0) {
43
+ goto fail;
44
+ }
45
46
- for (j = 0; j < s->l2_size; j++) {
47
- uint64_t cluster_index;
48
- uint64_t offset;
49
-
50
- entry = be64_to_cpu(l2_table[j]);
51
- old_entry = entry;
52
- entry &= ~QCOW_OFLAG_COPIED;
53
- offset = entry & L2E_OFFSET_MASK;
54
-
55
- switch (qcow2_get_cluster_type(entry)) {
56
- case QCOW2_CLUSTER_COMPRESSED:
57
- nb_csectors = ((entry >> s->csize_shift) &
58
- s->csize_mask) + 1;
59
- if (addend != 0) {
60
- ret = update_refcount(bs,
61
- (entry & s->cluster_offset_mask) & ~511,
62
+ for (j = 0; j < s->l2_size; j++) {
63
+ uint64_t cluster_index;
64
+ uint64_t offset;
65
+
66
+ entry = be64_to_cpu(l2_table[j]);
67
+ old_entry = entry;
68
+ entry &= ~QCOW_OFLAG_COPIED;
69
+ offset = entry & L2E_OFFSET_MASK;
70
+
71
+ switch (qcow2_get_cluster_type(entry)) {
72
+ case QCOW2_CLUSTER_COMPRESSED:
73
+ nb_csectors = ((entry >> s->csize_shift) &
74
+ s->csize_mask) + 1;
75
+ if (addend != 0) {
76
+ ret = update_refcount(
77
+ bs, (entry & s->cluster_offset_mask) & ~511,
78
nb_csectors * 512, abs(addend), addend < 0,
79
QCOW2_DISCARD_SNAPSHOT);
80
- if (ret < 0) {
81
+ if (ret < 0) {
82
+ goto fail;
83
+ }
84
+ }
85
+ /* compressed clusters are never modified */
86
+ refcount = 2;
87
+ break;
88
+
89
+ case QCOW2_CLUSTER_NORMAL:
90
+ case QCOW2_CLUSTER_ZERO_ALLOC:
91
+ if (offset_into_cluster(s, offset)) {
92
+ qcow2_signal_corruption(
93
+ bs, true, -1, -1, "Cluster "
94
+ "allocation offset %#" PRIx64
95
+ " unaligned (L2 offset: %#"
96
+ PRIx64 ", L2 index: %#x)",
97
+ offset, l2_offset, j);
98
+ ret = -EIO;
99
goto fail;
100
}
101
- }
102
- /* compressed clusters are never modified */
103
- refcount = 2;
104
- break;
105
-
106
- case QCOW2_CLUSTER_NORMAL:
107
- case QCOW2_CLUSTER_ZERO_ALLOC:
108
- if (offset_into_cluster(s, offset)) {
109
- qcow2_signal_corruption(bs, true, -1, -1, "Cluster "
110
- "allocation offset %#" PRIx64
111
- " unaligned (L2 offset: %#"
112
- PRIx64 ", L2 index: %#x)",
113
- offset, l2_offset, j);
114
- ret = -EIO;
115
- goto fail;
116
- }
117
118
- cluster_index = offset >> s->cluster_bits;
119
- assert(cluster_index);
120
- if (addend != 0) {
121
- ret = qcow2_update_cluster_refcount(bs,
122
- cluster_index, abs(addend), addend < 0,
123
- QCOW2_DISCARD_SNAPSHOT);
124
+ cluster_index = offset >> s->cluster_bits;
125
+ assert(cluster_index);
126
+ if (addend != 0) {
127
+ ret = qcow2_update_cluster_refcount(
128
+ bs, cluster_index, abs(addend), addend < 0,
129
+ QCOW2_DISCARD_SNAPSHOT);
130
+ if (ret < 0) {
131
+ goto fail;
132
+ }
133
+ }
134
+
135
+ ret = qcow2_get_refcount(bs, cluster_index, &refcount);
136
if (ret < 0) {
137
goto fail;
138
}
139
- }
140
+ break;
141
142
- ret = qcow2_get_refcount(bs, cluster_index, &refcount);
143
- if (ret < 0) {
144
- goto fail;
145
- }
146
- break;
147
-
148
- case QCOW2_CLUSTER_ZERO_PLAIN:
149
- case QCOW2_CLUSTER_UNALLOCATED:
150
- refcount = 0;
151
- break;
152
+ case QCOW2_CLUSTER_ZERO_PLAIN:
153
+ case QCOW2_CLUSTER_UNALLOCATED:
154
+ refcount = 0;
155
+ break;
156
157
- default:
158
- abort();
159
- }
160
+ default:
161
+ abort();
162
+ }
163
164
- if (refcount == 1) {
165
- entry |= QCOW_OFLAG_COPIED;
166
- }
167
- if (entry != old_entry) {
168
- if (addend > 0) {
169
- qcow2_cache_set_dependency(bs, s->l2_table_cache,
170
- s->refcount_block_cache);
171
+ if (refcount == 1) {
172
+ entry |= QCOW_OFLAG_COPIED;
173
+ }
174
+ if (entry != old_entry) {
175
+ if (addend > 0) {
176
+ qcow2_cache_set_dependency(bs, s->l2_table_cache,
177
+ s->refcount_block_cache);
178
+ }
179
+ l2_table[j] = cpu_to_be64(entry);
180
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache,
181
+ l2_table);
182
}
183
- l2_table[j] = cpu_to_be64(entry);
184
- qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
185
}
186
- }
187
188
- qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
189
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
190
+
191
+ }
192
193
if (addend != 0) {
194
ret = qcow2_update_cluster_refcount(bs, l2_offset >>
195
--
196
2.13.6
197
198
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
qcow2_update_snapshot_refcount() increases the refcount of all
4
clusters of a given snapshot. In order to do that it needs to load all
5
its L2 tables and iterate over their entries. Since we'll be loading
6
L2 slices instead of full tables we need to add an extra loop that
7
iterates over all slices of each L2 table.
8
9
This function doesn't need any additional changes so apart from that
10
this patch simply updates the variable name from l2_table to l2_slice.
11
12
Signed-off-by: Alberto Garcia <berto@igalia.com>
13
Message-id: 5f4db199b9637f4833b58487135124d70add8cf0.1517840877.git.berto@igalia.com
14
Reviewed-by: Max Reitz <mreitz@redhat.com>
15
Reviewed-by: Eric Blake <eblake@redhat.com>
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
17
---
18
block/qcow2-refcount.c | 32 ++++++++++++++++++--------------
19
1 file changed, 18 insertions(+), 14 deletions(-)
20
21
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
22
index XXXXXXX..XXXXXXX 100644
23
--- a/block/qcow2-refcount.c
24
+++ b/block/qcow2-refcount.c
25
@@ -XXX,XX +XXX,XX @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
26
int64_t l1_table_offset, int l1_size, int addend)
27
{
28
BDRVQcow2State *s = bs->opaque;
29
- uint64_t *l1_table, *l2_table, l2_offset, entry, l1_size2, refcount;
30
+ uint64_t *l1_table, *l2_slice, l2_offset, entry, l1_size2, refcount;
31
bool l1_allocated = false;
32
int64_t old_entry, old_l2_offset;
33
+ unsigned slice, slice_size2, n_slices;
34
int i, j, l1_modified = 0, nb_csectors;
35
int ret;
36
37
assert(addend >= -1 && addend <= 1);
38
39
- l2_table = NULL;
40
+ l2_slice = NULL;
41
l1_table = NULL;
42
l1_size2 = l1_size * sizeof(uint64_t);
43
+ slice_size2 = s->l2_slice_size * sizeof(uint64_t);
44
+ n_slices = s->cluster_size / slice_size2;
45
46
s->cache_discards = true;
47
48
@@ -XXX,XX +XXX,XX @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
49
goto fail;
50
}
51
52
- {
53
+ for (slice = 0; slice < n_slices; slice++) {
54
ret = qcow2_cache_get(bs, s->l2_table_cache,
55
- l2_offset,
56
- (void **) &l2_table);
57
+ l2_offset + slice * slice_size2,
58
+ (void **) &l2_slice);
59
if (ret < 0) {
60
goto fail;
61
}
62
63
- for (j = 0; j < s->l2_size; j++) {
64
+ for (j = 0; j < s->l2_slice_size; j++) {
65
uint64_t cluster_index;
66
uint64_t offset;
67
68
- entry = be64_to_cpu(l2_table[j]);
69
+ entry = be64_to_cpu(l2_slice[j]);
70
old_entry = entry;
71
entry &= ~QCOW_OFLAG_COPIED;
72
offset = entry & L2E_OFFSET_MASK;
73
@@ -XXX,XX +XXX,XX @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
74
case QCOW2_CLUSTER_NORMAL:
75
case QCOW2_CLUSTER_ZERO_ALLOC:
76
if (offset_into_cluster(s, offset)) {
77
+ /* Here l2_index means table (not slice) index */
78
+ int l2_index = slice * s->l2_slice_size + j;
79
qcow2_signal_corruption(
80
bs, true, -1, -1, "Cluster "
81
"allocation offset %#" PRIx64
82
" unaligned (L2 offset: %#"
83
PRIx64 ", L2 index: %#x)",
84
- offset, l2_offset, j);
85
+ offset, l2_offset, l2_index);
86
ret = -EIO;
87
goto fail;
88
}
89
@@ -XXX,XX +XXX,XX @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
90
qcow2_cache_set_dependency(bs, s->l2_table_cache,
91
s->refcount_block_cache);
92
}
93
- l2_table[j] = cpu_to_be64(entry);
94
+ l2_slice[j] = cpu_to_be64(entry);
95
qcow2_cache_entry_mark_dirty(s->l2_table_cache,
96
- l2_table);
97
+ l2_slice);
98
}
99
}
100
101
- qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
102
-
103
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
104
}
105
106
if (addend != 0) {
107
@@ -XXX,XX +XXX,XX @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
108
109
ret = bdrv_flush(bs);
110
fail:
111
- if (l2_table) {
112
- qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
113
+ if (l2_slice) {
114
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
115
}
116
117
s->cache_discards = false;
118
--
119
2.13.6
120
121
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
At the moment it doesn't really make a difference whether we call
4
qcow2_get_refcount() before of after reading the L2 table, but if we
5
want to support L2 slices we'll need to read the refcount first.
6
7
This patch simply changes the order of those two operations to prepare
8
for that. The patch with the actual semantic changes will be easier to
9
read because of this.
10
11
Signed-off-by: Alberto Garcia <berto@igalia.com>
12
Reviewed-by: Eric Blake <eblake@redhat.com>
13
Reviewed-by: Max Reitz <mreitz@redhat.com>
14
Message-id: 947a91d934053a2dbfef979aeb9568f57ef57c5d.1517840877.git.berto@igalia.com
15
Signed-off-by: Max Reitz <mreitz@redhat.com>
16
---
17
block/qcow2-cluster.c | 12 ++++++------
18
1 file changed, 6 insertions(+), 6 deletions(-)
19
20
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
21
index XXXXXXX..XXXXXXX 100644
22
--- a/block/qcow2-cluster.c
23
+++ b/block/qcow2-cluster.c
24
@@ -XXX,XX +XXX,XX @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
25
goto fail;
26
}
27
28
+ ret = qcow2_get_refcount(bs, l2_offset >> s->cluster_bits,
29
+ &l2_refcount);
30
+ if (ret < 0) {
31
+ goto fail;
32
+ }
33
+
34
if (is_active_l1) {
35
/* get active L2 tables from cache */
36
ret = qcow2_cache_get(bs, s->l2_table_cache, l2_offset,
37
@@ -XXX,XX +XXX,XX @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
38
goto fail;
39
}
40
41
- ret = qcow2_get_refcount(bs, l2_offset >> s->cluster_bits,
42
- &l2_refcount);
43
- if (ret < 0) {
44
- goto fail;
45
- }
46
-
47
for (j = 0; j < s->l2_size; j++) {
48
uint64_t l2_entry = be64_to_cpu(l2_table[j]);
49
int64_t offset = l2_entry & L2E_OFFSET_MASK;
50
--
51
2.13.6
52
53
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
The qcow2_truncate() code is mostly independent from whether
4
we're using L2 slices or full L2 tables, but in full and
5
falloc preallocation modes new L2 tables are allocated using
6
qcow2_alloc_cluster_link_l2(). Therefore the code needs to be
7
modified to ensure that all nb_clusters that are processed in each
8
call can be allocated with just one L2 slice.
9
10
Signed-off-by: Alberto Garcia <berto@igalia.com>
11
Message-id: 1fd7d272b5e7b66254a090b74cf2bed1cc334c0e.1517840877.git.berto@igalia.com
12
Reviewed-by: Max Reitz <mreitz@redhat.com>
13
Reviewed-by: Eric Blake <eblake@redhat.com>
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
---
16
block/qcow2.c | 6 +++---
17
1 file changed, 3 insertions(+), 3 deletions(-)
18
19
diff --git a/block/qcow2.c b/block/qcow2.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/block/qcow2.c
22
+++ b/block/qcow2.c
23
@@ -XXX,XX +XXX,XX @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
24
host_offset = allocation_start;
25
guest_offset = old_length;
26
while (nb_new_data_clusters) {
27
- int64_t guest_cluster = guest_offset >> s->cluster_bits;
28
- int64_t nb_clusters = MIN(nb_new_data_clusters,
29
- s->l2_size - guest_cluster % s->l2_size);
30
+ int64_t nb_clusters = MIN(
31
+ nb_new_data_clusters,
32
+ s->l2_slice_size - offset_to_l2_slice_index(s, guest_offset));
33
QCowL2Meta allocation = {
34
.offset = guest_offset,
35
.alloc_offset = host_offset,
36
--
37
2.13.6
38
39
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
This function doesn't need any changes to support L2 slices, but since
4
it's now dealing with slices instead of full tables, the l2_table
5
variable is renamed for clarity.
6
7
Signed-off-by: Alberto Garcia <berto@igalia.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Message-id: 78bcc54bc632574dd0b900a77a00a1b6ffc359e6.1517840877.git.berto@igalia.com
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
13
block/qcow2-cluster.c | 6 +++---
14
1 file changed, 3 insertions(+), 3 deletions(-)
15
16
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/block/qcow2-cluster.c
19
+++ b/block/qcow2-cluster.c
20
@@ -XXX,XX +XXX,XX @@ static int count_contiguous_clusters(int nb_clusters, int cluster_size,
21
22
/*
23
* Checks how many consecutive unallocated clusters in a given L2
24
- * table have the same cluster type.
25
+ * slice have the same cluster type.
26
*/
27
static int count_contiguous_clusters_unallocated(int nb_clusters,
28
- uint64_t *l2_table,
29
+ uint64_t *l2_slice,
30
QCow2ClusterType wanted_type)
31
{
32
int i;
33
@@ -XXX,XX +XXX,XX @@ static int count_contiguous_clusters_unallocated(int nb_clusters,
34
assert(wanted_type == QCOW2_CLUSTER_ZERO_PLAIN ||
35
wanted_type == QCOW2_CLUSTER_UNALLOCATED);
36
for (i = 0; i < nb_clusters; i++) {
37
- uint64_t entry = be64_to_cpu(l2_table[i]);
38
+ uint64_t entry = be64_to_cpu(l2_slice[i]);
39
QCow2ClusterType type = qcow2_get_cluster_type(entry);
40
41
if (type != wanted_type) {
42
--
43
2.13.6
44
45
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
This function doesn't need any changes to support L2 slices, but since
4
it's now dealing with slices intead of full tables, the l2_table
5
variable is renamed for clarity.
6
7
Signed-off-by: Alberto Garcia <berto@igalia.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Message-id: 6107001fc79e6739242f1de7d191375e4f130aac.1517840877.git.berto@igalia.com
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
13
block/qcow2-cluster.c | 4 ++--
14
1 file changed, 2 insertions(+), 2 deletions(-)
15
16
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/block/qcow2-cluster.c
19
+++ b/block/qcow2-cluster.c
20
@@ -XXX,XX +XXX,XX @@ err:
21
* which must copy from the backing file)
22
*/
23
static int count_cow_clusters(BDRVQcow2State *s, int nb_clusters,
24
- uint64_t *l2_table, int l2_index)
25
+ uint64_t *l2_slice, int l2_index)
26
{
27
int i;
28
29
for (i = 0; i < nb_clusters; i++) {
30
- uint64_t l2_entry = be64_to_cpu(l2_table[l2_index + i]);
31
+ uint64_t l2_entry = be64_to_cpu(l2_slice[l2_index + i]);
32
QCow2ClusterType cluster_type = qcow2_get_cluster_type(l2_entry);
33
34
switch(cluster_type) {
35
--
36
2.13.6
37
38
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
expand_zero_clusters_in_l1() is used when downgrading qcow2 images
4
from v3 to v2 (compat=0.10). This is one of the functions that needed
5
more changes to support L2 slices, so this patch extends iotest 061 to
6
test downgrading a qcow2 image using a smaller slice size.
7
8
Signed-off-by: Alberto Garcia <berto@igalia.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Reviewed-by: Max Reitz <mreitz@redhat.com>
11
Message-id: 3e5662dce5e4926c8fabbad4c0b9142b2a506dd4.1517840877.git.berto@igalia.com
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
---
14
tests/qemu-iotests/061 | 16 ++++++++++++
15
tests/qemu-iotests/061.out | 61 ++++++++++++++++++++++++++++++++++++++++++++++
16
2 files changed, 77 insertions(+)
17
18
diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061
19
index XXXXXXX..XXXXXXX 100755
20
--- a/tests/qemu-iotests/061
21
+++ b/tests/qemu-iotests/061
22
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c "read -P 0 0 128k" "$TEST_IMG" | _filter_qemu_io
23
_check_test_img
24
25
echo
26
+echo "=== Testing version downgrade with zero expansion and 4K cache entries ==="
27
+echo
28
+IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M
29
+$QEMU_IO -c "write -z 0 128k" "$TEST_IMG" | _filter_qemu_io
30
+$QEMU_IO -c "write -z 32M 128k" "$TEST_IMG" | _filter_qemu_io
31
+$QEMU_IO -c map "$TEST_IMG" | _filter_qemu_io
32
+$PYTHON qcow2.py "$TEST_IMG" dump-header
33
+$QEMU_IMG amend -o "compat=0.10" --image-opts \
34
+ driver=qcow2,file.filename=$TEST_IMG,l2-cache-entry-size=4096
35
+$PYTHON qcow2.py "$TEST_IMG" dump-header
36
+$QEMU_IO -c "read -P 0 0 128k" "$TEST_IMG" | _filter_qemu_io
37
+$QEMU_IO -c "read -P 0 32M 128k" "$TEST_IMG" | _filter_qemu_io
38
+$QEMU_IO -c map "$TEST_IMG" | _filter_qemu_io
39
+_check_test_img
40
+
41
+echo
42
echo "=== Testing dirty version downgrade ==="
43
echo
44
IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M
45
diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out
46
index XXXXXXX..XXXXXXX 100644
47
--- a/tests/qemu-iotests/061.out
48
+++ b/tests/qemu-iotests/061.out
49
@@ -XXX,XX +XXX,XX @@ read 131072/131072 bytes at offset 0
50
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
51
No errors were found on the image.
52
53
+=== Testing version downgrade with zero expansion and 4K cache entries ===
54
+
55
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
56
+wrote 131072/131072 bytes at offset 0
57
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
58
+wrote 131072/131072 bytes at offset 33554432
59
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
60
+128 KiB (0x20000) bytes allocated at offset 0 bytes (0x0)
61
+31.875 MiB (0x1fe0000) bytes not allocated at offset 128 KiB (0x20000)
62
+128 KiB (0x20000) bytes allocated at offset 32 MiB (0x2000000)
63
+31.875 MiB (0x1fe0000) bytes not allocated at offset 32.125 MiB (0x2020000)
64
+magic 0x514649fb
65
+version 3
66
+backing_file_offset 0x0
67
+backing_file_size 0x0
68
+cluster_bits 16
69
+size 67108864
70
+crypt_method 0
71
+l1_size 1
72
+l1_table_offset 0x30000
73
+refcount_table_offset 0x10000
74
+refcount_table_clusters 1
75
+nb_snapshots 0
76
+snapshot_offset 0x0
77
+incompatible_features 0x0
78
+compatible_features 0x1
79
+autoclear_features 0x0
80
+refcount_order 4
81
+header_length 104
82
+
83
+Header extension:
84
+magic 0x6803f857
85
+length 144
86
+data <binary>
87
+
88
+magic 0x514649fb
89
+version 2
90
+backing_file_offset 0x0
91
+backing_file_size 0x0
92
+cluster_bits 16
93
+size 67108864
94
+crypt_method 0
95
+l1_size 1
96
+l1_table_offset 0x30000
97
+refcount_table_offset 0x10000
98
+refcount_table_clusters 1
99
+nb_snapshots 0
100
+snapshot_offset 0x0
101
+incompatible_features 0x0
102
+compatible_features 0x0
103
+autoclear_features 0x0
104
+refcount_order 4
105
+header_length 72
106
+
107
+read 131072/131072 bytes at offset 0
108
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
109
+read 131072/131072 bytes at offset 33554432
110
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
111
+64 MiB (0x4000000) bytes not allocated at offset 0 bytes (0x0)
112
+No errors were found on the image.
113
+
114
=== Testing dirty version downgrade ===
115
116
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
117
--
118
2.13.6
119
120
diff view generated by jsdifflib