1
The following changes since commit 411ad78115ebeb3411cf4b7622784b93dfabe259:
1
The following changes since commit ba29883206d92a29ad5a466e679ccfc2ee6132ef:
2
2
3
Merge remote-tracking branch 'remotes/stefanberger/tags/pull-tpm-2017-12-15-1' into staging (2017-12-17 15:27:41 +0000)
3
Merge remote-tracking branch 'remotes/borntraeger/tags/s390x-20200310' into staging (2020-03-10 16:50:28 +0000)
4
4
5
are available in the Git repository at:
5
are available in the Git repository at:
6
6
7
git://github.com/stefanha/qemu.git tags/block-pull-request
7
https://github.com/XanClic/qemu.git tags/pull-block-2020-03-11
8
8
9
for you to fetch changes up to 585426c518958aa768564596091474be786aae51:
9
for you to fetch changes up to 397f4e9d83e9c0000905f0a988ba1aeda162571c:
10
10
11
qemu-iotests: add 203 savevm with IOThreads test (2017-12-18 13:12:53 +0000)
11
block/block-copy: hide structure definitions (2020-03-11 12:42:30 +0100)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block patches for the 5.0 softfreeze:
15
- qemu-img measure for LUKS
16
- Improve block-copy's performance by reducing inter-request
17
dependencies
18
- Make curl's detection of accept-ranges more robust
19
- Memleak fixes
20
- iotest fix
14
21
15
----------------------------------------------------------------
22
----------------------------------------------------------------
23
David Edmondson (2):
24
block/curl: HTTP header fields allow whitespace around values
25
block/curl: HTTP header field names are case insensitive
16
26
17
Mao Zhongyi (4):
27
Eric Blake (1):
18
hw/block/nvme: Convert to realize
28
iotests: Fix nonportable use of od --endian
19
hw/block: Fix the return type
20
hw/block: Use errp directly rather than local_err
21
dev-storage: Fix the unusual function name
22
29
23
Mark Kanda (2):
30
Pan Nengyuan (2):
24
virtio-blk: make queue size configurable
31
block/qcow2: do free crypto_opts in qcow2_close()
25
virtio-blk: reject configs with logical block size > physical block
32
qemu-img: free memory before re-assign
26
size
27
33
28
Paolo Bonzini (1):
34
Stefan Hajnoczi (4):
29
block: avoid recursive AioContext acquire in bdrv_inactivate_all()
35
luks: extract qcrypto_block_calculate_payload_offset()
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
30
39
31
Stefan Hajnoczi (16):
40
Vladimir Sementsov-Ogievskiy (10):
32
coroutine: simplify co_aio_sleep_ns() prototype
41
block/qcow2-threads: fix qcow2_decompress
33
qdev: drop unused #include "sysemu/iothread.h"
42
job: refactor progress to separate object
34
blockdev: hold AioContext for bdrv_unref() in
43
block/block-copy: fix progress calculation
35
external_snapshot_clean()
44
block/block-copy: specialcase first copy_range request
36
block: don't keep AioContext acquired after
45
block/block-copy: use block_status
37
external_snapshot_prepare()
46
block/block-copy: factor out find_conflicting_inflight_req
38
block: don't keep AioContext acquired after drive_backup_prepare()
47
block/block-copy: refactor interfaces to use bytes instead of end
39
block: don't keep AioContext acquired after blockdev_backup_prepare()
48
block/block-copy: rename start to offset in interfaces
40
block: don't keep AioContext acquired after
49
block/block-copy: reduce intersecting request lock
41
internal_snapshot_prepare()
50
block/block-copy: hide structure definitions
42
block: drop unused BlockDirtyBitmapState->aio_context field
43
iothread: add iothread_by_id() API
44
blockdev: add x-blockdev-set-iothread testing command
45
qemu-iotests: add 202 external snapshots IOThread test
46
docs: mark nested AioContext locking as a legacy API
47
blockdev: add x-blockdev-set-iothread force boolean
48
iotests: add VM.add_object()
49
iothread: fix iothread_stop() race condition
50
qemu-iotests: add 203 savevm with IOThreads test
51
51
52
docs/devel/multiple-iothreads.txt | 7 +-
52
block/backup-top.c | 6 +-
53
qapi/block-core.json | 40 ++++++
53
block/backup.c | 38 ++-
54
hw/block/dataplane/virtio-blk.h | 2 +-
54
block/block-copy.c | 405 ++++++++++++++++++++++++-------
55
include/hw/block/block.h | 4 +-
55
block/crypto.c | 62 +++++
56
include/hw/virtio/virtio-blk.h | 1 +
56
block/curl.c | 32 ++-
57
include/qemu/coroutine.h | 6 +-
57
block/qcow2-threads.c | 12 +-
58
include/sysemu/iothread.h | 4 +-
58
block/qcow2.c | 75 ++----
59
block.c | 14 ++-
59
block/trace-events | 1 +
60
block/null.c | 3 +-
60
blockjob.c | 16 +-
61
block/sheepdog.c | 3 +-
61
crypto/block.c | 36 +++
62
blockdev.c | 259 +++++++++++++++++++++++++++-----------
62
include/block/block-copy.h | 65 +----
63
hw/block/block.c | 15 ++-
63
include/crypto/block.h | 22 ++
64
hw/block/dataplane/virtio-blk.c | 12 +-
64
include/qemu/job.h | 11 +-
65
hw/block/fdc.c | 17 +--
65
include/qemu/progress_meter.h | 58 +++++
66
hw/block/nvme.c | 23 ++--
66
job-qmp.c | 4 +-
67
hw/block/virtio-blk.c | 35 ++++--
67
job.c | 6 +-
68
hw/core/qdev-properties-system.c | 1 -
68
qemu-img.c | 14 +-
69
hw/ide/qdev.c | 12 +-
69
tests/qemu-iotests/178 | 2 +-
70
hw/scsi/scsi-disk.c | 13 +-
70
tests/qemu-iotests/178.out.qcow2 | 8 +-
71
hw/usb/dev-storage.c | 29 ++---
71
tests/qemu-iotests/178.out.raw | 8 +-
72
iothread.c | 27 +++-
72
tests/qemu-iotests/288 | 93 +++++++
73
util/qemu-coroutine-sleep.c | 4 +-
73
tests/qemu-iotests/288.out | 30 +++
74
tests/qemu-iotests/202 | 95 ++++++++++++++
74
tests/qemu-iotests/common.rc | 22 +-
75
tests/qemu-iotests/202.out | 11 ++
75
tests/qemu-iotests/group | 1 +
76
tests/qemu-iotests/203 | 59 +++++++++
76
24 files changed, 749 insertions(+), 278 deletions(-)
77
tests/qemu-iotests/203.out | 6 +
77
create mode 100644 include/qemu/progress_meter.h
78
tests/qemu-iotests/group | 2 +
78
create mode 100755 tests/qemu-iotests/288
79
tests/qemu-iotests/iotests.py | 5 +
79
create mode 100644 tests/qemu-iotests/288.out
80
28 files changed, 532 insertions(+), 177 deletions(-)
81
create mode 100755 tests/qemu-iotests/202
82
create mode 100644 tests/qemu-iotests/202.out
83
create mode 100755 tests/qemu-iotests/203
84
create mode 100644 tests/qemu-iotests/203.out
85
80
86
--
81
--
87
2.14.3
82
2.24.1
88
83
89
84
diff view generated by jsdifflib
Deleted patch
1
The AioContext pointer argument to co_aio_sleep_ns() is only used for
2
the sleep timer. It does not affect where the caller coroutine is
3
resumed.
4
1
5
Due to changes to coroutine and AIO APIs it is now possible to drop the
6
AioContext pointer argument. This is safe to do since no caller has
7
specific requirements for which AioContext the timer must run in.
8
9
This patch drops the AioContext pointer argument and renames the
10
function to simplify the API.
11
12
Reported-by: Paolo Bonzini <pbonzini@redhat.com>
13
Reported-by: Eric Blake <eblake@redhat.com>
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
15
Reviewed-by: Eric Blake <eblake@redhat.com>
16
Message-id: 20171109102652.6360-1-stefanha@redhat.com
17
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
18
---
19
include/qemu/coroutine.h | 6 +-----
20
block/null.c | 3 +--
21
block/sheepdog.c | 3 +--
22
util/qemu-coroutine-sleep.c | 4 ++--
23
4 files changed, 5 insertions(+), 11 deletions(-)
24
25
diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h
26
index XXXXXXX..XXXXXXX 100644
27
--- a/include/qemu/coroutine.h
28
+++ b/include/qemu/coroutine.h
29
@@ -XXX,XX +XXX,XX @@ void qemu_co_rwlock_unlock(CoRwlock *lock);
30
31
/**
32
* Yield the coroutine for a given duration
33
- *
34
- * Behaves similarly to co_sleep_ns(), but the sleeping coroutine will be
35
- * resumed when using aio_poll().
36
*/
37
-void coroutine_fn co_aio_sleep_ns(AioContext *ctx, QEMUClockType type,
38
- int64_t ns);
39
+void coroutine_fn qemu_co_sleep_ns(QEMUClockType type, int64_t ns);
40
41
/**
42
* Yield until a file descriptor becomes readable
43
diff --git a/block/null.c b/block/null.c
44
index XXXXXXX..XXXXXXX 100644
45
--- a/block/null.c
46
+++ b/block/null.c
47
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int null_co_common(BlockDriverState *bs)
48
BDRVNullState *s = bs->opaque;
49
50
if (s->latency_ns) {
51
- co_aio_sleep_ns(bdrv_get_aio_context(bs), QEMU_CLOCK_REALTIME,
52
- s->latency_ns);
53
+ qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, s->latency_ns);
54
}
55
return 0;
56
}
57
diff --git a/block/sheepdog.c b/block/sheepdog.c
58
index XXXXXXX..XXXXXXX 100644
59
--- a/block/sheepdog.c
60
+++ b/block/sheepdog.c
61
@@ -XXX,XX +XXX,XX @@ static coroutine_fn void reconnect_to_sdog(void *opaque)
62
if (s->fd < 0) {
63
DPRINTF("Wait for connection to be established\n");
64
error_report_err(local_err);
65
- co_aio_sleep_ns(bdrv_get_aio_context(s->bs), QEMU_CLOCK_REALTIME,
66
- 1000000000ULL);
67
+ qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 1000000000ULL);
68
}
69
};
70
71
diff --git a/util/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c
72
index XXXXXXX..XXXXXXX 100644
73
--- a/util/qemu-coroutine-sleep.c
74
+++ b/util/qemu-coroutine-sleep.c
75
@@ -XXX,XX +XXX,XX @@ static void co_sleep_cb(void *opaque)
76
aio_co_wake(sleep_cb->co);
77
}
78
79
-void coroutine_fn co_aio_sleep_ns(AioContext *ctx, QEMUClockType type,
80
- int64_t ns)
81
+void coroutine_fn qemu_co_sleep_ns(QEMUClockType type, int64_t ns)
82
{
83
+ AioContext *ctx = qemu_get_current_aio_context();
84
CoSleepCB sleep_cb = {
85
.co = qemu_coroutine_self(),
86
};
87
--
88
2.14.3
89
90
diff view generated by jsdifflib
1
The dirty bitmap actions in qmp_transaction have not used AioContext
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
since the dirty bitmap locking discipline was introduced in commit
2
3
2119882c7eb7e2c612b24fc0c8d86f5887d6f1c3 ("block: introduce
3
The qcow2 .bdrv_measure() code calculates the crypto payload offset.
4
dirty_bitmap_mutex"). Remove the unused field.
4
This logic really belongs in crypto/block.c where it can be reused by
5
other image formats.
6
7
The "luks" block driver will need this same logic in order to implement
8
.bdrv_measure(), so extract the qcrypto_block_calculate_payload_offset()
9
function now.
5
10
6
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
12
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
13
Message-Id: <20200221112522.1497712-2-stefanha@redhat.com>
9
Message-id: 20171206144550.22295-7-stefanha@redhat.com
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
---
15
---
12
blockdev.c | 13 -------------
16
block/qcow2.c | 74 +++++++++++-------------------------------
13
1 file changed, 13 deletions(-)
17
crypto/block.c | 36 ++++++++++++++++++++
14
18
include/crypto/block.h | 22 +++++++++++++
15
diff --git a/blockdev.c b/blockdev.c
19
3 files changed, 77 insertions(+), 55 deletions(-)
20
21
diff --git a/block/qcow2.c b/block/qcow2.c
16
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
17
--- a/blockdev.c
23
--- a/block/qcow2.c
18
+++ b/blockdev.c
24
+++ b/block/qcow2.c
19
@@ -XXX,XX +XXX,XX @@ typedef struct BlockDirtyBitmapState {
25
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_flush_to_os(BlockDriverState *bs)
20
BlkActionState common;
26
return ret;
21
BdrvDirtyBitmap *bitmap;
22
BlockDriverState *bs;
23
- AioContext *aio_context;
24
HBitmap *backup;
25
bool prepared;
26
} BlockDirtyBitmapState;
27
@@ -XXX,XX +XXX,XX @@ static void block_dirty_bitmap_clear_prepare(BlkActionState *common,
28
}
29
30
bdrv_clear_dirty_bitmap(state->bitmap, &state->backup);
31
- /* AioContext is released in .clean() */
32
}
27
}
33
28
34
static void block_dirty_bitmap_clear_abort(BlkActionState *common)
29
-static ssize_t qcow2_measure_crypto_hdr_init_func(QCryptoBlock *block,
35
@@ -XXX,XX +XXX,XX @@ static void block_dirty_bitmap_clear_commit(BlkActionState *common)
30
- size_t headerlen, void *opaque, Error **errp)
36
hbitmap_free(state->backup);
31
-{
32
- size_t *headerlenp = opaque;
33
-
34
- /* Stash away the payload size */
35
- *headerlenp = headerlen;
36
- return 0;
37
-}
38
-
39
-static ssize_t qcow2_measure_crypto_hdr_write_func(QCryptoBlock *block,
40
- size_t offset, const uint8_t *buf, size_t buflen,
41
- void *opaque, Error **errp)
42
-{
43
- /* Discard the bytes, we're not actually writing to an image */
44
- return buflen;
45
-}
46
-
47
-/* Determine the number of bytes for the LUKS payload */
48
-static bool qcow2_measure_luks_headerlen(QemuOpts *opts, size_t *len,
49
- Error **errp)
50
-{
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
- }
68
-
69
- /* Fake LUKS creation in order to determine the payload size */
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
-
79
- qcrypto_block_free(crypto);
80
- return true;
81
-}
82
-
83
static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
84
Error **errp)
85
{
86
@@ -XXX,XX +XXX,XX @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
87
g_free(optstr);
88
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,
37
}
120
}
38
121
39
-static void block_dirty_bitmap_clear_clean(BlkActionState *common)
122
40
-{
123
+static ssize_t qcrypto_block_headerlen_hdr_init_func(QCryptoBlock *block,
41
- BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
124
+ size_t headerlen, void *opaque, Error **errp)
42
- common, common);
125
+{
43
-
126
+ size_t *headerlenp = opaque;
44
- if (state->aio_context) {
127
+
45
- aio_context_release(state->aio_context);
128
+ /* Stash away the payload size */
46
- }
129
+ *headerlenp = headerlen;
47
-}
130
+ return 0;
48
-
131
+}
49
static void abort_prepare(BlkActionState *common, Error **errp)
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)
50
{
161
{
51
error_setg(errp, "Transaction aborted using Abort action");
162
diff --git a/include/crypto/block.h b/include/crypto/block.h
52
@@ -XXX,XX +XXX,XX @@ static const BlkActionOps actions[] = {
163
index XXXXXXX..XXXXXXX 100644
53
.prepare = block_dirty_bitmap_clear_prepare,
164
--- a/include/crypto/block.h
54
.commit = block_dirty_bitmap_clear_commit,
165
+++ b/include/crypto/block.h
55
.abort = block_dirty_bitmap_clear_abort,
166
@@ -XXX,XX +XXX,XX @@ QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options,
56
- .clean = block_dirty_bitmap_clear_clean,
167
Error **errp);
57
}
168
58
};
169
59
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 */
60
--
201
--
61
2.14.3
202
2.24.1
62
203
63
204
diff view generated by jsdifflib
1
When a node is already associated with a BlockBackend the
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
x-blockdev-set-iothread command refuses to set the IOThread. This is to
3
prevent accidentally changing the IOThread when the nodes are in use.
4
2
5
When the nodes are created with -drive they automatically get a
3
Add qemu-img measure support in the "luks" block driver.
6
BlockBackend. In that case we know nothing is using them yet and it's
7
safe to set the IOThread. Add a force boolean to override the check.
8
4
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Reviewed-by: Eric Blake <eblake@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
11
Message-id: 20171207201320.19284-4-stefanha@redhat.com
7
Message-Id: <20200221112522.1497712-3-stefanha@redhat.com>
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
---
9
---
14
qapi/block-core.json | 6 +++++-
10
block/crypto.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++
15
blockdev.c | 11 ++++++-----
11
1 file changed, 62 insertions(+)
16
2 files changed, 11 insertions(+), 6 deletions(-)
17
12
18
diff --git a/qapi/block-core.json b/qapi/block-core.json
13
diff --git a/block/crypto.c b/block/crypto.c
19
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
20
--- a/qapi/block-core.json
15
--- a/block/crypto.c
21
+++ b/qapi/block-core.json
16
+++ b/block/crypto.c
22
@@ -XXX,XX +XXX,XX @@
17
@@ -XXX,XX +XXX,XX @@ static int64_t block_crypto_getlength(BlockDriverState *bs)
23
#
24
# @iothread: the name of the IOThread object or null for the main loop
25
#
26
+# @force: true if the node and its children should be moved when a BlockBackend
27
+# is already attached
28
+#
29
# Note: this command is experimental and intended for test cases that need
30
# control over IOThreads only.
31
#
32
@@ -XXX,XX +XXX,XX @@
33
##
34
{ 'command': 'x-blockdev-set-iothread',
35
'data' : { 'node-name': 'str',
36
- 'iothread': 'StrOrNull' } }
37
+ 'iothread': 'StrOrNull',
38
+ '*force': 'bool' } }
39
diff --git a/blockdev.c b/blockdev.c
40
index XXXXXXX..XXXXXXX 100644
41
--- a/blockdev.c
42
+++ b/blockdev.c
43
@@ -XXX,XX +XXX,XX @@ BlockJobInfoList *qmp_query_block_jobs(Error **errp)
44
}
18
}
45
19
46
void qmp_x_blockdev_set_iothread(const char *node_name, StrOrNull *iothread,
20
47
- Error **errp)
21
+static BlockMeasureInfo *block_crypto_measure(QemuOpts *opts,
48
+ bool has_force, bool force, Error **errp)
22
+ BlockDriverState *in_bs,
49
{
23
+ Error **errp)
50
AioContext *old_context;
24
+{
51
AioContext *new_context;
25
+ g_autoptr(QCryptoBlockCreateOptions) create_opts = NULL;
52
@@ -XXX,XX +XXX,XX @@ void qmp_x_blockdev_set_iothread(const char *node_name, StrOrNull *iothread,
26
+ Error *local_err = NULL;
53
return;
27
+ BlockMeasureInfo *info;
54
}
28
+ uint64_t size;
55
29
+ size_t luks_payload_size;
56
- /* If we want to allow more extreme test scenarios this guard could be
30
+ QDict *cryptoopts;
57
- * removed. For now it protects against accidents. */
31
+
58
- if (bdrv_has_blk(bs)) {
32
+ /*
59
- error_setg(errp, "Node %s is in use", node_name);
33
+ * Preallocation mode doesn't affect size requirements but we must consume
60
+ /* Protects against accidents. */
34
+ * the option.
61
+ if (!(has_force && force) && bdrv_has_blk(bs)) {
35
+ */
62
+ error_setg(errp, "Node %s is associated with a BlockBackend and could "
36
+ g_free(qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC));
63
+ "be in use (use force=true to override this check)",
37
+
64
+ node_name);
38
+ size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
65
return;
39
+
66
}
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,
67
92
68
--
93
--
69
2.14.3
94
2.24.1
70
95
71
96
diff view generated by jsdifflib
1
The VM.add_object() method can be used to add IOThreads or memory
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
backend objects.
2
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.
3
7
4
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
5
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Message-id: 20171207201320.19284-5-stefanha@redhat.com
10
Message-Id: <20200221112522.1497712-4-stefanha@redhat.com>
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
---
12
---
9
tests/qemu-iotests/iotests.py | 5 +++++
13
qemu-img.c | 6 ++----
10
1 file changed, 5 insertions(+)
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(-)
11
18
12
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
19
diff --git a/qemu-img.c b/qemu-img.c
13
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
14
--- a/tests/qemu-iotests/iotests.py
21
--- a/qemu-img.c
15
+++ b/tests/qemu-iotests/iotests.py
22
+++ b/qemu-img.c
16
@@ -XXX,XX +XXX,XX @@ class VM(qtest.QEMUQtestMachine):
23
@@ -XXX,XX +XXX,XX @@ static int img_measure(int argc, char **argv)
17
socket_scm_helper=socket_scm_helper)
24
filename = argv[optind];
18
self._num_drives = 0
25
}
19
26
20
+ def add_object(self, opts):
27
- if (!filename &&
21
+ self._args.append('-object')
28
- (object_opts || image_opts || fmt || snapshot_name || sn_opts)) {
22
+ self._args.append(opts)
29
- error_report("--object, --image-opts, -f, and -l "
23
+ return self
30
- "require a filename argument.");
24
+
31
+ if (!filename && (image_opts || fmt || snapshot_name || sn_opts)) {
25
def add_device(self, opts):
32
+ error_report("--image-opts, -f, and -l require a filename argument.");
26
self._args.append('-device')
33
goto out;
27
self._args.append(opts)
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'
28
--
87
--
29
2.14.3
88
2.24.1
30
89
31
90
diff view generated by jsdifflib
1
This test case will prevent future regressions with savevm and
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
IOThreads.
2
3
This test exercises the block/crypto.c "luks" block driver
4
.bdrv_measure() code.
3
5
4
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
6
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
5
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Message-id: 20171207201320.19284-7-stefanha@redhat.com
8
Message-Id: <20200221112522.1497712-5-stefanha@redhat.com>
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
[mreitz: Renamed test from 282 to 288]
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
---
11
---
9
tests/qemu-iotests/203 | 59 ++++++++++++++++++++++++++++++++++++++++++++++
12
tests/qemu-iotests/288 | 93 ++++++++++++++++++++++++++++++++++++++
10
tests/qemu-iotests/203.out | 6 +++++
13
tests/qemu-iotests/288.out | 30 ++++++++++++
11
tests/qemu-iotests/group | 1 +
14
tests/qemu-iotests/group | 1 +
12
3 files changed, 66 insertions(+)
15
3 files changed, 124 insertions(+)
13
create mode 100755 tests/qemu-iotests/203
16
create mode 100755 tests/qemu-iotests/288
14
create mode 100644 tests/qemu-iotests/203.out
17
create mode 100644 tests/qemu-iotests/288.out
15
18
16
diff --git a/tests/qemu-iotests/203 b/tests/qemu-iotests/203
19
diff --git a/tests/qemu-iotests/288 b/tests/qemu-iotests/288
17
new file mode 100755
20
new file mode 100755
18
index XXXXXXX..XXXXXXX
21
index XXXXXXX..XXXXXXX
19
--- /dev/null
22
--- /dev/null
20
+++ b/tests/qemu-iotests/203
23
+++ b/tests/qemu-iotests/288
21
@@ -XXX,XX +XXX,XX @@
24
@@ -XXX,XX +XXX,XX @@
22
+#!/usr/bin/env python
25
+#!/usr/bin/env bash
23
+#
26
+#
24
+# Copyright (C) 2017 Red Hat, Inc.
27
+# qemu-img measure tests for LUKS images
28
+#
29
+# Copyright (C) 2020 Red Hat, Inc.
25
+#
30
+#
26
+# This program is free software; you can redistribute it and/or modify
31
+# This program is free software; you can redistribute it and/or modify
27
+# it under the terms of the GNU General Public License as published by
32
+# it under the terms of the GNU General Public License as published by
28
+# the Free Software Foundation; either version 2 of the License, or
33
+# the Free Software Foundation; either version 2 of the License, or
29
+# (at your option) any later version.
34
+# (at your option) any later version.
...
...
34
+# GNU General Public License for more details.
39
+# GNU General Public License for more details.
35
+#
40
+#
36
+# You should have received a copy of the GNU General Public License
41
+# You should have received a copy of the GNU General Public License
37
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
42
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
38
+#
43
+#
39
+# Creator/Owner: Stefan Hajnoczi <stefanha@redhat.com>
40
+#
41
+# Check that QMP 'migrate' with multiple drives on a single IOThread completes
42
+# successfully. This particular command triggered a hang in the source QEMU
43
+# process due to recursive AioContext locking in bdrv_invalidate_all() and
44
+# BDRV_POLL_WHILE().
45
+
44
+
46
+import iotests
45
+# creator
46
+owner=stefanha@redhat.com
47
+
47
+
48
+iotests.verify_image_format(supported_fmts=['qcow2'])
48
+seq=`basename $0`
49
+iotests.verify_platform(['linux'])
49
+echo "QA output created by $seq"
50
+
50
+
51
+with iotests.FilePath('disk0.img') as disk0_img_path, \
51
+status=1 # failure is the default!
52
+ iotests.FilePath('disk1.img') as disk1_img_path, \
53
+ iotests.VM() as vm:
54
+
52
+
55
+ img_size = '10M'
53
+_cleanup()
56
+ iotests.qemu_img_pipe('create', '-f', iotests.imgfmt, disk0_img_path, img_size)
54
+{
57
+ iotests.qemu_img_pipe('create', '-f', iotests.imgfmt, disk1_img_path, img_size)
55
+ _cleanup_test_img
56
+ rm -f "$TEST_IMG.converted"
57
+}
58
+trap "_cleanup; exit \$status" 0 1 2 3 15
58
+
59
+
59
+ iotests.log('Launching VM...')
60
+# get standard environment, filters and checks
60
+ (vm.add_object('iothread,id=iothread0')
61
+. ./common.rc
61
+ .add_drive(disk0_img_path, 'node-name=drive0-node', interface='none')
62
+. ./common.filter
62
+ .add_drive(disk1_img_path, 'node-name=drive1-node', interface='none')
63
+. ./common.pattern
63
+ .launch())
64
+
64
+
65
+ iotests.log('Setting IOThreads...')
65
+_supported_fmt luks
66
+ iotests.log(vm.qmp('x-blockdev-set-iothread',
66
+_supported_proto file
67
+ node_name='drive0-node', iothread='iothread0',
67
+_supported_os Linux
68
+ force=True))
69
+ iotests.log(vm.qmp('x-blockdev-set-iothread',
70
+ node_name='drive1-node', iothread='iothread0',
71
+ force=True))
72
+
68
+
73
+ iotests.log('Starting migration...')
69
+SECRET=secret,id=sec0,data=passphrase
74
+ iotests.log(vm.qmp('migrate', uri='exec:cat >/dev/null'))
70
+
75
+ while True:
71
+echo "== measure 1G image file =="
76
+ vm.get_qmp_event(wait=60.0)
72
+echo
77
+ result = vm.qmp('query-migrate')
73
+
78
+ status = result.get('return', {}).get('status', None)
74
+$QEMU_IMG measure --object "$SECRET" \
79
+ if status == 'completed':
75
+     -O "$IMGFMT" \
80
+ break
76
+         -o key-secret=sec0,iter-time=10 \
81
diff --git a/tests/qemu-iotests/203.out b/tests/qemu-iotests/203.out
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
82
new file mode 100644
119
new file mode 100644
83
index XXXXXXX..XXXXXXX
120
index XXXXXXX..XXXXXXX
84
--- /dev/null
121
--- /dev/null
85
+++ b/tests/qemu-iotests/203.out
122
+++ b/tests/qemu-iotests/288.out
86
@@ -XXX,XX +XXX,XX @@
123
@@ -XXX,XX +XXX,XX @@
87
+Launching VM...
124
+QA output created by 288
88
+Setting IOThreads...
125
+== measure 1G image file ==
89
+{u'return': {}}
126
+
90
+{u'return': {}}
127
+required size: 1075810304
91
+Starting migration...
128
+fully allocated size: 1075810304
92
+{u'return': {}}
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
93
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
154
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
94
index XXXXXXX..XXXXXXX 100644
155
index XXXXXXX..XXXXXXX 100644
95
--- a/tests/qemu-iotests/group
156
--- a/tests/qemu-iotests/group
96
+++ b/tests/qemu-iotests/group
157
+++ b/tests/qemu-iotests/group
97
@@ -XXX,XX +XXX,XX @@
158
@@ -XXX,XX +XXX,XX @@
98
198 rw auto
159
283 auto quick
99
200 rw auto
160
284 rw
100
202 rw auto quick
161
286 rw quick
101
+203 rw auto
162
+288 quick
102
--
163
--
103
2.14.3
164
2.24.1
104
165
105
166
diff view generated by jsdifflib
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
From: David Edmondson <david.edmondson@oracle.com>
2
2
3
BDRV_POLL_WHILE() does not support recursive AioContext locking. It
3
RFC 7230 section 3.2 indicates that whitespace is permitted between
4
only releases the AioContext lock once regardless of how many times the
4
the field name and field value and after the field value.
5
caller has acquired it. This results in a hang since the IOThread does
6
not make progress while the AioContext is still locked.
7
5
8
The following steps trigger the hang:
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(-)
9
13
10
$ qemu-system-x86_64 -M accel=kvm -m 1G -cpu host \
14
diff --git a/block/curl.c b/block/curl.c
11
-object iothread,id=iothread0 \
12
-device virtio-scsi-pci,iothread=iothread0 \
13
-drive if=none,id=drive0,file=test.img,format=raw \
14
-device scsi-hd,drive=drive0 \
15
-drive if=none,id=drive1,file=test.img,format=raw \
16
-device scsi-hd,drive=drive1
17
$ qemu-system-x86_64 ...same options... \
18
-incoming tcp::1234
19
(qemu) migrate tcp:127.0.0.1:1234
20
...hang...
21
22
Tested-by: Stefan Hajnoczi <stefanha@redhat.com>
23
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
24
Reviewed-by: Eric Blake <eblake@redhat.com>
25
Message-id: 20171207201320.19284-2-stefanha@redhat.com
26
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
27
---
28
block.c | 14 +++++++++++---
29
1 file changed, 11 insertions(+), 3 deletions(-)
30
31
diff --git a/block.c b/block.c
32
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
33
--- a/block.c
16
--- a/block/curl.c
34
+++ b/block.c
17
+++ b/block/curl.c
35
@@ -XXX,XX +XXX,XX @@ int bdrv_inactivate_all(void)
18
@@ -XXX,XX +XXX,XX @@ static size_t curl_header_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
36
BdrvNextIterator it;
19
{
37
int ret = 0;
20
BDRVCURLState *s = opaque;
38
int pass;
21
size_t realsize = size * nmemb;
39
+ GSList *aio_ctxs = NULL, *ctx;
22
- const char *accept_line = "Accept-Ranges: bytes";
40
23
+ const char *header = (char *)ptr;
41
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
24
+ const char *end = header + realsize;
42
- aio_context_acquire(bdrv_get_aio_context(bs));
25
+ const char *accept_ranges = "Accept-Ranges:";
43
+ AioContext *aio_context = bdrv_get_aio_context(bs);
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) {
44
+
33
+
45
+ if (!g_slist_find(aio_ctxs, aio_context)) {
34
+ char *p = strchr(header, ':') + 1;
46
+ aio_ctxs = g_slist_prepend(aio_ctxs, aio_context);
35
+
47
+ aio_context_acquire(aio_context);
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
+ }
48
+ }
53
+ }
49
}
54
}
50
55
51
/* We do two passes of inactivation. The first pass calls to drivers'
56
return realsize;
52
@@ -XXX,XX +XXX,XX @@ int bdrv_inactivate_all(void)
53
}
54
55
out:
56
- for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
57
- aio_context_release(bdrv_get_aio_context(bs));
58
+ for (ctx = aio_ctxs; ctx != NULL; ctx = ctx->next) {
59
+ AioContext *aio_context = ctx->data;
60
+ aio_context_release(aio_context);
61
}
62
+ g_slist_free(aio_ctxs);
63
64
return ret;
65
}
66
--
57
--
67
2.14.3
58
2.24.1
68
59
69
60
diff view generated by jsdifflib
1
From: Mark Kanda <mark.kanda@oracle.com>
1
From: David Edmondson <david.edmondson@oracle.com>
2
2
3
virtio-blk logical block size should never be larger than physical block
3
RFC 7230 section 3.2 indicates that HTTP header field names are case
4
size because it doesn't make sense to have such configurations. QEMU doesn't
4
insensitive.
5
have a way to effectively express this condition; the best it can do is
6
report the physical block exponent as 0 - indicating the logical block size
7
equals the physical block size.
8
5
9
This is identical to commit 3da023b5827543ee4c022986ea2ad9d1274410b2
6
Signed-off-by: David Edmondson <david.edmondson@oracle.com>
10
but applied to virtio-blk (instead of virtio-scsi).
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(-)
11
13
12
Signed-off-by: Mark Kanda <mark.kanda@oracle.com>
14
diff --git a/block/curl.c b/block/curl.c
13
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
14
Reviewed-by: Ameya More <ameya.more@oracle.com>
15
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
16
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
17
Message-id: 773169891f9f2deb4cb7c4ef2655580dbe24c1d1.1513005190.git.mark.kanda@oracle.com
18
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
19
---
20
hw/block/virtio-blk.c | 7 +++++++
21
1 file changed, 7 insertions(+)
22
23
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
24
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
25
--- a/hw/block/virtio-blk.c
16
--- a/block/curl.c
26
+++ b/hw/block/virtio-blk.c
17
+++ b/block/curl.c
27
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
18
@@ -XXX,XX +XXX,XX @@ static size_t curl_header_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
28
19
size_t realsize = size * nmemb;
29
blkconf_blocksizes(&conf->conf);
20
const char *header = (char *)ptr;
30
21
const char *end = header + realsize;
31
+ if (conf->conf.logical_block_size >
22
- const char *accept_ranges = "Accept-Ranges:";
32
+ conf->conf.physical_block_size) {
23
+ const char *accept_ranges = "accept-ranges:";
33
+ error_setg(errp,
24
const char *bytes = "bytes";
34
+ "logical_block_size > physical_block_size not supported");
25
35
+ return;
26
if (realsize >= strlen(accept_ranges)
36
+ }
27
- && strncmp(header, accept_ranges, strlen(accept_ranges)) == 0) {
37
+
28
+ && g_ascii_strncasecmp(header, accept_ranges,
38
virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK,
29
+ strlen(accept_ranges)) == 0) {
39
sizeof(struct virtio_blk_config));
30
31
char *p = strchr(header, ':') + 1;
40
32
41
--
33
--
42
2.14.3
34
2.24.1
43
35
44
36
diff view generated by jsdifflib
1
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
1
From: Eric Blake <eblake@redhat.com>
2
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
2
3
Reviewed-by: Eric Blake <eblake@redhat.com>
3
Tests 261 and 272 fail on RHEL 7 with coreutils 8.22, since od
4
Message-id: 20171206144550.22295-6-stefanha@redhat.com
4
--endian was not added until coreutils 8.23. Fix this by manually
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
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>
6
---
13
---
7
blockdev.c | 47 +++++++++++++++++++++++++++++++----------------
14
tests/qemu-iotests/common.rc | 22 +++++++++++++++++-----
8
1 file changed, 31 insertions(+), 16 deletions(-)
15
1 file changed, 17 insertions(+), 5 deletions(-)
9
16
10
diff --git a/blockdev.c b/blockdev.c
17
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
11
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
12
--- a/blockdev.c
19
--- a/tests/qemu-iotests/common.rc
13
+++ b/blockdev.c
20
+++ b/tests/qemu-iotests/common.rc
14
@@ -XXX,XX +XXX,XX @@ struct BlkActionState {
21
@@ -XXX,XX +XXX,XX @@ poke_file()
15
typedef struct InternalSnapshotState {
22
# peek_file_le 'test.img' 512 2 => 65534
16
BlkActionState common;
23
peek_file_le()
17
BlockDriverState *bs;
24
{
18
- AioContext *aio_context;
25
- # Wrap in echo $() to strip spaces
19
QEMUSnapshotInfo sn;
26
- echo $(od -j"$2" -N"$3" --endian=little -An -vtu"$3" "$1")
20
bool created;
27
+ local val=0 shift=0 byte
21
} InternalSnapshotState;
22
@@ -XXX,XX +XXX,XX @@ static void internal_snapshot_prepare(BlkActionState *common,
23
qemu_timeval tv;
24
BlockdevSnapshotInternal *internal;
25
InternalSnapshotState *state;
26
+ AioContext *aio_context;
27
int ret1;
28
29
g_assert(common->action->type ==
30
@@ -XXX,XX +XXX,XX @@ static void internal_snapshot_prepare(BlkActionState *common,
31
return;
32
}
33
34
- /* AioContext is released in .clean() */
35
- state->aio_context = bdrv_get_aio_context(bs);
36
- aio_context_acquire(state->aio_context);
37
+ aio_context = bdrv_get_aio_context(bs);
38
+ aio_context_acquire(aio_context);
39
40
state->bs = bs;
41
+
28
+
42
+ /* Paired with .clean() */
29
+ # coreutils' od --endian is not portable, so manually assemble bytes.
43
bdrv_drained_begin(bs);
30
+ for byte in $(od -j"$2" -N"$3" -An -v -tu1 "$1"); do
44
31
+ val=$(( val | (byte << shift) ))
45
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT, errp)) {
32
+ shift=$((shift + 8))
46
- return;
33
+ done
47
+ goto out;
34
+ printf %llu $val
48
}
35
}
49
36
50
if (bdrv_is_read_only(bs)) {
37
# peek_file_be 'test.img' 512 2 => 65279
51
error_setg(errp, "Device '%s' is read only", device);
38
peek_file_be()
52
- return;
39
{
53
+ goto out;
40
- # Wrap in echo $() to strip spaces
54
}
41
- echo $(od -j"$2" -N"$3" --endian=big -An -vtu"$3" "$1")
55
42
+ local val=0 byte
56
if (!bdrv_can_snapshot(bs)) {
57
error_setg(errp, "Block format '%s' used by device '%s' "
58
"does not support internal snapshots",
59
bs->drv->format_name, device);
60
- return;
61
+ goto out;
62
}
63
64
if (!strlen(name)) {
65
error_setg(errp, "Name is empty");
66
- return;
67
+ goto out;
68
}
69
70
/* check whether a snapshot with name exist */
71
@@ -XXX,XX +XXX,XX @@ static void internal_snapshot_prepare(BlkActionState *common,
72
&local_err);
73
if (local_err) {
74
error_propagate(errp, local_err);
75
- return;
76
+ goto out;
77
} else if (ret) {
78
error_setg(errp,
79
"Snapshot with name '%s' already exists on device '%s'",
80
name, device);
81
- return;
82
+ goto out;
83
}
84
85
/* 3. take the snapshot */
86
@@ -XXX,XX +XXX,XX @@ static void internal_snapshot_prepare(BlkActionState *common,
87
error_setg_errno(errp, -ret1,
88
"Failed to create snapshot '%s' on device '%s'",
89
name, device);
90
- return;
91
+ goto out;
92
}
93
94
/* 4. succeed, mark a snapshot is created */
95
state->created = true;
96
+
43
+
97
+out:
44
+ # coreutils' od --endian is not portable, so manually assemble bytes.
98
+ aio_context_release(aio_context);
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
99
}
49
}
100
50
101
static void internal_snapshot_abort(BlkActionState *common)
51
-# peek_file_raw 'test.img' 512 2 => '\xff\xfe'
102
@@ -XXX,XX +XXX,XX @@ static void internal_snapshot_abort(BlkActionState *common)
52
+# peek_file_raw 'test.img' 512 2 => '\xff\xfe'. Do not use if the raw data
103
DO_UPCAST(InternalSnapshotState, common, common);
53
+# is likely to contain \0 or trailing \n.
104
BlockDriverState *bs = state->bs;
54
peek_file_raw()
105
QEMUSnapshotInfo *sn = &state->sn;
106
+ AioContext *aio_context;
107
Error *local_error = NULL;
108
109
if (!state->created) {
110
return;
111
}
112
113
+ aio_context = bdrv_get_aio_context(state->bs);
114
+ aio_context_acquire(aio_context);
115
+
116
if (bdrv_snapshot_delete(bs, sn->id_str, sn->name, &local_error) < 0) {
117
error_reportf_err(local_error,
118
"Failed to delete snapshot with id '%s' and "
119
@@ -XXX,XX +XXX,XX @@ static void internal_snapshot_abort(BlkActionState *common)
120
sn->id_str, sn->name,
121
bdrv_get_device_name(bs));
122
}
123
+
124
+ aio_context_release(aio_context);
125
}
126
127
static void internal_snapshot_clean(BlkActionState *common)
128
{
55
{
129
InternalSnapshotState *state = DO_UPCAST(InternalSnapshotState,
56
dd if="$1" bs=1 skip="$2" count="$3" status=none
130
common, common);
131
+ AioContext *aio_context;
132
133
- if (state->aio_context) {
134
- if (state->bs) {
135
- bdrv_drained_end(state->bs);
136
- }
137
- aio_context_release(state->aio_context);
138
+ if (!state->bs) {
139
+ return;
140
}
141
+
142
+ aio_context = bdrv_get_aio_context(state->bs);
143
+ aio_context_acquire(aio_context);
144
+
145
+ bdrv_drained_end(state->bs);
146
+
147
+ aio_context_release(aio_context);
148
}
149
150
/* external snapshot private data */
151
--
57
--
152
2.14.3
58
2.24.1
153
59
154
60
diff view generated by jsdifflib
1
See the patch for why nested AioContext locking is no longer allowed.
1
From: Pan Nengyuan <pannengyuan@huawei.com>
2
2
3
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
3
'crypto_opts' forgot to free in qcow2_close(), this patch fix the bellow leak stack:
4
Reviewed-by: Eric Blake <eblake@redhat.com>
4
5
Message-id: 20171207201320.19284-3-stefanha@redhat.com
5
Direct leak of 24 byte(s) in 1 object(s) allocated from:
6
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
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>
7
---
32
---
8
docs/devel/multiple-iothreads.txt | 7 ++++---
33
block/qcow2.c | 1 +
9
1 file changed, 4 insertions(+), 3 deletions(-)
34
1 file changed, 1 insertion(+)
10
35
11
diff --git a/docs/devel/multiple-iothreads.txt b/docs/devel/multiple-iothreads.txt
36
diff --git a/block/qcow2.c b/block/qcow2.c
12
index XXXXXXX..XXXXXXX 100644
37
index XXXXXXX..XXXXXXX 100644
13
--- a/docs/devel/multiple-iothreads.txt
38
--- a/block/qcow2.c
14
+++ b/docs/devel/multiple-iothreads.txt
39
+++ b/block/qcow2.c
15
@@ -XXX,XX +XXX,XX @@
40
@@ -XXX,XX +XXX,XX @@ static void qcow2_close(BlockDriverState *bs)
16
-Copyright (c) 2014 Red Hat Inc.
41
17
+Copyright (c) 2014-2017 Red Hat Inc.
42
qcrypto_block_free(s->crypto);
18
43
s->crypto = NULL;
19
This work is licensed under the terms of the GNU GPL, version 2 or later. See
44
+ qapi_free_QCryptoBlockOpenOptions(s->crypto_opts);
20
the COPYING file in the top-level directory.
45
21
@@ -XXX,XX +XXX,XX @@ aio_context_acquire()/aio_context_release() for mutual exclusion. Once the
46
g_free(s->unknown_header_fields);
22
context is acquired no other thread can access it or run event loop iterations
47
cleanup_unknown_header_ext(bs);
23
in this AioContext.
24
25
-aio_context_acquire()/aio_context_release() calls may be nested. This
26
-means you can call them if you're not sure whether #2 applies.
27
+Legacy code sometimes nests aio_context_acquire()/aio_context_release() calls.
28
+Do not use nesting anymore, it is incompatible with the BDRV_POLL_WHILE() macro
29
+used in the block layer and can lead to hangs.
30
31
There is currently no lock ordering rule if a thread needs to acquire multiple
32
AioContexts simultaneously. Therefore, it is only safe for code holding the
33
--
48
--
34
2.14.3
49
2.24.1
35
50
36
51
diff view generated by jsdifflib
1
From: Mark Kanda <mark.kanda@oracle.com>
1
From: Pan Nengyuan <pannengyuan@huawei.com>
2
2
3
Depending on the configuration, it can be beneficial to adjust the virtio-blk
3
collect_image_check() is called twice in img_check(), the filename/format will be alloced without free the original memory.
4
queue size to something other than the current default of 128. Add a new
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
property to make the queue size configurable.
6
5
7
Signed-off-by: Mark Kanda <mark.kanda@oracle.com>
6
Reported-by: Euler Robot <euler.robot@huawei.com>
8
Reviewed-by: Karl Heubaum <karl.heubaum@oracle.com>
7
Signed-off-by: Pan Nengyuan <pannengyuan@huawei.com>
9
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
8
Message-Id: <20200227012950.12256-3-pannengyuan@huawei.com>
10
Reviewed-by: Ameya More <ameya.more@oracle.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
Message-id: 52e6d742811f10dbd16e996e86cf375b9577c187.1513005190.git.mark.kanda@oracle.com
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
13
---
10
---
14
include/hw/virtio/virtio-blk.h | 1 +
11
qemu-img.c | 2 ++
15
hw/block/virtio-blk.c | 10 +++++++++-
12
1 file changed, 2 insertions(+)
16
2 files changed, 10 insertions(+), 1 deletion(-)
17
13
18
diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h
14
diff --git a/qemu-img.c b/qemu-img.c
19
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
20
--- a/include/hw/virtio/virtio-blk.h
16
--- a/qemu-img.c
21
+++ b/include/hw/virtio/virtio-blk.h
17
+++ b/qemu-img.c
22
@@ -XXX,XX +XXX,XX @@ struct VirtIOBlkConf
18
@@ -XXX,XX +XXX,XX @@ static int img_check(int argc, char **argv)
23
uint32_t config_wce;
19
check->corruptions_fixed);
24
uint32_t request_merging;
20
}
25
uint16_t num_queues;
21
26
+ uint16_t queue_size;
22
+ qapi_free_ImageCheck(check);
27
};
23
+ check = g_new0(ImageCheck, 1);
28
24
ret = collect_image_check(bs, check, filename, fmt, 0);
29
struct VirtIOBlockDataPlane;
25
30
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
26
check->leaks_fixed = leaks_fixed;
31
index XXXXXXX..XXXXXXX 100644
32
--- a/hw/block/virtio-blk.c
33
+++ b/hw/block/virtio-blk.c
34
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
35
error_setg(errp, "num-queues property must be larger than 0");
36
return;
37
}
38
+ if (!is_power_of_2(conf->queue_size) ||
39
+ conf->queue_size > VIRTQUEUE_MAX_SIZE) {
40
+ error_setg(errp, "invalid queue-size property (%" PRIu16 "), "
41
+ "must be a power of 2 (max %d)",
42
+ conf->queue_size, VIRTQUEUE_MAX_SIZE);
43
+ return;
44
+ }
45
46
blkconf_serial(&conf->conf, &conf->serial);
47
if (!blkconf_apply_backend_options(&conf->conf,
48
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
49
s->sector_mask = (s->conf.conf.logical_block_size / BDRV_SECTOR_SIZE) - 1;
50
51
for (i = 0; i < conf->num_queues; i++) {
52
- virtio_add_queue(vdev, 128, virtio_blk_handle_output);
53
+ virtio_add_queue(vdev, conf->queue_size, virtio_blk_handle_output);
54
}
55
if (!virtio_blk_data_plane_create(vdev, conf, &s->dataplane, errp)) {
56
virtio_cleanup(vdev);
57
@@ -XXX,XX +XXX,XX @@ static Property virtio_blk_properties[] = {
58
DEFINE_PROP_BIT("request-merging", VirtIOBlock, conf.request_merging, 0,
59
true),
60
DEFINE_PROP_UINT16("num-queues", VirtIOBlock, conf.num_queues, 1),
61
+ DEFINE_PROP_UINT16("queue-size", VirtIOBlock, conf.queue_size, 128),
62
DEFINE_PROP_LINK("iothread", VirtIOBlock, conf.iothread, TYPE_IOTHREAD,
63
IOThread *),
64
DEFINE_PROP_END_OF_LIST(),
65
--
27
--
66
2.14.3
28
2.24.1
67
29
68
30
diff view generated by jsdifflib
1
From: Mao Zhongyi <maozy.fnst@cn.fujitsu.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
Convert nvme_init() to realize and rename it to nvme_realize().
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.
4
6
5
Cc: John Snow <jsnow@redhat.com>
7
While being here, switch to errno return code, to be closer to
6
Cc: Keith Busch <keith.busch@intel.com>
8
qcow2_compress API (and usual expectations).
7
Cc: Kevin Wolf <kwolf@redhat.com>
8
Cc: Max Reitz <mreitz@redhat.com>
9
Cc: Markus Armbruster <armbru@redhat.com>
10
9
11
Signed-off-by: Mao Zhongyi <maozy.fnst@cn.fujitsu.com>
10
Revert condition in if to be more positive. Drop dead initialization of
12
Message-id: 2882e72d795e04cbe2120f569d551aef2467ac60.1511317952.git.maozy.fnst@cn.fujitsu.com
11
ret.
13
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
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>
14
---
20
---
15
hw/block/nvme.c | 18 ++++++++++--------
21
block/qcow2-threads.c | 12 +++++++-----
16
1 file changed, 10 insertions(+), 8 deletions(-)
22
1 file changed, 7 insertions(+), 5 deletions(-)
17
23
18
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
24
diff --git a/block/qcow2-threads.c b/block/qcow2-threads.c
19
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
20
--- a/hw/block/nvme.c
26
--- a/block/qcow2-threads.c
21
+++ b/hw/block/nvme.c
27
+++ b/block/qcow2-threads.c
22
@@ -XXX,XX +XXX,XX @@ static const MemoryRegionOps nvme_cmb_ops = {
28
@@ -XXX,XX +XXX,XX @@ static ssize_t qcow2_compress(void *dest, size_t dest_size,
23
},
29
* @src - source buffer, @src_size bytes
24
};
30
*
25
31
* Returns: 0 on success
26
-static int nvme_init(PCIDevice *pci_dev)
32
- * -1 on fail
27
+static void nvme_realize(PCIDevice *pci_dev, Error **errp)
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)
28
{
37
{
29
NvmeCtrl *n = NVME(pci_dev);
38
- int ret = 0;
30
NvmeIdCtrl *id = &n->id_ctrl;
39
+ int ret;
31
@@ -XXX,XX +XXX,XX @@ static int nvme_init(PCIDevice *pci_dev)
40
z_stream strm;
32
Error *local_err = NULL;
41
33
42
memset(&strm, 0, sizeof(strm));
34
if (!n->conf.blk) {
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) {
35
- return -1;
47
- return -1;
36
+ error_setg(errp, "drive property not set");
48
+ return -EIO;
37
+ return;
38
}
49
}
39
50
40
bs_size = blk_getlength(n->conf.blk);
51
ret = inflate(&strm, Z_FINISH);
41
if (bs_size < 0) {
52
- if ((ret != Z_STREAM_END && ret != Z_BUF_ERROR) || strm.avail_out != 0) {
42
- return -1;
53
+ if ((ret == Z_STREAM_END || ret == Z_BUF_ERROR) && strm.avail_out == 0) {
43
+ error_setg(errp, "could not get backing file size");
54
/*
44
+ return;
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;
45
}
63
}
46
64
47
blkconf_serial(&n->conf, &n->serial);
65
inflateEnd(&strm);
48
if (!n->serial) {
49
- return -1;
50
+ error_setg(errp, "serial property not set");
51
+ return;
52
}
53
blkconf_blocksizes(&n->conf);
54
blkconf_apply_backend_options(&n->conf, blk_is_read_only(n->conf.blk),
55
false, &local_err);
56
if (local_err) {
57
- error_report_err(local_err);
58
- return -1;
59
+ error_propagate(errp, local_err);
60
+ return;
61
}
62
63
pci_conf = pci_dev->config;
64
@@ -XXX,XX +XXX,XX @@ static int nvme_init(PCIDevice *pci_dev)
65
cpu_to_le64(n->ns_size >>
66
id_ns->lbaf[NVME_ID_NS_FLBAS_INDEX(ns->id_ns.flbas)].ds);
67
}
68
- return 0;
69
}
70
71
static void nvme_exit(PCIDevice *pci_dev)
72
@@ -XXX,XX +XXX,XX @@ static void nvme_class_init(ObjectClass *oc, void *data)
73
DeviceClass *dc = DEVICE_CLASS(oc);
74
PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc);
75
76
- pc->init = nvme_init;
77
+ pc->realize = nvme_realize;
78
pc->exit = nvme_exit;
79
pc->class_id = PCI_CLASS_STORAGE_EXPRESS;
80
pc->vendor_id = PCI_VENDOR_ID_INTEL;
81
--
66
--
82
2.14.3
67
2.24.1
83
68
84
69
diff view generated by jsdifflib
1
QMP 'transaction' blockdev-snapshot-sync with multiple disks in an
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
IOThread is an untested code path. Several bugs have been found in
2
3
connection with this command. This patch adds a test case to prevent
3
We need it in separate to pass to the block-copy object in the next
4
future regressions.
4
commit.
5
5
6
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
6
Cc: qemu-stable@nongnu.org
7
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Reviewed-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
9
Message-id: 20171206144550.22295-10-stefanha@redhat.com
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Message-Id: <20200311103004.7649-2-vsementsov@virtuozzo.com>
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
12
---
12
tests/qemu-iotests/202 | 95 ++++++++++++++++++++++++++++++++++++++++++++++
13
blockjob.c | 16 +++++-----
13
tests/qemu-iotests/202.out | 11 ++++++
14
include/qemu/job.h | 11 ++-----
14
tests/qemu-iotests/group | 1 +
15
include/qemu/progress_meter.h | 58 +++++++++++++++++++++++++++++++++++
15
3 files changed, 107 insertions(+)
16
job-qmp.c | 4 +--
16
create mode 100755 tests/qemu-iotests/202
17
job.c | 6 ++--
17
create mode 100644 tests/qemu-iotests/202.out
18
qemu-img.c | 6 ++--
18
19
6 files changed, 76 insertions(+), 25 deletions(-)
19
diff --git a/tests/qemu-iotests/202 b/tests/qemu-iotests/202
20
create mode 100644 include/qemu/progress_meter.h
20
new file mode 100755
21
21
index XXXXXXX..XXXXXXX
22
diff --git a/blockjob.c b/blockjob.c
22
--- /dev/null
23
index XXXXXXX..XXXXXXX 100644
23
+++ b/tests/qemu-iotests/202
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
24
@@ -XXX,XX +XXX,XX @@
74
@@ -XXX,XX +XXX,XX @@
25
+#!/usr/bin/env python
75
26
+#
76
#include "qapi/qapi-types-job.h"
27
+# Copyright (C) 2017 Red Hat, Inc.
77
#include "qemu/queue.h"
28
+#
78
+#include "qemu/progress_meter.h"
29
+# This program is free software; you can redistribute it and/or modify
79
#include "qemu/coroutine.h"
30
+# it under the terms of the GNU General Public License as published by
80
#include "block/aio.h"
31
+# the Free Software Foundation; either version 2 of the License, or
81
32
+# (at your option) any later version.
82
@@ -XXX,XX +XXX,XX @@ typedef struct Job {
33
+#
83
/** True if this job should automatically dismiss itself */
34
+# This program is distributed in the hope that it will be useful,
84
bool auto_dismiss;
35
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
85
36
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
86
- /**
37
+# GNU General Public License for more details.
87
- * Current progress. The unit is arbitrary as long as the ratio between
38
+#
88
- * progress_current and progress_total represents the estimated percentage
39
+# You should have received a copy of the GNU General Public License
89
- * of work already done.
40
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
90
- */
41
+#
91
- int64_t progress_current;
42
+# Creator/Owner: Stefan Hajnoczi <stefanha@redhat.com>
92
-
43
+#
93
- /** Estimated progress_current value at the completion of the job */
44
+# Check that QMP 'transaction' blockdev-snapshot-sync with multiple drives on a
94
- int64_t progress_total;
45
+# single IOThread completes successfully. This particular command triggered a
95
+ ProgressMeter progress;
46
+# hang due to recursive AioContext locking and BDRV_POLL_WHILE(). Protect
96
47
+# against regressions.
97
/**
48
+
98
* Return code from @run and/or @prepare callback(s).
49
+import iotests
99
diff --git a/include/qemu/progress_meter.h b/include/qemu/progress_meter.h
50
+
51
+iotests.verify_image_format(supported_fmts=['qcow2'])
52
+iotests.verify_platform(['linux'])
53
+
54
+with iotests.FilePath('disk0.img') as disk0_img_path, \
55
+ iotests.FilePath('disk1.img') as disk1_img_path, \
56
+ iotests.FilePath('disk0-snap.img') as disk0_snap_img_path, \
57
+ iotests.FilePath('disk1-snap.img') as disk1_snap_img_path, \
58
+ iotests.VM() as vm:
59
+
60
+ img_size = '10M'
61
+ iotests.qemu_img_pipe('create', '-f', iotests.imgfmt, disk0_img_path, img_size)
62
+ iotests.qemu_img_pipe('create', '-f', iotests.imgfmt, disk1_img_path, img_size)
63
+
64
+ iotests.log('Launching VM...')
65
+ vm.launch()
66
+
67
+ iotests.log('Adding IOThread...')
68
+ iotests.log(vm.qmp('object-add',
69
+ qom_type='iothread',
70
+ id='iothread0'))
71
+
72
+ iotests.log('Adding blockdevs...')
73
+ iotests.log(vm.qmp('blockdev-add',
74
+ driver=iotests.imgfmt,
75
+ node_name='disk0',
76
+ file={
77
+ 'driver': 'file',
78
+ 'filename': disk0_img_path,
79
+ }))
80
+ iotests.log(vm.qmp('blockdev-add',
81
+ driver=iotests.imgfmt,
82
+ node_name='disk1',
83
+ file={
84
+ 'driver': 'file',
85
+ 'filename': disk1_img_path,
86
+ }))
87
+
88
+ iotests.log('Setting iothread...')
89
+ iotests.log(vm.qmp('x-blockdev-set-iothread',
90
+ node_name='disk0',
91
+ iothread='iothread0'))
92
+ iotests.log(vm.qmp('x-blockdev-set-iothread',
93
+ node_name='disk1',
94
+ iothread='iothread0'))
95
+
96
+ iotests.log('Creating external snapshots...')
97
+ iotests.log(vm.qmp(
98
+ 'transaction',
99
+ actions=[
100
+ {
101
+ 'data': {
102
+ 'node-name': 'disk0',
103
+ 'snapshot-file': disk0_snap_img_path,
104
+ 'snapshot-node-name': 'disk0-snap',
105
+ 'mode': 'absolute-paths',
106
+ 'format': iotests.imgfmt,
107
+ },
108
+ 'type': 'blockdev-snapshot-sync'
109
+ }, {
110
+ 'data': {
111
+ 'node-name': 'disk1',
112
+ 'snapshot-file': disk1_snap_img_path,
113
+ 'snapshot-node-name': 'disk1-snap',
114
+ 'mode': 'absolute-paths',
115
+ 'format': iotests.imgfmt
116
+ },
117
+ 'type': 'blockdev-snapshot-sync'
118
+ }
119
+ ]))
120
diff --git a/tests/qemu-iotests/202.out b/tests/qemu-iotests/202.out
121
new file mode 100644
100
new file mode 100644
122
index XXXXXXX..XXXXXXX
101
index XXXXXXX..XXXXXXX
123
--- /dev/null
102
--- /dev/null
124
+++ b/tests/qemu-iotests/202.out
103
+++ b/include/qemu/progress_meter.h
125
@@ -XXX,XX +XXX,XX @@
104
@@ -XXX,XX +XXX,XX @@
126
+Launching VM...
105
+/*
127
+Adding IOThread...
106
+ * Helper functionality for some process progress tracking.
128
+{u'return': {}}
107
+ *
129
+Adding blockdevs...
108
+ * Copyright (c) 2011 IBM Corp.
130
+{u'return': {}}
109
+ * Copyright (c) 2012, 2018 Red Hat, Inc.
131
+{u'return': {}}
110
+ * Copyright (c) 2020 Virtuozzo International GmbH
132
+Setting iothread...
111
+ *
133
+{u'return': {}}
112
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
134
+{u'return': {}}
113
+ * of this software and associated documentation files (the "Software"), to deal
135
+Creating external snapshots...
114
+ * in the Software without restriction, including without limitation the rights
136
+{u'return': {}}
115
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
137
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
116
+ * copies of the Software, and to permit persons to whom the Software is
138
index XXXXXXX..XXXXXXX 100644
117
+ * furnished to do so, subject to the following conditions:
139
--- a/tests/qemu-iotests/group
118
+ *
140
+++ b/tests/qemu-iotests/group
119
+ * The above copyright notice and this permission notice shall be included in
141
@@ -XXX,XX +XXX,XX @@
120
+ * all copies or substantial portions of the Software.
142
197 rw auto quick
121
+ *
143
198 rw auto
122
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
144
200 rw auto
123
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
145
+202 rw auto quick
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));
146
--
220
--
147
2.14.3
221
2.24.1
148
222
149
223
diff view generated by jsdifflib
1
From: Mao Zhongyi <maozy.fnst@cn.fujitsu.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
The function name of usb_msd_{realize,unrealize}_*,
3
Assume we have two regions, A and B, and region B is in-flight now,
4
usb_msd_class_initfn_* are unusual. Rename it to
4
region A is not yet touched, but it is unallocated and should be
5
usb_msd_*_{realize,unrealize}, usb_msd_class_*_initfn.
5
skipped.
6
6
7
Cc: Gerd Hoffmann <kraxel@redhat.com>
7
Correspondingly, as progress we have
8
8
9
Signed-off-by: Mao Zhongyi <maozy.fnst@cn.fujitsu.com>
9
total = A + B
10
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
10
current = 0
11
Message-id: 11e6003433abce35f3f4970e1acc71ee92dbcf51.1511317952.git.maozy.fnst@cn.fujitsu.com
11
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
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>
13
---
43
---
14
hw/usb/dev-storage.c | 20 ++++++++++----------
44
block/backup.c | 13 ++-----------
15
1 file changed, 10 insertions(+), 10 deletions(-)
45
block/block-copy.c | 16 ++++++++++++----
46
include/block/block-copy.h | 15 +++++----------
47
3 files changed, 19 insertions(+), 25 deletions(-)
16
48
17
diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
49
diff --git a/block/backup.c b/block/backup.c
18
index XXXXXXX..XXXXXXX 100644
50
index XXXXXXX..XXXXXXX 100644
19
--- a/hw/usb/dev-storage.c
51
--- a/block/backup.c
20
+++ b/hw/usb/dev-storage.c
52
+++ b/block/backup.c
21
@@ -XXX,XX +XXX,XX @@ static void usb_msd_unrealize_storage(USBDevice *dev, Error **errp)
53
@@ -XXX,XX +XXX,XX @@ static void backup_progress_bytes_callback(int64_t bytes, void *opaque)
22
object_unref(OBJECT(&s->bus));
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);
23
}
66
}
24
67
25
-static void usb_msd_realize_storage(USBDevice *dev, Error **errp)
68
static int coroutine_fn backup_do_cow(BackupBlockJob *job,
26
+static void usb_msd_storage_realize(USBDevice *dev, Error **errp)
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)
27
{
94
{
28
MSDState *s = USB_STORAGE_DEV(dev);
95
s->progress_bytes_callback = progress_bytes_callback;
29
BlockBackend *blk = s->conf.blk;
96
- s->progress_reset_callback = progress_reset_callback;
30
@@ -XXX,XX +XXX,XX @@ static void usb_msd_realize_storage(USBDevice *dev, Error **errp)
97
s->progress_opaque = progress_opaque;
31
s->scsi_dev = scsi_dev;
32
}
98
}
33
99
34
-static void usb_msd_unrealize_bot(USBDevice *dev, Error **errp)
100
+void block_copy_set_progress_meter(BlockCopyState *s, ProgressMeter *pm)
35
+static void usb_msd_bot_unrealize(USBDevice *dev, Error **errp)
101
+{
36
{
102
+ s->progress = pm;
37
MSDState *s = USB_STORAGE_DEV(dev);
103
+}
38
104
+
39
object_unref(OBJECT(&s->bus));
105
/*
40
}
106
* block_copy_do_copy
41
107
*
42
-static void usb_msd_realize_bot(USBDevice *dev, Error **errp)
108
@@ -XXX,XX +XXX,XX @@ int64_t block_copy_reset_unallocated(BlockCopyState *s,
43
+static void usb_msd_bot_realize(USBDevice *dev, Error **errp)
109
44
{
110
if (!ret) {
45
MSDState *s = USB_STORAGE_DEV(dev);
111
bdrv_reset_dirty_bitmap(s->copy_bitmap, offset, bytes);
46
DeviceState *d = DEVICE(dev);
112
- s->progress_reset_callback(s->progress_opaque);
47
@@ -XXX,XX +XXX,XX @@ static void usb_msd_class_initfn_common(ObjectClass *klass, void *data)
113
+ progress_set_remaining(s->progress,
48
dc->vmsd = &vmstate_usb_msd;
114
+ bdrv_get_dirty_count(s->copy_bitmap) +
49
}
115
+ s->in_flight_bytes);
50
116
}
51
-static void usb_msd_class_initfn_storage(ObjectClass *klass, void *data)
117
52
+static void usb_msd_class_storage_initfn(ObjectClass *klass, void *data)
118
*count = bytes;
53
{
119
@@ -XXX,XX +XXX,XX @@ int coroutine_fn block_copy(BlockCopyState *s,
54
DeviceClass *dc = DEVICE_CLASS(klass);
120
trace_block_copy_process(s, start);
55
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
121
56
122
bdrv_reset_dirty_bitmap(s->copy_bitmap, start, chunk_end - start);
57
- uc->realize = usb_msd_realize_storage;
123
+ s->in_flight_bytes += chunk_end - start;
58
+ uc->realize = usb_msd_storage_realize;
124
59
uc->unrealize = usb_msd_unrealize_storage;
125
co_get_from_shres(s->mem, chunk_end - start);
60
dc->props = msd_properties;
126
ret = block_copy_do_copy(s, start, chunk_end, error_is_read);
61
}
127
co_put_to_shres(s->mem, chunk_end - start);
62
@@ -XXX,XX +XXX,XX @@ static void usb_msd_instance_init(Object *obj)
128
+ s->in_flight_bytes -= chunk_end - start;
63
object_property_set_int(obj, -1, "bootindex", NULL);
129
if (ret < 0) {
64
}
130
bdrv_set_dirty_bitmap(s->copy_bitmap, start, chunk_end - start);
65
131
break;
66
-static void usb_msd_class_initfn_bot(ObjectClass *klass, void *data)
132
}
67
+static void usb_msd_class_bot_initfn(ObjectClass *klass, void *data)
133
68
{
134
+ progress_work_done(s->progress, chunk_end - start);
69
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
135
s->progress_bytes_callback(chunk_end - start, s->progress_opaque);
70
136
start = chunk_end;
71
- uc->realize = usb_msd_realize_bot;
137
ret = 0;
72
- uc->unrealize = usb_msd_unrealize_bot;
138
diff --git a/include/block/block-copy.h b/include/block/block-copy.h
73
+ uc->realize = usb_msd_bot_realize;
139
index XXXXXXX..XXXXXXX 100644
74
+ uc->unrealize = usb_msd_bot_unrealize;
140
--- a/include/block/block-copy.h
75
uc->attached_settable = true;
141
+++ b/include/block/block-copy.h
76
}
142
@@ -XXX,XX +XXX,XX @@ typedef struct BlockCopyInFlightReq {
77
143
} BlockCopyInFlightReq;
78
static const TypeInfo msd_info = {
144
79
.name = "usb-storage",
145
typedef void (*ProgressBytesCallbackFunc)(int64_t bytes, void *opaque);
80
.parent = TYPE_USB_STORAGE,
146
-typedef void (*ProgressResetCallbackFunc)(void *opaque);
81
- .class_init = usb_msd_class_initfn_storage,
147
typedef struct BlockCopyState {
82
+ .class_init = usb_msd_class_storage_initfn,
148
/*
83
.instance_init = usb_msd_instance_init,
149
* BdrvChild objects are not owned or managed by block-copy. They are
84
};
150
@@ -XXX,XX +XXX,XX @@ typedef struct BlockCopyState {
85
151
BdrvChild *source;
86
static const TypeInfo bot_info = {
152
BdrvChild *target;
87
.name = "usb-bot",
153
BdrvDirtyBitmap *copy_bitmap;
88
.parent = TYPE_USB_STORAGE,
154
+ int64_t in_flight_bytes;
89
- .class_init = usb_msd_class_initfn_bot,
155
int64_t cluster_size;
90
+ .class_init = usb_msd_class_bot_initfn,
156
bool use_copy_range;
91
};
157
int64_t copy_size;
92
158
@@ -XXX,XX +XXX,XX @@ typedef struct BlockCopyState {
93
static void usb_msd_register_types(void)
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,
94
--
191
--
95
2.14.3
192
2.24.1
96
193
97
194
diff view generated by jsdifflib
1
It is not necessary to hold AioContext across transactions anymore since
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
bdrv_drained_begin/end() is used to keep the nodes quiesced. In fact,
3
using the AioContext lock for this purpose was always buggy.
4
2
5
This patch reduces the scope of AioContext locked regions. This is not
3
In block_copy_do_copy we fallback to read+write if copy_range failed.
6
just a cleanup but also fixes hangs that occur in BDRV_POLL_WHILE()
4
In this case copy_size is larger than defined for buffered IO, and
7
because it is unware of recursive locking and does not release the
5
there is corresponding commit. Still, backup copies data cluster by
8
AioContext the necessary number of times to allow progress to be made.
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
9
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Further patch will move backup to use block_copy directly, than for
11
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
11
cases where copy_range is not supported, first request will be
12
Reviewed-by: Eric Blake <eblake@redhat.com>
12
oversized in each backup. It's not good, let's change it now.
13
Message-id: 20171206144550.22295-3-stefanha@redhat.com
13
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
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>
15
---
22
---
16
blockdev.c | 71 ++++++++++++++++++++++++++++++++++++++++++--------------------
23
block/block-copy.c | 41 +++++++++++++++++++++++++++++++----------
17
1 file changed, 48 insertions(+), 23 deletions(-)
24
1 file changed, 31 insertions(+), 10 deletions(-)
18
25
19
diff --git a/blockdev.c b/blockdev.c
26
diff --git a/block/block-copy.c b/block/block-copy.c
20
index XXXXXXX..XXXXXXX 100644
27
index XXXXXXX..XXXXXXX 100644
21
--- a/blockdev.c
28
--- a/block/block-copy.c
22
+++ b/blockdev.c
29
+++ b/block/block-copy.c
23
@@ -XXX,XX +XXX,XX @@ typedef struct ExternalSnapshotState {
30
@@ -XXX,XX +XXX,XX @@ void block_copy_state_free(BlockCopyState *s)
24
BlkActionState common;
31
g_free(s);
25
BlockDriverState *old_bs;
32
}
26
BlockDriverState *new_bs;
33
27
- AioContext *aio_context;
34
+static uint32_t block_copy_max_transfer(BdrvChild *source, BdrvChild *target)
28
bool overlay_appended;
35
+{
29
} ExternalSnapshotState;
36
+ return MIN_NON_ZERO(INT_MAX,
30
37
+ MIN_NON_ZERO(source->bs->bl.max_transfer,
31
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_prepare(BlkActionState *common,
38
+ target->bs->bl.max_transfer));
32
ExternalSnapshotState *state =
39
+}
33
DO_UPCAST(ExternalSnapshotState, common, common);
40
+
34
TransactionAction *action = common->action;
41
BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
35
+ AioContext *aio_context;
42
int64_t cluster_size,
36
43
BdrvRequestFlags write_flags, Error **errp)
37
/* 'blockdev-snapshot' and 'blockdev-snapshot-sync' have similar
44
{
38
* purpose but a different set of parameters */
45
BlockCopyState *s;
39
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_prepare(BlkActionState *common,
46
BdrvDirtyBitmap *copy_bitmap;
40
return;
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);
41
}
76
}
42
77
43
- /* Acquire AioContext now so any threads operating on old_bs stop */
78
QLIST_INIT(&s->inflight_reqs);
44
- state->aio_context = bdrv_get_aio_context(state->old_bs);
79
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn block_copy_do_copy(BlockCopyState *s,
45
- aio_context_acquire(state->aio_context);
80
s->copy_size = MAX(s->cluster_size, BLOCK_COPY_MAX_BUFFER);
46
+ aio_context = bdrv_get_aio_context(state->old_bs);
81
/* Fallback to read+write with allocated buffer */
47
+ aio_context_acquire(aio_context);
82
} else {
48
+
83
+ if (s->use_copy_range) {
49
+ /* Paired with .clean() */
84
+ /*
50
bdrv_drained_begin(state->old_bs);
85
+ * Successful copy-range. Now increase copy_size. copy_range
51
86
+ * does not respect max_transfer (it's a TODO), so we factor
52
if (!bdrv_is_inserted(state->old_bs)) {
87
+ * that in here.
53
error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
88
+ *
54
- return;
89
+ * Note: we double-check s->use_copy_range for the case when
55
+ goto out;
90
+ * parallel block-copy request unsets it during previous
56
}
91
+ * bdrv_co_copy_range call.
57
92
+ */
58
if (bdrv_op_is_blocked(state->old_bs,
93
+ s->copy_size =
59
BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT, errp)) {
94
+ MIN(MAX(s->cluster_size, BLOCK_COPY_MAX_COPY_RANGE),
60
- return;
95
+ QEMU_ALIGN_DOWN(block_copy_max_transfer(s->source,
61
+ goto out;
96
+ s->target),
62
}
97
+ s->cluster_size));
63
98
+ }
64
if (!bdrv_is_read_only(state->old_bs)) {
99
goto out;
65
if (bdrv_flush(state->old_bs)) {
66
error_setg(errp, QERR_IO_ERROR);
67
- return;
68
+ goto out;
69
}
100
}
70
}
101
}
71
102
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn block_copy_do_copy(BlockCopyState *s,
72
if (!bdrv_is_first_non_filter(state->old_bs)) {
103
/*
73
error_setg(errp, QERR_FEATURE_DISABLED, "snapshot");
104
* In case of failed copy_range request above, we may proceed with buffered
74
- return;
105
* request larger than BLOCK_COPY_MAX_BUFFER. Still, further requests will
75
+ goto out;
106
- * be properly limited, so don't care too much.
76
}
107
+ * be properly limited, so don't care too much. Moreover the most likely
77
108
+ * case (copy_range is unsupported for the configuration, so the very first
78
if (action->type == TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC) {
109
+ * copy_range request fails) is handled by setting large copy_size only
79
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_prepare(BlkActionState *common,
110
+ * after first successful copy_range.
80
111
*/
81
if (node_name && !snapshot_node_name) {
112
82
error_setg(errp, "New snapshot node name missing");
113
bounce_buffer = qemu_blockalign(s->source->bs, nbytes);
83
- return;
84
+ goto out;
85
}
86
87
if (snapshot_node_name &&
88
bdrv_lookup_bs(snapshot_node_name, snapshot_node_name, NULL)) {
89
error_setg(errp, "New snapshot node name already in use");
90
- return;
91
+ goto out;
92
}
93
94
flags = state->old_bs->open_flags;
95
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_prepare(BlkActionState *common,
96
int64_t size = bdrv_getlength(state->old_bs);
97
if (size < 0) {
98
error_setg_errno(errp, -size, "bdrv_getlength failed");
99
- return;
100
+ goto out;
101
}
102
bdrv_img_create(new_image_file, format,
103
state->old_bs->filename,
104
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_prepare(BlkActionState *common,
105
NULL, size, flags, false, &local_err);
106
if (local_err) {
107
error_propagate(errp, local_err);
108
- return;
109
+ goto out;
110
}
111
}
112
113
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_prepare(BlkActionState *common,
114
errp);
115
/* We will manually add the backing_hd field to the bs later */
116
if (!state->new_bs) {
117
- return;
118
+ goto out;
119
}
120
121
if (bdrv_has_blk(state->new_bs)) {
122
error_setg(errp, "The snapshot is already in use");
123
- return;
124
+ goto out;
125
}
126
127
if (bdrv_op_is_blocked(state->new_bs, BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT,
128
errp)) {
129
- return;
130
+ goto out;
131
}
132
133
if (state->new_bs->backing != NULL) {
134
error_setg(errp, "The snapshot already has a backing image");
135
- return;
136
+ goto out;
137
}
138
139
if (!state->new_bs->drv->supports_backing) {
140
error_setg(errp, "The snapshot does not support backing images");
141
- return;
142
+ goto out;
143
}
144
145
- bdrv_set_aio_context(state->new_bs, state->aio_context);
146
+ bdrv_set_aio_context(state->new_bs, aio_context);
147
148
/* This removes our old bs and adds the new bs. This is an operation that
149
* can fail, so we need to do it in .prepare; undoing it for abort is
150
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_prepare(BlkActionState *common,
151
bdrv_append(state->new_bs, state->old_bs, &local_err);
152
if (local_err) {
153
error_propagate(errp, local_err);
154
- return;
155
+ goto out;
156
}
157
state->overlay_appended = true;
158
+
159
+out:
160
+ aio_context_release(aio_context);
161
}
162
163
static void external_snapshot_commit(BlkActionState *common)
164
{
165
ExternalSnapshotState *state =
166
DO_UPCAST(ExternalSnapshotState, common, common);
167
+ AioContext *aio_context;
168
+
169
+ aio_context = bdrv_get_aio_context(state->old_bs);
170
+ aio_context_acquire(aio_context);
171
172
/* We don't need (or want) to use the transactional
173
* bdrv_reopen_multiple() across all the entries at once, because we
174
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_commit(BlkActionState *common)
175
bdrv_reopen(state->old_bs, state->old_bs->open_flags & ~BDRV_O_RDWR,
176
NULL);
177
}
178
+
179
+ aio_context_release(aio_context);
180
}
181
182
static void external_snapshot_abort(BlkActionState *common)
183
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_abort(BlkActionState *common)
184
DO_UPCAST(ExternalSnapshotState, common, common);
185
if (state->new_bs) {
186
if (state->overlay_appended) {
187
+ AioContext *aio_context;
188
+
189
+ aio_context = bdrv_get_aio_context(state->old_bs);
190
+ aio_context_acquire(aio_context);
191
+
192
bdrv_ref(state->old_bs); /* we can't let bdrv_set_backind_hd()
193
close state->old_bs; we need it */
194
bdrv_set_backing_hd(state->new_bs, NULL, &error_abort);
195
bdrv_replace_node(state->new_bs, state->old_bs, &error_abort);
196
bdrv_unref(state->old_bs); /* bdrv_replace_node() ref'ed old_bs */
197
+
198
+ aio_context_release(aio_context);
199
}
200
}
201
}
202
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_clean(BlkActionState *common)
203
{
204
ExternalSnapshotState *state =
205
DO_UPCAST(ExternalSnapshotState, common, common);
206
- if (state->aio_context) {
207
- bdrv_drained_end(state->old_bs);
208
- bdrv_unref(state->new_bs);
209
- aio_context_release(state->aio_context);
210
+ AioContext *aio_context;
211
+
212
+ if (!state->old_bs) {
213
+ return;
214
}
215
+
216
+ aio_context = bdrv_get_aio_context(state->old_bs);
217
+ aio_context_acquire(aio_context);
218
+
219
+ bdrv_drained_end(state->old_bs);
220
+ bdrv_unref(state->new_bs);
221
+
222
+ aio_context_release(aio_context);
223
}
224
225
typedef struct DriveBackupState {
226
--
114
--
227
2.14.3
115
2.24.1
228
116
229
117
diff view generated by jsdifflib
1
Currently there is no easy way for iotests to ensure that a BDS is bound
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
to a particular IOThread. Normally the virtio-blk device calls
3
blk_set_aio_context() when dataplane is enabled during guest driver
4
initialization. This never happens in iotests since -machine
5
accel=qtest means there is no guest activity (including device driver
6
initialization).
7
2
8
This patch adds a QMP command to explicitly assign IOThreads in test
3
Use bdrv_block_status_above to chose effective chunk size and to handle
9
cases. See qapi/block-core.json for a description of the command.
4
zeroes effectively.
10
5
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
6
This substitutes checking for just being allocated or not, and drops
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
7
old code path for it. Assistance by backup job is dropped too, as
13
Reviewed-by: Eric Blake <eblake@redhat.com>
8
caching block-status information is more difficult than just caching
14
Message-id: 20171206144550.22295-9-stefanha@redhat.com
9
is-allocated information in our dirty bitmap, and backup job is not
15
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
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>
16
---
17
---
17
qapi/block-core.json | 36 ++++++++++++++++++++++++++++++++++++
18
block/block-copy.c | 73 +++++++++++++++++++++++++++++++++++++---------
18
blockdev.c | 41 +++++++++++++++++++++++++++++++++++++++++
19
block/trace-events | 1 +
19
2 files changed, 77 insertions(+)
20
2 files changed, 61 insertions(+), 13 deletions(-)
20
21
21
diff --git a/qapi/block-core.json b/qapi/block-core.json
22
diff --git a/block/block-copy.c b/block/block-copy.c
22
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
23
--- a/qapi/block-core.json
24
--- a/block/block-copy.c
24
+++ b/qapi/block-core.json
25
+++ b/block/block-copy.c
25
@@ -XXX,XX +XXX,XX @@
26
@@ -XXX,XX +XXX,XX @@ void block_copy_set_progress_meter(BlockCopyState *s, ProgressMeter *pm)
26
'data' : { 'parent': 'str',
27
*/
27
'*child': 'str',
28
static int coroutine_fn block_copy_do_copy(BlockCopyState *s,
28
'*node': 'str' } }
29
int64_t start, int64_t end,
29
+
30
- bool *error_is_read)
30
+##
31
+ bool zeroes, bool *error_is_read)
31
+# @x-blockdev-set-iothread:
32
{
32
+#
33
int ret;
33
+# Move @node and its children into the @iothread. If @iothread is null then
34
int nbytes = MIN(end, s->len) - start;
34
+# move @node and its children into the main loop.
35
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn block_copy_do_copy(BlockCopyState *s,
35
+#
36
assert(QEMU_IS_ALIGNED(end, s->cluster_size));
36
+# The node must not be attached to a BlockBackend.
37
assert(end < s->len || end == QEMU_ALIGN_UP(s->len, s->cluster_size));
37
+#
38
38
+# @node-name: the name of the block driver node
39
+ if (zeroes) {
39
+#
40
+ ret = bdrv_co_pwrite_zeroes(s->target, start, nbytes, s->write_flags &
40
+# @iothread: the name of the IOThread object or null for the main loop
41
+ ~BDRV_REQ_WRITE_COMPRESSED);
41
+#
42
+ if (ret < 0) {
42
+# Note: this command is experimental and intended for test cases that need
43
+ trace_block_copy_write_zeroes_fail(s, start, ret);
43
+# control over IOThreads only.
44
+ if (error_is_read) {
44
+#
45
+ *error_is_read = false;
45
+# Since: 2.12
46
+ }
46
+#
47
+ }
47
+# Example:
48
+ return ret;
48
+#
49
+# 1. Move a node into an IOThread
50
+# -> { "execute": "x-blockdev-set-iothread",
51
+# "arguments": { "node-name": "disk1",
52
+# "iothread": "iothread0" } }
53
+# <- { "return": {} }
54
+#
55
+# 2. Move a node into the main loop
56
+# -> { "execute": "x-blockdev-set-iothread",
57
+# "arguments": { "node-name": "disk1",
58
+# "iothread": null } }
59
+# <- { "return": {} }
60
+#
61
+##
62
+{ 'command': 'x-blockdev-set-iothread',
63
+ 'data' : { 'node-name': 'str',
64
+ 'iothread': 'StrOrNull' } }
65
diff --git a/blockdev.c b/blockdev.c
66
index XXXXXXX..XXXXXXX 100644
67
--- a/blockdev.c
68
+++ b/blockdev.c
69
@@ -XXX,XX +XXX,XX @@
70
#include "qapi/qmp/qerror.h"
71
#include "qapi/qobject-output-visitor.h"
72
#include "sysemu/sysemu.h"
73
+#include "sysemu/iothread.h"
74
#include "block/block_int.h"
75
#include "qmp-commands.h"
76
#include "block/trace.h"
77
@@ -XXX,XX +XXX,XX @@ BlockJobInfoList *qmp_query_block_jobs(Error **errp)
78
return head;
79
}
80
81
+void qmp_x_blockdev_set_iothread(const char *node_name, StrOrNull *iothread,
82
+ Error **errp)
83
+{
84
+ AioContext *old_context;
85
+ AioContext *new_context;
86
+ BlockDriverState *bs;
87
+
88
+ bs = bdrv_find_node(node_name);
89
+ if (!bs) {
90
+ error_setg(errp, "Cannot find node %s", node_name);
91
+ return;
92
+ }
49
+ }
93
+
50
+
94
+ /* If we want to allow more extreme test scenarios this guard could be
51
if (s->use_copy_range) {
95
+ * removed. For now it protects against accidents. */
52
ret = bdrv_co_copy_range(s->source, start, s->target, start, nbytes,
96
+ if (bdrv_has_blk(bs)) {
53
0, s->write_flags);
97
+ error_setg(errp, "Node %s is in use", node_name);
54
@@ -XXX,XX +XXX,XX @@ out:
98
+ return;
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;
99
+ }
69
+ }
100
+
70
+
101
+ if (iothread->type == QTYPE_QSTRING) {
71
+ ret = bdrv_block_status_above(s->source->bs, base, offset, bytes, &num,
102
+ IOThread *obj = iothread_by_id(iothread->u.s);
72
+ NULL, NULL);
103
+ if (!obj) {
73
+ if (ret < 0 || num < s->cluster_size) {
104
+ error_setg(errp, "Cannot find iothread %s", iothread->u.s);
74
+ /*
105
+ return;
75
+ * On error or if failed to obtain large enough chunk just fallback to
106
+ }
76
+ * copy one cluster.
107
+
77
+ */
108
+ new_context = iothread_get_aio_context(obj);
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);
109
+ } else {
82
+ } else {
110
+ new_context = qemu_get_aio_context();
83
+ num = QEMU_ALIGN_DOWN(num, s->cluster_size);
111
+ }
84
+ }
112
+
85
+
113
+ old_context = bdrv_get_aio_context(bs);
86
+ *pnum = num;
114
+ aio_context_acquire(old_context);
87
+ return ret;
115
+
116
+ bdrv_set_aio_context(bs, new_context);
117
+
118
+ aio_context_release(old_context);
119
+}
88
+}
120
+
89
+
121
QemuOptsList qemu_common_drive_opts = {
90
/*
122
.name = "drive",
91
* Check if the cluster starting at offset is allocated or not.
123
.head = QTAILQ_HEAD_INITIALIZER(qemu_common_drive_opts.head),
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"
124
--
161
--
125
2.14.3
162
2.24.1
126
163
127
164
diff view generated by jsdifflib
1
There is a small chance that iothread_stop() hangs as follows:
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
Thread 3 (Thread 0x7f63eba5f700 (LWP 16105)):
3
Split find_conflicting_inflight_req to be used separately.
4
#0 0x00007f64012c09b6 in ppoll () at /lib64/libc.so.6
5
#1 0x000055959992eac9 in ppoll (__ss=0x0, __timeout=0x0, __nfds=<optimized out>, __fds=<optimized out>) at /usr/include/bits/poll2.h:77
6
#2 0x000055959992eac9 in qemu_poll_ns (fds=<optimized out>, nfds=<optimized out>, timeout=<optimized out>) at util/qemu-timer.c:322
7
#3 0x0000559599930711 in aio_poll (ctx=0x55959bdb83c0, blocking=blocking@entry=true) at util/aio-posix.c:629
8
#4 0x00005595996806fe in iothread_run (opaque=0x55959bd78400) at iothread.c:59
9
#5 0x00007f640159f609 in start_thread () at /lib64/libpthread.so.0
10
#6 0x00007f64012cce6f in clone () at /lib64/libc.so.6
11
4
12
Thread 1 (Thread 0x7f640b45b280 (LWP 16103)):
5
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
13
#0 0x00007f64015a0b6d in pthread_join () at /lib64/libpthread.so.0
6
Reviewed-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
14
#1 0x00005595999332ef in qemu_thread_join (thread=<optimized out>) at util/qemu-thread-posix.c:547
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
15
#2 0x00005595996808ae in iothread_stop (iothread=<optimized out>) at iothread.c:91
8
Message-Id: <20200311103004.7649-6-vsementsov@virtuozzo.com>
16
#3 0x000055959968094d in iothread_stop_iter (object=<optimized out>, opaque=<optimized out>) at iothread.c:102
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
17
#4 0x0000559599857d97 in do_object_child_foreach (obj=obj@entry=0x55959bdb8100, fn=fn@entry=0x559599680930 <iothread_stop_iter>, opaque=opaque@entry=0x0, recurse=recurse@entry=false) at qom/object.c:852
10
---
18
#5 0x0000559599859477 in object_child_foreach (obj=obj@entry=0x55959bdb8100, fn=fn@entry=0x559599680930 <iothread_stop_iter>, opaque=opaque@entry=0x0) at qom/object.c:867
11
block/block-copy.c | 31 +++++++++++++++++++------------
19
#6 0x0000559599680a6e in iothread_stop_all () at iothread.c:341
12
1 file changed, 19 insertions(+), 12 deletions(-)
20
#7 0x000055959955b1d5 in main (argc=<optimized out>, argv=<optimized out>, envp=<optimized out>) at vl.c:4913
21
13
22
The relevant code from iothread_run() is:
14
diff --git a/block/block-copy.c b/block/block-copy.c
23
24
while (!atomic_read(&iothread->stopping)) {
25
aio_poll(iothread->ctx, true);
26
27
and iothread_stop():
28
29
iothread->stopping = true;
30
aio_notify(iothread->ctx);
31
...
32
qemu_thread_join(&iothread->thread);
33
34
The following scenario can occur:
35
36
1. IOThread:
37
while (!atomic_read(&iothread->stopping)) -> stopping=false
38
39
2. Main loop:
40
iothread->stopping = true;
41
aio_notify(iothread->ctx);
42
43
3. IOThread:
44
aio_poll(iothread->ctx, true); -> hang
45
46
The bug is explained by the AioContext->notify_me doc comments:
47
48
"If this field is 0, everything (file descriptors, bottom halves,
49
timers) will be re-evaluated before the next blocking poll(), thus the
50
event_notifier_set call can be skipped."
51
52
The problem is that "everything" does not include checking
53
iothread->stopping. This means iothread_run() will block in aio_poll()
54
if aio_notify() was called just before aio_poll().
55
56
This patch fixes the hang by replacing aio_notify() with
57
aio_bh_schedule_oneshot(). This makes aio_poll() or g_main_loop_run()
58
to return.
59
60
Implementing this properly required a new bool running flag. The new
61
flag prevents races that are tricky if we try to use iothread->stopping.
62
Now iothread->stopping is purely for iothread_stop() and
63
iothread->running is purely for the iothread_run() thread.
64
65
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
66
Reviewed-by: Eric Blake <eblake@redhat.com>
67
Message-id: 20171207201320.19284-6-stefanha@redhat.com
68
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
69
---
70
include/sysemu/iothread.h | 3 ++-
71
iothread.c | 20 +++++++++++++++-----
72
2 files changed, 17 insertions(+), 6 deletions(-)
73
74
diff --git a/include/sysemu/iothread.h b/include/sysemu/iothread.h
75
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
76
--- a/include/sysemu/iothread.h
16
--- a/block/block-copy.c
77
+++ b/include/sysemu/iothread.h
17
+++ b/block/block-copy.c
78
@@ -XXX,XX +XXX,XX @@ typedef struct {
18
@@ -XXX,XX +XXX,XX @@
79
GOnce once;
19
#define BLOCK_COPY_MAX_BUFFER (1 * MiB)
80
QemuMutex init_done_lock;
20
#define BLOCK_COPY_MAX_MEM (128 * MiB)
81
QemuCond init_done_cond; /* is thread initialization done? */
21
82
- bool stopping;
22
+static BlockCopyInFlightReq *find_conflicting_inflight_req(BlockCopyState *s,
83
+ bool stopping; /* has iothread_stop() been called? */
23
+ int64_t start,
84
+ bool running; /* should iothread_run() continue? */
24
+ int64_t end)
85
int thread_id;
86
87
/* AioContext poll parameters */
88
diff --git a/iothread.c b/iothread.c
89
index XXXXXXX..XXXXXXX 100644
90
--- a/iothread.c
91
+++ b/iothread.c
92
@@ -XXX,XX +XXX,XX @@ static void *iothread_run(void *opaque)
93
qemu_cond_signal(&iothread->init_done_cond);
94
qemu_mutex_unlock(&iothread->init_done_lock);
95
96
- while (!atomic_read(&iothread->stopping)) {
97
+ while (iothread->running) {
98
aio_poll(iothread->ctx, true);
99
100
if (atomic_read(&iothread->worker_context)) {
101
@@ -XXX,XX +XXX,XX @@ static void *iothread_run(void *opaque)
102
return NULL;
103
}
104
105
+/* Runs in iothread_run() thread */
106
+static void iothread_stop_bh(void *opaque)
107
+{
25
+{
108
+ IOThread *iothread = opaque;
26
+ BlockCopyInFlightReq *req;
109
+
27
+
110
+ iothread->running = false; /* stop iothread_run() */
28
+ QLIST_FOREACH(req, &s->inflight_reqs, list) {
29
+ if (end > req->start_byte && start < req->end_byte) {
30
+ return req;
31
+ }
32
+ }
111
+
33
+
112
+ if (iothread->main_loop) {
34
+ return NULL;
113
+ g_main_loop_quit(iothread->main_loop);
114
+ }
115
+}
35
+}
116
+
36
+
117
void iothread_stop(IOThread *iothread)
37
static void coroutine_fn block_copy_wait_inflight_reqs(BlockCopyState *s,
38
int64_t start,
39
int64_t end)
118
{
40
{
119
if (!iothread->ctx || iothread->stopping) {
41
BlockCopyInFlightReq *req;
120
return;
42
- bool waited;
121
}
43
-
122
iothread->stopping = true;
44
- do {
123
- aio_notify(iothread->ctx);
45
- waited = false;
124
- if (atomic_read(&iothread->main_loop)) {
46
- QLIST_FOREACH(req, &s->inflight_reqs, list) {
125
- g_main_loop_quit(iothread->main_loop);
47
- if (end > req->start_byte && start < req->end_byte) {
126
- }
48
- qemu_co_queue_wait(&req->wait_queue, NULL);
127
+ aio_bh_schedule_oneshot(iothread->ctx, iothread_stop_bh, iothread);
49
- waited = true;
128
qemu_thread_join(&iothread->thread);
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
+ }
129
}
58
}
130
59
131
@@ -XXX,XX +XXX,XX @@ static void iothread_complete(UserCreatable *obj, Error **errp)
60
static void block_copy_inflight_req_begin(BlockCopyState *s,
132
char *name, *thread_name;
133
134
iothread->stopping = false;
135
+ iothread->running = true;
136
iothread->thread_id = -1;
137
iothread->ctx = aio_context_new(&local_error);
138
if (!iothread->ctx) {
139
--
61
--
140
2.14.3
62
2.24.1
141
63
142
64
diff view generated by jsdifflib
1
bdrv_unref() requires the AioContext lock because bdrv_flush() uses
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
BDRV_POLL_WHILE(), which assumes the AioContext is currently held. If
2
3
BDRV_POLL_WHILE() runs without AioContext held the
3
We have a lot of "chunk_end - start" invocations, let's switch to
4
pthread_mutex_unlock() call in aio_context_release() fails.
4
bytes/cur_bytes scheme instead.
5
5
6
This patch moves bdrv_unref() into the AioContext locked region to solve
6
While being here, improve check on block_copy_do_copy parameters to not
7
the following pthread_mutex_unlock() failure:
7
overflow when calculating nbytes and use int64_t for bytes in
8
8
block_copy for consistency.
9
#0 0x00007f566181969b in raise () at /lib64/libc.so.6
9
10
#1 0x00007f566181b3b1 in abort () at /lib64/libc.so.6
10
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
11
#2 0x00005592cd590458 in error_exit (err=<optimized out>, msg=msg@entry=0x5592cdaf6d60 <__func__.23977> "qemu_mutex_unlock") at util/qemu-thread-posix.c:36
11
Reviewed-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
12
#3 0x00005592cd96e738 in qemu_mutex_unlock (mutex=mutex@entry=0x5592ce9505e0) at util/qemu-thread-posix.c:96
12
Reviewed-by: Max Reitz <mreitz@redhat.com>
13
#4 0x00005592cd969b69 in aio_context_release (ctx=ctx@entry=0x5592ce950580) at util/async.c:507
13
Message-Id: <20200311103004.7649-7-vsementsov@virtuozzo.com>
14
#5 0x00005592cd8ead78 in bdrv_flush (bs=bs@entry=0x5592cfa87210) at block/io.c:2478
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
#6 0x00005592cd89df30 in bdrv_close (bs=0x5592cfa87210) at block.c:3207
16
#7 0x00005592cd89df30 in bdrv_delete (bs=0x5592cfa87210) at block.c:3395
17
#8 0x00005592cd89df30 in bdrv_unref (bs=0x5592cfa87210) at block.c:4418
18
#9 0x00005592cd6b7f86 in qmp_transaction (dev_list=<optimized out>, has_props=<optimized out>, props=<optimized out>, errp=errp@entry=0x7ffe4a1fc9d8) at blockdev.c:2308
19
20
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
21
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
22
Reviewed-by: Eric Blake <eblake@redhat.com>
23
Message-id: 20171206144550.22295-2-stefanha@redhat.com
24
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
25
---
15
---
26
blockdev.c | 2 +-
16
block/block-copy.c | 78 ++++++++++++++++++++------------------
27
1 file changed, 1 insertion(+), 1 deletion(-)
17
include/block/block-copy.h | 6 +--
28
18
2 files changed, 44 insertions(+), 40 deletions(-)
29
diff --git a/blockdev.c b/blockdev.c
19
20
diff --git a/block/block-copy.c b/block/block-copy.c
30
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
31
--- a/blockdev.c
22
--- a/block/block-copy.c
32
+++ b/blockdev.c
23
+++ b/block/block-copy.c
33
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_clean(BlkActionState *common)
24
@@ -XXX,XX +XXX,XX @@
34
DO_UPCAST(ExternalSnapshotState, common, common);
25
35
if (state->aio_context) {
26
static BlockCopyInFlightReq *find_conflicting_inflight_req(BlockCopyState *s,
36
bdrv_drained_end(state->old_bs);
27
int64_t start,
37
- aio_context_release(state->aio_context);
28
- int64_t end)
38
bdrv_unref(state->new_bs);
29
+ int64_t bytes)
39
+ aio_context_release(state->aio_context);
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);
40
}
51
}
41
}
52
}
42
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 */
43
--
225
--
44
2.14.3
226
2.24.1
45
227
46
228
diff view generated by jsdifflib
1
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
2
3
Reviewed-by: Eric Blake <eblake@redhat.com>
3
offset/bytes pair is more usual naming in block layer, let's use it.
4
Message-id: 20171206144550.22295-5-stefanha@redhat.com
4
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
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-8-vsementsov@virtuozzo.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
---
10
---
7
blockdev.c | 44 ++++++++++++++++++++++++++++++++++----------
11
block/block-copy.c | 82 +++++++++++++++++++-------------------
8
1 file changed, 34 insertions(+), 10 deletions(-)
12
include/block/block-copy.h | 4 +-
9
13
2 files changed, 43 insertions(+), 43 deletions(-)
10
diff --git a/blockdev.c b/blockdev.c
14
15
diff --git a/block/block-copy.c b/block/block-copy.c
11
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
12
--- a/blockdev.c
17
--- a/block/block-copy.c
13
+++ b/blockdev.c
18
+++ b/block/block-copy.c
14
@@ -XXX,XX +XXX,XX @@ typedef struct BlockdevBackupState {
19
@@ -XXX,XX +XXX,XX @@
15
BlkActionState common;
20
#define BLOCK_COPY_MAX_MEM (128 * MiB)
16
BlockDriverState *bs;
21
17
BlockJob *job;
22
static BlockCopyInFlightReq *find_conflicting_inflight_req(BlockCopyState *s,
18
- AioContext *aio_context;
23
- int64_t start,
19
} BlockdevBackupState;
24
+ int64_t offset,
20
25
int64_t bytes)
21
static BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn,
26
{
22
@@ -XXX,XX +XXX,XX @@ static void blockdev_backup_prepare(BlkActionState *common, Error **errp)
27
BlockCopyInFlightReq *req;
23
BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common);
28
24
BlockdevBackup *backup;
29
QLIST_FOREACH(req, &s->inflight_reqs, list) {
25
BlockDriverState *bs, *target;
30
- if (start + bytes > req->start && start < req->start + req->bytes) {
26
+ AioContext *aio_context;
31
+ if (offset + bytes > req->offset && offset < req->offset + req->bytes) {
27
Error *local_err = NULL;
32
return req;
28
33
}
29
assert(common->action->type == TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP);
34
}
30
@@ -XXX,XX +XXX,XX @@ static void blockdev_backup_prepare(BlkActionState *common, Error **errp)
35
@@ -XXX,XX +XXX,XX @@ static BlockCopyInFlightReq *find_conflicting_inflight_req(BlockCopyState *s,
31
return;
32
}
33
34
- /* AioContext is released in .clean() */
35
- state->aio_context = bdrv_get_aio_context(bs);
36
- if (state->aio_context != bdrv_get_aio_context(target)) {
37
- state->aio_context = NULL;
38
+ aio_context = bdrv_get_aio_context(bs);
39
+ if (aio_context != bdrv_get_aio_context(target)) {
40
error_setg(errp, "Backup between two IO threads is not implemented");
41
return;
42
}
43
- aio_context_acquire(state->aio_context);
44
+ aio_context_acquire(aio_context);
45
state->bs = bs;
46
+
47
+ /* Paired with .clean() */
48
bdrv_drained_begin(state->bs);
49
50
state->job = do_blockdev_backup(backup, common->block_job_txn, &local_err);
51
if (local_err) {
52
error_propagate(errp, local_err);
53
- return;
54
+ goto out;
55
}
56
+
57
+out:
58
+ aio_context_release(aio_context);
59
}
36
}
60
37
61
static void blockdev_backup_commit(BlkActionState *common)
38
static void coroutine_fn block_copy_wait_inflight_reqs(BlockCopyState *s,
62
{
39
- int64_t start,
63
BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common);
40
+ int64_t offset,
64
+ AioContext *aio_context;
41
int64_t bytes)
65
+
42
{
66
+ aio_context = bdrv_get_aio_context(state->bs);
43
BlockCopyInFlightReq *req;
67
+ aio_context_acquire(aio_context);
44
68
+
45
- while ((req = find_conflicting_inflight_req(s, start, bytes))) {
69
assert(state->job);
46
+ while ((req = find_conflicting_inflight_req(s, offset, bytes))) {
70
block_job_start(state->job);
47
qemu_co_queue_wait(&req->wait_queue, NULL);
71
+
48
}
72
+ aio_context_release(aio_context);
73
}
49
}
74
50
75
static void blockdev_backup_abort(BlkActionState *common)
51
static void block_copy_inflight_req_begin(BlockCopyState *s,
76
@@ -XXX,XX +XXX,XX @@ static void blockdev_backup_abort(BlkActionState *common)
52
BlockCopyInFlightReq *req,
77
BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common);
53
- int64_t start, int64_t bytes)
78
54
+ int64_t offset, int64_t bytes)
79
if (state->job) {
55
{
80
+ AioContext *aio_context;
56
- req->start = start;
81
+
57
+ req->offset = offset;
82
+ aio_context = bdrv_get_aio_context(state->bs);
58
req->bytes = bytes;
83
+ aio_context_acquire(aio_context);
59
qemu_co_queue_init(&req->wait_queue);
84
+
60
QLIST_INSERT_HEAD(&s->inflight_reqs, req, list);
85
block_job_cancel_sync(state->job);
61
@@ -XXX,XX +XXX,XX @@ void block_copy_set_progress_meter(BlockCopyState *s, ProgressMeter *pm)
86
+
62
* Returns 0 on success.
87
+ aio_context_release(aio_context);
63
*/
88
}
64
static int coroutine_fn block_copy_do_copy(BlockCopyState *s,
65
- int64_t start, int64_t bytes,
66
+ int64_t offset, int64_t bytes,
67
bool zeroes, bool *error_is_read)
68
{
69
int ret;
70
- int64_t nbytes = MIN(start + bytes, s->len) - start;
71
+ int64_t nbytes = MIN(offset + bytes, s->len) - offset;
72
void *bounce_buffer = NULL;
73
74
- assert(start >= 0 && bytes > 0 && INT64_MAX - start >= bytes);
75
- assert(QEMU_IS_ALIGNED(start, s->cluster_size));
76
+ assert(offset >= 0 && bytes > 0 && INT64_MAX - offset >= bytes);
77
+ assert(QEMU_IS_ALIGNED(offset, s->cluster_size));
78
assert(QEMU_IS_ALIGNED(bytes, s->cluster_size));
79
- assert(start < s->len);
80
- assert(start + bytes <= s->len ||
81
- start + bytes == QEMU_ALIGN_UP(s->len, s->cluster_size));
82
+ assert(offset < s->len);
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,
89
}
135
}
90
136
91
static void blockdev_backup_clean(BlkActionState *common)
137
int coroutine_fn block_copy(BlockCopyState *s,
92
{
138
- int64_t start, int64_t bytes,
93
BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common);
139
+ int64_t offset, int64_t bytes,
94
+ AioContext *aio_context;
140
bool *error_is_read)
95
141
{
96
- if (state->aio_context) {
142
int ret = 0;
97
- bdrv_drained_end(state->bs);
143
@@ -XXX,XX +XXX,XX @@ int coroutine_fn block_copy(BlockCopyState *s,
98
- aio_context_release(state->aio_context);
144
assert(bdrv_get_aio_context(s->source->bs) ==
99
+ if (!state->bs) {
145
bdrv_get_aio_context(s->target->bs));
100
+ return;
146
101
}
147
- assert(QEMU_IS_ALIGNED(start, s->cluster_size));
102
+
148
+ assert(QEMU_IS_ALIGNED(offset, s->cluster_size));
103
+ aio_context = bdrv_get_aio_context(state->bs);
149
assert(QEMU_IS_ALIGNED(bytes, s->cluster_size));
104
+ aio_context_acquire(aio_context);
150
105
+
151
- block_copy_wait_inflight_reqs(s, start, bytes);
106
+ bdrv_drained_end(state->bs);
152
- block_copy_inflight_req_begin(s, &req, start, bytes);
107
+
153
+ block_copy_wait_inflight_reqs(s, offset, bytes);
108
+ aio_context_release(aio_context);
154
+ block_copy_inflight_req_begin(s, &req, offset, bytes);
109
}
155
110
156
while (bytes) {
111
typedef struct BlockDirtyBitmapState {
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
229
--- a/include/block/block-copy.h
230
+++ b/include/block/block-copy.h
231
@@ -XXX,XX +XXX,XX @@
232
#include "qemu/co-shared-resource.h"
233
234
typedef struct BlockCopyInFlightReq {
235
- int64_t start;
236
+ int64_t offset;
237
int64_t bytes;
238
QLIST_ENTRY(BlockCopyInFlightReq) list;
239
CoQueue wait_queue; /* coroutines blocked on this request */
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 */
112
--
249
--
113
2.14.3
250
2.24.1
114
251
115
252
diff view generated by jsdifflib
1
From: Mao Zhongyi <maozy.fnst@cn.fujitsu.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
When the function no success value to transmit, it usually make the
3
Currently, block_copy operation lock the whole requested region. But
4
function return void. It has turned out not to be a success, because
4
there is no reason to lock clusters, which are already copied, it will
5
it means that the extra local_err variable and error_propagate() will
5
disturb other parallel block_copy requests for no reason.
6
be needed. It leads to cumbersome code, therefore, transmit success/
6
7
failure in the return value is worth.
7
Let's instead do the following:
8
8
9
So fix the return type of blkconf_apply_backend_options(),
9
Lock only sub-region, which we are going to operate on. Then, after
10
blkconf_geometry() and virtio_blk_data_plane_create() to avoid it.
10
copying all dirty sub-regions, we should wait for intersecting
11
11
requests block-copy, if they failed, we should retry these new dirty
12
Cc: John Snow <jsnow@redhat.com>
12
clusters.
13
Cc: Kevin Wolf <kwolf@redhat.com>
13
14
Cc: Max Reitz <mreitz@redhat.com>
14
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
15
Cc: Stefan Hajnoczi <stefanha@redhat.com>
15
Reviewed-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
16
16
Message-Id: <20200311103004.7649-9-vsementsov@virtuozzo.com>
17
Signed-off-by: Mao Zhongyi <maozy.fnst@cn.fujitsu.com>
17
Signed-off-by: Max Reitz <mreitz@redhat.com>
18
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
19
Message-id: ac0edc1fc70c4457e5cec94405eb7d1f89f9c2c1.1511317952.git.maozy.fnst@cn.fujitsu.com
20
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
21
---
18
---
22
hw/block/dataplane/virtio-blk.h | 2 +-
19
block/block-copy.c | 129 ++++++++++++++++++++++++++++++++++++---------
23
include/hw/block/block.h | 4 ++--
20
1 file changed, 105 insertions(+), 24 deletions(-)
24
hw/block/block.c | 15 +++++++++------
21
25
hw/block/dataplane/virtio-blk.c | 12 +++++++-----
22
diff --git a/block/block-copy.c b/block/block-copy.c
26
4 files changed, 19 insertions(+), 14 deletions(-)
27
28
diff --git a/hw/block/dataplane/virtio-blk.h b/hw/block/dataplane/virtio-blk.h
29
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
30
--- a/hw/block/dataplane/virtio-blk.h
24
--- a/block/block-copy.c
31
+++ b/hw/block/dataplane/virtio-blk.h
25
+++ b/block/block-copy.c
32
@@ -XXX,XX +XXX,XX @@
26
@@ -XXX,XX +XXX,XX @@ static BlockCopyInFlightReq *find_conflicting_inflight_req(BlockCopyState *s,
33
27
return NULL;
34
typedef struct VirtIOBlockDataPlane VirtIOBlockDataPlane;
28
}
35
29
36
-void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
30
-static void coroutine_fn block_copy_wait_inflight_reqs(BlockCopyState *s,
37
+bool virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
31
- int64_t offset,
38
VirtIOBlockDataPlane **dataplane,
32
- int64_t bytes)
39
Error **errp);
33
+/*
40
void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s);
34
+ * If there are no intersecting requests return false. Otherwise, wait for the
41
diff --git a/include/hw/block/block.h b/include/hw/block/block.h
35
+ * first found intersecting request to finish and return true.
42
index XXXXXXX..XXXXXXX 100644
36
+ */
43
--- a/include/hw/block/block.h
37
+static bool coroutine_fn block_copy_wait_one(BlockCopyState *s, int64_t offset,
44
+++ b/include/hw/block/block.h
38
+ int64_t bytes)
45
@@ -XXX,XX +XXX,XX @@ static inline unsigned int get_physical_block_exp(BlockConf *conf)
39
{
46
/* Configuration helpers */
40
- BlockCopyInFlightReq *req;
47
41
+ BlockCopyInFlightReq *req = find_conflicting_inflight_req(s, offset, bytes);
48
void blkconf_serial(BlockConf *conf, char **serial);
42
49
-void blkconf_geometry(BlockConf *conf, int *trans,
43
- while ((req = find_conflicting_inflight_req(s, offset, bytes))) {
50
+bool blkconf_geometry(BlockConf *conf, int *trans,
44
- qemu_co_queue_wait(&req->wait_queue, NULL);
51
unsigned cyls_max, unsigned heads_max, unsigned secs_max,
45
+ if (!req) {
52
Error **errp);
53
void blkconf_blocksizes(BlockConf *conf);
54
-void blkconf_apply_backend_options(BlockConf *conf, bool readonly,
55
+bool blkconf_apply_backend_options(BlockConf *conf, bool readonly,
56
bool resizable, Error **errp);
57
58
/* Hard disk geometry */
59
diff --git a/hw/block/block.c b/hw/block/block.c
60
index XXXXXXX..XXXXXXX 100644
61
--- a/hw/block/block.c
62
+++ b/hw/block/block.c
63
@@ -XXX,XX +XXX,XX @@ void blkconf_blocksizes(BlockConf *conf)
64
}
65
}
66
67
-void blkconf_apply_backend_options(BlockConf *conf, bool readonly,
68
+bool blkconf_apply_backend_options(BlockConf *conf, bool readonly,
69
bool resizable, Error **errp)
70
{
71
BlockBackend *blk = conf->blk;
72
@@ -XXX,XX +XXX,XX @@ void blkconf_apply_backend_options(BlockConf *conf, bool readonly,
73
74
ret = blk_set_perm(blk, perm, shared_perm, errp);
75
if (ret < 0) {
76
- return;
77
+ return false;
46
+ return false;
78
}
47
}
79
48
+
80
switch (conf->wce) {
49
+ qemu_co_queue_wait(&req->wait_queue, NULL);
81
@@ -XXX,XX +XXX,XX @@ void blkconf_apply_backend_options(BlockConf *conf, bool readonly,
82
83
blk_set_enable_write_cache(blk, wce);
84
blk_set_on_error(blk, rerror, werror);
85
+
50
+
86
+ return true;
51
+ return true;
87
}
52
}
88
53
89
-void blkconf_geometry(BlockConf *conf, int *ptrans,
54
+/* Called only on full-dirty region */
90
+bool blkconf_geometry(BlockConf *conf, int *ptrans,
55
static void block_copy_inflight_req_begin(BlockCopyState *s,
91
unsigned cyls_max, unsigned heads_max, unsigned secs_max,
56
BlockCopyInFlightReq *req,
92
Error **errp)
57
int64_t offset, int64_t bytes)
93
{
58
{
94
@@ -XXX,XX +XXX,XX @@ void blkconf_geometry(BlockConf *conf, int *ptrans,
59
+ assert(!find_conflicting_inflight_req(s, offset, bytes));
95
if (conf->cyls || conf->heads || conf->secs) {
60
+
96
if (conf->cyls < 1 || conf->cyls > cyls_max) {
61
+ bdrv_reset_dirty_bitmap(s->copy_bitmap, offset, bytes);
97
error_setg(errp, "cyls must be between 1 and %u", cyls_max);
62
+ s->in_flight_bytes += bytes;
98
- return;
63
+
99
+ return false;
64
req->offset = offset;
100
}
65
req->bytes = bytes;
101
if (conf->heads < 1 || conf->heads > heads_max) {
66
qemu_co_queue_init(&req->wait_queue);
102
error_setg(errp, "heads must be between 1 and %u", heads_max);
67
QLIST_INSERT_HEAD(&s->inflight_reqs, req, list);
103
- return;
68
}
104
+ return false;
69
105
}
70
-static void coroutine_fn block_copy_inflight_req_end(BlockCopyInFlightReq *req)
106
if (conf->secs < 1 || conf->secs > secs_max) {
71
+/*
107
error_setg(errp, "secs must be between 1 and %u", secs_max);
72
+ * block_copy_inflight_req_shrink
108
- return;
73
+ *
109
+ return false;
74
+ * Drop the tail of the request to be handled later. Set dirty bits back and
110
}
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;
108
}
109
110
-int coroutine_fn block_copy(BlockCopyState *s,
111
- int64_t offset, int64_t bytes,
112
- bool *error_is_read)
113
+/*
114
+ * block_copy_dirty_clusters
115
+ *
116
+ * Copy dirty clusters in @offset/@bytes range.
117
+ * Returns 1 if dirty clusters found and successfully copied, 0 if no dirty
118
+ * clusters found and -errno on failure.
119
+ */
120
+static int coroutine_fn block_copy_dirty_clusters(BlockCopyState *s,
121
+ int64_t offset, int64_t bytes,
122
+ bool *error_is_read)
123
{
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;
188
}
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;
111
}
193
}
112
+ return true;
194
113
}
195
- block_copy_inflight_req_end(&req);
114
diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c
196
+ return found_dirty;
115
index XXXXXXX..XXXXXXX 100644
197
+}
116
--- a/hw/block/dataplane/virtio-blk.c
198
+
117
+++ b/hw/block/dataplane/virtio-blk.c
199
+/*
118
@@ -XXX,XX +XXX,XX @@ static void notify_guest_bh(void *opaque)
200
+ * block_copy
119
}
201
+ *
120
202
+ * Copy requested region, accordingly to dirty bitmap.
121
/* Context: QEMU global mutex held */
203
+ * Collaborate with parallel block_copy requests: if they succeed it will help
122
-void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
204
+ * us. If they fail, we will retry not-copied regions. So, if we return error,
123
+bool virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
205
+ * it means that some I/O operation failed in context of _this_ block_copy call,
124
VirtIOBlockDataPlane **dataplane,
206
+ * not some parallel operation.
125
Error **errp)
207
+ */
126
{
208
+int coroutine_fn block_copy(BlockCopyState *s, int64_t offset, int64_t bytes,
127
@@ -XXX,XX +XXX,XX @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
209
+ bool *error_is_read)
128
error_setg(errp,
210
+{
129
"device is incompatible with iothread "
211
+ int ret;
130
"(transport does not support notifiers)");
212
+
131
- return;
213
+ do {
132
+ return false;
214
+ ret = block_copy_dirty_clusters(s, offset, bytes, error_is_read);
133
}
215
+
134
if (!virtio_device_ioeventfd_enabled(vdev)) {
216
+ if (ret == 0) {
135
error_setg(errp, "ioeventfd is required for iothread");
217
+ ret = block_copy_wait_one(s, offset, bytes);
136
- return;
218
+ }
137
+ return false;
219
+
138
}
220
+ /*
139
221
+ * We retry in two cases:
140
/* If dataplane is (re-)enabled while the guest is running there could
222
+ * 1. Some progress done
141
@@ -XXX,XX +XXX,XX @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
223
+ * Something was copied, which means that there were yield points
142
*/
224
+ * and some new dirty bits may have appeared (due to failed parallel
143
if (blk_op_is_blocked(conf->conf.blk, BLOCK_OP_TYPE_DATAPLANE, errp)) {
225
+ * block-copy requests).
144
error_prepend(errp, "cannot start virtio-blk dataplane: ");
226
+ * 2. We have waited for some intersecting block-copy request
145
- return;
227
+ * It may have failed and produced new dirty bits.
146
+ return false;
228
+ */
147
}
229
+ } while (ret > 0);
148
}
230
149
/* Don't try if transport does not support notifiers. */
231
return ret;
150
if (!virtio_device_ioeventfd_enabled(vdev)) {
232
}
151
- return;
152
+ return false;
153
}
154
155
s = g_new0(VirtIOBlockDataPlane, 1);
156
@@ -XXX,XX +XXX,XX @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
157
s->batch_notify_vqs = bitmap_new(conf->num_queues);
158
159
*dataplane = s;
160
+
161
+ return true;
162
}
163
164
/* Context: QEMU global mutex held */
165
--
233
--
166
2.14.3
234
2.24.1
167
235
168
236
diff view generated by jsdifflib
Deleted patch
1
From: Mao Zhongyi <maozy.fnst@cn.fujitsu.com>
2
1
3
Cc: John Snow <jsnow@redhat.com>
4
Cc: Kevin Wolf <kwolf@redhat.com>
5
Cc: Max Reitz <mreitz@redhat.com>
6
Cc: Keith Busch <keith.busch@intel.com>
7
Cc: Stefan Hajnoczi <stefanha@redhat.com>
8
Cc: "Michael S. Tsirkin" <mst@redhat.com>
9
Cc: Paolo Bonzini <pbonzini@redhat.com>
10
Cc: Gerd Hoffmann <kraxel@redhat.com>
11
Cc: Markus Armbruster <armbru@redhat.com>
12
13
Signed-off-by: Mao Zhongyi <maozy.fnst@cn.fujitsu.com>
14
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
15
Message-id: e77848d3735ba590f23ffbf8094379c646c33d79.1511317952.git.maozy.fnst@cn.fujitsu.com
16
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
17
---
18
hw/block/fdc.c | 17 ++++++-----------
19
hw/block/nvme.c | 7 ++-----
20
hw/block/virtio-blk.c | 18 ++++++------------
21
hw/ide/qdev.c | 12 ++++--------
22
hw/scsi/scsi-disk.c | 13 ++++---------
23
hw/usb/dev-storage.c | 9 +++------
24
6 files changed, 25 insertions(+), 51 deletions(-)
25
26
diff --git a/hw/block/fdc.c b/hw/block/fdc.c
27
index XXXXXXX..XXXXXXX 100644
28
--- a/hw/block/fdc.c
29
+++ b/hw/block/fdc.c
30
@@ -XXX,XX +XXX,XX @@ static void fd_revalidate(FDrive *drv)
31
static void fd_change_cb(void *opaque, bool load, Error **errp)
32
{
33
FDrive *drive = opaque;
34
- Error *local_err = NULL;
35
36
if (!load) {
37
blk_set_perm(drive->blk, 0, BLK_PERM_ALL, &error_abort);
38
} else {
39
- blkconf_apply_backend_options(drive->conf,
40
- blk_is_read_only(drive->blk), false,
41
- &local_err);
42
- if (local_err) {
43
- error_propagate(errp, local_err);
44
+ if (!blkconf_apply_backend_options(drive->conf,
45
+ blk_is_read_only(drive->blk), false,
46
+ errp)) {
47
return;
48
}
49
}
50
@@ -XXX,XX +XXX,XX @@ static void floppy_drive_realize(DeviceState *qdev, Error **errp)
51
FloppyDrive *dev = FLOPPY_DRIVE(qdev);
52
FloppyBus *bus = FLOPPY_BUS(qdev->parent_bus);
53
FDrive *drive;
54
- Error *local_err = NULL;
55
int ret;
56
57
if (dev->unit == -1) {
58
@@ -XXX,XX +XXX,XX @@ static void floppy_drive_realize(DeviceState *qdev, Error **errp)
59
dev->conf.rerror = BLOCKDEV_ON_ERROR_AUTO;
60
dev->conf.werror = BLOCKDEV_ON_ERROR_AUTO;
61
62
- blkconf_apply_backend_options(&dev->conf, blk_is_read_only(dev->conf.blk),
63
- false, &local_err);
64
- if (local_err) {
65
- error_propagate(errp, local_err);
66
+ if (!blkconf_apply_backend_options(&dev->conf,
67
+ blk_is_read_only(dev->conf.blk),
68
+ false, errp)) {
69
return;
70
}
71
72
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
73
index XXXXXXX..XXXXXXX 100644
74
--- a/hw/block/nvme.c
75
+++ b/hw/block/nvme.c
76
@@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
77
int i;
78
int64_t bs_size;
79
uint8_t *pci_conf;
80
- Error *local_err = NULL;
81
82
if (!n->conf.blk) {
83
error_setg(errp, "drive property not set");
84
@@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
85
return;
86
}
87
blkconf_blocksizes(&n->conf);
88
- blkconf_apply_backend_options(&n->conf, blk_is_read_only(n->conf.blk),
89
- false, &local_err);
90
- if (local_err) {
91
- error_propagate(errp, local_err);
92
+ if (!blkconf_apply_backend_options(&n->conf, blk_is_read_only(n->conf.blk),
93
+ false, errp)) {
94
return;
95
}
96
97
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
98
index XXXXXXX..XXXXXXX 100644
99
--- a/hw/block/virtio-blk.c
100
+++ b/hw/block/virtio-blk.c
101
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
102
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
103
VirtIOBlock *s = VIRTIO_BLK(dev);
104
VirtIOBlkConf *conf = &s->conf;
105
- Error *err = NULL;
106
unsigned i;
107
108
if (!conf->conf.blk) {
109
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
110
}
111
112
blkconf_serial(&conf->conf, &conf->serial);
113
- blkconf_apply_backend_options(&conf->conf,
114
- blk_is_read_only(conf->conf.blk), true,
115
- &err);
116
- if (err) {
117
- error_propagate(errp, err);
118
+ if (!blkconf_apply_backend_options(&conf->conf,
119
+ blk_is_read_only(conf->conf.blk), true,
120
+ errp)) {
121
return;
122
}
123
s->original_wce = blk_enable_write_cache(conf->conf.blk);
124
- blkconf_geometry(&conf->conf, NULL, 65535, 255, 255, &err);
125
- if (err) {
126
- error_propagate(errp, err);
127
+ if (!blkconf_geometry(&conf->conf, NULL, 65535, 255, 255, errp)) {
128
return;
129
}
130
+
131
blkconf_blocksizes(&conf->conf);
132
133
virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK,
134
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
135
for (i = 0; i < conf->num_queues; i++) {
136
virtio_add_queue(vdev, 128, virtio_blk_handle_output);
137
}
138
- virtio_blk_data_plane_create(vdev, conf, &s->dataplane, &err);
139
- if (err != NULL) {
140
- error_propagate(errp, err);
141
+ if (!virtio_blk_data_plane_create(vdev, conf, &s->dataplane, errp)) {
142
virtio_cleanup(vdev);
143
return;
144
}
145
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
146
index XXXXXXX..XXXXXXX 100644
147
--- a/hw/ide/qdev.c
148
+++ b/hw/ide/qdev.c
149
@@ -XXX,XX +XXX,XX @@ static void ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind, Error **errp)
150
{
151
IDEBus *bus = DO_UPCAST(IDEBus, qbus, dev->qdev.parent_bus);
152
IDEState *s = bus->ifs + dev->unit;
153
- Error *err = NULL;
154
int ret;
155
156
if (!dev->conf.blk) {
157
@@ -XXX,XX +XXX,XX @@ static void ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind, Error **errp)
158
159
blkconf_serial(&dev->conf, &dev->serial);
160
if (kind != IDE_CD) {
161
- blkconf_geometry(&dev->conf, &dev->chs_trans, 65535, 16, 255, &err);
162
- if (err) {
163
- error_propagate(errp, err);
164
+ if (!blkconf_geometry(&dev->conf, &dev->chs_trans, 65535, 16, 255,
165
+ errp)) {
166
return;
167
}
168
}
169
- blkconf_apply_backend_options(&dev->conf, kind == IDE_CD, kind != IDE_CD,
170
- &err);
171
- if (err) {
172
- error_propagate(errp, err);
173
+ if (!blkconf_apply_backend_options(&dev->conf, kind == IDE_CD,
174
+ kind != IDE_CD, errp)) {
175
return;
176
}
177
178
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
179
index XXXXXXX..XXXXXXX 100644
180
--- a/hw/scsi/scsi-disk.c
181
+++ b/hw/scsi/scsi-disk.c
182
@@ -XXX,XX +XXX,XX @@ static void scsi_disk_unit_attention_reported(SCSIDevice *dev)
183
static void scsi_realize(SCSIDevice *dev, Error **errp)
184
{
185
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
186
- Error *err = NULL;
187
188
if (!s->qdev.conf.blk) {
189
error_setg(errp, "drive property not set");
190
@@ -XXX,XX +XXX,XX @@ static void scsi_realize(SCSIDevice *dev, Error **errp)
191
}
192
193
if (dev->type == TYPE_DISK) {
194
- blkconf_geometry(&dev->conf, NULL, 65535, 255, 255, &err);
195
- if (err) {
196
- error_propagate(errp, err);
197
+ if (!blkconf_geometry(&dev->conf, NULL, 65535, 255, 255, errp)) {
198
return;
199
}
200
}
201
- blkconf_apply_backend_options(&dev->conf,
202
- blk_is_read_only(s->qdev.conf.blk),
203
- dev->type == TYPE_DISK, &err);
204
- if (err) {
205
- error_propagate(errp, err);
206
+ if (!blkconf_apply_backend_options(&dev->conf,
207
+ blk_is_read_only(s->qdev.conf.blk),
208
+ dev->type == TYPE_DISK, errp)) {
209
return;
210
}
211
212
diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
213
index XXXXXXX..XXXXXXX 100644
214
--- a/hw/usb/dev-storage.c
215
+++ b/hw/usb/dev-storage.c
216
@@ -XXX,XX +XXX,XX @@ static void usb_msd_realize_storage(USBDevice *dev, Error **errp)
217
MSDState *s = USB_STORAGE_DEV(dev);
218
BlockBackend *blk = s->conf.blk;
219
SCSIDevice *scsi_dev;
220
- Error *err = NULL;
221
222
if (!blk) {
223
error_setg(errp, "drive property not set");
224
@@ -XXX,XX +XXX,XX @@ static void usb_msd_realize_storage(USBDevice *dev, Error **errp)
225
226
blkconf_serial(&s->conf, &dev->serial);
227
blkconf_blocksizes(&s->conf);
228
- blkconf_apply_backend_options(&s->conf, blk_is_read_only(blk), true, &err);
229
- if (err) {
230
- error_propagate(errp, err);
231
+ if (!blkconf_apply_backend_options(&s->conf, blk_is_read_only(blk), true,
232
+ errp)) {
233
return;
234
}
235
236
@@ -XXX,XX +XXX,XX @@ static void usb_msd_realize_storage(USBDevice *dev, Error **errp)
237
&usb_msd_scsi_info_storage, NULL);
238
scsi_dev = scsi_bus_legacy_add_drive(&s->bus, blk, 0, !!s->removable,
239
s->conf.bootindex, dev->serial,
240
- &err);
241
+ errp);
242
blk_unref(blk);
243
if (!scsi_dev) {
244
- error_propagate(errp, err);
245
return;
246
}
247
usb_msd_handle_reset(dev);
248
--
249
2.14.3
250
251
diff view generated by jsdifflib
Deleted patch
1
Commit 1351d1ec89eabebc9fdff20451a62c413d7accc1 ("qdev: drop iothread
2
property type") forgot to remove this include.
3
1
4
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
5
Message-id: 20171205133954.31006-1-stefanha@redhat.com
6
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
7
---
8
hw/core/qdev-properties-system.c | 1 -
9
1 file changed, 1 deletion(-)
10
11
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/hw/core/qdev-properties-system.c
14
+++ b/hw/core/qdev-properties-system.c
15
@@ -XXX,XX +XXX,XX @@
16
#include "qapi/visitor.h"
17
#include "chardev/char-fe.h"
18
#include "sysemu/tpm_backend.h"
19
-#include "sysemu/iothread.h"
20
21
static void get_pointer(Object *obj, Visitor *v, Property *prop,
22
char *(*print)(void *ptr),
23
--
24
2.14.3
25
26
diff view generated by jsdifflib
1
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
2
3
Reviewed-by: Eric Blake <eblake@redhat.com>
3
Hide structure definitions and add explicit API instead, to keep an
4
Message-id: 20171206144550.22295-4-stefanha@redhat.com
4
eye on the scope of the shared fields.
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
5
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Reviewed-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Message-Id: <20200311103004.7649-10-vsementsov@virtuozzo.com>
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
---
11
---
7
blockdev.c | 42 ++++++++++++++++++++++++++++++++++--------
12
block/backup-top.c | 6 ++--
8
1 file changed, 34 insertions(+), 8 deletions(-)
13
block/backup.c | 25 ++++++++--------
9
14
block/block-copy.c | 59 ++++++++++++++++++++++++++++++++++++++
10
diff --git a/blockdev.c b/blockdev.c
15
include/block/block-copy.h | 52 +++------------------------------
11
index XXXXXXX..XXXXXXX 100644
16
4 files changed, 80 insertions(+), 62 deletions(-)
12
--- a/blockdev.c
17
13
+++ b/blockdev.c
18
diff --git a/block/backup-top.c b/block/backup-top.c
14
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_clean(BlkActionState *common)
19
index XXXXXXX..XXXXXXX 100644
15
typedef struct DriveBackupState {
20
--- a/block/backup-top.c
16
BlkActionState common;
21
+++ b/block/backup-top.c
17
BlockDriverState *bs;
22
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVBackupTopState {
18
- AioContext *aio_context;
23
BlockCopyState *bcs;
19
BlockJob *job;
24
BdrvChild *target;
20
} DriveBackupState;
25
bool active;
21
26
+ int64_t cluster_size;
22
@@ -XXX,XX +XXX,XX @@ static void drive_backup_prepare(BlkActionState *common, Error **errp)
27
} BDRVBackupTopState;
23
DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common);
28
24
BlockDriverState *bs;
29
static coroutine_fn int backup_top_co_preadv(
25
DriveBackup *backup;
30
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int backup_top_cbw(BlockDriverState *bs, uint64_t offset,
26
+ AioContext *aio_context;
31
return 0;
27
Error *local_err = NULL;
32
}
28
33
29
assert(common->action->type == TRANSACTION_ACTION_KIND_DRIVE_BACKUP);
34
- off = QEMU_ALIGN_DOWN(offset, s->bcs->cluster_size);
30
@@ -XXX,XX +XXX,XX @@ static void drive_backup_prepare(BlkActionState *common, Error **errp)
35
- end = QEMU_ALIGN_UP(offset + bytes, s->bcs->cluster_size);
36
+ off = QEMU_ALIGN_DOWN(offset, s->cluster_size);
37
+ end = QEMU_ALIGN_UP(offset + bytes, s->cluster_size);
38
39
return block_copy(s->bcs, off, end - off, NULL);
40
}
41
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source,
42
goto fail;
43
}
44
45
+ state->cluster_size = cluster_size;
46
state->bcs = block_copy_state_new(top->backing, state->target,
47
cluster_size, write_flags, &local_err);
48
if (local_err) {
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_cleanup_sync_bitmap(BackupBlockJob *job, int ret)
54
55
if (ret < 0 && job->bitmap_mode == BITMAP_SYNC_MODE_ALWAYS) {
56
/* If we failed and synced, merge in the bits we didn't copy: */
57
- bdrv_dirty_bitmap_merge_internal(bm, job->bcs->copy_bitmap,
58
+ bdrv_dirty_bitmap_merge_internal(bm, block_copy_dirty_bitmap(job->bcs),
59
NULL, true);
60
}
61
}
62
@@ -XXX,XX +XXX,XX @@ void backup_do_checkpoint(BlockJob *job, Error **errp)
31
return;
63
return;
32
}
64
}
33
65
34
- /* AioContext is released in .clean() */
66
- bdrv_set_dirty_bitmap(backup_job->bcs->copy_bitmap, 0, backup_job->len);
35
- state->aio_context = bdrv_get_aio_context(bs);
67
+ bdrv_set_dirty_bitmap(block_copy_dirty_bitmap(backup_job->bcs), 0,
36
- aio_context_acquire(state->aio_context);
68
+ backup_job->len);
37
+ aio_context = bdrv_get_aio_context(bs);
69
}
38
+ aio_context_acquire(aio_context);
70
39
+
71
static BlockErrorAction backup_error_action(BackupBlockJob *job,
40
+ /* Paired with .clean() */
72
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_loop(BackupBlockJob *job)
41
bdrv_drained_begin(bs);
73
BdrvDirtyBitmapIter *bdbi;
42
+
74
int ret = 0;
43
state->bs = bs;
75
44
76
- bdbi = bdrv_dirty_iter_new(job->bcs->copy_bitmap);
45
state->job = do_drive_backup(backup, common->block_job_txn, &local_err);
77
+ bdbi = bdrv_dirty_iter_new(block_copy_dirty_bitmap(job->bcs));
46
if (local_err) {
78
while ((offset = bdrv_dirty_iter_next(bdbi)) != -1) {
47
error_propagate(errp, local_err);
79
do {
48
- return;
80
if (yield_and_check(job)) {
49
+ goto out;
81
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_loop(BackupBlockJob *job)
50
}
82
return ret;
51
+
83
}
52
+out:
84
53
+ aio_context_release(aio_context);
85
-static void backup_init_copy_bitmap(BackupBlockJob *job)
54
}
86
+static void backup_init_bcs_bitmap(BackupBlockJob *job)
55
56
static void drive_backup_commit(BlkActionState *common)
57
{
87
{
58
DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common);
88
bool ret;
59
+ AioContext *aio_context;
89
uint64_t estimate;
60
+
90
+ BdrvDirtyBitmap *bcs_bitmap = block_copy_dirty_bitmap(job->bcs);
61
+ aio_context = bdrv_get_aio_context(state->bs);
91
62
+ aio_context_acquire(aio_context);
92
if (job->sync_mode == MIRROR_SYNC_MODE_BITMAP) {
63
+
93
- ret = bdrv_dirty_bitmap_merge_internal(job->bcs->copy_bitmap,
64
assert(state->job);
94
- job->sync_bitmap,
65
block_job_start(state->job);
95
+ ret = bdrv_dirty_bitmap_merge_internal(bcs_bitmap, job->sync_bitmap,
66
+
96
NULL, true);
67
+ aio_context_release(aio_context);
97
assert(ret);
68
}
98
} else {
69
99
@@ -XXX,XX +XXX,XX @@ static void backup_init_copy_bitmap(BackupBlockJob *job)
70
static void drive_backup_abort(BlkActionState *common)
100
* We can't hog the coroutine to initialize this thoroughly.
71
@@ -XXX,XX +XXX,XX @@ static void drive_backup_abort(BlkActionState *common)
101
* Set a flag and resume work when we are able to yield safely.
72
DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common);
102
*/
73
103
- job->bcs->skip_unallocated = true;
74
if (state->job) {
104
+ block_copy_set_skip_unallocated(job->bcs, true);
75
+ AioContext *aio_context;
105
}
76
+
106
- bdrv_set_dirty_bitmap(job->bcs->copy_bitmap, 0, job->len);
77
+ aio_context = bdrv_get_aio_context(state->bs);
107
+ bdrv_set_dirty_bitmap(bcs_bitmap, 0, job->len);
78
+ aio_context_acquire(aio_context);
108
}
79
+
109
80
block_job_cancel_sync(state->job);
110
- estimate = bdrv_get_dirty_count(job->bcs->copy_bitmap);
81
+
111
+ estimate = bdrv_get_dirty_count(bcs_bitmap);
82
+ aio_context_release(aio_context);
112
job_progress_set_remaining(&job->common.job, estimate);
83
}
113
}
84
}
114
85
115
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_run(Job *job, Error **errp)
86
static void drive_backup_clean(BlkActionState *common)
116
BackupBlockJob *s = container_of(job, BackupBlockJob, common.job);
87
{
117
int ret = 0;
88
DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common);
118
89
+ AioContext *aio_context;
119
- backup_init_copy_bitmap(s);
90
120
+ backup_init_bcs_bitmap(s);
91
- if (state->aio_context) {
121
92
- bdrv_drained_end(state->bs);
122
if (s->sync_mode == MIRROR_SYNC_MODE_TOP) {
93
- aio_context_release(state->aio_context);
123
int64_t offset = 0;
94
+ if (!state->bs) {
124
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_run(Job *job, Error **errp)
95
+ return;
125
96
}
126
offset += count;
97
+
127
}
98
+ aio_context = bdrv_get_aio_context(state->bs);
128
- s->bcs->skip_unallocated = false;
99
+ aio_context_acquire(aio_context);
129
+ block_copy_set_skip_unallocated(s->bcs, false);
100
+
130
}
101
+ bdrv_drained_end(state->bs);
131
102
+
132
if (s->sync_mode == MIRROR_SYNC_MODE_NONE) {
103
+ aio_context_release(aio_context);
133
/*
104
}
134
- * All bits are set in copy_bitmap to allow any cluster to be copied.
105
135
+ * All bits are set in bcs bitmap to allow any cluster to be copied.
106
typedef struct BlockdevBackupState {
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 @@
144
#define BLOCK_COPY_MAX_BUFFER (1 * MiB)
145
#define BLOCK_COPY_MAX_MEM (128 * MiB)
146
147
+typedef struct BlockCopyInFlightReq {
148
+ int64_t offset;
149
+ int64_t bytes;
150
+ QLIST_ENTRY(BlockCopyInFlightReq) list;
151
+ CoQueue wait_queue; /* coroutines blocked on this request */
152
+} BlockCopyInFlightReq;
153
+
154
+typedef struct BlockCopyState {
155
+ /*
156
+ * BdrvChild objects are not owned or managed by block-copy. They are
157
+ * provided by block-copy user and user is responsible for appropriate
158
+ * permissions on these children.
159
+ */
160
+ BdrvChild *source;
161
+ BdrvChild *target;
162
+ BdrvDirtyBitmap *copy_bitmap;
163
+ int64_t in_flight_bytes;
164
+ int64_t cluster_size;
165
+ bool use_copy_range;
166
+ int64_t copy_size;
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 */
107
--
282
--
108
2.14.3
283
2.24.1
109
284
110
285
diff view generated by jsdifflib
Deleted patch
1
Encapsulate IOThread QOM object lookup so that callers don't need to
2
know how and where IOThread objects live.
3
1
4
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
5
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Message-id: 20171206144550.22295-8-stefanha@redhat.com
8
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
---
10
include/sysemu/iothread.h | 1 +
11
iothread.c | 7 +++++++
12
2 files changed, 8 insertions(+)
13
14
diff --git a/include/sysemu/iothread.h b/include/sysemu/iothread.h
15
index XXXXXXX..XXXXXXX 100644
16
--- a/include/sysemu/iothread.h
17
+++ b/include/sysemu/iothread.h
18
@@ -XXX,XX +XXX,XX @@ typedef struct {
19
OBJECT_CHECK(IOThread, obj, TYPE_IOTHREAD)
20
21
char *iothread_get_id(IOThread *iothread);
22
+IOThread *iothread_by_id(const char *id);
23
AioContext *iothread_get_aio_context(IOThread *iothread);
24
void iothread_stop_all(void);
25
GMainContext *iothread_get_g_main_context(IOThread *iothread);
26
diff --git a/iothread.c b/iothread.c
27
index XXXXXXX..XXXXXXX 100644
28
--- a/iothread.c
29
+++ b/iothread.c
30
@@ -XXX,XX +XXX,XX @@ void iothread_destroy(IOThread *iothread)
31
{
32
object_unparent(OBJECT(iothread));
33
}
34
+
35
+/* Lookup IOThread by its id. Only finds user-created objects, not internal
36
+ * iothread_create() objects. */
37
+IOThread *iothread_by_id(const char *id)
38
+{
39
+ return IOTHREAD(object_resolve_path_type(id, TYPE_IOTHREAD, NULL));
40
+}
41
--
42
2.14.3
43
44
diff view generated by jsdifflib