1
The following changes since commit ba29883206d92a29ad5a466e679ccfc2ee6132ef:
1
The following changes since commit 27c94566379069fb8930bb1433dcffbf7df3203d:
2
2
3
Merge remote-tracking branch 'remotes/borntraeger/tags/s390x-20200310' into staging (2020-03-10 16:50:28 +0000)
3
Merge remote-tracking branch 'remotes/edgar/tags/edgar/xilinx-next-2020-04-30.for-upstream' into staging (2020-04-30 16:47:23 +0100)
4
4
5
are available in the Git repository at:
5
are available in the Git repository at:
6
6
7
https://github.com/XanClic/qemu.git tags/pull-block-2020-03-11
7
https://github.com/stefanha/qemu.git tags/block-pull-request
8
8
9
for you to fetch changes up to 397f4e9d83e9c0000905f0a988ba1aeda162571c:
9
for you to fetch changes up to cc1adc4488059ac16d4d2772a7aa7cd1323deeca:
10
10
11
block/block-copy: hide structure definitions (2020-03-11 12:42:30 +0100)
11
lockable: Replace locks with lock guard macros (2020-05-01 09:19:25 +0100)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block patches for the 5.0 softfreeze:
14
Pull request
15
- qemu-img measure for LUKS
15
16
- Improve block-copy's performance by reducing inter-request
16
Fix the QEMU_LOCK_GUARD() macros, use them more widely, and allow the fuzzer
17
dependencies
17
target to be selected from argv[0].
18
- Make curl's detection of accept-ranges more robust
19
- Memleak fixes
20
- iotest fix
21
18
22
----------------------------------------------------------------
19
----------------------------------------------------------------
23
David Edmondson (2):
24
block/curl: HTTP header fields allow whitespace around values
25
block/curl: HTTP header field names are case insensitive
26
20
27
Eric Blake (1):
21
Alexander Bulekov (1):
28
iotests: Fix nonportable use of od --endian
22
fuzz: select fuzz target using executable name
29
23
30
Pan Nengyuan (2):
24
Daniel Brodsky (2):
31
block/qcow2: do free crypto_opts in qcow2_close()
25
lockable: fix __COUNTER__ macro to be referenced properly
32
qemu-img: free memory before re-assign
26
lockable: replaced locks with lock guard macros where appropriate
33
27
34
Stefan Hajnoczi (4):
28
Simran Singhal (1):
35
luks: extract qcrypto_block_calculate_payload_offset()
29
lockable: Replace locks with lock guard macros
36
luks: implement .bdrv_measure()
37
qemu-img: allow qemu-img measure --object without a filename
38
iotests: add 288 luks qemu-img measure test
39
30
40
Vladimir Sementsov-Ogievskiy (10):
31
include/qemu/lockable.h | 7 +++---
41
block/qcow2-threads: fix qcow2_decompress
32
include/qemu/rcu.h | 2 +-
42
job: refactor progress to separate object
33
block/iscsi.c | 7 ++----
43
block/block-copy: fix progress calculation
34
block/nfs.c | 51 +++++++++++++++++++----------------------
44
block/block-copy: specialcase first copy_range request
35
cpus-common.c | 14 ++++-------
45
block/block-copy: use block_status
36
hw/display/qxl.c | 43 ++++++++++++++++------------------
46
block/block-copy: factor out find_conflicting_inflight_req
37
hw/hyperv/hyperv.c | 15 ++++++------
47
block/block-copy: refactor interfaces to use bytes instead of end
38
hw/rdma/rdma_backend.c | 50 ++++++++++++++++++++--------------------
48
block/block-copy: rename start to offset in interfaces
39
hw/rdma/rdma_rm.c | 3 +--
49
block/block-copy: reduce intersecting request lock
40
hw/vfio/platform.c | 5 ++--
50
block/block-copy: hide structure definitions
41
migration/migration.c | 3 +--
51
42
migration/multifd.c | 8 +++----
52
block/backup-top.c | 6 +-
43
migration/ram.c | 3 +--
53
block/backup.c | 38 ++-
44
monitor/misc.c | 4 +---
54
block/block-copy.c | 405 ++++++++++++++++++++++++-------
45
tests/qtest/fuzz/fuzz.c | 19 ++++++++-------
55
block/crypto.c | 62 +++++
46
ui/spice-display.c | 14 +++++------
56
block/curl.c | 32 ++-
47
util/log.c | 4 ++--
57
block/qcow2-threads.c | 12 +-
48
util/qemu-timer.c | 17 +++++++-------
58
block/qcow2.c | 75 ++----
49
util/rcu.c | 8 +++----
59
block/trace-events | 1 +
50
util/thread-pool.c | 3 +--
60
blockjob.c | 16 +-
51
util/vfio-helpers.c | 5 ++--
61
crypto/block.c | 36 +++
52
slirp | 2 +-
62
include/block/block-copy.h | 65 +----
53
22 files changed, 133 insertions(+), 154 deletions(-)
63
include/crypto/block.h | 22 ++
64
include/qemu/job.h | 11 +-
65
include/qemu/progress_meter.h | 58 +++++
66
job-qmp.c | 4 +-
67
job.c | 6 +-
68
qemu-img.c | 14 +-
69
tests/qemu-iotests/178 | 2 +-
70
tests/qemu-iotests/178.out.qcow2 | 8 +-
71
tests/qemu-iotests/178.out.raw | 8 +-
72
tests/qemu-iotests/288 | 93 +++++++
73
tests/qemu-iotests/288.out | 30 +++
74
tests/qemu-iotests/common.rc | 22 +-
75
tests/qemu-iotests/group | 1 +
76
24 files changed, 749 insertions(+), 278 deletions(-)
77
create mode 100644 include/qemu/progress_meter.h
78
create mode 100755 tests/qemu-iotests/288
79
create mode 100644 tests/qemu-iotests/288.out
80
54
81
--
55
--
82
2.24.1
56
2.25.3
83
57
84
diff view generated by jsdifflib
1
From: Stefan Hajnoczi <stefanha@redhat.com>
1
From: Alexander Bulekov <alxndr@bu.edu>
2
2
3
The qcow2 .bdrv_measure() code calculates the crypto payload offset.
3
The fuzzers are built into a binary (e.g. qemu-fuzz-i386). To select the
4
This logic really belongs in crypto/block.c where it can be reused by
4
device to fuzz/fuzz target, we usually use the --fuzz-target= argument.
5
other image formats.
5
This commit allows the fuzz-target to be specified using the name of the
6
executable. If the executable name ends with -target-FUZZ_TARGET, then
7
we select the fuzz target based on this name, rather than the
8
--fuzz-target argument. This is useful for systems such as oss-fuzz
9
where we don't have control of the arguments passed to the fuzzer.
6
10
7
The "luks" block driver will need this same logic in order to implement
11
[Fixed incorrect indentation.
8
.bdrv_measure(), so extract the qcrypto_block_calculate_payload_offset()
12
--Stefan]
9
function now.
10
13
14
Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
15
Reviewed-by: Darren Kenny <darren.kenny@oracle.com>
16
Message-id: 20200421182230.6313-1-alxndr@bu.edu
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
17
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Reviewed-by: Max Reitz <mreitz@redhat.com>
13
Message-Id: <20200221112522.1497712-2-stefanha@redhat.com>
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
---
18
---
16
block/qcow2.c | 74 +++++++++++-------------------------------
19
tests/qtest/fuzz/fuzz.c | 19 +++++++++++--------
17
crypto/block.c | 36 ++++++++++++++++++++
20
slirp | 2 +-
18
include/crypto/block.h | 22 +++++++++++++
21
2 files changed, 12 insertions(+), 9 deletions(-)
19
3 files changed, 77 insertions(+), 55 deletions(-)
20
22
21
diff --git a/block/qcow2.c b/block/qcow2.c
23
diff --git a/tests/qtest/fuzz/fuzz.c b/tests/qtest/fuzz/fuzz.c
22
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
23
--- a/block/qcow2.c
25
--- a/tests/qtest/fuzz/fuzz.c
24
+++ b/block/qcow2.c
26
+++ b/tests/qtest/fuzz/fuzz.c
25
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_flush_to_os(BlockDriverState *bs)
27
@@ -XXX,XX +XXX,XX @@ static void usage(char *path)
26
return ret;
28
printf(" * %s : %s\n", tmp->target->name,
29
tmp->target->description);
30
}
31
+ printf("Alternatively, add -target-FUZZ_TARGET to the executable name\n");
32
exit(0);
27
}
33
}
28
34
29
-static ssize_t qcow2_measure_crypto_hdr_init_func(QCryptoBlock *block,
35
@@ -XXX,XX +XXX,XX @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp)
30
- size_t headerlen, void *opaque, Error **errp)
36
module_call_init(MODULE_INIT_QOM);
31
-{
37
module_call_init(MODULE_INIT_LIBQOS);
32
- size_t *headerlenp = opaque;
38
33
-
39
- if (*argc <= 1) {
34
- /* Stash away the payload size */
40
+ target_name = strstr(**argv, "-target-");
35
- *headerlenp = headerlen;
41
+ if (target_name) { /* The binary name specifies the target */
36
- return 0;
42
+ target_name += strlen("-target-");
37
-}
43
+ } else if (*argc > 1) { /* The target is specified as an argument */
38
-
44
+ target_name = (*argv)[1];
39
-static ssize_t qcow2_measure_crypto_hdr_write_func(QCryptoBlock *block,
45
+ if (!strstr(target_name, "--fuzz-target=")) {
40
- size_t offset, const uint8_t *buf, size_t buflen,
46
+ usage(**argv);
41
- void *opaque, Error **errp)
47
+ }
42
-{
48
+ target_name += strlen("--fuzz-target=");
43
- /* Discard the bytes, we're not actually writing to an image */
49
+ } else {
44
- return buflen;
50
usage(**argv);
45
-}
51
}
46
-
52
47
-/* Determine the number of bytes for the LUKS payload */
53
/* Identify the fuzz target */
48
-static bool qcow2_measure_luks_headerlen(QemuOpts *opts, size_t *len,
54
- target_name = (*argv)[1];
49
- Error **errp)
55
- if (!strstr(target_name, "--fuzz-target=")) {
50
-{
56
- usage(**argv);
51
- QDict *opts_qdict;
52
- QDict *cryptoopts_qdict;
53
- QCryptoBlockCreateOptions *cryptoopts;
54
- QCryptoBlock *crypto;
55
-
56
- /* Extract "encrypt." options into a qdict */
57
- opts_qdict = qemu_opts_to_qdict(opts, NULL);
58
- qdict_extract_subqdict(opts_qdict, &cryptoopts_qdict, "encrypt.");
59
- qobject_unref(opts_qdict);
60
-
61
- /* Build QCryptoBlockCreateOptions object from qdict */
62
- qdict_put_str(cryptoopts_qdict, "format", "luks");
63
- cryptoopts = block_crypto_create_opts_init(cryptoopts_qdict, errp);
64
- qobject_unref(cryptoopts_qdict);
65
- if (!cryptoopts) {
66
- return false;
67
- }
57
- }
68
-
58
-
69
- /* Fake LUKS creation in order to determine the payload size */
59
- target_name += strlen("--fuzz-target=");
70
- crypto = qcrypto_block_create(cryptoopts, "encrypt.",
71
- qcow2_measure_crypto_hdr_init_func,
72
- qcow2_measure_crypto_hdr_write_func,
73
- len, errp);
74
- qapi_free_QCryptoBlockCreateOptions(cryptoopts);
75
- if (!crypto) {
76
- return false;
77
- }
78
-
60
-
79
- qcrypto_block_free(crypto);
61
fuzz_target = fuzz_get_target(target_name);
80
- return true;
62
if (!fuzz_target) {
81
-}
63
usage(**argv);
82
-
64
diff --git a/slirp b/slirp
83
static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
65
index XXXXXXX..XXXXXXX 160000
84
Error **errp)
66
--- a/slirp
85
{
67
+++ b/slirp
86
@@ -XXX,XX +XXX,XX @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
68
@@ -1 +1 @@
87
g_free(optstr);
69
-Subproject commit 2faae0f778f818fadc873308f983289df697eb93
88
70
+Subproject commit 55ab21c9a36852915b81f1b41ebaf3b6509dd8ba
89
if (has_luks) {
90
+ g_autoptr(QCryptoBlockCreateOptions) create_opts = NULL;
91
+ QDict *opts_qdict;
92
+ QDict *cryptoopts;
93
size_t headerlen;
94
95
- if (!qcow2_measure_luks_headerlen(opts, &headerlen, &local_err)) {
96
+ opts_qdict = qemu_opts_to_qdict(opts, NULL);
97
+ qdict_extract_subqdict(opts_qdict, &cryptoopts, "encrypt.");
98
+ qobject_unref(opts_qdict);
99
+
100
+ qdict_put_str(cryptoopts, "format", "luks");
101
+
102
+ create_opts = block_crypto_create_opts_init(cryptoopts, errp);
103
+ qobject_unref(cryptoopts);
104
+ if (!create_opts) {
105
+ goto err;
106
+ }
107
+
108
+ if (!qcrypto_block_calculate_payload_offset(create_opts,
109
+ "encrypt.",
110
+ &headerlen,
111
+ &local_err)) {
112
goto err;
113
}
114
115
diff --git a/crypto/block.c b/crypto/block.c
116
index XXXXXXX..XXXXXXX 100644
117
--- a/crypto/block.c
118
+++ b/crypto/block.c
119
@@ -XXX,XX +XXX,XX @@ QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options,
120
}
121
122
123
+static ssize_t qcrypto_block_headerlen_hdr_init_func(QCryptoBlock *block,
124
+ size_t headerlen, void *opaque, Error **errp)
125
+{
126
+ size_t *headerlenp = opaque;
127
+
128
+ /* Stash away the payload size */
129
+ *headerlenp = headerlen;
130
+ return 0;
131
+}
132
+
133
+
134
+static ssize_t qcrypto_block_headerlen_hdr_write_func(QCryptoBlock *block,
135
+ size_t offset, const uint8_t *buf, size_t buflen,
136
+ void *opaque, Error **errp)
137
+{
138
+ /* Discard the bytes, we're not actually writing to an image */
139
+ return buflen;
140
+}
141
+
142
+
143
+bool
144
+qcrypto_block_calculate_payload_offset(QCryptoBlockCreateOptions *create_opts,
145
+ const char *optprefix,
146
+ size_t *len,
147
+ Error **errp)
148
+{
149
+ /* Fake LUKS creation in order to determine the payload size */
150
+ g_autoptr(QCryptoBlock) crypto =
151
+ qcrypto_block_create(create_opts, optprefix,
152
+ qcrypto_block_headerlen_hdr_init_func,
153
+ qcrypto_block_headerlen_hdr_write_func,
154
+ len, errp);
155
+ return crypto != NULL;
156
+}
157
+
158
+
159
QCryptoBlockInfo *qcrypto_block_get_info(QCryptoBlock *block,
160
Error **errp)
161
{
162
diff --git a/include/crypto/block.h b/include/crypto/block.h
163
index XXXXXXX..XXXXXXX 100644
164
--- a/include/crypto/block.h
165
+++ b/include/crypto/block.h
166
@@ -XXX,XX +XXX,XX @@ QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options,
167
Error **errp);
168
169
170
+/**
171
+ * qcrypto_block_calculate_payload_offset:
172
+ * @create_opts: the encryption options
173
+ * @optprefix: name prefix for options
174
+ * @len: output for number of header bytes before payload
175
+ * @errp: pointer to a NULL-initialized error object
176
+ *
177
+ * Calculate the number of header bytes before the payload in an encrypted
178
+ * storage volume. The header is an area before the payload that is reserved
179
+ * for encryption metadata.
180
+ *
181
+ * Returns: true on success, false on error
182
+ */
183
+bool
184
+qcrypto_block_calculate_payload_offset(QCryptoBlockCreateOptions *create_opts,
185
+ const char *optprefix,
186
+ size_t *len,
187
+ Error **errp);
188
+
189
+
190
/**
191
* qcrypto_block_get_info:
192
* @block: the block encryption object
193
@@ -XXX,XX +XXX,XX @@ uint64_t qcrypto_block_get_sector_size(QCryptoBlock *block);
194
void qcrypto_block_free(QCryptoBlock *block);
195
196
G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoBlock, qcrypto_block_free)
197
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoBlockCreateOptions,
198
+ qapi_free_QCryptoBlockCreateOptions)
199
200
#endif /* QCRYPTO_BLOCK_H */
201
--
71
--
202
2.24.1
72
2.25.3
203
73
204
diff view generated by jsdifflib
Deleted patch
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
1
3
Add qemu-img measure support in the "luks" block driver.
4
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
Message-Id: <20200221112522.1497712-3-stefanha@redhat.com>
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
---
10
block/crypto.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++
11
1 file changed, 62 insertions(+)
12
13
diff --git a/block/crypto.c b/block/crypto.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/block/crypto.c
16
+++ b/block/crypto.c
17
@@ -XXX,XX +XXX,XX @@ static int64_t block_crypto_getlength(BlockDriverState *bs)
18
}
19
20
21
+static BlockMeasureInfo *block_crypto_measure(QemuOpts *opts,
22
+ BlockDriverState *in_bs,
23
+ Error **errp)
24
+{
25
+ g_autoptr(QCryptoBlockCreateOptions) create_opts = NULL;
26
+ Error *local_err = NULL;
27
+ BlockMeasureInfo *info;
28
+ uint64_t size;
29
+ size_t luks_payload_size;
30
+ QDict *cryptoopts;
31
+
32
+ /*
33
+ * Preallocation mode doesn't affect size requirements but we must consume
34
+ * the option.
35
+ */
36
+ g_free(qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC));
37
+
38
+ size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
39
+
40
+ if (in_bs) {
41
+ int64_t ssize = bdrv_getlength(in_bs);
42
+
43
+ if (ssize < 0) {
44
+ error_setg_errno(&local_err, -ssize,
45
+ "Unable to get image virtual_size");
46
+ goto err;
47
+ }
48
+
49
+ size = ssize;
50
+ }
51
+
52
+ cryptoopts = qemu_opts_to_qdict_filtered(opts, NULL,
53
+ &block_crypto_create_opts_luks, true);
54
+ qdict_put_str(cryptoopts, "format", "luks");
55
+ create_opts = block_crypto_create_opts_init(cryptoopts, &local_err);
56
+ qobject_unref(cryptoopts);
57
+ if (!create_opts) {
58
+ goto err;
59
+ }
60
+
61
+ if (!qcrypto_block_calculate_payload_offset(create_opts, NULL,
62
+ &luks_payload_size,
63
+ &local_err)) {
64
+ goto err;
65
+ }
66
+
67
+ /*
68
+ * Unallocated blocks are still encrypted so allocation status makes no
69
+ * difference to the file size.
70
+ */
71
+ info = g_new(BlockMeasureInfo, 1);
72
+ info->fully_allocated = luks_payload_size + size;
73
+ info->required = luks_payload_size + size;
74
+ return info;
75
+
76
+err:
77
+ error_propagate(errp, local_err);
78
+ return NULL;
79
+}
80
+
81
+
82
static int block_crypto_probe_luks(const uint8_t *buf,
83
int buf_size,
84
const char *filename) {
85
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_crypto_luks = {
86
.bdrv_co_preadv = block_crypto_co_preadv,
87
.bdrv_co_pwritev = block_crypto_co_pwritev,
88
.bdrv_getlength = block_crypto_getlength,
89
+ .bdrv_measure = block_crypto_measure,
90
.bdrv_get_info = block_crypto_get_info_luks,
91
.bdrv_get_specific_info = block_crypto_get_specific_info_luks,
92
93
--
94
2.24.1
95
96
diff view generated by jsdifflib
Deleted patch
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
1
3
In most qemu-img sub-commands the --object option only makes sense when
4
there is a filename. qemu-img measure is an exception because objects
5
may be referenced from the image creation options instead of an existing
6
image file. Allow --object without a filename.
7
8
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Message-Id: <20200221112522.1497712-4-stefanha@redhat.com>
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
13
qemu-img.c | 6 ++----
14
tests/qemu-iotests/178 | 2 +-
15
tests/qemu-iotests/178.out.qcow2 | 8 ++++----
16
tests/qemu-iotests/178.out.raw | 8 ++++----
17
4 files changed, 11 insertions(+), 13 deletions(-)
18
19
diff --git a/qemu-img.c b/qemu-img.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/qemu-img.c
22
+++ b/qemu-img.c
23
@@ -XXX,XX +XXX,XX @@ static int img_measure(int argc, char **argv)
24
filename = argv[optind];
25
}
26
27
- if (!filename &&
28
- (object_opts || image_opts || fmt || snapshot_name || sn_opts)) {
29
- error_report("--object, --image-opts, -f, and -l "
30
- "require a filename argument.");
31
+ if (!filename && (image_opts || fmt || snapshot_name || sn_opts)) {
32
+ error_report("--image-opts, -f, and -l require a filename argument.");
33
goto out;
34
}
35
if (filename && img_size != UINT64_MAX) {
36
diff --git a/tests/qemu-iotests/178 b/tests/qemu-iotests/178
37
index XXXXXXX..XXXXXXX 100755
38
--- a/tests/qemu-iotests/178
39
+++ b/tests/qemu-iotests/178
40
@@ -XXX,XX +XXX,XX @@ _make_test_img 1G
41
$QEMU_IMG measure # missing arguments
42
$QEMU_IMG measure --size 2G "$TEST_IMG" # only one allowed
43
$QEMU_IMG measure "$TEST_IMG" a # only one filename allowed
44
-$QEMU_IMG measure --object secret,id=sec0,data=MTIzNDU2,format=base64 # missing filename
45
+$QEMU_IMG measure --object secret,id=sec0,data=MTIzNDU2,format=base64 # size or filename needed
46
$QEMU_IMG measure --image-opts # missing filename
47
$QEMU_IMG measure -f qcow2 # missing filename
48
$QEMU_IMG measure -l snap1 # missing filename
49
diff --git a/tests/qemu-iotests/178.out.qcow2 b/tests/qemu-iotests/178.out.qcow2
50
index XXXXXXX..XXXXXXX 100644
51
--- a/tests/qemu-iotests/178.out.qcow2
52
+++ b/tests/qemu-iotests/178.out.qcow2
53
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
54
qemu-img: Either --size N or one filename must be specified.
55
qemu-img: --size N cannot be used together with a filename.
56
qemu-img: At most one filename argument is allowed.
57
-qemu-img: --object, --image-opts, -f, and -l require a filename argument.
58
-qemu-img: --object, --image-opts, -f, and -l require a filename argument.
59
-qemu-img: --object, --image-opts, -f, and -l require a filename argument.
60
-qemu-img: --object, --image-opts, -f, and -l require a filename argument.
61
+qemu-img: Either --size N or one filename must be specified.
62
+qemu-img: --image-opts, -f, and -l require a filename argument.
63
+qemu-img: --image-opts, -f, and -l require a filename argument.
64
+qemu-img: --image-opts, -f, and -l require a filename argument.
65
qemu-img: Invalid option list: ,
66
qemu-img: Invalid parameter 'snapshot.foo'
67
qemu-img: Failed in parsing snapshot param 'snapshot.foo'
68
diff --git a/tests/qemu-iotests/178.out.raw b/tests/qemu-iotests/178.out.raw
69
index XXXXXXX..XXXXXXX 100644
70
--- a/tests/qemu-iotests/178.out.raw
71
+++ b/tests/qemu-iotests/178.out.raw
72
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
73
qemu-img: Either --size N or one filename must be specified.
74
qemu-img: --size N cannot be used together with a filename.
75
qemu-img: At most one filename argument is allowed.
76
-qemu-img: --object, --image-opts, -f, and -l require a filename argument.
77
-qemu-img: --object, --image-opts, -f, and -l require a filename argument.
78
-qemu-img: --object, --image-opts, -f, and -l require a filename argument.
79
-qemu-img: --object, --image-opts, -f, and -l require a filename argument.
80
+qemu-img: Either --size N or one filename must be specified.
81
+qemu-img: --image-opts, -f, and -l require a filename argument.
82
+qemu-img: --image-opts, -f, and -l require a filename argument.
83
+qemu-img: --image-opts, -f, and -l require a filename argument.
84
qemu-img: Invalid option list: ,
85
qemu-img: Invalid parameter 'snapshot.foo'
86
qemu-img: Failed in parsing snapshot param 'snapshot.foo'
87
--
88
2.24.1
89
90
diff view generated by jsdifflib
Deleted patch
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
1
3
This test exercises the block/crypto.c "luks" block driver
4
.bdrv_measure() code.
5
6
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Message-Id: <20200221112522.1497712-5-stefanha@redhat.com>
9
[mreitz: Renamed test from 282 to 288]
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
12
tests/qemu-iotests/288 | 93 ++++++++++++++++++++++++++++++++++++++
13
tests/qemu-iotests/288.out | 30 ++++++++++++
14
tests/qemu-iotests/group | 1 +
15
3 files changed, 124 insertions(+)
16
create mode 100755 tests/qemu-iotests/288
17
create mode 100644 tests/qemu-iotests/288.out
18
19
diff --git a/tests/qemu-iotests/288 b/tests/qemu-iotests/288
20
new file mode 100755
21
index XXXXXXX..XXXXXXX
22
--- /dev/null
23
+++ b/tests/qemu-iotests/288
24
@@ -XXX,XX +XXX,XX @@
25
+#!/usr/bin/env bash
26
+#
27
+# qemu-img measure tests for LUKS images
28
+#
29
+# Copyright (C) 2020 Red Hat, Inc.
30
+#
31
+# This program is free software; you can redistribute it and/or modify
32
+# it under the terms of the GNU General Public License as published by
33
+# the Free Software Foundation; either version 2 of the License, or
34
+# (at your option) any later version.
35
+#
36
+# This program is distributed in the hope that it will be useful,
37
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
38
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
39
+# GNU General Public License for more details.
40
+#
41
+# You should have received a copy of the GNU General Public License
42
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
43
+#
44
+
45
+# creator
46
+owner=stefanha@redhat.com
47
+
48
+seq=`basename $0`
49
+echo "QA output created by $seq"
50
+
51
+status=1 # failure is the default!
52
+
53
+_cleanup()
54
+{
55
+ _cleanup_test_img
56
+ rm -f "$TEST_IMG.converted"
57
+}
58
+trap "_cleanup; exit \$status" 0 1 2 3 15
59
+
60
+# get standard environment, filters and checks
61
+. ./common.rc
62
+. ./common.filter
63
+. ./common.pattern
64
+
65
+_supported_fmt luks
66
+_supported_proto file
67
+_supported_os Linux
68
+
69
+SECRET=secret,id=sec0,data=passphrase
70
+
71
+echo "== measure 1G image file =="
72
+echo
73
+
74
+$QEMU_IMG measure --object "$SECRET" \
75
+     -O "$IMGFMT" \
76
+         -o key-secret=sec0,iter-time=10 \
77
+         --size 1G
78
+
79
+echo
80
+echo "== create 1G image file (size should be no greater than measured) =="
81
+echo
82
+
83
+_make_test_img 1G
84
+stat -c "image file size in bytes: %s" "$TEST_IMG_FILE"
85
+
86
+echo
87
+echo "== modified 1G image file (size should be no greater than measured) =="
88
+echo
89
+
90
+$QEMU_IO --object "$SECRET" --image-opts "$TEST_IMG" -c "write -P 0x51 0x10000 0x400" | _filter_qemu_io | _filter_testdir
91
+stat -c "image file size in bytes: %s" "$TEST_IMG_FILE"
92
+
93
+echo
94
+echo "== measure preallocation=falloc 1G image file =="
95
+echo
96
+
97
+$QEMU_IMG measure --object "$SECRET" \
98
+     -O "$IMGFMT" \
99
+         -o key-secret=sec0,iter-time=10,preallocation=falloc \
100
+         --size 1G
101
+
102
+echo
103
+echo "== measure with input image file =="
104
+echo
105
+
106
+IMGFMT=raw IMGKEYSECRET= IMGOPTS= _make_test_img 1G | _filter_imgfmt
107
+QEMU_IO_OPTIONS= IMGOPTSSYNTAX= $QEMU_IO -f raw -c "write -P 0x51 0x10000 0x400" "$TEST_IMG_FILE" | _filter_qemu_io | _filter_testdir
108
+$QEMU_IMG measure --object "$SECRET" \
109
+     -O "$IMGFMT" \
110
+         -o key-secret=sec0,iter-time=10 \
111
+         -f raw \
112
+         "$TEST_IMG_FILE"
113
+
114
+# success, all done
115
+echo "*** done"
116
+rm -f $seq.full
117
+status=0
118
diff --git a/tests/qemu-iotests/288.out b/tests/qemu-iotests/288.out
119
new file mode 100644
120
index XXXXXXX..XXXXXXX
121
--- /dev/null
122
+++ b/tests/qemu-iotests/288.out
123
@@ -XXX,XX +XXX,XX @@
124
+QA output created by 288
125
+== measure 1G image file ==
126
+
127
+required size: 1075810304
128
+fully allocated size: 1075810304
129
+
130
+== create 1G image file (size should be no greater than measured) ==
131
+
132
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
133
+image file size in bytes: 1075810304
134
+
135
+== modified 1G image file (size should be no greater than measured) ==
136
+
137
+wrote 1024/1024 bytes at offset 65536
138
+1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
139
+image file size in bytes: 1075810304
140
+
141
+== measure preallocation=falloc 1G image file ==
142
+
143
+required size: 1075810304
144
+fully allocated size: 1075810304
145
+
146
+== measure with input image file ==
147
+
148
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
149
+wrote 1024/1024 bytes at offset 65536
150
+1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
151
+required size: 1075810304
152
+fully allocated size: 1075810304
153
+*** done
154
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
155
index XXXXXXX..XXXXXXX 100644
156
--- a/tests/qemu-iotests/group
157
+++ b/tests/qemu-iotests/group
158
@@ -XXX,XX +XXX,XX @@
159
283 auto quick
160
284 rw
161
286 rw quick
162
+288 quick
163
--
164
2.24.1
165
166
diff view generated by jsdifflib
Deleted patch
1
From: David Edmondson <david.edmondson@oracle.com>
2
1
3
RFC 7230 section 3.2 indicates that whitespace is permitted between
4
the field name and field value and after the field value.
5
6
Signed-off-by: David Edmondson <david.edmondson@oracle.com>
7
Message-Id: <20200224101310.101169-2-david.edmondson@oracle.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
11
block/curl.c | 31 +++++++++++++++++++++++++++----
12
1 file changed, 27 insertions(+), 4 deletions(-)
13
14
diff --git a/block/curl.c b/block/curl.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/block/curl.c
17
+++ b/block/curl.c
18
@@ -XXX,XX +XXX,XX @@ static size_t curl_header_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
19
{
20
BDRVCURLState *s = opaque;
21
size_t realsize = size * nmemb;
22
- const char *accept_line = "Accept-Ranges: bytes";
23
+ const char *header = (char *)ptr;
24
+ const char *end = header + realsize;
25
+ const char *accept_ranges = "Accept-Ranges:";
26
+ const char *bytes = "bytes";
27
28
- if (realsize >= strlen(accept_line)
29
- && strncmp((char *)ptr, accept_line, strlen(accept_line)) == 0) {
30
- s->accept_range = true;
31
+ if (realsize >= strlen(accept_ranges)
32
+ && strncmp(header, accept_ranges, strlen(accept_ranges)) == 0) {
33
+
34
+ char *p = strchr(header, ':') + 1;
35
+
36
+ /* Skip whitespace between the header name and value. */
37
+ while (p < end && *p && g_ascii_isspace(*p)) {
38
+ p++;
39
+ }
40
+
41
+ if (end - p >= strlen(bytes)
42
+ && strncmp(p, bytes, strlen(bytes)) == 0) {
43
+
44
+ /* Check that there is nothing but whitespace after the value. */
45
+ p += strlen(bytes);
46
+ while (p < end && *p && g_ascii_isspace(*p)) {
47
+ p++;
48
+ }
49
+
50
+ if (p == end || !*p) {
51
+ s->accept_range = true;
52
+ }
53
+ }
54
}
55
56
return realsize;
57
--
58
2.24.1
59
60
diff view generated by jsdifflib
Deleted patch
1
From: David Edmondson <david.edmondson@oracle.com>
2
1
3
RFC 7230 section 3.2 indicates that HTTP header field names are case
4
insensitive.
5
6
Signed-off-by: David Edmondson <david.edmondson@oracle.com>
7
Message-Id: <20200224101310.101169-3-david.edmondson@oracle.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
11
block/curl.c | 5 +++--
12
1 file changed, 3 insertions(+), 2 deletions(-)
13
14
diff --git a/block/curl.c b/block/curl.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/block/curl.c
17
+++ b/block/curl.c
18
@@ -XXX,XX +XXX,XX @@ static size_t curl_header_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
19
size_t realsize = size * nmemb;
20
const char *header = (char *)ptr;
21
const char *end = header + realsize;
22
- const char *accept_ranges = "Accept-Ranges:";
23
+ const char *accept_ranges = "accept-ranges:";
24
const char *bytes = "bytes";
25
26
if (realsize >= strlen(accept_ranges)
27
- && strncmp(header, accept_ranges, strlen(accept_ranges)) == 0) {
28
+ && g_ascii_strncasecmp(header, accept_ranges,
29
+ strlen(accept_ranges)) == 0) {
30
31
char *p = strchr(header, ':') + 1;
32
33
--
34
2.24.1
35
36
diff view generated by jsdifflib
Deleted patch
1
From: Eric Blake <eblake@redhat.com>
2
1
3
Tests 261 and 272 fail on RHEL 7 with coreutils 8.22, since od
4
--endian was not added until coreutils 8.23. Fix this by manually
5
constructing the final value one byte at a time.
6
7
Fixes: fc8ba423
8
Reported-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
9
Signed-off-by: Eric Blake <eblake@redhat.com>
10
Reviewed-by: Max Reitz <mreitz@redhat.com>
11
Message-Id: <20200226125424.481840-1-eblake@redhat.com>
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
---
14
tests/qemu-iotests/common.rc | 22 +++++++++++++++++-----
15
1 file changed, 17 insertions(+), 5 deletions(-)
16
17
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
18
index XXXXXXX..XXXXXXX 100644
19
--- a/tests/qemu-iotests/common.rc
20
+++ b/tests/qemu-iotests/common.rc
21
@@ -XXX,XX +XXX,XX @@ poke_file()
22
# peek_file_le 'test.img' 512 2 => 65534
23
peek_file_le()
24
{
25
- # Wrap in echo $() to strip spaces
26
- echo $(od -j"$2" -N"$3" --endian=little -An -vtu"$3" "$1")
27
+ local val=0 shift=0 byte
28
+
29
+ # coreutils' od --endian is not portable, so manually assemble bytes.
30
+ for byte in $(od -j"$2" -N"$3" -An -v -tu1 "$1"); do
31
+ val=$(( val | (byte << shift) ))
32
+ shift=$((shift + 8))
33
+ done
34
+ printf %llu $val
35
}
36
37
# peek_file_be 'test.img' 512 2 => 65279
38
peek_file_be()
39
{
40
- # Wrap in echo $() to strip spaces
41
- echo $(od -j"$2" -N"$3" --endian=big -An -vtu"$3" "$1")
42
+ local val=0 byte
43
+
44
+ # coreutils' od --endian is not portable, so manually assemble bytes.
45
+ for byte in $(od -j"$2" -N"$3" -An -v -tu1 "$1"); do
46
+ val=$(( (val << 8) | byte ))
47
+ done
48
+ printf %llu $val
49
}
50
51
-# peek_file_raw 'test.img' 512 2 => '\xff\xfe'
52
+# peek_file_raw 'test.img' 512 2 => '\xff\xfe'. Do not use if the raw data
53
+# is likely to contain \0 or trailing \n.
54
peek_file_raw()
55
{
56
dd if="$1" bs=1 skip="$2" count="$3" status=none
57
--
58
2.24.1
59
60
diff view generated by jsdifflib
Deleted patch
1
From: Pan Nengyuan <pannengyuan@huawei.com>
2
1
3
'crypto_opts' forgot to free in qcow2_close(), this patch fix the bellow leak stack:
4
5
Direct leak of 24 byte(s) in 1 object(s) allocated from:
6
#0 0x7f0edd81f970 in __interceptor_calloc (/lib64/libasan.so.5+0xef970)
7
#1 0x7f0edc6d149d in g_malloc0 (/lib64/libglib-2.0.so.0+0x5249d)
8
#2 0x55d7eaede63d in qobject_input_start_struct /mnt/sdb/qemu-new/qemu_test/qemu/qapi/qobject-input-visitor.c:295
9
#3 0x55d7eaed78b8 in visit_start_struct /mnt/sdb/qemu-new/qemu_test/qemu/qapi/qapi-visit-core.c:49
10
#4 0x55d7eaf5140b in visit_type_QCryptoBlockOpenOptions qapi/qapi-visit-crypto.c:290
11
#5 0x55d7eae43af3 in block_crypto_open_opts_init /mnt/sdb/qemu-new/qemu_test/qemu/block/crypto.c:163
12
#6 0x55d7eacd2924 in qcow2_update_options_prepare /mnt/sdb/qemu-new/qemu_test/qemu/block/qcow2.c:1148
13
#7 0x55d7eacd33f7 in qcow2_update_options /mnt/sdb/qemu-new/qemu_test/qemu/block/qcow2.c:1232
14
#8 0x55d7eacd9680 in qcow2_do_open /mnt/sdb/qemu-new/qemu_test/qemu/block/qcow2.c:1512
15
#9 0x55d7eacdc55e in qcow2_open_entry /mnt/sdb/qemu-new/qemu_test/qemu/block/qcow2.c:1792
16
#10 0x55d7eacdc8fe in qcow2_open /mnt/sdb/qemu-new/qemu_test/qemu/block/qcow2.c:1819
17
#11 0x55d7eac3742d in bdrv_open_driver /mnt/sdb/qemu-new/qemu_test/qemu/block.c:1317
18
#12 0x55d7eac3e990 in bdrv_open_common /mnt/sdb/qemu-new/qemu_test/qemu/block.c:1575
19
#13 0x55d7eac4442c in bdrv_open_inherit /mnt/sdb/qemu-new/qemu_test/qemu/block.c:3126
20
#14 0x55d7eac45c3f in bdrv_open /mnt/sdb/qemu-new/qemu_test/qemu/block.c:3219
21
#15 0x55d7ead8e8a4 in blk_new_open /mnt/sdb/qemu-new/qemu_test/qemu/block/block-backend.c:397
22
#16 0x55d7eacde74c in qcow2_co_create /mnt/sdb/qemu-new/qemu_test/qemu/block/qcow2.c:3534
23
#17 0x55d7eacdfa6d in qcow2_co_create_opts /mnt/sdb/qemu-new/qemu_test/qemu/block/qcow2.c:3668
24
#18 0x55d7eac1c678 in bdrv_create_co_entry /mnt/sdb/qemu-new/qemu_test/qemu/block.c:485
25
#19 0x55d7eb0024d2 in coroutine_trampoline /mnt/sdb/qemu-new/qemu_test/qemu/util/coroutine-ucontext.c:115
26
27
Reported-by: Euler Robot <euler.robot@huawei.com>
28
Signed-off-by: Pan Nengyuan <pannengyuan@huawei.com>
29
Reviewed-by: Max Reitz <mreitz@redhat.com>
30
Message-Id: <20200227012950.12256-2-pannengyuan@huawei.com>
31
Signed-off-by: Max Reitz <mreitz@redhat.com>
32
---
33
block/qcow2.c | 1 +
34
1 file changed, 1 insertion(+)
35
36
diff --git a/block/qcow2.c b/block/qcow2.c
37
index XXXXXXX..XXXXXXX 100644
38
--- a/block/qcow2.c
39
+++ b/block/qcow2.c
40
@@ -XXX,XX +XXX,XX @@ static void qcow2_close(BlockDriverState *bs)
41
42
qcrypto_block_free(s->crypto);
43
s->crypto = NULL;
44
+ qapi_free_QCryptoBlockOpenOptions(s->crypto_opts);
45
46
g_free(s->unknown_header_fields);
47
cleanup_unknown_header_ext(bs);
48
--
49
2.24.1
50
51
diff view generated by jsdifflib
Deleted patch
1
From: Pan Nengyuan <pannengyuan@huawei.com>
2
1
3
collect_image_check() is called twice in img_check(), the filename/format will be alloced without free the original memory.
4
It is not a big deal since the process will exit anyway, but seems like a clean code and it will remove the warning spotted by asan.
5
6
Reported-by: Euler Robot <euler.robot@huawei.com>
7
Signed-off-by: Pan Nengyuan <pannengyuan@huawei.com>
8
Message-Id: <20200227012950.12256-3-pannengyuan@huawei.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
11
qemu-img.c | 2 ++
12
1 file changed, 2 insertions(+)
13
14
diff --git a/qemu-img.c b/qemu-img.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/qemu-img.c
17
+++ b/qemu-img.c
18
@@ -XXX,XX +XXX,XX @@ static int img_check(int argc, char **argv)
19
check->corruptions_fixed);
20
}
21
22
+ qapi_free_ImageCheck(check);
23
+ check = g_new0(ImageCheck, 1);
24
ret = collect_image_check(bs, check, filename, fmt, 0);
25
26
check->leaks_fixed = leaks_fixed;
27
--
28
2.24.1
29
30
diff view generated by jsdifflib
Deleted patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
1
3
On success path we return what inflate() returns instead of 0. And it
4
most probably works for Z_STREAM_END as it is positive, but is
5
definitely broken for Z_BUF_ERROR.
6
7
While being here, switch to errno return code, to be closer to
8
qcow2_compress API (and usual expectations).
9
10
Revert condition in if to be more positive. Drop dead initialization of
11
ret.
12
13
Cc: qemu-stable@nongnu.org # v4.0
14
Fixes: 341926ab83e2b
15
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
16
Message-Id: <20200302150930.16218-1-vsementsov@virtuozzo.com>
17
Reviewed-by: Alberto Garcia <berto@igalia.com>
18
Reviewed-by: Ján Tomko <jtomko@redhat.com>
19
Signed-off-by: Max Reitz <mreitz@redhat.com>
20
---
21
block/qcow2-threads.c | 12 +++++++-----
22
1 file changed, 7 insertions(+), 5 deletions(-)
23
24
diff --git a/block/qcow2-threads.c b/block/qcow2-threads.c
25
index XXXXXXX..XXXXXXX 100644
26
--- a/block/qcow2-threads.c
27
+++ b/block/qcow2-threads.c
28
@@ -XXX,XX +XXX,XX @@ static ssize_t qcow2_compress(void *dest, size_t dest_size,
29
* @src - source buffer, @src_size bytes
30
*
31
* Returns: 0 on success
32
- * -1 on fail
33
+ * -EIO on fail
34
*/
35
static ssize_t qcow2_decompress(void *dest, size_t dest_size,
36
const void *src, size_t src_size)
37
{
38
- int ret = 0;
39
+ int ret;
40
z_stream strm;
41
42
memset(&strm, 0, sizeof(strm));
43
@@ -XXX,XX +XXX,XX @@ static ssize_t qcow2_decompress(void *dest, size_t dest_size,
44
45
ret = inflateInit2(&strm, -12);
46
if (ret != Z_OK) {
47
- return -1;
48
+ return -EIO;
49
}
50
51
ret = inflate(&strm, Z_FINISH);
52
- if ((ret != Z_STREAM_END && ret != Z_BUF_ERROR) || strm.avail_out != 0) {
53
+ if ((ret == Z_STREAM_END || ret == Z_BUF_ERROR) && strm.avail_out == 0) {
54
/*
55
* We approve Z_BUF_ERROR because we need @dest buffer to be filled, but
56
* @src buffer may be processed partly (because in qcow2 we know size of
57
* compressed data with precision of one sector)
58
*/
59
- ret = -1;
60
+ ret = 0;
61
+ } else {
62
+ ret = -EIO;
63
}
64
65
inflateEnd(&strm);
66
--
67
2.24.1
68
69
diff view generated by jsdifflib
Deleted patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
1
3
We need it in separate to pass to the block-copy object in the next
4
commit.
5
6
Cc: qemu-stable@nongnu.org
7
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Reviewed-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Message-Id: <20200311103004.7649-2-vsementsov@virtuozzo.com>
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
13
blockjob.c | 16 +++++-----
14
include/qemu/job.h | 11 ++-----
15
include/qemu/progress_meter.h | 58 +++++++++++++++++++++++++++++++++++
16
job-qmp.c | 4 +--
17
job.c | 6 ++--
18
qemu-img.c | 6 ++--
19
6 files changed, 76 insertions(+), 25 deletions(-)
20
create mode 100644 include/qemu/progress_meter.h
21
22
diff --git a/blockjob.c b/blockjob.c
23
index XXXXXXX..XXXXXXX 100644
24
--- a/blockjob.c
25
+++ b/blockjob.c
26
@@ -XXX,XX +XXX,XX @@ BlockJobInfo *block_job_query(BlockJob *job, Error **errp)
27
info->device = g_strdup(job->job.id);
28
info->busy = atomic_read(&job->job.busy);
29
info->paused = job->job.pause_count > 0;
30
- info->offset = job->job.progress_current;
31
- info->len = job->job.progress_total;
32
+ info->offset = job->job.progress.current;
33
+ info->len = job->job.progress.total;
34
info->speed = job->speed;
35
info->io_status = job->iostatus;
36
info->ready = job_is_ready(&job->job),
37
@@ -XXX,XX +XXX,XX @@ static void block_job_event_cancelled(Notifier *n, void *opaque)
38
39
qapi_event_send_block_job_cancelled(job_type(&job->job),
40
job->job.id,
41
- job->job.progress_total,
42
- job->job.progress_current,
43
+ job->job.progress.total,
44
+ job->job.progress.current,
45
job->speed);
46
}
47
48
@@ -XXX,XX +XXX,XX @@ static void block_job_event_completed(Notifier *n, void *opaque)
49
50
qapi_event_send_block_job_completed(job_type(&job->job),
51
job->job.id,
52
- job->job.progress_total,
53
- job->job.progress_current,
54
+ job->job.progress.total,
55
+ job->job.progress.current,
56
job->speed,
57
!!msg,
58
msg);
59
@@ -XXX,XX +XXX,XX @@ static void block_job_event_ready(Notifier *n, void *opaque)
60
61
qapi_event_send_block_job_ready(job_type(&job->job),
62
job->job.id,
63
- job->job.progress_total,
64
- job->job.progress_current,
65
+ job->job.progress.total,
66
+ job->job.progress.current,
67
job->speed);
68
}
69
70
diff --git a/include/qemu/job.h b/include/qemu/job.h
71
index XXXXXXX..XXXXXXX 100644
72
--- a/include/qemu/job.h
73
+++ b/include/qemu/job.h
74
@@ -XXX,XX +XXX,XX @@
75
76
#include "qapi/qapi-types-job.h"
77
#include "qemu/queue.h"
78
+#include "qemu/progress_meter.h"
79
#include "qemu/coroutine.h"
80
#include "block/aio.h"
81
82
@@ -XXX,XX +XXX,XX @@ typedef struct Job {
83
/** True if this job should automatically dismiss itself */
84
bool auto_dismiss;
85
86
- /**
87
- * Current progress. The unit is arbitrary as long as the ratio between
88
- * progress_current and progress_total represents the estimated percentage
89
- * of work already done.
90
- */
91
- int64_t progress_current;
92
-
93
- /** Estimated progress_current value at the completion of the job */
94
- int64_t progress_total;
95
+ ProgressMeter progress;
96
97
/**
98
* Return code from @run and/or @prepare callback(s).
99
diff --git a/include/qemu/progress_meter.h b/include/qemu/progress_meter.h
100
new file mode 100644
101
index XXXXXXX..XXXXXXX
102
--- /dev/null
103
+++ b/include/qemu/progress_meter.h
104
@@ -XXX,XX +XXX,XX @@
105
+/*
106
+ * Helper functionality for some process progress tracking.
107
+ *
108
+ * Copyright (c) 2011 IBM Corp.
109
+ * Copyright (c) 2012, 2018 Red Hat, Inc.
110
+ * Copyright (c) 2020 Virtuozzo International GmbH
111
+ *
112
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
113
+ * of this software and associated documentation files (the "Software"), to deal
114
+ * in the Software without restriction, including without limitation the rights
115
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
116
+ * copies of the Software, and to permit persons to whom the Software is
117
+ * furnished to do so, subject to the following conditions:
118
+ *
119
+ * The above copyright notice and this permission notice shall be included in
120
+ * all copies or substantial portions of the Software.
121
+ *
122
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
123
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
124
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
125
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
126
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
127
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
128
+ * THE SOFTWARE.
129
+ */
130
+
131
+#ifndef QEMU_PROGRESS_METER_H
132
+#define QEMU_PROGRESS_METER_H
133
+
134
+typedef struct ProgressMeter {
135
+ /**
136
+ * Current progress. The unit is arbitrary as long as the ratio between
137
+ * current and total represents the estimated percentage
138
+ * of work already done.
139
+ */
140
+ uint64_t current;
141
+
142
+ /** Estimated current value at the completion of the process */
143
+ uint64_t total;
144
+} ProgressMeter;
145
+
146
+static inline void progress_work_done(ProgressMeter *pm, uint64_t done)
147
+{
148
+ pm->current += done;
149
+}
150
+
151
+static inline void progress_set_remaining(ProgressMeter *pm, uint64_t remaining)
152
+{
153
+ pm->total = pm->current + remaining;
154
+}
155
+
156
+static inline void progress_increase_remaining(ProgressMeter *pm,
157
+ uint64_t delta)
158
+{
159
+ pm->total += delta;
160
+}
161
+
162
+#endif /* QEMU_PROGRESS_METER_H */
163
diff --git a/job-qmp.c b/job-qmp.c
164
index XXXXXXX..XXXXXXX 100644
165
--- a/job-qmp.c
166
+++ b/job-qmp.c
167
@@ -XXX,XX +XXX,XX @@ static JobInfo *job_query_single(Job *job, Error **errp)
168
.id = g_strdup(job->id),
169
.type = job_type(job),
170
.status = job->status,
171
- .current_progress = job->progress_current,
172
- .total_progress = job->progress_total,
173
+ .current_progress = job->progress.current,
174
+ .total_progress = job->progress.total,
175
.has_error = !!job->err,
176
.error = job->err ? \
177
g_strdup(error_get_pretty(job->err)) : NULL,
178
diff --git a/job.c b/job.c
179
index XXXXXXX..XXXXXXX 100644
180
--- a/job.c
181
+++ b/job.c
182
@@ -XXX,XX +XXX,XX @@ void job_unref(Job *job)
183
184
void job_progress_update(Job *job, uint64_t done)
185
{
186
- job->progress_current += done;
187
+ progress_work_done(&job->progress, done);
188
}
189
190
void job_progress_set_remaining(Job *job, uint64_t remaining)
191
{
192
- job->progress_total = job->progress_current + remaining;
193
+ progress_set_remaining(&job->progress, remaining);
194
}
195
196
void job_progress_increase_remaining(Job *job, uint64_t delta)
197
{
198
- job->progress_total += delta;
199
+ progress_increase_remaining(&job->progress, delta);
200
}
201
202
void job_event_cancelled(Job *job)
203
diff --git a/qemu-img.c b/qemu-img.c
204
index XXXXXXX..XXXXXXX 100644
205
--- a/qemu-img.c
206
+++ b/qemu-img.c
207
@@ -XXX,XX +XXX,XX @@ static void run_block_job(BlockJob *job, Error **errp)
208
do {
209
float progress = 0.0f;
210
aio_poll(aio_context, true);
211
- if (job->job.progress_total) {
212
- progress = (float)job->job.progress_current /
213
- job->job.progress_total * 100.f;
214
+ if (job->job.progress.total) {
215
+ progress = (float)job->job.progress.current /
216
+ job->job.progress.total * 100.f;
217
}
218
qemu_progress_print(progress, 0);
219
} while (!job_is_ready(&job->job) && !job_is_completed(&job->job));
220
--
221
2.24.1
222
223
diff view generated by jsdifflib
Deleted patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
1
3
Assume we have two regions, A and B, and region B is in-flight now,
4
region A is not yet touched, but it is unallocated and should be
5
skipped.
6
7
Correspondingly, as progress we have
8
9
total = A + B
10
current = 0
11
12
If we reset unallocated region A and call progress_reset_callback,
13
it will calculate 0 bytes dirty in the bitmap and call
14
job_progress_set_remaining, which will set
15
16
total = current + 0 = 0 + 0 = 0
17
18
So, B bytes are actually removed from total accounting. When job
19
finishes we'll have
20
21
total = 0
22
current = B
23
24
, which doesn't sound good.
25
26
This is because we didn't considered in-flight bytes, actually when
27
calculating remaining, we should have set (in_flight + dirty_bytes)
28
as remaining, not only dirty_bytes.
29
30
To fix it, let's refactor progress calculation, moving it to block-copy
31
itself instead of fixing callback. And, of course, track in_flight
32
bytes count.
33
34
We still have to keep one callback, to maintain backup job bytes_read
35
calculation, but it will go on soon, when we turn the whole backup
36
process into one block_copy call.
37
38
Cc: qemu-stable@nongnu.org
39
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
40
Reviewed-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
41
Message-Id: <20200311103004.7649-3-vsementsov@virtuozzo.com>
42
Signed-off-by: Max Reitz <mreitz@redhat.com>
43
---
44
block/backup.c | 13 ++-----------
45
block/block-copy.c | 16 ++++++++++++----
46
include/block/block-copy.h | 15 +++++----------
47
3 files changed, 19 insertions(+), 25 deletions(-)
48
49
diff --git a/block/backup.c b/block/backup.c
50
index XXXXXXX..XXXXXXX 100644
51
--- a/block/backup.c
52
+++ b/block/backup.c
53
@@ -XXX,XX +XXX,XX @@ static void backup_progress_bytes_callback(int64_t bytes, void *opaque)
54
BackupBlockJob *s = opaque;
55
56
s->bytes_read += bytes;
57
- job_progress_update(&s->common.job, bytes);
58
-}
59
-
60
-static void backup_progress_reset_callback(void *opaque)
61
-{
62
- BackupBlockJob *s = opaque;
63
- uint64_t estimate = bdrv_get_dirty_count(s->bcs->copy_bitmap);
64
-
65
- job_progress_set_remaining(&s->common.job, estimate);
66
}
67
68
static int coroutine_fn backup_do_cow(BackupBlockJob *job,
69
@@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
70
job->cluster_size = cluster_size;
71
job->len = len;
72
73
- block_copy_set_callbacks(bcs, backup_progress_bytes_callback,
74
- backup_progress_reset_callback, job);
75
+ block_copy_set_progress_callback(bcs, backup_progress_bytes_callback, job);
76
+ block_copy_set_progress_meter(bcs, &job->common.job.progress);
77
78
/* Required permissions are already taken by backup-top target */
79
block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL,
80
diff --git a/block/block-copy.c b/block/block-copy.c
81
index XXXXXXX..XXXXXXX 100644
82
--- a/block/block-copy.c
83
+++ b/block/block-copy.c
84
@@ -XXX,XX +XXX,XX @@ BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
85
return s;
86
}
87
88
-void block_copy_set_callbacks(
89
+void block_copy_set_progress_callback(
90
BlockCopyState *s,
91
ProgressBytesCallbackFunc progress_bytes_callback,
92
- ProgressResetCallbackFunc progress_reset_callback,
93
void *progress_opaque)
94
{
95
s->progress_bytes_callback = progress_bytes_callback;
96
- s->progress_reset_callback = progress_reset_callback;
97
s->progress_opaque = progress_opaque;
98
}
99
100
+void block_copy_set_progress_meter(BlockCopyState *s, ProgressMeter *pm)
101
+{
102
+ s->progress = pm;
103
+}
104
+
105
/*
106
* block_copy_do_copy
107
*
108
@@ -XXX,XX +XXX,XX @@ int64_t block_copy_reset_unallocated(BlockCopyState *s,
109
110
if (!ret) {
111
bdrv_reset_dirty_bitmap(s->copy_bitmap, offset, bytes);
112
- s->progress_reset_callback(s->progress_opaque);
113
+ progress_set_remaining(s->progress,
114
+ bdrv_get_dirty_count(s->copy_bitmap) +
115
+ s->in_flight_bytes);
116
}
117
118
*count = bytes;
119
@@ -XXX,XX +XXX,XX @@ int coroutine_fn block_copy(BlockCopyState *s,
120
trace_block_copy_process(s, start);
121
122
bdrv_reset_dirty_bitmap(s->copy_bitmap, start, chunk_end - start);
123
+ s->in_flight_bytes += chunk_end - start;
124
125
co_get_from_shres(s->mem, chunk_end - start);
126
ret = block_copy_do_copy(s, start, chunk_end, error_is_read);
127
co_put_to_shres(s->mem, chunk_end - start);
128
+ s->in_flight_bytes -= chunk_end - start;
129
if (ret < 0) {
130
bdrv_set_dirty_bitmap(s->copy_bitmap, start, chunk_end - start);
131
break;
132
}
133
134
+ progress_work_done(s->progress, chunk_end - start);
135
s->progress_bytes_callback(chunk_end - start, s->progress_opaque);
136
start = chunk_end;
137
ret = 0;
138
diff --git a/include/block/block-copy.h b/include/block/block-copy.h
139
index XXXXXXX..XXXXXXX 100644
140
--- a/include/block/block-copy.h
141
+++ b/include/block/block-copy.h
142
@@ -XXX,XX +XXX,XX @@ typedef struct BlockCopyInFlightReq {
143
} BlockCopyInFlightReq;
144
145
typedef void (*ProgressBytesCallbackFunc)(int64_t bytes, void *opaque);
146
-typedef void (*ProgressResetCallbackFunc)(void *opaque);
147
typedef struct BlockCopyState {
148
/*
149
* BdrvChild objects are not owned or managed by block-copy. They are
150
@@ -XXX,XX +XXX,XX @@ typedef struct BlockCopyState {
151
BdrvChild *source;
152
BdrvChild *target;
153
BdrvDirtyBitmap *copy_bitmap;
154
+ int64_t in_flight_bytes;
155
int64_t cluster_size;
156
bool use_copy_range;
157
int64_t copy_size;
158
@@ -XXX,XX +XXX,XX @@ typedef struct BlockCopyState {
159
*/
160
bool skip_unallocated;
161
162
+ ProgressMeter *progress;
163
/* progress_bytes_callback: called when some copying progress is done. */
164
ProgressBytesCallbackFunc progress_bytes_callback;
165
-
166
- /*
167
- * progress_reset_callback: called when some bytes reset from copy_bitmap
168
- * (see @skip_unallocated above). The callee is assumed to recalculate how
169
- * many bytes remain based on the dirty bit count of copy_bitmap.
170
- */
171
- ProgressResetCallbackFunc progress_reset_callback;
172
void *progress_opaque;
173
174
SharedResource *mem;
175
@@ -XXX,XX +XXX,XX @@ BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
176
BdrvRequestFlags write_flags,
177
Error **errp);
178
179
-void block_copy_set_callbacks(
180
+void block_copy_set_progress_callback(
181
BlockCopyState *s,
182
ProgressBytesCallbackFunc progress_bytes_callback,
183
- ProgressResetCallbackFunc progress_reset_callback,
184
void *progress_opaque);
185
186
+void block_copy_set_progress_meter(BlockCopyState *s, ProgressMeter *pm);
187
+
188
void block_copy_state_free(BlockCopyState *s);
189
190
int64_t block_copy_reset_unallocated(BlockCopyState *s,
191
--
192
2.24.1
193
194
diff view generated by jsdifflib
Deleted patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
1
3
In block_copy_do_copy we fallback to read+write if copy_range failed.
4
In this case copy_size is larger than defined for buffered IO, and
5
there is corresponding commit. Still, backup copies data cluster by
6
cluster, and most of requests are limited to one cluster anyway, so the
7
only source of this one bad-limited request is copy-before-write
8
operation.
9
10
Further patch will move backup to use block_copy directly, than for
11
cases where copy_range is not supported, first request will be
12
oversized in each backup. It's not good, let's change it now.
13
14
Fix is simple: just limit first copy_range request like buffer-based
15
request. If it succeed, set larger copy_range limit.
16
17
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
18
Reviewed-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
19
Reviewed-by: Max Reitz <mreitz@redhat.com>
20
Message-Id: <20200311103004.7649-4-vsementsov@virtuozzo.com>
21
Signed-off-by: Max Reitz <mreitz@redhat.com>
22
---
23
block/block-copy.c | 41 +++++++++++++++++++++++++++++++----------
24
1 file changed, 31 insertions(+), 10 deletions(-)
25
26
diff --git a/block/block-copy.c b/block/block-copy.c
27
index XXXXXXX..XXXXXXX 100644
28
--- a/block/block-copy.c
29
+++ b/block/block-copy.c
30
@@ -XXX,XX +XXX,XX @@ void block_copy_state_free(BlockCopyState *s)
31
g_free(s);
32
}
33
34
+static uint32_t block_copy_max_transfer(BdrvChild *source, BdrvChild *target)
35
+{
36
+ return MIN_NON_ZERO(INT_MAX,
37
+ MIN_NON_ZERO(source->bs->bl.max_transfer,
38
+ target->bs->bl.max_transfer));
39
+}
40
+
41
BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
42
int64_t cluster_size,
43
BdrvRequestFlags write_flags, Error **errp)
44
{
45
BlockCopyState *s;
46
BdrvDirtyBitmap *copy_bitmap;
47
- uint32_t max_transfer =
48
- MIN_NON_ZERO(INT_MAX,
49
- MIN_NON_ZERO(source->bs->bl.max_transfer,
50
- target->bs->bl.max_transfer));
51
52
copy_bitmap = bdrv_create_dirty_bitmap(source->bs, cluster_size, NULL,
53
errp);
54
@@ -XXX,XX +XXX,XX @@ BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
55
.mem = shres_create(BLOCK_COPY_MAX_MEM),
56
};
57
58
- if (max_transfer < cluster_size) {
59
+ if (block_copy_max_transfer(source, target) < cluster_size) {
60
/*
61
* copy_range does not respect max_transfer. We don't want to bother
62
* with requests smaller than block-copy cluster size, so fallback to
63
@@ -XXX,XX +XXX,XX @@ BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
64
s->copy_size = cluster_size;
65
} else {
66
/*
67
- * copy_range does not respect max_transfer (it's a TODO), so we factor
68
- * that in here.
69
+ * We enable copy-range, but keep small copy_size, until first
70
+ * successful copy_range (look at block_copy_do_copy).
71
*/
72
s->use_copy_range = true;
73
- s->copy_size = MIN(MAX(cluster_size, BLOCK_COPY_MAX_COPY_RANGE),
74
- QEMU_ALIGN_DOWN(max_transfer, cluster_size));
75
+ s->copy_size = MAX(s->cluster_size, BLOCK_COPY_MAX_BUFFER);
76
}
77
78
QLIST_INIT(&s->inflight_reqs);
79
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn block_copy_do_copy(BlockCopyState *s,
80
s->copy_size = MAX(s->cluster_size, BLOCK_COPY_MAX_BUFFER);
81
/* Fallback to read+write with allocated buffer */
82
} else {
83
+ if (s->use_copy_range) {
84
+ /*
85
+ * Successful copy-range. Now increase copy_size. copy_range
86
+ * does not respect max_transfer (it's a TODO), so we factor
87
+ * that in here.
88
+ *
89
+ * Note: we double-check s->use_copy_range for the case when
90
+ * parallel block-copy request unsets it during previous
91
+ * bdrv_co_copy_range call.
92
+ */
93
+ s->copy_size =
94
+ MIN(MAX(s->cluster_size, BLOCK_COPY_MAX_COPY_RANGE),
95
+ QEMU_ALIGN_DOWN(block_copy_max_transfer(s->source,
96
+ s->target),
97
+ s->cluster_size));
98
+ }
99
goto out;
100
}
101
}
102
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn block_copy_do_copy(BlockCopyState *s,
103
/*
104
* In case of failed copy_range request above, we may proceed with buffered
105
* request larger than BLOCK_COPY_MAX_BUFFER. Still, further requests will
106
- * be properly limited, so don't care too much.
107
+ * be properly limited, so don't care too much. Moreover the most likely
108
+ * case (copy_range is unsupported for the configuration, so the very first
109
+ * copy_range request fails) is handled by setting large copy_size only
110
+ * after first successful copy_range.
111
*/
112
113
bounce_buffer = qemu_blockalign(s->source->bs, nbytes);
114
--
115
2.24.1
116
117
diff view generated by jsdifflib
Deleted patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
1
3
Use bdrv_block_status_above to chose effective chunk size and to handle
4
zeroes effectively.
5
6
This substitutes checking for just being allocated or not, and drops
7
old code path for it. Assistance by backup job is dropped too, as
8
caching block-status information is more difficult than just caching
9
is-allocated information in our dirty bitmap, and backup job is not
10
good place for this caching anyway.
11
12
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
13
Reviewed-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
14
Reviewed-by: Max Reitz <mreitz@redhat.com>
15
Message-Id: <20200311103004.7649-5-vsementsov@virtuozzo.com>
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
17
---
18
block/block-copy.c | 73 +++++++++++++++++++++++++++++++++++++---------
19
block/trace-events | 1 +
20
2 files changed, 61 insertions(+), 13 deletions(-)
21
22
diff --git a/block/block-copy.c b/block/block-copy.c
23
index XXXXXXX..XXXXXXX 100644
24
--- a/block/block-copy.c
25
+++ b/block/block-copy.c
26
@@ -XXX,XX +XXX,XX @@ void block_copy_set_progress_meter(BlockCopyState *s, ProgressMeter *pm)
27
*/
28
static int coroutine_fn block_copy_do_copy(BlockCopyState *s,
29
int64_t start, int64_t end,
30
- bool *error_is_read)
31
+ bool zeroes, bool *error_is_read)
32
{
33
int ret;
34
int nbytes = MIN(end, s->len) - start;
35
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn block_copy_do_copy(BlockCopyState *s,
36
assert(QEMU_IS_ALIGNED(end, s->cluster_size));
37
assert(end < s->len || end == QEMU_ALIGN_UP(s->len, s->cluster_size));
38
39
+ if (zeroes) {
40
+ ret = bdrv_co_pwrite_zeroes(s->target, start, nbytes, s->write_flags &
41
+ ~BDRV_REQ_WRITE_COMPRESSED);
42
+ if (ret < 0) {
43
+ trace_block_copy_write_zeroes_fail(s, start, ret);
44
+ if (error_is_read) {
45
+ *error_is_read = false;
46
+ }
47
+ }
48
+ return ret;
49
+ }
50
+
51
if (s->use_copy_range) {
52
ret = bdrv_co_copy_range(s->source, start, s->target, start, nbytes,
53
0, s->write_flags);
54
@@ -XXX,XX +XXX,XX @@ out:
55
return ret;
56
}
57
58
+static int block_copy_block_status(BlockCopyState *s, int64_t offset,
59
+ int64_t bytes, int64_t *pnum)
60
+{
61
+ int64_t num;
62
+ BlockDriverState *base;
63
+ int ret;
64
+
65
+ if (s->skip_unallocated && s->source->bs->backing) {
66
+ base = s->source->bs->backing->bs;
67
+ } else {
68
+ base = NULL;
69
+ }
70
+
71
+ ret = bdrv_block_status_above(s->source->bs, base, offset, bytes, &num,
72
+ NULL, NULL);
73
+ if (ret < 0 || num < s->cluster_size) {
74
+ /*
75
+ * On error or if failed to obtain large enough chunk just fallback to
76
+ * copy one cluster.
77
+ */
78
+ num = s->cluster_size;
79
+ ret = BDRV_BLOCK_ALLOCATED | BDRV_BLOCK_DATA;
80
+ } else if (offset + num == s->len) {
81
+ num = QEMU_ALIGN_UP(num, s->cluster_size);
82
+ } else {
83
+ num = QEMU_ALIGN_DOWN(num, s->cluster_size);
84
+ }
85
+
86
+ *pnum = num;
87
+ return ret;
88
+}
89
+
90
/*
91
* Check if the cluster starting at offset is allocated or not.
92
* return via pnum the number of contiguous clusters sharing this allocation.
93
@@ -XXX,XX +XXX,XX @@ int coroutine_fn block_copy(BlockCopyState *s,
94
{
95
int ret = 0;
96
int64_t end = bytes + start; /* bytes */
97
- int64_t status_bytes;
98
BlockCopyInFlightReq req;
99
100
/*
101
@@ -XXX,XX +XXX,XX @@ int coroutine_fn block_copy(BlockCopyState *s,
102
block_copy_inflight_req_begin(s, &req, start, end);
103
104
while (start < end) {
105
- int64_t next_zero, chunk_end;
106
+ int64_t next_zero, chunk_end, status_bytes;
107
108
if (!bdrv_dirty_bitmap_get(s->copy_bitmap, start)) {
109
trace_block_copy_skip(s, start);
110
@@ -XXX,XX +XXX,XX @@ int coroutine_fn block_copy(BlockCopyState *s,
111
chunk_end = next_zero;
112
}
113
114
- if (s->skip_unallocated) {
115
- ret = block_copy_reset_unallocated(s, start, &status_bytes);
116
- if (ret == 0) {
117
- trace_block_copy_skip_range(s, start, status_bytes);
118
- start += status_bytes;
119
- continue;
120
- }
121
- /* Clamp to known allocated region */
122
- chunk_end = MIN(chunk_end, start + status_bytes);
123
+ ret = block_copy_block_status(s, start, chunk_end - start,
124
+ &status_bytes);
125
+ if (s->skip_unallocated && !(ret & BDRV_BLOCK_ALLOCATED)) {
126
+ bdrv_reset_dirty_bitmap(s->copy_bitmap, start, status_bytes);
127
+ progress_set_remaining(s->progress,
128
+ bdrv_get_dirty_count(s->copy_bitmap) +
129
+ s->in_flight_bytes);
130
+ trace_block_copy_skip_range(s, start, status_bytes);
131
+ start += status_bytes;
132
+ continue;
133
}
134
135
+ chunk_end = MIN(chunk_end, start + status_bytes);
136
+
137
trace_block_copy_process(s, start);
138
139
bdrv_reset_dirty_bitmap(s->copy_bitmap, start, chunk_end - start);
140
s->in_flight_bytes += chunk_end - start;
141
142
co_get_from_shres(s->mem, chunk_end - start);
143
- ret = block_copy_do_copy(s, start, chunk_end, error_is_read);
144
+ ret = block_copy_do_copy(s, start, chunk_end, ret & BDRV_BLOCK_ZERO,
145
+ error_is_read);
146
co_put_to_shres(s->mem, chunk_end - start);
147
s->in_flight_bytes -= chunk_end - start;
148
if (ret < 0) {
149
diff --git a/block/trace-events b/block/trace-events
150
index XXXXXXX..XXXXXXX 100644
151
--- a/block/trace-events
152
+++ b/block/trace-events
153
@@ -XXX,XX +XXX,XX @@ block_copy_process(void *bcs, int64_t start) "bcs %p start %"PRId64
154
block_copy_copy_range_fail(void *bcs, int64_t start, int ret) "bcs %p start %"PRId64" ret %d"
155
block_copy_read_fail(void *bcs, int64_t start, int ret) "bcs %p start %"PRId64" ret %d"
156
block_copy_write_fail(void *bcs, int64_t start, int ret) "bcs %p start %"PRId64" ret %d"
157
+block_copy_write_zeroes_fail(void *bcs, int64_t start, int ret) "bcs %p start %"PRId64" ret %d"
158
159
# ../blockdev.c
160
qmp_block_job_cancel(void *job) "job %p"
161
--
162
2.24.1
163
164
diff view generated by jsdifflib
Deleted patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
1
3
Split find_conflicting_inflight_req to be used separately.
4
5
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Reviewed-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Message-Id: <20200311103004.7649-6-vsementsov@virtuozzo.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
11
block/block-copy.c | 31 +++++++++++++++++++------------
12
1 file changed, 19 insertions(+), 12 deletions(-)
13
14
diff --git a/block/block-copy.c b/block/block-copy.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/block/block-copy.c
17
+++ b/block/block-copy.c
18
@@ -XXX,XX +XXX,XX @@
19
#define BLOCK_COPY_MAX_BUFFER (1 * MiB)
20
#define BLOCK_COPY_MAX_MEM (128 * MiB)
21
22
+static BlockCopyInFlightReq *find_conflicting_inflight_req(BlockCopyState *s,
23
+ int64_t start,
24
+ int64_t end)
25
+{
26
+ BlockCopyInFlightReq *req;
27
+
28
+ QLIST_FOREACH(req, &s->inflight_reqs, list) {
29
+ if (end > req->start_byte && start < req->end_byte) {
30
+ return req;
31
+ }
32
+ }
33
+
34
+ return NULL;
35
+}
36
+
37
static void coroutine_fn block_copy_wait_inflight_reqs(BlockCopyState *s,
38
int64_t start,
39
int64_t end)
40
{
41
BlockCopyInFlightReq *req;
42
- bool waited;
43
-
44
- do {
45
- waited = false;
46
- QLIST_FOREACH(req, &s->inflight_reqs, list) {
47
- if (end > req->start_byte && start < req->end_byte) {
48
- qemu_co_queue_wait(&req->wait_queue, NULL);
49
- waited = true;
50
- break;
51
- }
52
- }
53
- } while (waited);
54
+
55
+ while ((req = find_conflicting_inflight_req(s, start, end))) {
56
+ qemu_co_queue_wait(&req->wait_queue, NULL);
57
+ }
58
}
59
60
static void block_copy_inflight_req_begin(BlockCopyState *s,
61
--
62
2.24.1
63
64
diff view generated by jsdifflib
Deleted patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
1
3
We have a lot of "chunk_end - start" invocations, let's switch to
4
bytes/cur_bytes scheme instead.
5
6
While being here, improve check on block_copy_do_copy parameters to not
7
overflow when calculating nbytes and use int64_t for bytes in
8
block_copy for consistency.
9
10
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
11
Reviewed-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
12
Reviewed-by: Max Reitz <mreitz@redhat.com>
13
Message-Id: <20200311103004.7649-7-vsementsov@virtuozzo.com>
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
---
16
block/block-copy.c | 78 ++++++++++++++++++++------------------
17
include/block/block-copy.h | 6 +--
18
2 files changed, 44 insertions(+), 40 deletions(-)
19
20
diff --git a/block/block-copy.c b/block/block-copy.c
21
index XXXXXXX..XXXXXXX 100644
22
--- a/block/block-copy.c
23
+++ b/block/block-copy.c
24
@@ -XXX,XX +XXX,XX @@
25
26
static BlockCopyInFlightReq *find_conflicting_inflight_req(BlockCopyState *s,
27
int64_t start,
28
- int64_t end)
29
+ int64_t bytes)
30
{
31
BlockCopyInFlightReq *req;
32
33
QLIST_FOREACH(req, &s->inflight_reqs, list) {
34
- if (end > req->start_byte && start < req->end_byte) {
35
+ if (start + bytes > req->start && start < req->start + req->bytes) {
36
return req;
37
}
38
}
39
@@ -XXX,XX +XXX,XX @@ static BlockCopyInFlightReq *find_conflicting_inflight_req(BlockCopyState *s,
40
41
static void coroutine_fn block_copy_wait_inflight_reqs(BlockCopyState *s,
42
int64_t start,
43
- int64_t end)
44
+ int64_t bytes)
45
{
46
BlockCopyInFlightReq *req;
47
48
- while ((req = find_conflicting_inflight_req(s, start, end))) {
49
+ while ((req = find_conflicting_inflight_req(s, start, bytes))) {
50
qemu_co_queue_wait(&req->wait_queue, NULL);
51
}
52
}
53
54
static void block_copy_inflight_req_begin(BlockCopyState *s,
55
BlockCopyInFlightReq *req,
56
- int64_t start, int64_t end)
57
+ int64_t start, int64_t bytes)
58
{
59
- req->start_byte = start;
60
- req->end_byte = end;
61
+ req->start = start;
62
+ req->bytes = bytes;
63
qemu_co_queue_init(&req->wait_queue);
64
QLIST_INSERT_HEAD(&s->inflight_reqs, req, list);
65
}
66
@@ -XXX,XX +XXX,XX @@ void block_copy_set_progress_meter(BlockCopyState *s, ProgressMeter *pm)
67
/*
68
* block_copy_do_copy
69
*
70
- * Do copy of cluser-aligned chunk. @end is allowed to exceed s->len only to
71
- * cover last cluster when s->len is not aligned to clusters.
72
+ * Do copy of cluster-aligned chunk. Requested region is allowed to exceed
73
+ * s->len only to cover last cluster when s->len is not aligned to clusters.
74
*
75
* No sync here: nor bitmap neighter intersecting requests handling, only copy.
76
*
77
* Returns 0 on success.
78
*/
79
static int coroutine_fn block_copy_do_copy(BlockCopyState *s,
80
- int64_t start, int64_t end,
81
+ int64_t start, int64_t bytes,
82
bool zeroes, bool *error_is_read)
83
{
84
int ret;
85
- int nbytes = MIN(end, s->len) - start;
86
+ int64_t nbytes = MIN(start + bytes, s->len) - start;
87
void *bounce_buffer = NULL;
88
89
+ assert(start >= 0 && bytes > 0 && INT64_MAX - start >= bytes);
90
assert(QEMU_IS_ALIGNED(start, s->cluster_size));
91
- assert(QEMU_IS_ALIGNED(end, s->cluster_size));
92
- assert(end < s->len || end == QEMU_ALIGN_UP(s->len, s->cluster_size));
93
+ assert(QEMU_IS_ALIGNED(bytes, s->cluster_size));
94
+ assert(start < s->len);
95
+ assert(start + bytes <= s->len ||
96
+ start + bytes == QEMU_ALIGN_UP(s->len, s->cluster_size));
97
+ assert(nbytes < INT_MAX);
98
99
if (zeroes) {
100
ret = bdrv_co_pwrite_zeroes(s->target, start, nbytes, s->write_flags &
101
@@ -XXX,XX +XXX,XX @@ int64_t block_copy_reset_unallocated(BlockCopyState *s,
102
}
103
104
int coroutine_fn block_copy(BlockCopyState *s,
105
- int64_t start, uint64_t bytes,
106
+ int64_t start, int64_t bytes,
107
bool *error_is_read)
108
{
109
int ret = 0;
110
- int64_t end = bytes + start; /* bytes */
111
BlockCopyInFlightReq req;
112
113
/*
114
@@ -XXX,XX +XXX,XX @@ int coroutine_fn block_copy(BlockCopyState *s,
115
bdrv_get_aio_context(s->target->bs));
116
117
assert(QEMU_IS_ALIGNED(start, s->cluster_size));
118
- assert(QEMU_IS_ALIGNED(end, s->cluster_size));
119
+ assert(QEMU_IS_ALIGNED(bytes, s->cluster_size));
120
121
block_copy_wait_inflight_reqs(s, start, bytes);
122
- block_copy_inflight_req_begin(s, &req, start, end);
123
+ block_copy_inflight_req_begin(s, &req, start, bytes);
124
125
- while (start < end) {
126
- int64_t next_zero, chunk_end, status_bytes;
127
+ while (bytes) {
128
+ int64_t next_zero, cur_bytes, status_bytes;
129
130
if (!bdrv_dirty_bitmap_get(s->copy_bitmap, start)) {
131
trace_block_copy_skip(s, start);
132
start += s->cluster_size;
133
+ bytes -= s->cluster_size;
134
continue; /* already copied */
135
}
136
137
- chunk_end = MIN(end, start + s->copy_size);
138
+ cur_bytes = MIN(bytes, s->copy_size);
139
140
next_zero = bdrv_dirty_bitmap_next_zero(s->copy_bitmap, start,
141
- chunk_end - start);
142
+ cur_bytes);
143
if (next_zero >= 0) {
144
assert(next_zero > start); /* start is dirty */
145
- assert(next_zero < chunk_end); /* no need to do MIN() */
146
- chunk_end = next_zero;
147
+ assert(next_zero < start + cur_bytes); /* no need to do MIN() */
148
+ cur_bytes = next_zero - start;
149
}
150
151
- ret = block_copy_block_status(s, start, chunk_end - start,
152
- &status_bytes);
153
+ ret = block_copy_block_status(s, start, cur_bytes, &status_bytes);
154
if (s->skip_unallocated && !(ret & BDRV_BLOCK_ALLOCATED)) {
155
bdrv_reset_dirty_bitmap(s->copy_bitmap, start, status_bytes);
156
progress_set_remaining(s->progress,
157
@@ -XXX,XX +XXX,XX @@ int coroutine_fn block_copy(BlockCopyState *s,
158
s->in_flight_bytes);
159
trace_block_copy_skip_range(s, start, status_bytes);
160
start += status_bytes;
161
+ bytes -= status_bytes;
162
continue;
163
}
164
165
- chunk_end = MIN(chunk_end, start + status_bytes);
166
+ cur_bytes = MIN(cur_bytes, status_bytes);
167
168
trace_block_copy_process(s, start);
169
170
- bdrv_reset_dirty_bitmap(s->copy_bitmap, start, chunk_end - start);
171
- s->in_flight_bytes += chunk_end - start;
172
+ bdrv_reset_dirty_bitmap(s->copy_bitmap, start, cur_bytes);
173
+ s->in_flight_bytes += cur_bytes;
174
175
- co_get_from_shres(s->mem, chunk_end - start);
176
- ret = block_copy_do_copy(s, start, chunk_end, ret & BDRV_BLOCK_ZERO,
177
+ co_get_from_shres(s->mem, cur_bytes);
178
+ ret = block_copy_do_copy(s, start, cur_bytes, ret & BDRV_BLOCK_ZERO,
179
error_is_read);
180
- co_put_to_shres(s->mem, chunk_end - start);
181
- s->in_flight_bytes -= chunk_end - start;
182
+ co_put_to_shres(s->mem, cur_bytes);
183
+ s->in_flight_bytes -= cur_bytes;
184
if (ret < 0) {
185
- bdrv_set_dirty_bitmap(s->copy_bitmap, start, chunk_end - start);
186
+ bdrv_set_dirty_bitmap(s->copy_bitmap, start, cur_bytes);
187
break;
188
}
189
190
- progress_work_done(s->progress, chunk_end - start);
191
- s->progress_bytes_callback(chunk_end - start, s->progress_opaque);
192
- start = chunk_end;
193
- ret = 0;
194
+ progress_work_done(s->progress, cur_bytes);
195
+ s->progress_bytes_callback(cur_bytes, s->progress_opaque);
196
+ start += cur_bytes;
197
+ bytes -= cur_bytes;
198
}
199
200
block_copy_inflight_req_end(&req);
201
diff --git a/include/block/block-copy.h b/include/block/block-copy.h
202
index XXXXXXX..XXXXXXX 100644
203
--- a/include/block/block-copy.h
204
+++ b/include/block/block-copy.h
205
@@ -XXX,XX +XXX,XX @@
206
#include "qemu/co-shared-resource.h"
207
208
typedef struct BlockCopyInFlightReq {
209
- int64_t start_byte;
210
- int64_t end_byte;
211
+ int64_t start;
212
+ int64_t bytes;
213
QLIST_ENTRY(BlockCopyInFlightReq) list;
214
CoQueue wait_queue; /* coroutines blocked on this request */
215
} BlockCopyInFlightReq;
216
@@ -XXX,XX +XXX,XX @@ void block_copy_state_free(BlockCopyState *s);
217
int64_t block_copy_reset_unallocated(BlockCopyState *s,
218
int64_t offset, int64_t *count);
219
220
-int coroutine_fn block_copy(BlockCopyState *s, int64_t start, uint64_t bytes,
221
+int coroutine_fn block_copy(BlockCopyState *s, int64_t start, int64_t bytes,
222
bool *error_is_read);
223
224
#endif /* BLOCK_COPY_H */
225
--
226
2.24.1
227
228
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Daniel Brodsky <dnbrdsky@gmail.com>
2
2
3
offset/bytes pair is more usual naming in block layer, let's use it.
3
- __COUNTER__ doesn't work with ## concat
4
- replaced ## with glue() macro so __COUNTER__ is evaluated
4
5
5
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Fixes: 3284c3ddc4
6
Reviewed-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
7
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Signed-off-by: Daniel Brodsky <dnbrdsky@gmail.com>
8
Message-Id: <20200311103004.7649-8-vsementsov@virtuozzo.com>
9
Message-id: 20200404042108.389635-2-dnbrdsky@gmail.com
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
---
11
---
11
block/block-copy.c | 82 +++++++++++++++++++-------------------
12
include/qemu/lockable.h | 7 ++++---
12
include/block/block-copy.h | 4 +-
13
include/qemu/rcu.h | 2 +-
13
2 files changed, 43 insertions(+), 43 deletions(-)
14
2 files changed, 5 insertions(+), 4 deletions(-)
14
15
15
diff --git a/block/block-copy.c b/block/block-copy.c
16
diff --git a/include/qemu/lockable.h b/include/qemu/lockable.h
16
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
17
--- a/block/block-copy.c
18
--- a/include/qemu/lockable.h
18
+++ b/block/block-copy.c
19
+++ b/include/qemu/lockable.h
19
@@ -XXX,XX +XXX,XX @@
20
@@ -XXX,XX +XXX,XX @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(QemuLockable, qemu_lockable_auto_unlock)
20
#define BLOCK_COPY_MAX_MEM (128 * MiB)
21
* }
21
22
static BlockCopyInFlightReq *find_conflicting_inflight_req(BlockCopyState *s,
23
- int64_t start,
24
+ int64_t offset,
25
int64_t bytes)
26
{
27
BlockCopyInFlightReq *req;
28
29
QLIST_FOREACH(req, &s->inflight_reqs, list) {
30
- if (start + bytes > req->start && start < req->start + req->bytes) {
31
+ if (offset + bytes > req->offset && offset < req->offset + req->bytes) {
32
return req;
33
}
34
}
35
@@ -XXX,XX +XXX,XX @@ static BlockCopyInFlightReq *find_conflicting_inflight_req(BlockCopyState *s,
36
}
37
38
static void coroutine_fn block_copy_wait_inflight_reqs(BlockCopyState *s,
39
- int64_t start,
40
+ int64_t offset,
41
int64_t bytes)
42
{
43
BlockCopyInFlightReq *req;
44
45
- while ((req = find_conflicting_inflight_req(s, start, bytes))) {
46
+ while ((req = find_conflicting_inflight_req(s, offset, bytes))) {
47
qemu_co_queue_wait(&req->wait_queue, NULL);
48
}
49
}
50
51
static void block_copy_inflight_req_begin(BlockCopyState *s,
52
BlockCopyInFlightReq *req,
53
- int64_t start, int64_t bytes)
54
+ int64_t offset, int64_t bytes)
55
{
56
- req->start = start;
57
+ req->offset = offset;
58
req->bytes = bytes;
59
qemu_co_queue_init(&req->wait_queue);
60
QLIST_INSERT_HEAD(&s->inflight_reqs, req, list);
61
@@ -XXX,XX +XXX,XX @@ void block_copy_set_progress_meter(BlockCopyState *s, ProgressMeter *pm)
62
* Returns 0 on success.
63
*/
22
*/
64
static int coroutine_fn block_copy_do_copy(BlockCopyState *s,
23
#define WITH_QEMU_LOCK_GUARD(x) \
65
- int64_t start, int64_t bytes,
24
- WITH_QEMU_LOCK_GUARD_((x), qemu_lockable_auto##__COUNTER__)
66
+ int64_t offset, int64_t bytes,
25
+ WITH_QEMU_LOCK_GUARD_((x), glue(qemu_lockable_auto, __COUNTER__))
67
bool zeroes, bool *error_is_read)
26
68
{
27
/**
69
int ret;
28
* QEMU_LOCK_GUARD - Lock an object until the end of the scope
70
- int64_t nbytes = MIN(start + bytes, s->len) - start;
29
@@ -XXX,XX +XXX,XX @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(QemuLockable, qemu_lockable_auto_unlock)
71
+ int64_t nbytes = MIN(offset + bytes, s->len) - offset;
30
* return; <-- mutex is automatically unlocked
72
void *bounce_buffer = NULL;
31
* }
73
32
*/
74
- assert(start >= 0 && bytes > 0 && INT64_MAX - start >= bytes);
33
-#define QEMU_LOCK_GUARD(x) \
75
- assert(QEMU_IS_ALIGNED(start, s->cluster_size));
34
- g_autoptr(QemuLockable) qemu_lockable_auto##__COUNTER__ = \
76
+ assert(offset >= 0 && bytes > 0 && INT64_MAX - offset >= bytes);
35
+#define QEMU_LOCK_GUARD(x) \
77
+ assert(QEMU_IS_ALIGNED(offset, s->cluster_size));
36
+ g_autoptr(QemuLockable) \
78
assert(QEMU_IS_ALIGNED(bytes, s->cluster_size));
37
+ glue(qemu_lockable_auto, __COUNTER__) G_GNUC_UNUSED = \
79
- assert(start < s->len);
38
qemu_lockable_auto_lock(QEMU_MAKE_LOCKABLE((x)))
80
- assert(start + bytes <= s->len ||
39
81
- start + bytes == QEMU_ALIGN_UP(s->len, s->cluster_size));
40
#endif
82
+ assert(offset < s->len);
41
diff --git a/include/qemu/rcu.h b/include/qemu/rcu.h
83
+ assert(offset + bytes <= s->len ||
84
+ offset + bytes == QEMU_ALIGN_UP(s->len, s->cluster_size));
85
assert(nbytes < INT_MAX);
86
87
if (zeroes) {
88
- ret = bdrv_co_pwrite_zeroes(s->target, start, nbytes, s->write_flags &
89
+ ret = bdrv_co_pwrite_zeroes(s->target, offset, nbytes, s->write_flags &
90
~BDRV_REQ_WRITE_COMPRESSED);
91
if (ret < 0) {
92
- trace_block_copy_write_zeroes_fail(s, start, ret);
93
+ trace_block_copy_write_zeroes_fail(s, offset, ret);
94
if (error_is_read) {
95
*error_is_read = false;
96
}
97
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn block_copy_do_copy(BlockCopyState *s,
98
}
99
100
if (s->use_copy_range) {
101
- ret = bdrv_co_copy_range(s->source, start, s->target, start, nbytes,
102
+ ret = bdrv_co_copy_range(s->source, offset, s->target, offset, nbytes,
103
0, s->write_flags);
104
if (ret < 0) {
105
- trace_block_copy_copy_range_fail(s, start, ret);
106
+ trace_block_copy_copy_range_fail(s, offset, ret);
107
s->use_copy_range = false;
108
s->copy_size = MAX(s->cluster_size, BLOCK_COPY_MAX_BUFFER);
109
/* Fallback to read+write with allocated buffer */
110
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn block_copy_do_copy(BlockCopyState *s,
111
112
bounce_buffer = qemu_blockalign(s->source->bs, nbytes);
113
114
- ret = bdrv_co_pread(s->source, start, nbytes, bounce_buffer, 0);
115
+ ret = bdrv_co_pread(s->source, offset, nbytes, bounce_buffer, 0);
116
if (ret < 0) {
117
- trace_block_copy_read_fail(s, start, ret);
118
+ trace_block_copy_read_fail(s, offset, ret);
119
if (error_is_read) {
120
*error_is_read = true;
121
}
122
goto out;
123
}
124
125
- ret = bdrv_co_pwrite(s->target, start, nbytes, bounce_buffer,
126
+ ret = bdrv_co_pwrite(s->target, offset, nbytes, bounce_buffer,
127
s->write_flags);
128
if (ret < 0) {
129
- trace_block_copy_write_fail(s, start, ret);
130
+ trace_block_copy_write_fail(s, offset, ret);
131
if (error_is_read) {
132
*error_is_read = false;
133
}
134
@@ -XXX,XX +XXX,XX @@ int64_t block_copy_reset_unallocated(BlockCopyState *s,
135
}
136
137
int coroutine_fn block_copy(BlockCopyState *s,
138
- int64_t start, int64_t bytes,
139
+ int64_t offset, int64_t bytes,
140
bool *error_is_read)
141
{
142
int ret = 0;
143
@@ -XXX,XX +XXX,XX @@ int coroutine_fn block_copy(BlockCopyState *s,
144
assert(bdrv_get_aio_context(s->source->bs) ==
145
bdrv_get_aio_context(s->target->bs));
146
147
- assert(QEMU_IS_ALIGNED(start, s->cluster_size));
148
+ assert(QEMU_IS_ALIGNED(offset, s->cluster_size));
149
assert(QEMU_IS_ALIGNED(bytes, s->cluster_size));
150
151
- block_copy_wait_inflight_reqs(s, start, bytes);
152
- block_copy_inflight_req_begin(s, &req, start, bytes);
153
+ block_copy_wait_inflight_reqs(s, offset, bytes);
154
+ block_copy_inflight_req_begin(s, &req, offset, bytes);
155
156
while (bytes) {
157
int64_t next_zero, cur_bytes, status_bytes;
158
159
- if (!bdrv_dirty_bitmap_get(s->copy_bitmap, start)) {
160
- trace_block_copy_skip(s, start);
161
- start += s->cluster_size;
162
+ if (!bdrv_dirty_bitmap_get(s->copy_bitmap, offset)) {
163
+ trace_block_copy_skip(s, offset);
164
+ offset += s->cluster_size;
165
bytes -= s->cluster_size;
166
continue; /* already copied */
167
}
168
169
cur_bytes = MIN(bytes, s->copy_size);
170
171
- next_zero = bdrv_dirty_bitmap_next_zero(s->copy_bitmap, start,
172
+ next_zero = bdrv_dirty_bitmap_next_zero(s->copy_bitmap, offset,
173
cur_bytes);
174
if (next_zero >= 0) {
175
- assert(next_zero > start); /* start is dirty */
176
- assert(next_zero < start + cur_bytes); /* no need to do MIN() */
177
- cur_bytes = next_zero - start;
178
+ assert(next_zero > offset); /* offset is dirty */
179
+ assert(next_zero < offset + cur_bytes); /* no need to do MIN() */
180
+ cur_bytes = next_zero - offset;
181
}
182
183
- ret = block_copy_block_status(s, start, cur_bytes, &status_bytes);
184
+ ret = block_copy_block_status(s, offset, cur_bytes, &status_bytes);
185
if (s->skip_unallocated && !(ret & BDRV_BLOCK_ALLOCATED)) {
186
- bdrv_reset_dirty_bitmap(s->copy_bitmap, start, status_bytes);
187
+ bdrv_reset_dirty_bitmap(s->copy_bitmap, offset, status_bytes);
188
progress_set_remaining(s->progress,
189
bdrv_get_dirty_count(s->copy_bitmap) +
190
s->in_flight_bytes);
191
- trace_block_copy_skip_range(s, start, status_bytes);
192
- start += status_bytes;
193
+ trace_block_copy_skip_range(s, offset, status_bytes);
194
+ offset += status_bytes;
195
bytes -= status_bytes;
196
continue;
197
}
198
199
cur_bytes = MIN(cur_bytes, status_bytes);
200
201
- trace_block_copy_process(s, start);
202
+ trace_block_copy_process(s, offset);
203
204
- bdrv_reset_dirty_bitmap(s->copy_bitmap, start, cur_bytes);
205
+ bdrv_reset_dirty_bitmap(s->copy_bitmap, offset, cur_bytes);
206
s->in_flight_bytes += cur_bytes;
207
208
co_get_from_shres(s->mem, cur_bytes);
209
- ret = block_copy_do_copy(s, start, cur_bytes, ret & BDRV_BLOCK_ZERO,
210
+ ret = block_copy_do_copy(s, offset, cur_bytes, ret & BDRV_BLOCK_ZERO,
211
error_is_read);
212
co_put_to_shres(s->mem, cur_bytes);
213
s->in_flight_bytes -= cur_bytes;
214
if (ret < 0) {
215
- bdrv_set_dirty_bitmap(s->copy_bitmap, start, cur_bytes);
216
+ bdrv_set_dirty_bitmap(s->copy_bitmap, offset, cur_bytes);
217
break;
218
}
219
220
progress_work_done(s->progress, cur_bytes);
221
s->progress_bytes_callback(cur_bytes, s->progress_opaque);
222
- start += cur_bytes;
223
+ offset += cur_bytes;
224
bytes -= cur_bytes;
225
}
226
227
diff --git a/include/block/block-copy.h b/include/block/block-copy.h
228
index XXXXXXX..XXXXXXX 100644
42
index XXXXXXX..XXXXXXX 100644
229
--- a/include/block/block-copy.h
43
--- a/include/qemu/rcu.h
230
+++ b/include/block/block-copy.h
44
+++ b/include/qemu/rcu.h
231
@@ -XXX,XX +XXX,XX @@
45
@@ -XXX,XX +XXX,XX @@ static inline void rcu_read_auto_unlock(RCUReadAuto *r)
232
#include "qemu/co-shared-resource.h"
46
G_DEFINE_AUTOPTR_CLEANUP_FUNC(RCUReadAuto, rcu_read_auto_unlock)
233
47
234
typedef struct BlockCopyInFlightReq {
48
#define WITH_RCU_READ_LOCK_GUARD() \
235
- int64_t start;
49
- WITH_RCU_READ_LOCK_GUARD_(_rcu_read_auto##__COUNTER__)
236
+ int64_t offset;
50
+ WITH_RCU_READ_LOCK_GUARD_(glue(_rcu_read_auto, __COUNTER__))
237
int64_t bytes;
51
238
QLIST_ENTRY(BlockCopyInFlightReq) list;
52
#define WITH_RCU_READ_LOCK_GUARD_(var) \
239
CoQueue wait_queue; /* coroutines blocked on this request */
53
for (g_autoptr(RCUReadAuto) var = rcu_read_auto_lock(); \
240
@@ -XXX,XX +XXX,XX @@ void block_copy_state_free(BlockCopyState *s);
241
int64_t block_copy_reset_unallocated(BlockCopyState *s,
242
int64_t offset, int64_t *count);
243
244
-int coroutine_fn block_copy(BlockCopyState *s, int64_t start, int64_t bytes,
245
+int coroutine_fn block_copy(BlockCopyState *s, int64_t offset, int64_t bytes,
246
bool *error_is_read);
247
248
#endif /* BLOCK_COPY_H */
249
--
54
--
250
2.24.1
55
2.25.3
251
56
252
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Daniel Brodsky <dnbrdsky@gmail.com>
2
2
3
Hide structure definitions and add explicit API instead, to keep an
3
- ran regexp "qemu_mutex_lock\(.*\).*\n.*if" to find targets
4
eye on the scope of the shared fields.
4
- replaced result with QEMU_LOCK_GUARD if all unlocks at function end
5
- replaced result with WITH_QEMU_LOCK_GUARD if unlock not at end
5
6
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Signed-off-by: Daniel Brodsky <dnbrdsky@gmail.com>
7
Reviewed-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
8
Reviewed-by: Juan Quintela <quintela@redhat.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Message-id: 20200404042108.389635-3-dnbrdsky@gmail.com
9
Message-Id: <20200311103004.7649-10-vsementsov@virtuozzo.com>
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
11
---
12
block/backup-top.c | 6 ++--
12
block/iscsi.c | 7 ++----
13
block/backup.c | 25 ++++++++--------
13
block/nfs.c | 51 ++++++++++++++++++++-----------------------
14
block/block-copy.c | 59 ++++++++++++++++++++++++++++++++++++++
14
cpus-common.c | 14 +++++-------
15
include/block/block-copy.h | 52 +++------------------------------
15
hw/display/qxl.c | 43 +++++++++++++++++-------------------
16
4 files changed, 80 insertions(+), 62 deletions(-)
16
hw/vfio/platform.c | 5 ++---
17
migration/migration.c | 3 +--
18
migration/multifd.c | 8 +++----
19
migration/ram.c | 3 +--
20
monitor/misc.c | 4 +---
21
ui/spice-display.c | 14 ++++++------
22
util/log.c | 4 ++--
23
util/qemu-timer.c | 17 +++++++--------
24
util/rcu.c | 8 +++----
25
util/thread-pool.c | 3 +--
26
util/vfio-helpers.c | 5 ++---
27
15 files changed, 83 insertions(+), 106 deletions(-)
17
28
18
diff --git a/block/backup-top.c b/block/backup-top.c
29
diff --git a/block/iscsi.c b/block/iscsi.c
19
index XXXXXXX..XXXXXXX 100644
30
index XXXXXXX..XXXXXXX 100644
20
--- a/block/backup-top.c
31
--- a/block/iscsi.c
21
+++ b/block/backup-top.c
32
+++ b/block/iscsi.c
22
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVBackupTopState {
33
@@ -XXX,XX +XXX,XX @@ static void iscsi_nop_timed_event(void *opaque)
23
BlockCopyState *bcs;
34
{
24
BdrvChild *target;
35
IscsiLun *iscsilun = opaque;
25
bool active;
36
26
+ int64_t cluster_size;
37
- qemu_mutex_lock(&iscsilun->mutex);
27
} BDRVBackupTopState;
38
+ QEMU_LOCK_GUARD(&iscsilun->mutex);
28
39
if (iscsi_get_nops_in_flight(iscsilun->iscsi) >= MAX_NOP_FAILURES) {
29
static coroutine_fn int backup_top_co_preadv(
40
error_report("iSCSI: NOP timeout. Reconnecting...");
30
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int backup_top_cbw(BlockDriverState *bs, uint64_t offset,
41
iscsilun->request_timed_out = true;
31
return 0;
42
} else if (iscsi_nop_out_async(iscsilun->iscsi, NULL, NULL, 0, NULL) != 0) {
32
}
43
error_report("iSCSI: failed to sent NOP-Out. Disabling NOP messages.");
33
44
- goto out;
34
- off = QEMU_ALIGN_DOWN(offset, s->bcs->cluster_size);
45
+ return;
35
- end = QEMU_ALIGN_UP(offset + bytes, s->bcs->cluster_size);
46
}
36
+ off = QEMU_ALIGN_DOWN(offset, s->cluster_size);
47
37
+ end = QEMU_ALIGN_UP(offset + bytes, s->cluster_size);
48
timer_mod(iscsilun->nop_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + NOP_INTERVAL);
38
49
iscsi_set_events(iscsilun);
39
return block_copy(s->bcs, off, end - off, NULL);
50
-
40
}
51
-out:
41
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source,
52
- qemu_mutex_unlock(&iscsilun->mutex);
42
goto fail;
53
}
43
}
54
44
55
static void iscsi_readcapacity_sync(IscsiLun *iscsilun, Error **errp)
45
+ state->cluster_size = cluster_size;
56
diff --git a/block/nfs.c b/block/nfs.c
46
state->bcs = block_copy_state_new(top->backing, state->target,
57
index XXXXXXX..XXXXXXX 100644
47
cluster_size, write_flags, &local_err);
58
--- a/block/nfs.c
48
if (local_err) {
59
+++ b/block/nfs.c
49
diff --git a/block/backup.c b/block/backup.c
60
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn nfs_co_preadv(BlockDriverState *bs, uint64_t offset,
50
index XXXXXXX..XXXXXXX 100644
61
nfs_co_init_task(bs, &task);
51
--- a/block/backup.c
62
task.iov = iov;
52
+++ b/block/backup.c
63
53
@@ -XXX,XX +XXX,XX @@ static void backup_cleanup_sync_bitmap(BackupBlockJob *job, int ret)
64
- qemu_mutex_lock(&client->mutex);
54
65
- if (nfs_pread_async(client->context, client->fh,
55
if (ret < 0 && job->bitmap_mode == BITMAP_SYNC_MODE_ALWAYS) {
66
- offset, bytes, nfs_co_generic_cb, &task) != 0) {
56
/* If we failed and synced, merge in the bits we didn't copy: */
67
- qemu_mutex_unlock(&client->mutex);
57
- bdrv_dirty_bitmap_merge_internal(bm, job->bcs->copy_bitmap,
68
- return -ENOMEM;
58
+ bdrv_dirty_bitmap_merge_internal(bm, block_copy_dirty_bitmap(job->bcs),
69
- }
59
NULL, true);
70
+ WITH_QEMU_LOCK_GUARD(&client->mutex) {
60
}
71
+ if (nfs_pread_async(client->context, client->fh,
61
}
72
+ offset, bytes, nfs_co_generic_cb, &task) != 0) {
62
@@ -XXX,XX +XXX,XX @@ void backup_do_checkpoint(BlockJob *job, Error **errp)
73
+ return -ENOMEM;
74
+ }
75
76
- nfs_set_events(client);
77
- qemu_mutex_unlock(&client->mutex);
78
+ nfs_set_events(client);
79
+ }
80
while (!task.complete) {
81
qemu_coroutine_yield();
82
}
83
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn nfs_co_pwritev(BlockDriverState *bs, uint64_t offset,
84
buf = iov->iov[0].iov_base;
85
}
86
87
- qemu_mutex_lock(&client->mutex);
88
- if (nfs_pwrite_async(client->context, client->fh,
89
- offset, bytes, buf,
90
- nfs_co_generic_cb, &task) != 0) {
91
- qemu_mutex_unlock(&client->mutex);
92
- if (my_buffer) {
93
- g_free(buf);
94
+ WITH_QEMU_LOCK_GUARD(&client->mutex) {
95
+ if (nfs_pwrite_async(client->context, client->fh,
96
+ offset, bytes, buf,
97
+ nfs_co_generic_cb, &task) != 0) {
98
+ if (my_buffer) {
99
+ g_free(buf);
100
+ }
101
+ return -ENOMEM;
102
}
103
- return -ENOMEM;
104
- }
105
106
- nfs_set_events(client);
107
- qemu_mutex_unlock(&client->mutex);
108
+ nfs_set_events(client);
109
+ }
110
while (!task.complete) {
111
qemu_coroutine_yield();
112
}
113
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn nfs_co_flush(BlockDriverState *bs)
114
115
nfs_co_init_task(bs, &task);
116
117
- qemu_mutex_lock(&client->mutex);
118
- if (nfs_fsync_async(client->context, client->fh, nfs_co_generic_cb,
119
- &task) != 0) {
120
- qemu_mutex_unlock(&client->mutex);
121
- return -ENOMEM;
122
- }
123
+ WITH_QEMU_LOCK_GUARD(&client->mutex) {
124
+ if (nfs_fsync_async(client->context, client->fh, nfs_co_generic_cb,
125
+ &task) != 0) {
126
+ return -ENOMEM;
127
+ }
128
129
- nfs_set_events(client);
130
- qemu_mutex_unlock(&client->mutex);
131
+ nfs_set_events(client);
132
+ }
133
while (!task.complete) {
134
qemu_coroutine_yield();
135
}
136
diff --git a/cpus-common.c b/cpus-common.c
137
index XXXXXXX..XXXXXXX 100644
138
--- a/cpus-common.c
139
+++ b/cpus-common.c
140
@@ -XXX,XX +XXX,XX @@
141
#include "exec/cpu-common.h"
142
#include "hw/core/cpu.h"
143
#include "sysemu/cpus.h"
144
+#include "qemu/lockable.h"
145
146
static QemuMutex qemu_cpu_list_lock;
147
static QemuCond exclusive_cond;
148
@@ -XXX,XX +XXX,XX @@ static int cpu_get_free_index(void)
149
150
void cpu_list_add(CPUState *cpu)
151
{
152
- qemu_mutex_lock(&qemu_cpu_list_lock);
153
+ QEMU_LOCK_GUARD(&qemu_cpu_list_lock);
154
if (cpu->cpu_index == UNASSIGNED_CPU_INDEX) {
155
cpu->cpu_index = cpu_get_free_index();
156
assert(cpu->cpu_index != UNASSIGNED_CPU_INDEX);
157
@@ -XXX,XX +XXX,XX @@ void cpu_list_add(CPUState *cpu)
158
assert(!cpu_index_auto_assigned);
159
}
160
QTAILQ_INSERT_TAIL_RCU(&cpus, cpu, node);
161
- qemu_mutex_unlock(&qemu_cpu_list_lock);
162
}
163
164
void cpu_list_remove(CPUState *cpu)
165
{
166
- qemu_mutex_lock(&qemu_cpu_list_lock);
167
+ QEMU_LOCK_GUARD(&qemu_cpu_list_lock);
168
if (!QTAILQ_IN_USE(cpu, node)) {
169
/* there is nothing to undo since cpu_exec_init() hasn't been called */
170
- qemu_mutex_unlock(&qemu_cpu_list_lock);
63
return;
171
return;
64
}
172
}
65
173
66
- bdrv_set_dirty_bitmap(backup_job->bcs->copy_bitmap, 0, backup_job->len);
174
@@ -XXX,XX +XXX,XX @@ void cpu_list_remove(CPUState *cpu)
67
+ bdrv_set_dirty_bitmap(block_copy_dirty_bitmap(backup_job->bcs), 0,
175
68
+ backup_job->len);
176
QTAILQ_REMOVE_RCU(&cpus, cpu, node);
69
}
177
cpu->cpu_index = UNASSIGNED_CPU_INDEX;
70
178
- qemu_mutex_unlock(&qemu_cpu_list_lock);
71
static BlockErrorAction backup_error_action(BackupBlockJob *job,
179
}
72
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_loop(BackupBlockJob *job)
180
73
BdrvDirtyBitmapIter *bdbi;
181
struct qemu_work_item {
74
int ret = 0;
182
@@ -XXX,XX +XXX,XX @@ void cpu_exec_start(CPUState *cpu)
75
183
* see cpu->running == true, and it will kick the CPU.
76
- bdbi = bdrv_dirty_iter_new(job->bcs->copy_bitmap);
184
*/
77
+ bdbi = bdrv_dirty_iter_new(block_copy_dirty_bitmap(job->bcs));
185
if (unlikely(atomic_read(&pending_cpus))) {
78
while ((offset = bdrv_dirty_iter_next(bdbi)) != -1) {
186
- qemu_mutex_lock(&qemu_cpu_list_lock);
79
do {
187
+ QEMU_LOCK_GUARD(&qemu_cpu_list_lock);
80
if (yield_and_check(job)) {
188
if (!cpu->has_waiter) {
81
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_loop(BackupBlockJob *job)
189
/* Not counted in pending_cpus, let the exclusive item
190
* run. Since we have the lock, just set cpu->running to true
191
@@ -XXX,XX +XXX,XX @@ void cpu_exec_start(CPUState *cpu)
192
* waiter at cpu_exec_end.
193
*/
194
}
195
- qemu_mutex_unlock(&qemu_cpu_list_lock);
196
}
197
}
198
199
@@ -XXX,XX +XXX,XX @@ void cpu_exec_end(CPUState *cpu)
200
* next cpu_exec_start.
201
*/
202
if (unlikely(atomic_read(&pending_cpus))) {
203
- qemu_mutex_lock(&qemu_cpu_list_lock);
204
+ QEMU_LOCK_GUARD(&qemu_cpu_list_lock);
205
if (cpu->has_waiter) {
206
cpu->has_waiter = false;
207
atomic_set(&pending_cpus, pending_cpus - 1);
208
@@ -XXX,XX +XXX,XX @@ void cpu_exec_end(CPUState *cpu)
209
qemu_cond_signal(&exclusive_cond);
210
}
211
}
212
- qemu_mutex_unlock(&qemu_cpu_list_lock);
213
}
214
}
215
216
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
217
index XXXXXXX..XXXXXXX 100644
218
--- a/hw/display/qxl.c
219
+++ b/hw/display/qxl.c
220
@@ -XXX,XX +XXX,XX @@ static int qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext)
221
cmd->u.surface_create.stride);
222
return 1;
223
}
224
- qemu_mutex_lock(&qxl->track_lock);
225
- if (cmd->type == QXL_SURFACE_CMD_CREATE) {
226
- qxl->guest_surfaces.cmds[id] = ext->cmd.data;
227
- qxl->guest_surfaces.count++;
228
- if (qxl->guest_surfaces.max < qxl->guest_surfaces.count)
229
- qxl->guest_surfaces.max = qxl->guest_surfaces.count;
230
+ WITH_QEMU_LOCK_GUARD(&qxl->track_lock) {
231
+ if (cmd->type == QXL_SURFACE_CMD_CREATE) {
232
+ qxl->guest_surfaces.cmds[id] = ext->cmd.data;
233
+ qxl->guest_surfaces.count++;
234
+ if (qxl->guest_surfaces.max < qxl->guest_surfaces.count) {
235
+ qxl->guest_surfaces.max = qxl->guest_surfaces.count;
236
+ }
237
+ }
238
+ if (cmd->type == QXL_SURFACE_CMD_DESTROY) {
239
+ qxl->guest_surfaces.cmds[id] = 0;
240
+ qxl->guest_surfaces.count--;
241
+ }
242
}
243
- if (cmd->type == QXL_SURFACE_CMD_DESTROY) {
244
- qxl->guest_surfaces.cmds[id] = 0;
245
- qxl->guest_surfaces.count--;
246
- }
247
- qemu_mutex_unlock(&qxl->track_lock);
248
break;
249
}
250
case QXL_CMD_CURSOR:
251
@@ -XXX,XX +XXX,XX @@ static void interface_update_area_complete(QXLInstance *sin,
252
int i;
253
int qxl_i;
254
255
- qemu_mutex_lock(&qxl->ssd.lock);
256
+ QEMU_LOCK_GUARD(&qxl->ssd.lock);
257
if (surface_id != 0 || !num_updated_rects ||
258
!qxl->render_update_cookie_num) {
259
- qemu_mutex_unlock(&qxl->ssd.lock);
260
return;
261
}
262
trace_qxl_interface_update_area_complete(qxl->id, surface_id, dirty->left,
263
@@ -XXX,XX +XXX,XX @@ static void interface_update_area_complete(QXLInstance *sin,
264
* Don't bother copying or scheduling the bh since we will flip
265
* the whole area anyway on completion of the update_area async call
266
*/
267
- qemu_mutex_unlock(&qxl->ssd.lock);
268
return;
269
}
270
qxl_i = qxl->num_dirty_rects;
271
@@ -XXX,XX +XXX,XX @@ static void interface_update_area_complete(QXLInstance *sin,
272
trace_qxl_interface_update_area_complete_schedule_bh(qxl->id,
273
qxl->num_dirty_rects);
274
qemu_bh_schedule(qxl->update_area_bh);
275
- qemu_mutex_unlock(&qxl->ssd.lock);
276
}
277
278
/* called from spice server thread context only */
279
@@ -XXX,XX +XXX,XX @@ static void ioport_write(void *opaque, hwaddr addr,
280
case QXL_IO_MONITORS_CONFIG_ASYNC:
281
async_common:
282
async = QXL_ASYNC;
283
- qemu_mutex_lock(&d->async_lock);
284
- if (d->current_async != QXL_UNDEFINED_IO) {
285
- qxl_set_guest_bug(d, "%d async started before last (%d) complete",
286
- io_port, d->current_async);
287
- qemu_mutex_unlock(&d->async_lock);
288
- return;
289
+ WITH_QEMU_LOCK_GUARD(&d->async_lock) {
290
+ if (d->current_async != QXL_UNDEFINED_IO) {
291
+ qxl_set_guest_bug(d, "%d async started before last (%d) complete",
292
+ io_port, d->current_async);
293
+ return;
294
+ }
295
+ d->current_async = orig_io_port;
296
}
297
- d->current_async = orig_io_port;
298
- qemu_mutex_unlock(&d->async_lock);
299
break;
300
default:
301
break;
302
diff --git a/hw/vfio/platform.c b/hw/vfio/platform.c
303
index XXXXXXX..XXXXXXX 100644
304
--- a/hw/vfio/platform.c
305
+++ b/hw/vfio/platform.c
306
@@ -XXX,XX +XXX,XX @@
307
#include "hw/vfio/vfio-platform.h"
308
#include "migration/vmstate.h"
309
#include "qemu/error-report.h"
310
+#include "qemu/lockable.h"
311
#include "qemu/main-loop.h"
312
#include "qemu/module.h"
313
#include "qemu/range.h"
314
@@ -XXX,XX +XXX,XX @@ static void vfio_intp_interrupt(VFIOINTp *intp)
315
VFIOPlatformDevice *vdev = intp->vdev;
316
bool delay_handling = false;
317
318
- qemu_mutex_lock(&vdev->intp_mutex);
319
+ QEMU_LOCK_GUARD(&vdev->intp_mutex);
320
if (intp->state == VFIO_IRQ_INACTIVE) {
321
QLIST_FOREACH(tmp, &vdev->intp_list, next) {
322
if (tmp->state == VFIO_IRQ_ACTIVE ||
323
@@ -XXX,XX +XXX,XX @@ static void vfio_intp_interrupt(VFIOINTp *intp)
324
QSIMPLEQ_INSERT_TAIL(&vdev->pending_intp_queue,
325
intp, pqnext);
326
ret = event_notifier_test_and_clear(intp->interrupt);
327
- qemu_mutex_unlock(&vdev->intp_mutex);
328
return;
329
}
330
331
@@ -XXX,XX +XXX,XX @@ static void vfio_intp_interrupt(VFIOINTp *intp)
332
qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
333
vdev->mmap_timeout);
334
}
335
- qemu_mutex_unlock(&vdev->intp_mutex);
336
}
337
338
/**
339
diff --git a/migration/migration.c b/migration/migration.c
340
index XXXXXXX..XXXXXXX 100644
341
--- a/migration/migration.c
342
+++ b/migration/migration.c
343
@@ -XXX,XX +XXX,XX @@ static void migrate_fd_cleanup_bh(void *opaque)
344
345
void migrate_set_error(MigrationState *s, const Error *error)
346
{
347
- qemu_mutex_lock(&s->error_mutex);
348
+ QEMU_LOCK_GUARD(&s->error_mutex);
349
if (!s->error) {
350
s->error = error_copy(error);
351
}
352
- qemu_mutex_unlock(&s->error_mutex);
353
}
354
355
void migrate_fd_error(MigrationState *s, const Error *error)
356
diff --git a/migration/multifd.c b/migration/multifd.c
357
index XXXXXXX..XXXXXXX 100644
358
--- a/migration/multifd.c
359
+++ b/migration/multifd.c
360
@@ -XXX,XX +XXX,XX @@ void multifd_recv_sync_main(void)
361
for (i = 0; i < migrate_multifd_channels(); i++) {
362
MultiFDRecvParams *p = &multifd_recv_state->params[i];
363
364
- qemu_mutex_lock(&p->mutex);
365
- if (multifd_recv_state->packet_num < p->packet_num) {
366
- multifd_recv_state->packet_num = p->packet_num;
367
+ WITH_QEMU_LOCK_GUARD(&p->mutex) {
368
+ if (multifd_recv_state->packet_num < p->packet_num) {
369
+ multifd_recv_state->packet_num = p->packet_num;
370
+ }
371
}
372
- qemu_mutex_unlock(&p->mutex);
373
trace_multifd_recv_sync_main_signal(p->id);
374
qemu_sem_post(&p->sem_sync);
375
}
376
diff --git a/migration/ram.c b/migration/ram.c
377
index XXXXXXX..XXXXXXX 100644
378
--- a/migration/ram.c
379
+++ b/migration/ram.c
380
@@ -XXX,XX +XXX,XX @@ static RAMBlock *unqueue_page(RAMState *rs, ram_addr_t *offset)
381
return NULL;
382
}
383
384
- qemu_mutex_lock(&rs->src_page_req_mutex);
385
+ QEMU_LOCK_GUARD(&rs->src_page_req_mutex);
386
if (!QSIMPLEQ_EMPTY(&rs->src_page_requests)) {
387
struct RAMSrcPageRequest *entry =
388
QSIMPLEQ_FIRST(&rs->src_page_requests);
389
@@ -XXX,XX +XXX,XX @@ static RAMBlock *unqueue_page(RAMState *rs, ram_addr_t *offset)
390
migration_consume_urgent_request();
391
}
392
}
393
- qemu_mutex_unlock(&rs->src_page_req_mutex);
394
395
return block;
396
}
397
diff --git a/monitor/misc.c b/monitor/misc.c
398
index XXXXXXX..XXXXXXX 100644
399
--- a/monitor/misc.c
400
+++ b/monitor/misc.c
401
@@ -XXX,XX +XXX,XX @@ AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id,
402
MonFdsetFd *mon_fdset_fd;
403
AddfdInfo *fdinfo;
404
405
- qemu_mutex_lock(&mon_fdsets_lock);
406
+ QEMU_LOCK_GUARD(&mon_fdsets_lock);
407
if (has_fdset_id) {
408
QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
409
/* Break if match found or match impossible due to ordering by ID */
410
@@ -XXX,XX +XXX,XX @@ AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id,
411
if (fdset_id < 0) {
412
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "fdset-id",
413
"a non-negative value");
414
- qemu_mutex_unlock(&mon_fdsets_lock);
415
return NULL;
416
}
417
/* Use specified fdset ID */
418
@@ -XXX,XX +XXX,XX @@ AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id,
419
fdinfo->fdset_id = mon_fdset->id;
420
fdinfo->fd = mon_fdset_fd->fd;
421
422
- qemu_mutex_unlock(&mon_fdsets_lock);
423
return fdinfo;
424
}
425
426
diff --git a/ui/spice-display.c b/ui/spice-display.c
427
index XXXXXXX..XXXXXXX 100644
428
--- a/ui/spice-display.c
429
+++ b/ui/spice-display.c
430
@@ -XXX,XX +XXX,XX @@
431
#include "qemu/osdep.h"
432
#include "ui/qemu-spice.h"
433
#include "qemu/timer.h"
434
+#include "qemu/lockable.h"
435
#include "qemu/main-loop.h"
436
#include "qemu/option.h"
437
#include "qemu/queue.h"
438
@@ -XXX,XX +XXX,XX @@ void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd)
439
{
440
graphic_hw_update(ssd->dcl.con);
441
442
- qemu_mutex_lock(&ssd->lock);
443
- if (QTAILQ_EMPTY(&ssd->updates) && ssd->ds) {
444
- qemu_spice_create_update(ssd);
445
- ssd->notify++;
446
+ WITH_QEMU_LOCK_GUARD(&ssd->lock) {
447
+ if (QTAILQ_EMPTY(&ssd->updates) && ssd->ds) {
448
+ qemu_spice_create_update(ssd);
449
+ ssd->notify++;
450
+ }
451
}
452
- qemu_mutex_unlock(&ssd->lock);
453
454
trace_qemu_spice_display_refresh(ssd->qxl.id, ssd->notify);
455
if (ssd->notify) {
456
@@ -XXX,XX +XXX,XX @@ static int interface_get_cursor_command(QXLInstance *sin, QXLCommandExt *ext)
457
SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
458
int ret;
459
460
- qemu_mutex_lock(&ssd->lock);
461
+ QEMU_LOCK_GUARD(&ssd->lock);
462
if (ssd->ptr_define) {
463
*ext = ssd->ptr_define->ext;
464
ssd->ptr_define = NULL;
465
@@ -XXX,XX +XXX,XX @@ static int interface_get_cursor_command(QXLInstance *sin, QXLCommandExt *ext)
466
} else {
467
ret = false;
468
}
469
- qemu_mutex_unlock(&ssd->lock);
82
return ret;
470
return ret;
83
}
471
}
84
472
85
-static void backup_init_copy_bitmap(BackupBlockJob *job)
473
diff --git a/util/log.c b/util/log.c
86
+static void backup_init_bcs_bitmap(BackupBlockJob *job)
474
index XXXXXXX..XXXXXXX 100644
475
--- a/util/log.c
476
+++ b/util/log.c
477
@@ -XXX,XX +XXX,XX @@
478
#include "qemu/cutils.h"
479
#include "trace/control.h"
480
#include "qemu/thread.h"
481
+#include "qemu/lockable.h"
482
483
static char *logfilename;
484
static QemuMutex qemu_logfile_mutex;
485
@@ -XXX,XX +XXX,XX @@ void qemu_set_log(int log_flags)
486
if (qemu_loglevel && (!is_daemonized() || logfilename)) {
487
need_to_open_file = true;
488
}
489
- qemu_mutex_lock(&qemu_logfile_mutex);
490
+ QEMU_LOCK_GUARD(&qemu_logfile_mutex);
491
if (qemu_logfile && !need_to_open_file) {
492
logfile = qemu_logfile;
493
atomic_rcu_set(&qemu_logfile, NULL);
494
@@ -XXX,XX +XXX,XX @@ void qemu_set_log(int log_flags)
495
}
496
atomic_rcu_set(&qemu_logfile, logfile);
497
}
498
- qemu_mutex_unlock(&qemu_logfile_mutex);
499
}
500
501
void qemu_log_needs_buffers(void)
502
diff --git a/util/qemu-timer.c b/util/qemu-timer.c
503
index XXXXXXX..XXXXXXX 100644
504
--- a/util/qemu-timer.c
505
+++ b/util/qemu-timer.c
506
@@ -XXX,XX +XXX,XX @@ void timer_mod_anticipate_ns(QEMUTimer *ts, int64_t expire_time)
507
QEMUTimerList *timer_list = ts->timer_list;
508
bool rearm;
509
510
- qemu_mutex_lock(&timer_list->active_timers_lock);
511
- if (ts->expire_time == -1 || ts->expire_time > expire_time) {
512
- if (ts->expire_time != -1) {
513
- timer_del_locked(timer_list, ts);
514
+ WITH_QEMU_LOCK_GUARD(&timer_list->active_timers_lock) {
515
+ if (ts->expire_time == -1 || ts->expire_time > expire_time) {
516
+ if (ts->expire_time != -1) {
517
+ timer_del_locked(timer_list, ts);
518
+ }
519
+ rearm = timer_mod_ns_locked(timer_list, ts, expire_time);
520
+ } else {
521
+ rearm = false;
522
}
523
- rearm = timer_mod_ns_locked(timer_list, ts, expire_time);
524
- } else {
525
- rearm = false;
526
}
527
- qemu_mutex_unlock(&timer_list->active_timers_lock);
528
-
529
if (rearm) {
530
timerlist_rearm(timer_list);
531
}
532
diff --git a/util/rcu.c b/util/rcu.c
533
index XXXXXXX..XXXXXXX 100644
534
--- a/util/rcu.c
535
+++ b/util/rcu.c
536
@@ -XXX,XX +XXX,XX @@
537
#include "qemu/atomic.h"
538
#include "qemu/thread.h"
539
#include "qemu/main-loop.h"
540
+#include "qemu/lockable.h"
541
#if defined(CONFIG_MALLOC_TRIM)
542
#include <malloc.h>
543
#endif
544
@@ -XXX,XX +XXX,XX @@ static void wait_for_readers(void)
545
546
void synchronize_rcu(void)
87
{
547
{
88
bool ret;
548
- qemu_mutex_lock(&rcu_sync_lock);
89
uint64_t estimate;
549
+ QEMU_LOCK_GUARD(&rcu_sync_lock);
90
+ BdrvDirtyBitmap *bcs_bitmap = block_copy_dirty_bitmap(job->bcs);
550
91
551
/* Write RCU-protected pointers before reading p_rcu_reader->ctr.
92
if (job->sync_mode == MIRROR_SYNC_MODE_BITMAP) {
552
* Pairs with smp_mb_placeholder() in rcu_read_lock().
93
- ret = bdrv_dirty_bitmap_merge_internal(job->bcs->copy_bitmap,
553
*/
94
- job->sync_bitmap,
554
smp_mb_global();
95
+ ret = bdrv_dirty_bitmap_merge_internal(bcs_bitmap, job->sync_bitmap,
555
96
NULL, true);
556
- qemu_mutex_lock(&rcu_registry_lock);
97
assert(ret);
557
+ QEMU_LOCK_GUARD(&rcu_registry_lock);
98
} else {
558
if (!QLIST_EMPTY(&registry)) {
99
@@ -XXX,XX +XXX,XX @@ static void backup_init_copy_bitmap(BackupBlockJob *job)
559
/* In either case, the atomic_mb_set below blocks stores that free
100
* We can't hog the coroutine to initialize this thoroughly.
560
* old RCU-protected pointers.
101
* Set a flag and resume work when we are able to yield safely.
561
@@ -XXX,XX +XXX,XX @@ void synchronize_rcu(void)
102
*/
562
103
- job->bcs->skip_unallocated = true;
563
wait_for_readers();
104
+ block_copy_set_skip_unallocated(job->bcs, true);
564
}
105
}
565
-
106
- bdrv_set_dirty_bitmap(job->bcs->copy_bitmap, 0, job->len);
566
- qemu_mutex_unlock(&rcu_registry_lock);
107
+ bdrv_set_dirty_bitmap(bcs_bitmap, 0, job->len);
567
- qemu_mutex_unlock(&rcu_sync_lock);
108
}
568
}
109
569
110
- estimate = bdrv_get_dirty_count(job->bcs->copy_bitmap);
570
111
+ estimate = bdrv_get_dirty_count(bcs_bitmap);
571
diff --git a/util/thread-pool.c b/util/thread-pool.c
112
job_progress_set_remaining(&job->common.job, estimate);
572
index XXXXXXX..XXXXXXX 100644
113
}
573
--- a/util/thread-pool.c
114
574
+++ b/util/thread-pool.c
115
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_run(Job *job, Error **errp)
575
@@ -XXX,XX +XXX,XX @@ static void thread_pool_cancel(BlockAIOCB *acb)
116
BackupBlockJob *s = container_of(job, BackupBlockJob, common.job);
576
117
int ret = 0;
577
trace_thread_pool_cancel(elem, elem->common.opaque);
118
578
119
- backup_init_copy_bitmap(s);
579
- qemu_mutex_lock(&pool->lock);
120
+ backup_init_bcs_bitmap(s);
580
+ QEMU_LOCK_GUARD(&pool->lock);
121
581
if (elem->state == THREAD_QUEUED &&
122
if (s->sync_mode == MIRROR_SYNC_MODE_TOP) {
582
/* No thread has yet started working on elem. we can try to "steal"
123
int64_t offset = 0;
583
* the item from the worker if we can get a signal from the
124
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_run(Job *job, Error **errp)
584
@@ -XXX,XX +XXX,XX @@ static void thread_pool_cancel(BlockAIOCB *acb)
125
585
elem->ret = -ECANCELED;
126
offset += count;
586
}
127
}
587
128
- s->bcs->skip_unallocated = false;
588
- qemu_mutex_unlock(&pool->lock);
129
+ block_copy_set_skip_unallocated(s->bcs, false);
589
}
130
}
590
131
591
static AioContext *thread_pool_get_aio_context(BlockAIOCB *acb)
132
if (s->sync_mode == MIRROR_SYNC_MODE_NONE) {
592
diff --git a/util/vfio-helpers.c b/util/vfio-helpers.c
133
/*
593
index XXXXXXX..XXXXXXX 100644
134
- * All bits are set in copy_bitmap to allow any cluster to be copied.
594
--- a/util/vfio-helpers.c
135
+ * All bits are set in bcs bitmap to allow any cluster to be copied.
595
+++ b/util/vfio-helpers.c
136
* This does not actually require them to be copied.
137
*/
138
while (!job_is_cancelled(job)) {
139
diff --git a/block/block-copy.c b/block/block-copy.c
140
index XXXXXXX..XXXXXXX 100644
141
--- a/block/block-copy.c
142
+++ b/block/block-copy.c
143
@@ -XXX,XX +XXX,XX @@
596
@@ -XXX,XX +XXX,XX @@
144
#define BLOCK_COPY_MAX_BUFFER (1 * MiB)
597
#include "standard-headers/linux/pci_regs.h"
145
#define BLOCK_COPY_MAX_MEM (128 * MiB)
598
#include "qemu/event_notifier.h"
146
599
#include "qemu/vfio-helpers.h"
147
+typedef struct BlockCopyInFlightReq {
600
+#include "qemu/lockable.h"
148
+ int64_t offset;
601
#include "trace.h"
149
+ int64_t bytes;
602
150
+ QLIST_ENTRY(BlockCopyInFlightReq) list;
603
#define QEMU_VFIO_DEBUG 0
151
+ CoQueue wait_queue; /* coroutines blocked on this request */
604
@@ -XXX,XX +XXX,XX @@ int qemu_vfio_dma_reset_temporary(QEMUVFIOState *s)
152
+} BlockCopyInFlightReq;
605
.size = QEMU_VFIO_IOVA_MAX - s->high_water_mark,
153
+
606
};
154
+typedef struct BlockCopyState {
607
trace_qemu_vfio_dma_reset_temporary(s);
155
+ /*
608
- qemu_mutex_lock(&s->lock);
156
+ * BdrvChild objects are not owned or managed by block-copy. They are
609
+ QEMU_LOCK_GUARD(&s->lock);
157
+ * provided by block-copy user and user is responsible for appropriate
610
if (ioctl(s->container, VFIO_IOMMU_UNMAP_DMA, &unmap)) {
158
+ * permissions on these children.
611
error_report("VFIO_UNMAP_DMA failed: %s", strerror(errno));
159
+ */
612
- qemu_mutex_unlock(&s->lock);
160
+ BdrvChild *source;
613
return -errno;
161
+ BdrvChild *target;
614
}
162
+ BdrvDirtyBitmap *copy_bitmap;
615
s->high_water_mark = QEMU_VFIO_IOVA_MAX;
163
+ int64_t in_flight_bytes;
616
- qemu_mutex_unlock(&s->lock);
164
+ int64_t cluster_size;
617
return 0;
165
+ bool use_copy_range;
618
}
166
+ int64_t copy_size;
619
167
+ uint64_t len;
168
+ QLIST_HEAD(, BlockCopyInFlightReq) inflight_reqs;
169
+
170
+ BdrvRequestFlags write_flags;
171
+
172
+ /*
173
+ * skip_unallocated:
174
+ *
175
+ * Used by sync=top jobs, which first scan the source node for unallocated
176
+ * areas and clear them in the copy_bitmap. During this process, the bitmap
177
+ * is thus not fully initialized: It may still have bits set for areas that
178
+ * are unallocated and should actually not be copied.
179
+ *
180
+ * This is indicated by skip_unallocated.
181
+ *
182
+ * In this case, block_copy() will query the source’s allocation status,
183
+ * skip unallocated regions, clear them in the copy_bitmap, and invoke
184
+ * block_copy_reset_unallocated() every time it does.
185
+ */
186
+ bool skip_unallocated;
187
+
188
+ ProgressMeter *progress;
189
+ /* progress_bytes_callback: called when some copying progress is done. */
190
+ ProgressBytesCallbackFunc progress_bytes_callback;
191
+ void *progress_opaque;
192
+
193
+ SharedResource *mem;
194
+} BlockCopyState;
195
+
196
static BlockCopyInFlightReq *find_conflicting_inflight_req(BlockCopyState *s,
197
int64_t offset,
198
int64_t bytes)
199
@@ -XXX,XX +XXX,XX @@ int coroutine_fn block_copy(BlockCopyState *s, int64_t offset, int64_t bytes,
200
201
return ret;
202
}
203
+
204
+BdrvDirtyBitmap *block_copy_dirty_bitmap(BlockCopyState *s)
205
+{
206
+ return s->copy_bitmap;
207
+}
208
+
209
+void block_copy_set_skip_unallocated(BlockCopyState *s, bool skip)
210
+{
211
+ s->skip_unallocated = skip;
212
+}
213
diff --git a/include/block/block-copy.h b/include/block/block-copy.h
214
index XXXXXXX..XXXXXXX 100644
215
--- a/include/block/block-copy.h
216
+++ b/include/block/block-copy.h
217
@@ -XXX,XX +XXX,XX @@
218
#include "block/block.h"
219
#include "qemu/co-shared-resource.h"
220
221
-typedef struct BlockCopyInFlightReq {
222
- int64_t offset;
223
- int64_t bytes;
224
- QLIST_ENTRY(BlockCopyInFlightReq) list;
225
- CoQueue wait_queue; /* coroutines blocked on this request */
226
-} BlockCopyInFlightReq;
227
-
228
typedef void (*ProgressBytesCallbackFunc)(int64_t bytes, void *opaque);
229
-typedef struct BlockCopyState {
230
- /*
231
- * BdrvChild objects are not owned or managed by block-copy. They are
232
- * provided by block-copy user and user is responsible for appropriate
233
- * permissions on these children.
234
- */
235
- BdrvChild *source;
236
- BdrvChild *target;
237
- BdrvDirtyBitmap *copy_bitmap;
238
- int64_t in_flight_bytes;
239
- int64_t cluster_size;
240
- bool use_copy_range;
241
- int64_t copy_size;
242
- uint64_t len;
243
- QLIST_HEAD(, BlockCopyInFlightReq) inflight_reqs;
244
-
245
- BdrvRequestFlags write_flags;
246
-
247
- /*
248
- * skip_unallocated:
249
- *
250
- * Used by sync=top jobs, which first scan the source node for unallocated
251
- * areas and clear them in the copy_bitmap. During this process, the bitmap
252
- * is thus not fully initialized: It may still have bits set for areas that
253
- * are unallocated and should actually not be copied.
254
- *
255
- * This is indicated by skip_unallocated.
256
- *
257
- * In this case, block_copy() will query the source’s allocation status,
258
- * skip unallocated regions, clear them in the copy_bitmap, and invoke
259
- * block_copy_reset_unallocated() every time it does.
260
- */
261
- bool skip_unallocated;
262
-
263
- ProgressMeter *progress;
264
- /* progress_bytes_callback: called when some copying progress is done. */
265
- ProgressBytesCallbackFunc progress_bytes_callback;
266
- void *progress_opaque;
267
-
268
- SharedResource *mem;
269
-} BlockCopyState;
270
+typedef struct BlockCopyState BlockCopyState;
271
272
BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
273
int64_t cluster_size,
274
@@ -XXX,XX +XXX,XX @@ int64_t block_copy_reset_unallocated(BlockCopyState *s,
275
int coroutine_fn block_copy(BlockCopyState *s, int64_t offset, int64_t bytes,
276
bool *error_is_read);
277
278
+BdrvDirtyBitmap *block_copy_dirty_bitmap(BlockCopyState *s);
279
+void block_copy_set_skip_unallocated(BlockCopyState *s, bool skip);
280
+
281
#endif /* BLOCK_COPY_H */
282
--
620
--
283
2.24.1
621
2.25.3
284
622
285
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Simran Singhal <singhalsimran0@gmail.com>
2
2
3
Currently, block_copy operation lock the whole requested region. But
3
Replace manual lock()/unlock() calls with lock guard macros
4
there is no reason to lock clusters, which are already copied, it will
4
(QEMU_LOCK_GUARD/WITH_QEMU_LOCK_GUARD).
5
disturb other parallel block_copy requests for no reason.
6
5
7
Let's instead do the following:
6
Signed-off-by: Simran Singhal <singhalsimran0@gmail.com>
7
Reviewed-by: Yuval Shaia <yuval.shaia.ml@gmail.com>
8
Reviewed-by: Marcel Apfelbaum<marcel.apfelbaum@gmail.com>
9
Tested-by: Yuval Shaia <yuval.shaia.ml@gmail.com>
10
Message-id: 20200402065035.GA15477@simran-Inspiron-5558
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
---
13
hw/hyperv/hyperv.c | 15 ++++++-------
14
hw/rdma/rdma_backend.c | 50 +++++++++++++++++++++---------------------
15
hw/rdma/rdma_rm.c | 3 +--
16
3 files changed, 33 insertions(+), 35 deletions(-)
8
17
9
Lock only sub-region, which we are going to operate on. Then, after
18
diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c
10
copying all dirty sub-regions, we should wait for intersecting
11
requests block-copy, if they failed, we should retry these new dirty
12
clusters.
13
14
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
15
Reviewed-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
16
Message-Id: <20200311103004.7649-9-vsementsov@virtuozzo.com>
17
Signed-off-by: Max Reitz <mreitz@redhat.com>
18
---
19
block/block-copy.c | 129 ++++++++++++++++++++++++++++++++++++---------
20
1 file changed, 105 insertions(+), 24 deletions(-)
21
22
diff --git a/block/block-copy.c b/block/block-copy.c
23
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
24
--- a/block/block-copy.c
20
--- a/hw/hyperv/hyperv.c
25
+++ b/block/block-copy.c
21
+++ b/hw/hyperv/hyperv.c
26
@@ -XXX,XX +XXX,XX @@ static BlockCopyInFlightReq *find_conflicting_inflight_req(BlockCopyState *s,
22
@@ -XXX,XX +XXX,XX @@
27
return NULL;
23
#include "sysemu/kvm.h"
28
}
24
#include "qemu/bitops.h"
29
25
#include "qemu/error-report.h"
30
-static void coroutine_fn block_copy_wait_inflight_reqs(BlockCopyState *s,
26
+#include "qemu/lockable.h"
31
- int64_t offset,
27
#include "qemu/queue.h"
32
- int64_t bytes)
28
#include "qemu/rcu.h"
33
+/*
29
#include "qemu/rcu_queue.h"
34
+ * If there are no intersecting requests return false. Otherwise, wait for the
30
@@ -XXX,XX +XXX,XX @@ int hyperv_set_msg_handler(uint32_t conn_id, HvMsgHandler handler, void *data)
35
+ * first found intersecting request to finish and return true.
31
int ret;
36
+ */
32
MsgHandler *mh;
37
+static bool coroutine_fn block_copy_wait_one(BlockCopyState *s, int64_t offset,
33
38
+ int64_t bytes)
34
- qemu_mutex_lock(&handlers_mutex);
39
{
35
+ QEMU_LOCK_GUARD(&handlers_mutex);
40
- BlockCopyInFlightReq *req;
36
QLIST_FOREACH(mh, &msg_handlers, link) {
41
+ BlockCopyInFlightReq *req = find_conflicting_inflight_req(s, offset, bytes);
37
if (mh->conn_id == conn_id) {
42
38
if (handler) {
43
- while ((req = find_conflicting_inflight_req(s, offset, bytes))) {
39
@@ -XXX,XX +XXX,XX @@ int hyperv_set_msg_handler(uint32_t conn_id, HvMsgHandler handler, void *data)
44
- qemu_co_queue_wait(&req->wait_queue, NULL);
40
g_free_rcu(mh, rcu);
45
+ if (!req) {
41
ret = 0;
46
+ return false;
42
}
43
- goto unlock;
44
+ return ret;
45
}
47
}
46
}
47
48
@@ -XXX,XX +XXX,XX @@ int hyperv_set_msg_handler(uint32_t conn_id, HvMsgHandler handler, void *data)
49
} else {
50
ret = -ENOENT;
51
}
52
-unlock:
53
- qemu_mutex_unlock(&handlers_mutex);
48
+
54
+
49
+ qemu_co_queue_wait(&req->wait_queue, NULL);
50
+
51
+ return true;
52
}
53
54
+/* Called only on full-dirty region */
55
static void block_copy_inflight_req_begin(BlockCopyState *s,
56
BlockCopyInFlightReq *req,
57
int64_t offset, int64_t bytes)
58
{
59
+ assert(!find_conflicting_inflight_req(s, offset, bytes));
60
+
61
+ bdrv_reset_dirty_bitmap(s->copy_bitmap, offset, bytes);
62
+ s->in_flight_bytes += bytes;
63
+
64
req->offset = offset;
65
req->bytes = bytes;
66
qemu_co_queue_init(&req->wait_queue);
67
QLIST_INSERT_HEAD(&s->inflight_reqs, req, list);
68
}
69
70
-static void coroutine_fn block_copy_inflight_req_end(BlockCopyInFlightReq *req)
71
+/*
72
+ * block_copy_inflight_req_shrink
73
+ *
74
+ * Drop the tail of the request to be handled later. Set dirty bits back and
75
+ * wake up all requests waiting for us (may be some of them are not intersecting
76
+ * with shrunk request)
77
+ */
78
+static void coroutine_fn block_copy_inflight_req_shrink(BlockCopyState *s,
79
+ BlockCopyInFlightReq *req, int64_t new_bytes)
80
{
81
+ if (new_bytes == req->bytes) {
82
+ return;
83
+ }
84
+
85
+ assert(new_bytes > 0 && new_bytes < req->bytes);
86
+
87
+ s->in_flight_bytes -= req->bytes - new_bytes;
88
+ bdrv_set_dirty_bitmap(s->copy_bitmap,
89
+ req->offset + new_bytes, req->bytes - new_bytes);
90
+
91
+ req->bytes = new_bytes;
92
+ qemu_co_queue_restart_all(&req->wait_queue);
93
+}
94
+
95
+static void coroutine_fn block_copy_inflight_req_end(BlockCopyState *s,
96
+ BlockCopyInFlightReq *req,
97
+ int ret)
98
+{
99
+ s->in_flight_bytes -= req->bytes;
100
+ if (ret < 0) {
101
+ bdrv_set_dirty_bitmap(s->copy_bitmap, req->offset, req->bytes);
102
+ }
103
QLIST_REMOVE(req, list);
104
qemu_co_queue_restart_all(&req->wait_queue);
105
}
106
@@ -XXX,XX +XXX,XX @@ int64_t block_copy_reset_unallocated(BlockCopyState *s,
107
return ret;
55
return ret;
108
}
56
}
109
57
110
-int coroutine_fn block_copy(BlockCopyState *s,
58
@@ -XXX,XX +XXX,XX @@ static int set_event_flag_handler(uint32_t conn_id, EventNotifier *notifier)
111
- int64_t offset, int64_t bytes,
59
int ret;
112
- bool *error_is_read)
60
EventFlagHandler *handler;
113
+/*
61
114
+ * block_copy_dirty_clusters
62
- qemu_mutex_lock(&handlers_mutex);
115
+ *
63
+ QEMU_LOCK_GUARD(&handlers_mutex);
116
+ * Copy dirty clusters in @offset/@bytes range.
64
QLIST_FOREACH(handler, &event_flag_handlers, link) {
117
+ * Returns 1 if dirty clusters found and successfully copied, 0 if no dirty
65
if (handler->conn_id == conn_id) {
118
+ * clusters found and -errno on failure.
66
if (notifier) {
119
+ */
67
@@ -XXX,XX +XXX,XX @@ static int set_event_flag_handler(uint32_t conn_id, EventNotifier *notifier)
120
+static int coroutine_fn block_copy_dirty_clusters(BlockCopyState *s,
68
g_free_rcu(handler, rcu);
121
+ int64_t offset, int64_t bytes,
69
ret = 0;
122
+ bool *error_is_read)
70
}
123
{
71
- goto unlock;
124
int ret = 0;
125
- BlockCopyInFlightReq req;
126
+ bool found_dirty = false;
127
128
/*
129
* block_copy() user is responsible for keeping source and target in same
130
@@ -XXX,XX +XXX,XX @@ int coroutine_fn block_copy(BlockCopyState *s,
131
assert(QEMU_IS_ALIGNED(offset, s->cluster_size));
132
assert(QEMU_IS_ALIGNED(bytes, s->cluster_size));
133
134
- block_copy_wait_inflight_reqs(s, offset, bytes);
135
- block_copy_inflight_req_begin(s, &req, offset, bytes);
136
-
137
while (bytes) {
138
+ BlockCopyInFlightReq req;
139
int64_t next_zero, cur_bytes, status_bytes;
140
141
if (!bdrv_dirty_bitmap_get(s->copy_bitmap, offset)) {
142
@@ -XXX,XX +XXX,XX @@ int coroutine_fn block_copy(BlockCopyState *s,
143
continue; /* already copied */
144
}
145
146
+ found_dirty = true;
147
+
148
cur_bytes = MIN(bytes, s->copy_size);
149
150
next_zero = bdrv_dirty_bitmap_next_zero(s->copy_bitmap, offset,
151
@@ -XXX,XX +XXX,XX @@ int coroutine_fn block_copy(BlockCopyState *s,
152
assert(next_zero < offset + cur_bytes); /* no need to do MIN() */
153
cur_bytes = next_zero - offset;
154
}
155
+ block_copy_inflight_req_begin(s, &req, offset, cur_bytes);
156
157
ret = block_copy_block_status(s, offset, cur_bytes, &status_bytes);
158
+ assert(ret >= 0); /* never fail */
159
+ cur_bytes = MIN(cur_bytes, status_bytes);
160
+ block_copy_inflight_req_shrink(s, &req, cur_bytes);
161
if (s->skip_unallocated && !(ret & BDRV_BLOCK_ALLOCATED)) {
162
- bdrv_reset_dirty_bitmap(s->copy_bitmap, offset, status_bytes);
163
+ block_copy_inflight_req_end(s, &req, 0);
164
progress_set_remaining(s->progress,
165
bdrv_get_dirty_count(s->copy_bitmap) +
166
s->in_flight_bytes);
167
@@ -XXX,XX +XXX,XX @@ int coroutine_fn block_copy(BlockCopyState *s,
168
continue;
169
}
170
171
- cur_bytes = MIN(cur_bytes, status_bytes);
172
-
173
trace_block_copy_process(s, offset);
174
175
- bdrv_reset_dirty_bitmap(s->copy_bitmap, offset, cur_bytes);
176
- s->in_flight_bytes += cur_bytes;
177
-
178
co_get_from_shres(s->mem, cur_bytes);
179
ret = block_copy_do_copy(s, offset, cur_bytes, ret & BDRV_BLOCK_ZERO,
180
error_is_read);
181
co_put_to_shres(s->mem, cur_bytes);
182
- s->in_flight_bytes -= cur_bytes;
183
+ block_copy_inflight_req_end(s, &req, ret);
184
if (ret < 0) {
185
- bdrv_set_dirty_bitmap(s->copy_bitmap, offset, cur_bytes);
186
- break;
187
+ return ret;
72
+ return ret;
188
}
73
}
189
190
progress_work_done(s->progress, cur_bytes);
191
@@ -XXX,XX +XXX,XX @@ int coroutine_fn block_copy(BlockCopyState *s,
192
bytes -= cur_bytes;
193
}
74
}
194
75
195
- block_copy_inflight_req_end(&req);
76
@@ -XXX,XX +XXX,XX @@ static int set_event_flag_handler(uint32_t conn_id, EventNotifier *notifier)
196
+ return found_dirty;
77
} else {
197
+}
78
ret = -ENOENT;
79
}
80
-unlock:
81
- qemu_mutex_unlock(&handlers_mutex);
198
+
82
+
199
+/*
200
+ * block_copy
201
+ *
202
+ * Copy requested region, accordingly to dirty bitmap.
203
+ * Collaborate with parallel block_copy requests: if they succeed it will help
204
+ * us. If they fail, we will retry not-copied regions. So, if we return error,
205
+ * it means that some I/O operation failed in context of _this_ block_copy call,
206
+ * not some parallel operation.
207
+ */
208
+int coroutine_fn block_copy(BlockCopyState *s, int64_t offset, int64_t bytes,
209
+ bool *error_is_read)
210
+{
211
+ int ret;
212
+
213
+ do {
214
+ ret = block_copy_dirty_clusters(s, offset, bytes, error_is_read);
215
+
216
+ if (ret == 0) {
217
+ ret = block_copy_wait_one(s, offset, bytes);
218
+ }
219
+
220
+ /*
221
+ * We retry in two cases:
222
+ * 1. Some progress done
223
+ * Something was copied, which means that there were yield points
224
+ * and some new dirty bits may have appeared (due to failed parallel
225
+ * block-copy requests).
226
+ * 2. We have waited for some intersecting block-copy request
227
+ * It may have failed and produced new dirty bits.
228
+ */
229
+ } while (ret > 0);
230
231
return ret;
83
return ret;
232
}
84
}
85
86
diff --git a/hw/rdma/rdma_backend.c b/hw/rdma/rdma_backend.c
87
index XXXXXXX..XXXXXXX 100644
88
--- a/hw/rdma/rdma_backend.c
89
+++ b/hw/rdma/rdma_backend.c
90
@@ -XXX,XX +XXX,XX @@ static int rdma_poll_cq(RdmaDeviceResources *rdma_dev_res, struct ibv_cq *ibcq)
91
struct ibv_wc wc[2];
92
RdmaProtectedGSList *cqe_ctx_list;
93
94
- qemu_mutex_lock(&rdma_dev_res->lock);
95
- do {
96
- ne = ibv_poll_cq(ibcq, ARRAY_SIZE(wc), wc);
97
+ WITH_QEMU_LOCK_GUARD(&rdma_dev_res->lock) {
98
+ do {
99
+ ne = ibv_poll_cq(ibcq, ARRAY_SIZE(wc), wc);
100
101
- trace_rdma_poll_cq(ne, ibcq);
102
+ trace_rdma_poll_cq(ne, ibcq);
103
104
- for (i = 0; i < ne; i++) {
105
- bctx = rdma_rm_get_cqe_ctx(rdma_dev_res, wc[i].wr_id);
106
- if (unlikely(!bctx)) {
107
- rdma_error_report("No matching ctx for req %"PRId64,
108
- wc[i].wr_id);
109
- continue;
110
- }
111
+ for (i = 0; i < ne; i++) {
112
+ bctx = rdma_rm_get_cqe_ctx(rdma_dev_res, wc[i].wr_id);
113
+ if (unlikely(!bctx)) {
114
+ rdma_error_report("No matching ctx for req %"PRId64,
115
+ wc[i].wr_id);
116
+ continue;
117
+ }
118
119
- comp_handler(bctx->up_ctx, &wc[i]);
120
+ comp_handler(bctx->up_ctx, &wc[i]);
121
122
- if (bctx->backend_qp) {
123
- cqe_ctx_list = &bctx->backend_qp->cqe_ctx_list;
124
- } else {
125
- cqe_ctx_list = &bctx->backend_srq->cqe_ctx_list;
126
- }
127
+ if (bctx->backend_qp) {
128
+ cqe_ctx_list = &bctx->backend_qp->cqe_ctx_list;
129
+ } else {
130
+ cqe_ctx_list = &bctx->backend_srq->cqe_ctx_list;
131
+ }
132
133
- rdma_protected_gslist_remove_int32(cqe_ctx_list, wc[i].wr_id);
134
- rdma_rm_dealloc_cqe_ctx(rdma_dev_res, wc[i].wr_id);
135
- g_free(bctx);
136
- }
137
- total_ne += ne;
138
- } while (ne > 0);
139
- atomic_sub(&rdma_dev_res->stats.missing_cqe, total_ne);
140
- qemu_mutex_unlock(&rdma_dev_res->lock);
141
+ rdma_protected_gslist_remove_int32(cqe_ctx_list, wc[i].wr_id);
142
+ rdma_rm_dealloc_cqe_ctx(rdma_dev_res, wc[i].wr_id);
143
+ g_free(bctx);
144
+ }
145
+ total_ne += ne;
146
+ } while (ne > 0);
147
+ atomic_sub(&rdma_dev_res->stats.missing_cqe, total_ne);
148
+ }
149
150
if (ne < 0) {
151
rdma_error_report("ibv_poll_cq fail, rc=%d, errno=%d", ne, errno);
152
diff --git a/hw/rdma/rdma_rm.c b/hw/rdma/rdma_rm.c
153
index XXXXXXX..XXXXXXX 100644
154
--- a/hw/rdma/rdma_rm.c
155
+++ b/hw/rdma/rdma_rm.c
156
@@ -XXX,XX +XXX,XX @@ static inline void rdma_res_tbl_dealloc(RdmaRmResTbl *tbl, uint32_t handle)
157
{
158
trace_rdma_res_tbl_dealloc(tbl->name, handle);
159
160
- qemu_mutex_lock(&tbl->lock);
161
+ QEMU_LOCK_GUARD(&tbl->lock);
162
163
if (handle < tbl->tbl_sz) {
164
clear_bit(handle, tbl->bitmap);
165
tbl->used--;
166
}
167
168
- qemu_mutex_unlock(&tbl->lock);
169
}
170
171
int rdma_rm_alloc_pd(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
233
--
172
--
234
2.24.1
173
2.25.3
235
174
236
diff view generated by jsdifflib