1
The following changes since commit 4c8c1cc544dbd5e2564868e61c5037258e393832:
1
The following changes since commit 16aaacb307ed607b9780c12702c44f0fe52edc7e:
2
2
3
Merge remote-tracking branch 'remotes/vivier/tags/m68k-for-2.10-pull-request' into staging (2017-06-22 19:01:58 +0100)
3
Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20200430' into staging (2020-04-30 14:00:36 +0100)
4
4
5
are available in the git repository at:
5
are available in the Git repository at:
6
7
6
8
git://repo.or.cz/qemu/kevin.git tags/for-upstream
7
git://repo.or.cz/qemu/kevin.git tags/for-upstream
9
8
10
for you to fetch changes up to 1512008812410ca4054506a7c44343088abdd977:
9
for you to fetch changes up to eaae29ef89d498d0eac553c77b554f310a47f809:
11
10
12
Merge remote-tracking branch 'mreitz/tags/pull-block-2017-06-23' into queue-block (2017-06-23 14:09:12 +0200)
11
qemu-storage-daemon: Fix non-string --object properties (2020-04-30 17:51:07 +0200)
13
12
14
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block layer patches:
15
15
16
Block layer patches
16
- Fix resize (extending) of short overlays
17
- nvme: introduce PMR support from NVMe 1.4 spec
18
- qemu-storage-daemon: Fix non-string --object properties
17
19
18
----------------------------------------------------------------
20
----------------------------------------------------------------
19
Alberto Garcia (9):
21
Alberto Garcia (1):
20
throttle: Update throttle-groups.c documentation
22
qcow2: Add incompatibility note between backing files and raw external data files
21
qcow2: Remove unused Error variable in do_perform_cow()
22
qcow2: Use unsigned int for both members of Qcow2COWRegion
23
qcow2: Make perform_cow() call do_perform_cow() twice
24
qcow2: Split do_perform_cow() into _read(), _encrypt() and _write()
25
qcow2: Allow reading both COW regions with only one request
26
qcow2: Pass a QEMUIOVector to do_perform_cow_{read,write}()
27
qcow2: Merge the writing of the COW regions with the guest data
28
qcow2: Use offset_into_cluster() and offset_to_l2_index()
29
23
30
Kevin Wolf (37):
24
Andrzej Jakowski (1):
31
commit: Fix completion with extra reference
25
nvme: introduce PMR support from NVMe 1.4 spec
32
qemu-iotests: Allow starting new qemu after cleanup
33
qemu-iotests: Test exiting qemu with running job
34
doc: Document generic -blockdev options
35
doc: Document driver-specific -blockdev options
36
qed: Use bottom half to resume waiting requests
37
qed: Make qed_read_table() synchronous
38
qed: Remove callback from qed_read_table()
39
qed: Remove callback from qed_read_l2_table()
40
qed: Remove callback from qed_find_cluster()
41
qed: Make qed_read_backing_file() synchronous
42
qed: Make qed_copy_from_backing_file() synchronous
43
qed: Remove callback from qed_copy_from_backing_file()
44
qed: Make qed_write_header() synchronous
45
qed: Remove callback from qed_write_header()
46
qed: Make qed_write_table() synchronous
47
qed: Remove GenericCB
48
qed: Remove callback from qed_write_table()
49
qed: Make qed_aio_read_data() synchronous
50
qed: Make qed_aio_write_main() synchronous
51
qed: Inline qed_commit_l2_update()
52
qed: Add return value to qed_aio_write_l1_update()
53
qed: Add return value to qed_aio_write_l2_update()
54
qed: Add return value to qed_aio_write_main()
55
qed: Add return value to qed_aio_write_cow()
56
qed: Add return value to qed_aio_write_inplace/alloc()
57
qed: Add return value to qed_aio_read/write_data()
58
qed: Remove ret argument from qed_aio_next_io()
59
qed: Remove recursion in qed_aio_next_io()
60
qed: Implement .bdrv_co_readv/writev
61
qed: Use CoQueue for serialising allocations
62
qed: Simplify request handling
63
qed: Use a coroutine for need_check_timer
64
qed: Add coroutine_fn to I/O path functions
65
qed: Use bdrv_co_* for coroutine_fns
66
block: Remove bdrv_aio_readv/writev/flush()
67
Merge remote-tracking branch 'mreitz/tags/pull-block-2017-06-23' into queue-block
68
26
69
Manos Pitsidianakis (1):
27
Kevin Wolf (12):
70
block: change variable names in BlockDriverState
28
block: Add flags to BlockDriver.bdrv_co_truncate()
29
block: Add flags to bdrv(_co)_truncate()
30
block-backend: Add flags to blk_truncate()
31
qcow2: Support BDRV_REQ_ZERO_WRITE for truncate
32
raw-format: Support BDRV_REQ_ZERO_WRITE for truncate
33
file-posix: Support BDRV_REQ_ZERO_WRITE for truncate
34
block: truncate: Don't make backing file data visible
35
iotests: Filter testfiles out in filter_img_info()
36
iotests: Test committing to short backing file
37
qcow2: Forward ZERO_WRITE flag for full preallocation
38
qom: Factor out user_creatable_add_dict()
39
qemu-storage-daemon: Fix non-string --object properties
71
40
72
Max Reitz (3):
41
Paolo Bonzini (1):
73
blkdebug: Catch bs->exact_filename overflow
42
qemu-iotests: allow qcow2 external discarded clusters to contain stale data
74
blkverify: Catch bs->exact_filename overflow
75
block: Do not strcmp() with NULL uri->scheme
76
43
77
Stefan Hajnoczi (10):
44
docs/interop/qcow2.txt | 3 +
78
block: count bdrv_co_rw_vmstate() requests
45
hw/block/nvme.h | 2 +
79
block: use BDRV_POLL_WHILE() in bdrv_rw_vmstate()
46
include/block/block.h | 5 +-
80
migration: avoid recursive AioContext locking in save_vmstate()
47
include/block/block_int.h | 10 +-
81
migration: use bdrv_drain_all_begin/end() instead bdrv_drain_all()
48
include/block/nvme.h | 172 ++++++++++++++++++++++++++
82
virtio-pci: use ioeventfd even when KVM is disabled
49
include/qom/object_interfaces.h | 16 +++
83
migration: hold AioContext lock for loadvm qemu_fclose()
50
include/sysemu/block-backend.h | 2 +-
84
qemu-iotests: 068: extract _qemu() function
51
block.c | 3 +-
85
qemu-iotests: 068: use -drive/-device instead of -hda
52
block/block-backend.c | 4 +-
86
qemu-iotests: 068: test iothread mode
53
block/commit.c | 4 +-
87
qemu-img: don't shadow opts variable in img_dd()
54
block/crypto.c | 7 +-
55
block/file-posix.c | 6 +-
56
block/file-win32.c | 2 +-
57
block/gluster.c | 1 +
58
block/io.c | 43 ++++++-
59
block/iscsi.c | 2 +-
60
block/mirror.c | 2 +-
61
block/nfs.c | 3 +-
62
block/parallels.c | 6 +-
63
block/qcow.c | 4 +-
64
block/qcow2-cluster.c | 2 +-
65
block/qcow2-refcount.c | 2 +-
66
block/qcow2.c | 73 +++++++++--
67
block/qed.c | 3 +-
68
block/raw-format.c | 6 +-
69
block/rbd.c | 1 +
70
block/sheepdog.c | 4 +-
71
block/ssh.c | 2 +-
72
block/vdi.c | 2 +-
73
block/vhdx-log.c | 2 +-
74
block/vhdx.c | 6 +-
75
block/vmdk.c | 8 +-
76
block/vpc.c | 2 +-
77
blockdev.c | 2 +-
78
hw/block/nvme.c | 109 ++++++++++++++++
79
qemu-img.c | 2 +-
80
qemu-io-cmds.c | 2 +-
81
qemu-storage-daemon.c | 4 +-
82
qom/object_interfaces.c | 31 +++++
83
qom/qom-qmp-cmds.c | 24 +---
84
tests/test-block-iothread.c | 9 +-
85
tests/qemu-iotests/iotests.py | 5 +-
86
hw/block/Makefile.objs | 2 +-
87
hw/block/trace-events | 4 +
88
tests/qemu-iotests/244 | 10 +-
89
tests/qemu-iotests/244.out | 9 +-
90
tests/qemu-iotests/274 | 155 +++++++++++++++++++++++
91
tests/qemu-iotests/274.out | 268 ++++++++++++++++++++++++++++++++++++++++
92
tests/qemu-iotests/group | 1 +
93
49 files changed, 951 insertions(+), 96 deletions(-)
94
create mode 100755 tests/qemu-iotests/274
95
create mode 100644 tests/qemu-iotests/274.out
88
96
89
Stephen Bates (1):
90
nvme: Add support for Read Data and Write Data in CMBs.
91
97
92
sochin.jiang (1):
93
fix: avoid an infinite loop or a dangling pointer problem in img_commit
94
95
block/Makefile.objs | 2 +-
96
block/blkdebug.c | 46 +--
97
block/blkreplay.c | 8 +-
98
block/blkverify.c | 12 +-
99
block/block-backend.c | 22 +-
100
block/commit.c | 7 +
101
block/file-posix.c | 34 +-
102
block/io.c | 240 ++-----------
103
block/iscsi.c | 20 +-
104
block/mirror.c | 8 +-
105
block/nbd-client.c | 8 +-
106
block/nbd-client.h | 4 +-
107
block/nbd.c | 6 +-
108
block/nfs.c | 2 +-
109
block/qcow2-cluster.c | 201 ++++++++---
110
block/qcow2.c | 94 +++--
111
block/qcow2.h | 11 +-
112
block/qed-cluster.c | 124 +++----
113
block/qed-gencb.c | 33 --
114
block/qed-table.c | 261 +++++---------
115
block/qed.c | 779 ++++++++++++++++-------------------------
116
block/qed.h | 54 +--
117
block/raw-format.c | 8 +-
118
block/rbd.c | 4 +-
119
block/sheepdog.c | 12 +-
120
block/ssh.c | 2 +-
121
block/throttle-groups.c | 2 +-
122
block/trace-events | 3 -
123
blockjob.c | 4 +-
124
hw/block/nvme.c | 83 +++--
125
hw/block/nvme.h | 1 +
126
hw/virtio/virtio-pci.c | 2 +-
127
include/block/block.h | 16 +-
128
include/block/block_int.h | 6 +-
129
include/block/blockjob.h | 18 +
130
include/sysemu/block-backend.h | 20 +-
131
migration/savevm.c | 32 +-
132
qemu-img.c | 29 +-
133
qemu-io-cmds.c | 46 +--
134
qemu-options.hx | 221 ++++++++++--
135
tests/qemu-iotests/068 | 37 +-
136
tests/qemu-iotests/068.out | 11 +-
137
tests/qemu-iotests/185 | 206 +++++++++++
138
tests/qemu-iotests/185.out | 59 ++++
139
tests/qemu-iotests/common.qemu | 3 +
140
tests/qemu-iotests/group | 1 +
141
46 files changed, 1477 insertions(+), 1325 deletions(-)
142
delete mode 100644 block/qed-gencb.c
143
create mode 100755 tests/qemu-iotests/185
144
create mode 100644 tests/qemu-iotests/185.out
145
diff view generated by jsdifflib
Deleted patch
1
commit_complete() can't assume that after its block_job_completed() the
2
job is actually immediately freed; someone else may still be holding
3
references. In this case, the op blockers on the intermediate nodes make
4
the graph reconfiguration in the completion code fail.
5
1
6
Call block_job_remove_all_bdrv() manually so that we know for sure that
7
any blockers on intermediate nodes are given up.
8
9
Cc: qemu-stable@nongnu.org
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Reviewed-by: Max Reitz <mreitz@redhat.com>
13
---
14
block/commit.c | 7 +++++++
15
1 file changed, 7 insertions(+)
16
17
diff --git a/block/commit.c b/block/commit.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/block/commit.c
20
+++ b/block/commit.c
21
@@ -XXX,XX +XXX,XX @@ static void commit_complete(BlockJob *job, void *opaque)
22
}
23
g_free(s->backing_file_str);
24
blk_unref(s->top);
25
+
26
+ /* If there is more than one reference to the job (e.g. if called from
27
+ * block_job_finish_sync()), block_job_completed() won't free it and
28
+ * therefore the blockers on the intermediate nodes remain. This would
29
+ * cause bdrv_set_backing_hd() to fail. */
30
+ block_job_remove_all_bdrv(job);
31
+
32
block_job_completed(&s->common, ret);
33
g_free(data);
34
35
--
36
1.8.3.1
37
38
diff view generated by jsdifflib
Deleted patch
1
After _cleanup_qemu(), test cases should be able to start the next qemu
2
process and call _cleanup_qemu() for that one as well. For this to work
3
cleanly, we need to improve the cleanup so that the second invocation
4
doesn't try to kill the qemu instances from the first invocation a
5
second time (which would result in error messages).
6
1
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
---
11
tests/qemu-iotests/common.qemu | 3 +++
12
1 file changed, 3 insertions(+)
13
14
diff --git a/tests/qemu-iotests/common.qemu b/tests/qemu-iotests/common.qemu
15
index XXXXXXX..XXXXXXX 100644
16
--- a/tests/qemu-iotests/common.qemu
17
+++ b/tests/qemu-iotests/common.qemu
18
@@ -XXX,XX +XXX,XX @@ function _cleanup_qemu()
19
rm -f "${QEMU_FIFO_IN}_${i}" "${QEMU_FIFO_OUT}_${i}"
20
eval "exec ${QEMU_IN[$i]}<&-" # close file descriptors
21
eval "exec ${QEMU_OUT[$i]}<&-"
22
+
23
+ unset QEMU_IN[$i]
24
+ unset QEMU_OUT[$i]
25
done
26
}
27
--
28
1.8.3.1
29
30
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
There used to be throttle_timers_{detach,attach}_aio_context() calls
3
Backing files and raw external data files are mutually exclusive.
4
in bdrv_set_aio_context(), but since 7ca7f0f6db1fedd28d490795d778cf239
4
The documentation of the raw external data bit (in autoclear_features)
5
they are now in blk_set_aio_context().
5
already indicates that, but we should also mention it on the other
6
side.
6
7
8
Suggested-by: Eric Blake <eblake@redhat.com>
7
Signed-off-by: Alberto Garcia <berto@igalia.com>
9
Signed-off-by: Alberto Garcia <berto@igalia.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Message-Id: <20200410121816.8334-1-berto@igalia.com>
11
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
13
---
11
block/throttle-groups.c | 2 +-
14
docs/interop/qcow2.txt | 3 +++
12
1 file changed, 1 insertion(+), 1 deletion(-)
15
1 file changed, 3 insertions(+)
13
16
14
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
17
diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt
15
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
16
--- a/block/throttle-groups.c
19
--- a/docs/interop/qcow2.txt
17
+++ b/block/throttle-groups.c
20
+++ b/docs/interop/qcow2.txt
18
@@ -XXX,XX +XXX,XX @@
21
@@ -XXX,XX +XXX,XX @@ The first cluster of a qcow2 image contains the file header:
19
* Again, all this is handled internally and is mostly transparent to
22
is stored (NB: The string is not null terminated). 0 if the
20
* the outside. The 'throttle_timers' field however has an additional
23
image doesn't have a backing file.
21
* constraint because it may be temporarily invalid (see for example
24
22
- * bdrv_set_aio_context()). Therefore in this file a thread will
25
+ Note: backing files are incompatible with raw external data
23
+ * blk_set_aio_context()). Therefore in this file a thread will
26
+ files (auto-clear feature bit 1).
24
* access some other BlockBackend's timers only after verifying that
27
+
25
* that BlockBackend has throttled requests in the queue.
28
16 - 19: backing_file_size
26
*/
29
Length of the backing file name in bytes. Must not be
30
longer than 1023 bytes. Undefined if the image doesn't have
27
--
31
--
28
1.8.3.1
32
2.25.3
29
33
30
34
diff view generated by jsdifflib
1
From: Stefan Hajnoczi <stefanha@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
blk/bdrv_drain_all() only takes effect for a single instant and then
3
Test 244 checks the expected behavior of qcow2 external data files
4
resumes block jobs, guest devices, and other external clients like the
4
with respect to zero and discarded clusters. Filesystems however
5
NBD server. This can be handy when performing a synchronous drain
5
are free to ignore discard requests, and this seems to be the
6
before terminating the program, for example.
6
case for overlayfs. Relax the tests to skip checks on the
7
external data file for discarded areas, which implies not using
8
qemu-img compare in the data_file_raw=on case.
7
9
8
Monitor commands usually need to quiesce I/O across an entire code
10
This fixes docker tests on RHEL8.
9
region so blk/bdrv_drain_all() is not suitable. They must use
10
bdrv_drain_all_begin/end() to mark the region. This prevents new I/O
11
requests from slipping in or worse - block jobs completing and modifying
12
the graph.
13
11
14
I audited other blk/bdrv_drain_all() callers but did not find anything
12
Cc: Kevin Wolf <kwolf@redhat.com>
15
that needs a similar fix. This patch fixes the savevm/loadvm commands.
13
Cc: qemu-block@nongnu.org
16
Although I haven't encountered a read world issue this makes the code
14
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
17
safer.
15
Message-Id: <20200409191006.24429-1-pbonzini@redhat.com>
18
19
Suggested-by: Kevin Wolf <kwolf@redhat.com>
20
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
21
Reviewed-by: Eric Blake <eblake@redhat.com>
22
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
23
---
17
---
24
migration/savevm.c | 18 +++++++++++++++---
18
tests/qemu-iotests/244 | 10 ++++++++--
25
1 file changed, 15 insertions(+), 3 deletions(-)
19
tests/qemu-iotests/244.out | 9 ++++++---
20
2 files changed, 14 insertions(+), 5 deletions(-)
26
21
27
diff --git a/migration/savevm.c b/migration/savevm.c
22
diff --git a/tests/qemu-iotests/244 b/tests/qemu-iotests/244
23
index XXXXXXX..XXXXXXX 100755
24
--- a/tests/qemu-iotests/244
25
+++ b/tests/qemu-iotests/244
26
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c 'read -P 0 0 1M' \
27
echo
28
$QEMU_IO -c 'read -P 0 0 1M' \
29
-c 'read -P 0x11 1M 1M' \
30
- -c 'read -P 0 2M 2M' \
31
-c 'read -P 0x11 4M 1M' \
32
-c 'read -P 0 5M 1M' \
33
-f raw "$TEST_IMG.data" |
34
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c 'read -P 0 0 1M' \
35
-f $IMGFMT "$TEST_IMG" |
36
_filter_qemu_io
37
38
+# Discarded clusters are only marked as such in the qcow2 metadata, but
39
+# they can contain stale data in the external data file. Instead, zero
40
+# clusters must be zeroed in the external data file too.
41
echo
42
-$QEMU_IMG compare "$TEST_IMG" "$TEST_IMG.data"
43
+$QEMU_IO -c 'read -P 0 0 1M' \
44
+ -c 'read -P 0x11 1M 1M' \
45
+ -c 'read -P 0 3M 3M' \
46
+ -f raw "$TEST_IMG".data |
47
+ _filter_qemu_io
48
49
echo -n "qcow2 file size after I/O: "
50
du -b $TEST_IMG | cut -f1
51
diff --git a/tests/qemu-iotests/244.out b/tests/qemu-iotests/244.out
28
index XXXXXXX..XXXXXXX 100644
52
index XXXXXXX..XXXXXXX 100644
29
--- a/migration/savevm.c
53
--- a/tests/qemu-iotests/244.out
30
+++ b/migration/savevm.c
54
+++ b/tests/qemu-iotests/244.out
31
@@ -XXX,XX +XXX,XX @@ int save_snapshot(const char *name, Error **errp)
55
@@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 0
32
}
56
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
33
vm_stop(RUN_STATE_SAVE_VM);
57
read 1048576/1048576 bytes at offset 1048576
34
58
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
35
+ bdrv_drain_all_begin();
59
-read 2097152/2097152 bytes at offset 2097152
36
+
60
-2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
37
aio_context_acquire(aio_context);
61
read 1048576/1048576 bytes at offset 4194304
38
62
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
39
memset(sn, 0, sizeof(*sn));
63
read 1048576/1048576 bytes at offset 5242880
40
@@ -XXX,XX +XXX,XX @@ int save_snapshot(const char *name, Error **errp)
64
@@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 1048576
41
if (aio_context) {
65
read 4194304/4194304 bytes at offset 2097152
42
aio_context_release(aio_context);
66
4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
43
}
67
44
+
68
-Images are identical.
45
+ bdrv_drain_all_end();
69
+read 1048576/1048576 bytes at offset 0
46
+
70
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
47
if (saved_vm_running) {
71
+read 1048576/1048576 bytes at offset 1048576
48
vm_start();
72
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
49
}
73
+read 3145728/3145728 bytes at offset 3145728
50
@@ -XXX,XX +XXX,XX @@ int load_snapshot(const char *name, Error **errp)
74
+3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
51
}
75
qcow2 file size after I/O: 327680
52
76
53
/* Flush all IO requests so they don't interfere with the new state. */
77
=== bdrv_co_block_status test for file and offset=0 ===
54
- bdrv_drain_all();
55
+ bdrv_drain_all_begin();
56
57
ret = bdrv_all_goto_snapshot(name, &bs);
58
if (ret < 0) {
59
error_setg(errp, "Error %d while activating snapshot '%s' on '%s'",
60
ret, name, bdrv_get_device_name(bs));
61
- return ret;
62
+ goto err_drain;
63
}
64
65
/* restore the VM state */
66
f = qemu_fopen_bdrv(bs_vm_state, 0);
67
if (!f) {
68
error_setg(errp, "Could not open VM state file");
69
- return -EINVAL;
70
+ ret = -EINVAL;
71
+ goto err_drain;
72
}
73
74
qemu_system_reset(SHUTDOWN_CAUSE_NONE);
75
@@ -XXX,XX +XXX,XX @@ int load_snapshot(const char *name, Error **errp)
76
ret = qemu_loadvm_state(f);
77
aio_context_release(aio_context);
78
79
+ bdrv_drain_all_end();
80
+
81
migration_incoming_state_destroy();
82
if (ret < 0) {
83
error_setg(errp, "Error %d while loading VM state", ret);
84
@@ -XXX,XX +XXX,XX @@ int load_snapshot(const char *name, Error **errp)
85
}
86
87
return 0;
88
+
89
+err_drain:
90
+ bdrv_drain_all_end();
91
+ return ret;
92
}
93
94
void vmstate_register_ram(MemoryRegion *mr, DeviceState *dev)
95
--
78
--
96
1.8.3.1
79
2.25.3
97
80
98
81
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
This adds a new BdrvRequestFlags parameter to the .bdrv_co_truncate()
2
2
driver callbacks, and a supported_truncate_flags field in
3
uri_parse(...)->scheme may be NULL. In fact, probably every field may be
3
BlockDriverState that allows drivers to advertise support for request
4
NULL, and the callers do test this for all of the other fields but not
4
flags in the context of truncate.
5
for scheme (except for block/gluster.c; block/vxhs.c does not access
5
6
that field at all).
6
For now, we always pass 0 and no drivers declare support for any flag.
7
7
8
We can easily fix this by using g_strcmp0() instead of strcmp().
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
9
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10
Cc: qemu-stable@nongnu.org
10
Reviewed-by: Alberto Garcia <berto@igalia.com>
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
Reviewed-by: Max Reitz <mreitz@redhat.com>
12
Message-id: 20170613205726.13544-1-mreitz@redhat.com
12
Message-Id: <20200424125448.63318-2-kwolf@redhat.com>
13
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
---
14
---
16
block/nbd.c | 6 +++---
15
include/block/block_int.h | 10 +++++++++-
17
block/nfs.c | 2 +-
16
block/crypto.c | 3 ++-
18
block/sheepdog.c | 6 +++---
17
block/file-posix.c | 2 +-
19
block/ssh.c | 2 +-
18
block/file-win32.c | 2 +-
20
4 files changed, 8 insertions(+), 8 deletions(-)
19
block/gluster.c | 1 +
21
20
block/io.c | 8 +++++++-
22
diff --git a/block/nbd.c b/block/nbd.c
21
block/iscsi.c | 2 +-
23
index XXXXXXX..XXXXXXX 100644
22
block/nfs.c | 3 ++-
24
--- a/block/nbd.c
23
block/qcow2.c | 2 +-
25
+++ b/block/nbd.c
24
block/qed.c | 1 +
26
@@ -XXX,XX +XXX,XX @@ static int nbd_parse_uri(const char *filename, QDict *options)
25
block/raw-format.c | 2 +-
26
block/rbd.c | 1 +
27
block/sheepdog.c | 4 ++--
28
block/ssh.c | 2 +-
29
tests/test-block-iothread.c | 3 ++-
30
15 files changed, 33 insertions(+), 13 deletions(-)
31
32
diff --git a/include/block/block_int.h b/include/block/block_int.h
33
index XXXXXXX..XXXXXXX 100644
34
--- a/include/block/block_int.h
35
+++ b/include/block/block_int.h
36
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
37
*/
38
int coroutine_fn (*bdrv_co_truncate)(BlockDriverState *bs, int64_t offset,
39
bool exact, PreallocMode prealloc,
40
- Error **errp);
41
+ BdrvRequestFlags flags, Error **errp);
42
43
int64_t (*bdrv_getlength)(BlockDriverState *bs);
44
bool has_variable_length;
45
@@ -XXX,XX +XXX,XX @@ struct BlockDriverState {
46
/* Flags honored during pwrite_zeroes (so far: BDRV_REQ_FUA,
47
* BDRV_REQ_MAY_UNMAP, BDRV_REQ_WRITE_UNCHANGED) */
48
unsigned int supported_zero_flags;
49
+ /*
50
+ * Flags honoured during truncate (so far: BDRV_REQ_ZERO_WRITE).
51
+ *
52
+ * If BDRV_REQ_ZERO_WRITE is given, the truncate operation must make sure
53
+ * that any added space reads as all zeros. If this can't be guaranteed,
54
+ * the operation must fail.
55
+ */
56
+ unsigned int supported_truncate_flags;
57
58
/* the following member gives a name to every node on the bs graph. */
59
char node_name[32];
60
diff --git a/block/crypto.c b/block/crypto.c
61
index XXXXXXX..XXXXXXX 100644
62
--- a/block/crypto.c
63
+++ b/block/crypto.c
64
@@ -XXX,XX +XXX,XX @@ static int block_crypto_co_create_generic(BlockDriverState *bs,
65
66
static int coroutine_fn
67
block_crypto_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
68
- PreallocMode prealloc, Error **errp)
69
+ PreallocMode prealloc, BdrvRequestFlags flags,
70
+ Error **errp)
71
{
72
BlockCrypto *crypto = bs->opaque;
73
uint64_t payload_offset =
74
diff --git a/block/file-posix.c b/block/file-posix.c
75
index XXXXXXX..XXXXXXX 100644
76
--- a/block/file-posix.c
77
+++ b/block/file-posix.c
78
@@ -XXX,XX +XXX,XX @@ raw_regular_truncate(BlockDriverState *bs, int fd, int64_t offset,
79
80
static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
81
bool exact, PreallocMode prealloc,
82
- Error **errp)
83
+ BdrvRequestFlags flags, Error **errp)
84
{
85
BDRVRawState *s = bs->opaque;
86
struct stat st;
87
diff --git a/block/file-win32.c b/block/file-win32.c
88
index XXXXXXX..XXXXXXX 100644
89
--- a/block/file-win32.c
90
+++ b/block/file-win32.c
91
@@ -XXX,XX +XXX,XX @@ static void raw_close(BlockDriverState *bs)
92
93
static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
94
bool exact, PreallocMode prealloc,
95
- Error **errp)
96
+ BdrvRequestFlags flags, Error **errp)
97
{
98
BDRVRawState *s = bs->opaque;
99
LONG low, high;
100
diff --git a/block/gluster.c b/block/gluster.c
101
index XXXXXXX..XXXXXXX 100644
102
--- a/block/gluster.c
103
+++ b/block/gluster.c
104
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qemu_gluster_co_truncate(BlockDriverState *bs,
105
int64_t offset,
106
bool exact,
107
PreallocMode prealloc,
108
+ BdrvRequestFlags flags,
109
Error **errp)
110
{
111
BDRVGlusterState *s = bs->opaque;
112
diff --git a/block/io.c b/block/io.c
113
index XXXXXXX..XXXXXXX 100644
114
--- a/block/io.c
115
+++ b/block/io.c
116
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
117
BlockDriverState *bs = child->bs;
118
BlockDriver *drv = bs->drv;
119
BdrvTrackedRequest req;
120
+ BdrvRequestFlags flags = 0;
121
int64_t old_size, new_bytes;
122
int ret;
123
124
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
27
}
125
}
28
126
29
/* transport */
127
if (drv->bdrv_co_truncate) {
30
- if (!strcmp(uri->scheme, "nbd")) {
128
- ret = drv->bdrv_co_truncate(bs, offset, exact, prealloc, errp);
31
+ if (!g_strcmp0(uri->scheme, "nbd")) {
129
+ if (flags & ~bs->supported_truncate_flags) {
32
is_unix = false;
130
+ error_setg(errp, "Block driver does not support requested flags");
33
- } else if (!strcmp(uri->scheme, "nbd+tcp")) {
131
+ ret = -ENOTSUP;
34
+ } else if (!g_strcmp0(uri->scheme, "nbd+tcp")) {
132
+ goto out;
35
is_unix = false;
133
+ }
36
- } else if (!strcmp(uri->scheme, "nbd+unix")) {
134
+ ret = drv->bdrv_co_truncate(bs, offset, exact, prealloc, flags, errp);
37
+ } else if (!g_strcmp0(uri->scheme, "nbd+unix")) {
135
} else if (bs->file && drv->is_filter) {
38
is_unix = true;
136
ret = bdrv_co_truncate(bs->file, offset, exact, prealloc, errp);
39
} else {
137
} else {
40
ret = -EINVAL;
138
diff --git a/block/iscsi.c b/block/iscsi.c
139
index XXXXXXX..XXXXXXX 100644
140
--- a/block/iscsi.c
141
+++ b/block/iscsi.c
142
@@ -XXX,XX +XXX,XX @@ static void iscsi_reopen_commit(BDRVReopenState *reopen_state)
143
144
static int coroutine_fn iscsi_co_truncate(BlockDriverState *bs, int64_t offset,
145
bool exact, PreallocMode prealloc,
146
- Error **errp)
147
+ BdrvRequestFlags flags, Error **errp)
148
{
149
IscsiLun *iscsilun = bs->opaque;
150
int64_t cur_length;
41
diff --git a/block/nfs.c b/block/nfs.c
151
diff --git a/block/nfs.c b/block/nfs.c
42
index XXXXXXX..XXXXXXX 100644
152
index XXXXXXX..XXXXXXX 100644
43
--- a/block/nfs.c
153
--- a/block/nfs.c
44
+++ b/block/nfs.c
154
+++ b/block/nfs.c
45
@@ -XXX,XX +XXX,XX @@ static int nfs_parse_uri(const char *filename, QDict *options, Error **errp)
155
@@ -XXX,XX +XXX,XX @@ static int64_t nfs_get_allocated_file_size(BlockDriverState *bs)
46
error_setg(errp, "Invalid URI specified");
156
47
goto out;
157
static int coroutine_fn
48
}
158
nfs_file_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
49
- if (strcmp(uri->scheme, "nfs") != 0) {
159
- PreallocMode prealloc, Error **errp)
50
+ if (g_strcmp0(uri->scheme, "nfs") != 0) {
160
+ PreallocMode prealloc, BdrvRequestFlags flags,
51
error_setg(errp, "URI scheme must be 'nfs'");
161
+ Error **errp)
52
goto out;
162
{
53
}
163
NFSClient *client = bs->opaque;
164
int ret;
165
diff --git a/block/qcow2.c b/block/qcow2.c
166
index XXXXXXX..XXXXXXX 100644
167
--- a/block/qcow2.c
168
+++ b/block/qcow2.c
169
@@ -XXX,XX +XXX,XX @@ fail:
170
171
static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
172
bool exact, PreallocMode prealloc,
173
- Error **errp)
174
+ BdrvRequestFlags flags, Error **errp)
175
{
176
BDRVQcow2State *s = bs->opaque;
177
uint64_t old_length;
178
diff --git a/block/qed.c b/block/qed.c
179
index XXXXXXX..XXXXXXX 100644
180
--- a/block/qed.c
181
+++ b/block/qed.c
182
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_truncate(BlockDriverState *bs,
183
int64_t offset,
184
bool exact,
185
PreallocMode prealloc,
186
+ BdrvRequestFlags flags,
187
Error **errp)
188
{
189
BDRVQEDState *s = bs->opaque;
190
diff --git a/block/raw-format.c b/block/raw-format.c
191
index XXXXXXX..XXXXXXX 100644
192
--- a/block/raw-format.c
193
+++ b/block/raw-format.c
194
@@ -XXX,XX +XXX,XX @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
195
196
static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
197
bool exact, PreallocMode prealloc,
198
- Error **errp)
199
+ BdrvRequestFlags flags, Error **errp)
200
{
201
BDRVRawState *s = bs->opaque;
202
203
diff --git a/block/rbd.c b/block/rbd.c
204
index XXXXXXX..XXXXXXX 100644
205
--- a/block/rbd.c
206
+++ b/block/rbd.c
207
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qemu_rbd_co_truncate(BlockDriverState *bs,
208
int64_t offset,
209
bool exact,
210
PreallocMode prealloc,
211
+ BdrvRequestFlags flags,
212
Error **errp)
213
{
214
int r;
54
diff --git a/block/sheepdog.c b/block/sheepdog.c
215
diff --git a/block/sheepdog.c b/block/sheepdog.c
55
index XXXXXXX..XXXXXXX 100644
216
index XXXXXXX..XXXXXXX 100644
56
--- a/block/sheepdog.c
217
--- a/block/sheepdog.c
57
+++ b/block/sheepdog.c
218
+++ b/block/sheepdog.c
58
@@ -XXX,XX +XXX,XX @@ static void sd_parse_uri(SheepdogConfig *cfg, const char *filename,
219
@@ -XXX,XX +XXX,XX @@ static int64_t sd_getlength(BlockDriverState *bs)
59
}
220
60
221
static int coroutine_fn sd_co_truncate(BlockDriverState *bs, int64_t offset,
61
/* transport */
222
bool exact, PreallocMode prealloc,
62
- if (!strcmp(uri->scheme, "sheepdog")) {
223
- Error **errp)
63
+ if (!g_strcmp0(uri->scheme, "sheepdog")) {
224
+ BdrvRequestFlags flags, Error **errp)
64
is_unix = false;
225
{
65
- } else if (!strcmp(uri->scheme, "sheepdog+tcp")) {
226
BDRVSheepdogState *s = bs->opaque;
66
+ } else if (!g_strcmp0(uri->scheme, "sheepdog+tcp")) {
227
int ret, fd;
67
is_unix = false;
228
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num,
68
- } else if (!strcmp(uri->scheme, "sheepdog+unix")) {
229
69
+ } else if (!g_strcmp0(uri->scheme, "sheepdog+unix")) {
230
assert(!flags);
70
is_unix = true;
231
if (offset > s->inode.vdi_size) {
71
} else {
232
- ret = sd_co_truncate(bs, offset, false, PREALLOC_MODE_OFF, NULL);
72
error_setg(&err, "URI scheme must be 'sheepdog', 'sheepdog+tcp',"
233
+ ret = sd_co_truncate(bs, offset, false, PREALLOC_MODE_OFF, 0, NULL);
234
if (ret < 0) {
235
return ret;
236
}
73
diff --git a/block/ssh.c b/block/ssh.c
237
diff --git a/block/ssh.c b/block/ssh.c
74
index XXXXXXX..XXXXXXX 100644
238
index XXXXXXX..XXXXXXX 100644
75
--- a/block/ssh.c
239
--- a/block/ssh.c
76
+++ b/block/ssh.c
240
+++ b/block/ssh.c
77
@@ -XXX,XX +XXX,XX @@ static int parse_uri(const char *filename, QDict *options, Error **errp)
241
@@ -XXX,XX +XXX,XX @@ static int64_t ssh_getlength(BlockDriverState *bs)
78
return -EINVAL;
242
79
}
243
static int coroutine_fn ssh_co_truncate(BlockDriverState *bs, int64_t offset,
80
244
bool exact, PreallocMode prealloc,
81
- if (strcmp(uri->scheme, "ssh") != 0) {
245
- Error **errp)
82
+ if (g_strcmp0(uri->scheme, "ssh") != 0) {
246
+ BdrvRequestFlags flags, Error **errp)
83
error_setg(errp, "URI scheme must be 'ssh'");
247
{
84
goto err;
248
BDRVSSHState *s = bs->opaque;
85
}
249
250
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
251
index XXXXXXX..XXXXXXX 100644
252
--- a/tests/test-block-iothread.c
253
+++ b/tests/test-block-iothread.c
254
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_test_co_pdiscard(BlockDriverState *bs,
255
256
static int coroutine_fn
257
bdrv_test_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
258
- PreallocMode prealloc, Error **errp)
259
+ PreallocMode prealloc, BdrvRequestFlags flags,
260
+ Error **errp)
261
{
262
return 0;
263
}
86
--
264
--
87
1.8.3.1
265
2.25.3
88
266
89
267
diff view generated by jsdifflib
1
Now that we're running in coroutine context, the ad-hoc serialisation
1
Now that block drivers can support flags for .bdrv_co_truncate, expose
2
code (which drops a request that has to wait out of coroutine context)
2
the parameter in the node level interfaces bdrv_co_truncate() and
3
can be replaced by a CoQueue.
3
bdrv_truncate().
4
5
This means that when we resume a serialised request, it is running in
6
coroutine context again and its I/O isn't blocking any more.
7
4
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
6
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Reviewed-by: Alberto Garcia <berto@igalia.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Message-Id: <20200424125448.63318-3-kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
---
11
block/qed.c | 49 +++++++++++++++++--------------------------------
12
include/block/block.h | 5 +++--
12
block/qed.h | 3 ++-
13
block/block-backend.c | 2 +-
13
2 files changed, 19 insertions(+), 33 deletions(-)
14
block/crypto.c | 2 +-
15
block/io.c | 12 +++++++-----
16
block/parallels.c | 6 +++---
17
block/qcow.c | 4 ++--
18
block/qcow2-refcount.c | 2 +-
19
block/qcow2.c | 15 +++++++++------
20
block/raw-format.c | 2 +-
21
block/vhdx-log.c | 2 +-
22
block/vhdx.c | 2 +-
23
block/vmdk.c | 2 +-
24
tests/test-block-iothread.c | 6 +++---
25
13 files changed, 34 insertions(+), 28 deletions(-)
14
26
15
diff --git a/block/qed.c b/block/qed.c
27
diff --git a/include/block/block.h b/include/block/block.h
16
index XXXXXXX..XXXXXXX 100644
28
index XXXXXXX..XXXXXXX 100644
17
--- a/block/qed.c
29
--- a/include/block/block.h
18
+++ b/block/qed.c
30
+++ b/include/block/block.h
19
@@ -XXX,XX +XXX,XX @@ static void qed_plug_allocating_write_reqs(BDRVQEDState *s)
31
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
20
32
void bdrv_refresh_filename(BlockDriverState *bs);
21
static void qed_unplug_allocating_write_reqs(BDRVQEDState *s)
33
34
int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
35
- PreallocMode prealloc, Error **errp);
36
+ PreallocMode prealloc, BdrvRequestFlags flags,
37
+ Error **errp);
38
int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
39
- PreallocMode prealloc, Error **errp);
40
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp);
41
42
int64_t bdrv_nb_sectors(BlockDriverState *bs);
43
int64_t bdrv_getlength(BlockDriverState *bs);
44
diff --git a/block/block-backend.c b/block/block-backend.c
45
index XXXXXXX..XXXXXXX 100644
46
--- a/block/block-backend.c
47
+++ b/block/block-backend.c
48
@@ -XXX,XX +XXX,XX @@ int blk_truncate(BlockBackend *blk, int64_t offset, bool exact,
49
return -ENOMEDIUM;
50
}
51
52
- return bdrv_truncate(blk->root, offset, exact, prealloc, errp);
53
+ return bdrv_truncate(blk->root, offset, exact, prealloc, 0, errp);
54
}
55
56
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
57
diff --git a/block/crypto.c b/block/crypto.c
58
index XXXXXXX..XXXXXXX 100644
59
--- a/block/crypto.c
60
+++ b/block/crypto.c
61
@@ -XXX,XX +XXX,XX @@ block_crypto_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
62
63
offset += payload_offset;
64
65
- return bdrv_co_truncate(bs->file, offset, exact, prealloc, errp);
66
+ return bdrv_co_truncate(bs->file, offset, exact, prealloc, 0, errp);
67
}
68
69
static void block_crypto_close(BlockDriverState *bs)
70
diff --git a/block/io.c b/block/io.c
71
index XXXXXXX..XXXXXXX 100644
72
--- a/block/io.c
73
+++ b/block/io.c
74
@@ -XXX,XX +XXX,XX @@ static void bdrv_parent_cb_resize(BlockDriverState *bs)
75
* 'offset' bytes in length.
76
*/
77
int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
78
- PreallocMode prealloc, Error **errp)
79
+ PreallocMode prealloc, BdrvRequestFlags flags,
80
+ Error **errp)
22
{
81
{
23
- QEDAIOCB *acb;
82
BlockDriverState *bs = child->bs;
24
-
83
BlockDriver *drv = bs->drv;
25
assert(s->allocating_write_reqs_plugged);
84
BdrvTrackedRequest req;
26
85
- BdrvRequestFlags flags = 0;
27
s->allocating_write_reqs_plugged = false;
86
int64_t old_size, new_bytes;
28
-
29
- acb = QSIMPLEQ_FIRST(&s->allocating_write_reqs);
30
- if (acb) {
31
- qed_aio_start_io(acb);
32
- }
33
+ qemu_co_enter_next(&s->allocating_write_reqs);
34
}
35
36
static void qed_clear_need_check(void *opaque, int ret)
37
@@ -XXX,XX +XXX,XX @@ static void qed_need_check_timer_cb(void *opaque)
38
BDRVQEDState *s = opaque;
39
40
/* The timer should only fire when allocating writes have drained */
41
- assert(!QSIMPLEQ_FIRST(&s->allocating_write_reqs));
42
+ assert(!s->allocating_acb);
43
44
trace_qed_need_check_timer_cb(s);
45
46
@@ -XXX,XX +XXX,XX @@ static int bdrv_qed_do_open(BlockDriverState *bs, QDict *options, int flags,
47
int ret;
87
int ret;
48
88
49
s->bs = bs;
89
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
50
- QSIMPLEQ_INIT(&s->allocating_write_reqs);
90
}
51
+ qemu_co_queue_init(&s->allocating_write_reqs);
91
ret = drv->bdrv_co_truncate(bs, offset, exact, prealloc, flags, errp);
52
92
} else if (bs->file && drv->is_filter) {
53
ret = bdrv_pread(bs->file, 0, &le_header, sizeof(le_header));
93
- ret = bdrv_co_truncate(bs->file, offset, exact, prealloc, errp);
94
+ ret = bdrv_co_truncate(bs->file, offset, exact, prealloc, flags, errp);
95
} else {
96
error_setg(errp, "Image format driver does not support resize");
97
ret = -ENOTSUP;
98
@@ -XXX,XX +XXX,XX @@ typedef struct TruncateCo {
99
int64_t offset;
100
bool exact;
101
PreallocMode prealloc;
102
+ BdrvRequestFlags flags;
103
Error **errp;
104
int ret;
105
} TruncateCo;
106
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_truncate_co_entry(void *opaque)
107
{
108
TruncateCo *tco = opaque;
109
tco->ret = bdrv_co_truncate(tco->child, tco->offset, tco->exact,
110
- tco->prealloc, tco->errp);
111
+ tco->prealloc, tco->flags, tco->errp);
112
aio_wait_kick();
113
}
114
115
int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
116
- PreallocMode prealloc, Error **errp)
117
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp)
118
{
119
Coroutine *co;
120
TruncateCo tco = {
121
@@ -XXX,XX +XXX,XX @@ int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
122
.offset = offset,
123
.exact = exact,
124
.prealloc = prealloc,
125
+ .flags = flags,
126
.errp = errp,
127
.ret = NOT_DONE,
128
};
129
diff --git a/block/parallels.c b/block/parallels.c
130
index XXXXXXX..XXXXXXX 100644
131
--- a/block/parallels.c
132
+++ b/block/parallels.c
133
@@ -XXX,XX +XXX,XX @@ static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num,
134
} else {
135
ret = bdrv_truncate(bs->file,
136
(s->data_end + space) << BDRV_SECTOR_BITS,
137
- false, PREALLOC_MODE_OFF, NULL);
138
+ false, PREALLOC_MODE_OFF, 0, NULL);
139
}
140
if (ret < 0) {
141
return ret;
142
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs,
143
* That means we have to pass exact=true.
144
*/
145
ret = bdrv_truncate(bs->file, res->image_end_offset, true,
146
- PREALLOC_MODE_OFF, &local_err);
147
+ PREALLOC_MODE_OFF, 0, &local_err);
148
if (ret < 0) {
149
error_report_err(local_err);
150
res->check_errors++;
151
@@ -XXX,XX +XXX,XX @@ static void parallels_close(BlockDriverState *bs)
152
153
/* errors are ignored, so we might as well pass exact=true */
154
bdrv_truncate(bs->file, s->data_end << BDRV_SECTOR_BITS, true,
155
- PREALLOC_MODE_OFF, NULL);
156
+ PREALLOC_MODE_OFF, 0, NULL);
157
}
158
159
g_free(s->bat_dirty_bmap);
160
diff --git a/block/qcow.c b/block/qcow.c
161
index XXXXXXX..XXXXXXX 100644
162
--- a/block/qcow.c
163
+++ b/block/qcow.c
164
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
165
return -E2BIG;
166
}
167
ret = bdrv_truncate(bs->file, cluster_offset + s->cluster_size,
168
- false, PREALLOC_MODE_OFF, NULL);
169
+ false, PREALLOC_MODE_OFF, 0, NULL);
170
if (ret < 0) {
171
return ret;
172
}
173
@@ -XXX,XX +XXX,XX @@ static int qcow_make_empty(BlockDriverState *bs)
174
l1_length) < 0)
175
return -1;
176
ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length, false,
177
- PREALLOC_MODE_OFF, NULL);
178
+ PREALLOC_MODE_OFF, 0, NULL);
179
if (ret < 0)
180
return ret;
181
182
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
183
index XXXXXXX..XXXXXXX 100644
184
--- a/block/qcow2-refcount.c
185
+++ b/block/qcow2-refcount.c
186
@@ -XXX,XX +XXX,XX @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
187
}
188
189
ret = bdrv_truncate(bs->file, offset + s->cluster_size, false,
190
- PREALLOC_MODE_OFF, &local_err);
191
+ PREALLOC_MODE_OFF, 0, &local_err);
192
if (ret < 0) {
193
error_report_err(local_err);
194
goto resize_fail;
195
diff --git a/block/qcow2.c b/block/qcow2.c
196
index XXXXXXX..XXXXXXX 100644
197
--- a/block/qcow2.c
198
+++ b/block/qcow2.c
199
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn preallocate_co(BlockDriverState *bs, uint64_t offset,
200
mode = PREALLOC_MODE_OFF;
201
}
202
ret = bdrv_co_truncate(s->data_file, host_offset + cur_bytes, false,
203
- mode, errp);
204
+ mode, 0, errp);
205
if (ret < 0) {
206
return ret;
207
}
208
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
209
* always fulfilled, so there is no need to pass it on.)
210
*/
211
bdrv_co_truncate(bs->file, (last_cluster + 1) * s->cluster_size,
212
- false, PREALLOC_MODE_OFF, &local_err);
213
+ false, PREALLOC_MODE_OFF, 0, &local_err);
214
if (local_err) {
215
warn_reportf_err(local_err,
216
"Failed to truncate the tail of the image: ");
217
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
218
* file should be resized to the exact target size, too,
219
* so we pass @exact here.
220
*/
221
- ret = bdrv_co_truncate(s->data_file, offset, exact, prealloc, errp);
222
+ ret = bdrv_co_truncate(s->data_file, offset, exact, prealloc, 0,
223
+ errp);
224
if (ret < 0) {
225
goto fail;
226
}
227
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
228
new_file_size = allocation_start +
229
nb_new_data_clusters * s->cluster_size;
230
/* Image file grows, so @exact does not matter */
231
- ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, errp);
232
+ ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, 0,
233
+ errp);
234
if (ret < 0) {
235
error_prepend(errp, "Failed to resize underlying file: ");
236
qcow2_free_clusters(bs, allocation_start,
237
@@ -XXX,XX +XXX,XX @@ qcow2_co_pwritev_compressed_part(BlockDriverState *bs,
238
if (len < 0) {
239
return len;
240
}
241
- return bdrv_co_truncate(bs->file, len, false, PREALLOC_MODE_OFF, NULL);
242
+ return bdrv_co_truncate(bs->file, len, false, PREALLOC_MODE_OFF, 0,
243
+ NULL);
244
}
245
246
if (offset_into_cluster(s, offset)) {
247
@@ -XXX,XX +XXX,XX @@ static int make_completely_empty(BlockDriverState *bs)
248
}
249
250
ret = bdrv_truncate(bs->file, (3 + l1_clusters) * s->cluster_size, false,
251
- PREALLOC_MODE_OFF, &local_err);
252
+ PREALLOC_MODE_OFF, 0, &local_err);
54
if (ret < 0) {
253
if (ret < 0) {
55
@@ -XXX,XX +XXX,XX @@ static void qed_aio_complete_bh(void *opaque)
254
error_report_err(local_err);
56
qed_release(s);
255
goto fail;
57
}
256
diff --git a/block/raw-format.c b/block/raw-format.c
58
257
index XXXXXXX..XXXXXXX 100644
59
-static void qed_resume_alloc_bh(void *opaque)
258
--- a/block/raw-format.c
60
-{
259
+++ b/block/raw-format.c
61
- qed_aio_start_io(opaque);
260
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
62
-}
261
63
-
262
s->size = offset;
64
static void qed_aio_complete(QEDAIOCB *acb, int ret)
263
offset += s->offset;
65
{
264
- return bdrv_co_truncate(bs->file, offset, exact, prealloc, errp);
66
BDRVQEDState *s = acb_to_s(acb);
265
+ return bdrv_co_truncate(bs->file, offset, exact, prealloc, 0, errp);
67
@@ -XXX,XX +XXX,XX @@ static void qed_aio_complete(QEDAIOCB *acb, int ret)
266
}
68
* next request in the queue. This ensures that we don't cycle through
267
69
* requests multiple times but rather finish one at a time completely.
268
static void raw_eject(BlockDriverState *bs, bool eject_flag)
70
*/
269
diff --git a/block/vhdx-log.c b/block/vhdx-log.c
71
- if (acb == QSIMPLEQ_FIRST(&s->allocating_write_reqs)) {
270
index XXXXXXX..XXXXXXX 100644
72
- QEDAIOCB *next_acb;
271
--- a/block/vhdx-log.c
73
- QSIMPLEQ_REMOVE_HEAD(&s->allocating_write_reqs, next);
272
+++ b/block/vhdx-log.c
74
- next_acb = QSIMPLEQ_FIRST(&s->allocating_write_reqs);
273
@@ -XXX,XX +XXX,XX @@ static int vhdx_log_flush(BlockDriverState *bs, BDRVVHDXState *s,
75
- if (next_acb) {
274
goto exit;
76
- aio_bh_schedule_oneshot(bdrv_get_aio_context(acb->common.bs),
275
}
77
- qed_resume_alloc_bh, next_acb);
276
ret = bdrv_truncate(bs->file, new_file_size, false,
78
+ if (acb == s->allocating_acb) {
277
- PREALLOC_MODE_OFF, NULL);
79
+ s->allocating_acb = NULL;
278
+ PREALLOC_MODE_OFF, 0, NULL);
80
+ if (!qemu_co_queue_empty(&s->allocating_write_reqs)) {
279
if (ret < 0) {
81
+ qemu_co_enter_next(&s->allocating_write_reqs);
280
goto exit;
82
} else if (s->header.features & QED_F_NEED_CHECK) {
281
}
83
qed_start_need_check_timer(s);
282
diff --git a/block/vhdx.c b/block/vhdx.c
84
}
283
index XXXXXXX..XXXXXXX 100644
85
@@ -XXX,XX +XXX,XX @@ static int qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
284
--- a/block/vhdx.c
285
+++ b/block/vhdx.c
286
@@ -XXX,XX +XXX,XX @@ static int vhdx_allocate_block(BlockDriverState *bs, BDRVVHDXState *s,
287
}
288
289
return bdrv_truncate(bs->file, *new_offset + s->block_size, false,
290
- PREALLOC_MODE_OFF, NULL);
291
+ PREALLOC_MODE_OFF, 0, NULL);
292
}
293
294
/*
295
diff --git a/block/vmdk.c b/block/vmdk.c
296
index XXXXXXX..XXXXXXX 100644
297
--- a/block/vmdk.c
298
+++ b/block/vmdk.c
299
@@ -XXX,XX +XXX,XX @@ vmdk_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
300
}
301
length = QEMU_ALIGN_UP(length, BDRV_SECTOR_SIZE);
302
ret = bdrv_truncate(s->extents[i].file, length, false,
303
- PREALLOC_MODE_OFF, NULL);
304
+ PREALLOC_MODE_OFF, 0, NULL);
305
if (ret < 0) {
306
return ret;
307
}
308
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
309
index XXXXXXX..XXXXXXX 100644
310
--- a/tests/test-block-iothread.c
311
+++ b/tests/test-block-iothread.c
312
@@ -XXX,XX +XXX,XX @@ static void test_sync_op_truncate(BdrvChild *c)
86
int ret;
313
int ret;
87
314
88
/* Cancel timer when the first allocating request comes in */
315
/* Normal success path */
89
- if (QSIMPLEQ_EMPTY(&s->allocating_write_reqs)) {
316
- ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, NULL);
90
+ if (s->allocating_acb == NULL) {
317
+ ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, 0, NULL);
91
qed_cancel_need_check_timer(s);
318
g_assert_cmpint(ret, ==, 0);
92
}
319
93
320
/* Early error: Negative offset */
94
/* Freeze this request if another allocating write is in progress */
321
- ret = bdrv_truncate(c, -2, false, PREALLOC_MODE_OFF, NULL);
95
- if (acb != QSIMPLEQ_FIRST(&s->allocating_write_reqs)) {
322
+ ret = bdrv_truncate(c, -2, false, PREALLOC_MODE_OFF, 0, NULL);
96
- QSIMPLEQ_INSERT_TAIL(&s->allocating_write_reqs, acb, next);
323
g_assert_cmpint(ret, ==, -EINVAL);
97
- }
324
98
- if (acb != QSIMPLEQ_FIRST(&s->allocating_write_reqs) ||
325
/* Error: Read-only image */
99
- s->allocating_write_reqs_plugged) {
326
c->bs->read_only = true;
100
- return -EINPROGRESS; /* wait for existing request to finish */
327
c->bs->open_flags &= ~BDRV_O_RDWR;
101
+ if (s->allocating_acb != acb || s->allocating_write_reqs_plugged) {
328
102
+ if (s->allocating_acb != NULL) {
329
- ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, NULL);
103
+ qemu_co_queue_wait(&s->allocating_write_reqs, NULL);
330
+ ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, 0, NULL);
104
+ assert(s->allocating_acb == NULL);
331
g_assert_cmpint(ret, ==, -EACCES);
105
+ }
332
106
+ s->allocating_acb = acb;
333
c->bs->read_only = false;
107
+ return -EAGAIN; /* start over with looking up table entries */
108
}
109
110
acb->cur_nclusters = qed_bytes_to_clusters(s,
111
@@ -XXX,XX +XXX,XX @@ static void qed_aio_next_io(QEDAIOCB *acb)
112
ret = qed_aio_read_data(acb, ret, offset, len);
113
}
114
115
- if (ret < 0) {
116
- if (ret != -EINPROGRESS) {
117
- qed_aio_complete(acb, ret);
118
- }
119
+ if (ret < 0 && ret != -EAGAIN) {
120
+ qed_aio_complete(acb, ret);
121
return;
122
}
123
}
124
diff --git a/block/qed.h b/block/qed.h
125
index XXXXXXX..XXXXXXX 100644
126
--- a/block/qed.h
127
+++ b/block/qed.h
128
@@ -XXX,XX +XXX,XX @@ typedef struct {
129
uint32_t l2_mask;
130
131
/* Allocating write request queue */
132
- QSIMPLEQ_HEAD(, QEDAIOCB) allocating_write_reqs;
133
+ QEDAIOCB *allocating_acb;
134
+ CoQueue allocating_write_reqs;
135
bool allocating_write_reqs_plugged;
136
137
/* Periodic flush and clear need check flag */
138
--
334
--
139
1.8.3.1
335
2.25.3
140
336
141
337
diff view generated by jsdifflib
1
All functions that are marked coroutine_fn can directly call the
1
Now that node level interface bdrv_truncate() supports passing request
2
bdrv_co_* version of functions instead of going through the wrapper.
2
flags to the block driver, expose this on the BlockBackend level, too.
3
3
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
5
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
6
Reviewed-by: Alberto Garcia <berto@igalia.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Message-Id: <20200424125448.63318-4-kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
10
---
8
block/qed.c | 16 +++++++++-------
11
include/sysemu/block-backend.h | 2 +-
9
1 file changed, 9 insertions(+), 7 deletions(-)
12
block.c | 3 ++-
10
13
block/block-backend.c | 4 ++--
14
block/commit.c | 4 ++--
15
block/crypto.c | 2 +-
16
block/mirror.c | 2 +-
17
block/qcow2.c | 4 ++--
18
block/qed.c | 2 +-
19
block/vdi.c | 2 +-
20
block/vhdx.c | 4 ++--
21
block/vmdk.c | 6 +++---
22
block/vpc.c | 2 +-
23
blockdev.c | 2 +-
24
qemu-img.c | 2 +-
25
qemu-io-cmds.c | 2 +-
26
15 files changed, 22 insertions(+), 21 deletions(-)
27
28
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
29
index XXXXXXX..XXXXXXX 100644
30
--- a/include/sysemu/block-backend.h
31
+++ b/include/sysemu/block-backend.h
32
@@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_pwrite_zeroes(BlockBackend *blk, int64_t offset,
33
int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf,
34
int bytes);
35
int blk_truncate(BlockBackend *blk, int64_t offset, bool exact,
36
- PreallocMode prealloc, Error **errp);
37
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp);
38
int blk_pdiscard(BlockBackend *blk, int64_t offset, int bytes);
39
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
40
int64_t pos, int size);
41
diff --git a/block.c b/block.c
42
index XXXXXXX..XXXXXXX 100644
43
--- a/block.c
44
+++ b/block.c
45
@@ -XXX,XX +XXX,XX @@ static int64_t create_file_fallback_truncate(BlockBackend *blk,
46
int64_t size;
47
int ret;
48
49
- ret = blk_truncate(blk, minimum_size, false, PREALLOC_MODE_OFF, &local_err);
50
+ ret = blk_truncate(blk, minimum_size, false, PREALLOC_MODE_OFF, 0,
51
+ &local_err);
52
if (ret < 0 && ret != -ENOTSUP) {
53
error_propagate(errp, local_err);
54
return ret;
55
diff --git a/block/block-backend.c b/block/block-backend.c
56
index XXXXXXX..XXXXXXX 100644
57
--- a/block/block-backend.c
58
+++ b/block/block-backend.c
59
@@ -XXX,XX +XXX,XX @@ int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf,
60
}
61
62
int blk_truncate(BlockBackend *blk, int64_t offset, bool exact,
63
- PreallocMode prealloc, Error **errp)
64
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp)
65
{
66
if (!blk_is_available(blk)) {
67
error_setg(errp, "No medium inserted");
68
return -ENOMEDIUM;
69
}
70
71
- return bdrv_truncate(blk->root, offset, exact, prealloc, 0, errp);
72
+ return bdrv_truncate(blk->root, offset, exact, prealloc, flags, errp);
73
}
74
75
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
76
diff --git a/block/commit.c b/block/commit.c
77
index XXXXXXX..XXXXXXX 100644
78
--- a/block/commit.c
79
+++ b/block/commit.c
80
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn commit_run(Job *job, Error **errp)
81
}
82
83
if (base_len < len) {
84
- ret = blk_truncate(s->base, len, false, PREALLOC_MODE_OFF, NULL);
85
+ ret = blk_truncate(s->base, len, false, PREALLOC_MODE_OFF, 0, NULL);
86
if (ret) {
87
goto out;
88
}
89
@@ -XXX,XX +XXX,XX @@ int bdrv_commit(BlockDriverState *bs)
90
* grow the backing file image if possible. If not possible,
91
* we must return an error */
92
if (length > backing_length) {
93
- ret = blk_truncate(backing, length, false, PREALLOC_MODE_OFF,
94
+ ret = blk_truncate(backing, length, false, PREALLOC_MODE_OFF, 0,
95
&local_err);
96
if (ret < 0) {
97
error_report_err(local_err);
98
diff --git a/block/crypto.c b/block/crypto.c
99
index XXXXXXX..XXXXXXX 100644
100
--- a/block/crypto.c
101
+++ b/block/crypto.c
102
@@ -XXX,XX +XXX,XX @@ static ssize_t block_crypto_init_func(QCryptoBlock *block,
103
* which will be used by the crypto header
104
*/
105
return blk_truncate(data->blk, data->size + headerlen, false,
106
- data->prealloc, errp);
107
+ data->prealloc, 0, errp);
108
}
109
110
111
diff --git a/block/mirror.c b/block/mirror.c
112
index XXXXXXX..XXXXXXX 100644
113
--- a/block/mirror.c
114
+++ b/block/mirror.c
115
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
116
117
if (s->bdev_length > base_length) {
118
ret = blk_truncate(s->target, s->bdev_length, false,
119
- PREALLOC_MODE_OFF, NULL);
120
+ PREALLOC_MODE_OFF, 0, NULL);
121
if (ret < 0) {
122
goto immediate_exit;
123
}
124
diff --git a/block/qcow2.c b/block/qcow2.c
125
index XXXXXXX..XXXXXXX 100644
126
--- a/block/qcow2.c
127
+++ b/block/qcow2.c
128
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
129
130
/* Okay, now that we have a valid image, let's give it the right size */
131
ret = blk_truncate(blk, qcow2_opts->size, false, qcow2_opts->preallocation,
132
- errp);
133
+ 0, errp);
134
if (ret < 0) {
135
error_prepend(errp, "Could not resize image: ");
136
goto out;
137
@@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
138
* Amending image options should ensure that the image has
139
* exactly the given new values, so pass exact=true here.
140
*/
141
- ret = blk_truncate(blk, new_size, true, PREALLOC_MODE_OFF, errp);
142
+ ret = blk_truncate(blk, new_size, true, PREALLOC_MODE_OFF, 0, errp);
143
blk_unref(blk);
144
if (ret < 0) {
145
return ret;
11
diff --git a/block/qed.c b/block/qed.c
146
diff --git a/block/qed.c b/block/qed.c
12
index XXXXXXX..XXXXXXX 100644
147
index XXXXXXX..XXXXXXX 100644
13
--- a/block/qed.c
148
--- a/block/qed.c
14
+++ b/block/qed.c
149
+++ b/block/qed.c
15
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qed_write_header(BDRVQEDState *s)
150
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_create(BlockdevCreateOptions *opts,
16
};
151
* The QED format associates file length with allocation status,
17
qemu_iovec_init_external(&qiov, &iov, 1);
152
* so a new file (which is empty) must have a length of 0.
18
153
*/
19
- ret = bdrv_preadv(s->bs->file, 0, &qiov);
154
- ret = blk_truncate(blk, 0, true, PREALLOC_MODE_OFF, errp);
20
+ ret = bdrv_co_preadv(s->bs->file, 0, qiov.size, &qiov, 0);
155
+ ret = blk_truncate(blk, 0, true, PREALLOC_MODE_OFF, 0, errp);
21
if (ret < 0) {
156
if (ret < 0) {
22
goto out;
157
goto out;
23
}
158
}
24
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qed_write_header(BDRVQEDState *s)
159
diff --git a/block/vdi.c b/block/vdi.c
25
/* Update header */
160
index XXXXXXX..XXXXXXX 100644
26
qed_header_cpu_to_le(&s->header, (QEDHeader *) buf);
161
--- a/block/vdi.c
27
162
+++ b/block/vdi.c
28
- ret = bdrv_pwritev(s->bs->file, 0, &qiov);
163
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
29
+ ret = bdrv_co_pwritev(s->bs->file, 0, qiov.size, &qiov, 0);
164
30
if (ret < 0) {
165
if (image_type == VDI_TYPE_STATIC) {
31
goto out;
166
ret = blk_truncate(blk, offset + blocks * block_size, false,
32
}
167
- PREALLOC_MODE_OFF, errp);
33
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qed_read_backing_file(BDRVQEDState *s, uint64_t pos,
168
+ PREALLOC_MODE_OFF, 0, errp);
34
qemu_iovec_concat(*backing_qiov, qiov, 0, size);
169
if (ret < 0) {
35
170
error_prepend(errp, "Failed to statically allocate file");
36
BLKDBG_EVENT(s->bs->file, BLKDBG_READ_BACKING_AIO);
171
goto exit;
37
- ret = bdrv_preadv(s->bs->backing, pos, *backing_qiov);
172
diff --git a/block/vhdx.c b/block/vhdx.c
38
+ ret = bdrv_co_preadv(s->bs->backing, pos, size, *backing_qiov, 0);
173
index XXXXXXX..XXXXXXX 100644
174
--- a/block/vhdx.c
175
+++ b/block/vhdx.c
176
@@ -XXX,XX +XXX,XX @@ static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
177
/* All zeroes, so we can just extend the file - the end of the BAT
178
* is the furthest thing we have written yet */
179
ret = blk_truncate(blk, data_file_offset, false, PREALLOC_MODE_OFF,
180
- errp);
181
+ 0, errp);
182
if (ret < 0) {
183
goto exit;
184
}
185
} else if (type == VHDX_TYPE_FIXED) {
186
ret = blk_truncate(blk, data_file_offset + image_size, false,
187
- PREALLOC_MODE_OFF, errp);
188
+ PREALLOC_MODE_OFF, 0, errp);
189
if (ret < 0) {
190
goto exit;
191
}
192
diff --git a/block/vmdk.c b/block/vmdk.c
193
index XXXXXXX..XXXXXXX 100644
194
--- a/block/vmdk.c
195
+++ b/block/vmdk.c
196
@@ -XXX,XX +XXX,XX @@ static int vmdk_init_extent(BlockBackend *blk,
197
int gd_buf_size;
198
199
if (flat) {
200
- ret = blk_truncate(blk, filesize, false, PREALLOC_MODE_OFF, errp);
201
+ ret = blk_truncate(blk, filesize, false, PREALLOC_MODE_OFF, 0, errp);
202
goto exit;
203
}
204
magic = cpu_to_be32(VMDK4_MAGIC);
205
@@ -XXX,XX +XXX,XX @@ static int vmdk_init_extent(BlockBackend *blk,
206
}
207
208
ret = blk_truncate(blk, le64_to_cpu(header.grain_offset) << 9, false,
209
- PREALLOC_MODE_OFF, errp);
210
+ PREALLOC_MODE_OFF, 0, errp);
211
if (ret < 0) {
212
goto exit;
213
}
214
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vmdk_co_do_create(int64_t size,
215
/* bdrv_pwrite write padding zeros to align to sector, we don't need that
216
* for description file */
217
if (desc_offset == 0) {
218
- ret = blk_truncate(blk, desc_len, false, PREALLOC_MODE_OFF, errp);
219
+ ret = blk_truncate(blk, desc_len, false, PREALLOC_MODE_OFF, 0, errp);
220
if (ret < 0) {
221
goto exit;
222
}
223
diff --git a/block/vpc.c b/block/vpc.c
224
index XXXXXXX..XXXXXXX 100644
225
--- a/block/vpc.c
226
+++ b/block/vpc.c
227
@@ -XXX,XX +XXX,XX @@ static int create_fixed_disk(BlockBackend *blk, uint8_t *buf,
228
/* Add footer to total size */
229
total_size += HEADER_SIZE;
230
231
- ret = blk_truncate(blk, total_size, false, PREALLOC_MODE_OFF, errp);
232
+ ret = blk_truncate(blk, total_size, false, PREALLOC_MODE_OFF, 0, errp);
39
if (ret < 0) {
233
if (ret < 0) {
40
return ret;
234
return ret;
41
}
235
}
42
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qed_copy_from_backing_file(BDRVQEDState *s,
236
diff --git a/blockdev.c b/blockdev.c
43
}
237
index XXXXXXX..XXXXXXX 100644
44
238
--- a/blockdev.c
45
BLKDBG_EVENT(s->bs->file, BLKDBG_COW_WRITE);
239
+++ b/blockdev.c
46
- ret = bdrv_pwritev(s->bs->file, offset, &qiov);
240
@@ -XXX,XX +XXX,XX @@ void qmp_block_resize(bool has_device, const char *device,
47
+ ret = bdrv_co_pwritev(s->bs->file, offset, qiov.size, &qiov, 0);
241
}
48
if (ret < 0) {
242
49
goto out;
243
bdrv_drained_begin(bs);
50
}
244
- ret = blk_truncate(blk, size, false, PREALLOC_MODE_OFF, errp);
51
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qed_aio_write_main(QEDAIOCB *acb)
245
+ ret = blk_truncate(blk, size, false, PREALLOC_MODE_OFF, 0, errp);
52
trace_qed_aio_write_main(s, acb, 0, offset, acb->cur_qiov.size);
246
bdrv_drained_end(bs);
53
247
54
BLKDBG_EVENT(s->bs->file, BLKDBG_WRITE_AIO);
248
out:
55
- ret = bdrv_pwritev(s->bs->file, offset, &acb->cur_qiov);
249
diff --git a/qemu-img.c b/qemu-img.c
56
+ ret = bdrv_co_pwritev(s->bs->file, offset, acb->cur_qiov.size,
250
index XXXXXXX..XXXXXXX 100644
57
+ &acb->cur_qiov, 0);
251
--- a/qemu-img.c
58
if (ret < 0) {
252
+++ b/qemu-img.c
253
@@ -XXX,XX +XXX,XX @@ static int img_resize(int argc, char **argv)
254
* resizing, so pass @exact=true. It is of no use to report
255
* success when the image has not actually been resized.
256
*/
257
- ret = blk_truncate(blk, total_size, true, prealloc, &err);
258
+ ret = blk_truncate(blk, total_size, true, prealloc, 0, &err);
259
if (!ret) {
260
qprintf(quiet, "Image resized.\n");
261
} else {
262
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
263
index XXXXXXX..XXXXXXX 100644
264
--- a/qemu-io-cmds.c
265
+++ b/qemu-io-cmds.c
266
@@ -XXX,XX +XXX,XX @@ static int truncate_f(BlockBackend *blk, int argc, char **argv)
267
* exact=true. It is better to err on the "emit more errors" side
268
* than to be overly permissive.
269
*/
270
- ret = blk_truncate(blk, offset, true, PREALLOC_MODE_OFF, &local_err);
271
+ ret = blk_truncate(blk, offset, true, PREALLOC_MODE_OFF, 0, &local_err);
272
if (ret < 0) {
273
error_report_err(local_err);
59
return ret;
274
return ret;
60
}
61
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qed_aio_write_main(QEDAIOCB *acb)
62
* region. The solution is to flush after writing a new data
63
* cluster and before updating the L2 table.
64
*/
65
- ret = bdrv_flush(s->bs->file->bs);
66
+ ret = bdrv_co_flush(s->bs->file->bs);
67
if (ret < 0) {
68
return ret;
69
}
70
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qed_aio_read_data(void *opaque, int ret,
71
}
72
73
BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
74
- ret = bdrv_preadv(bs->file, offset, &acb->cur_qiov);
75
+ ret = bdrv_co_preadv(bs->file, offset, acb->cur_qiov.size,
76
+ &acb->cur_qiov, 0);
77
if (ret < 0) {
78
return ret;
79
}
80
--
275
--
81
1.8.3.1
276
2.25.3
82
277
83
278
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
If BDRV_REQ_ZERO_WRITE is set and we're extending the image, calling
2
qcow2_cluster_zeroize() with flags=0 does the right thing: It doesn't
3
undo any previous preallocation, but just adds the zero flag to all
4
relevant L2 entries. If an external data file is in use, a write_zeroes
5
request to the data file is made instead.
2
6
3
If the guest tries to write data that results on the allocation of a
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
new cluster, instead of writing the guest data first and then the data
8
Message-Id: <20200424125448.63318-5-kwolf@redhat.com>
5
from the COW regions, write everything together using one single I/O
9
Reviewed-by: Eric Blake <eblake@redhat.com>
6
operation.
10
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
8
This can improve the write performance by 25% or more, depending on
9
several factors such as the media type, the cluster size and the I/O
10
request size.
11
12
Signed-off-by: Alberto Garcia <berto@igalia.com>
13
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
12
---
16
block/qcow2-cluster.c | 40 ++++++++++++++++++++++++--------
13
block/qcow2-cluster.c | 2 +-
17
block/qcow2.c | 64 +++++++++++++++++++++++++++++++++++++++++++--------
14
block/qcow2.c | 34 ++++++++++++++++++++++++++++++++++
18
block/qcow2.h | 7 ++++++
15
2 files changed, 35 insertions(+), 1 deletion(-)
19
3 files changed, 91 insertions(+), 20 deletions(-)
20
16
21
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
17
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
22
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
23
--- a/block/qcow2-cluster.c
19
--- a/block/qcow2-cluster.c
24
+++ b/block/qcow2-cluster.c
20
+++ b/block/qcow2-cluster.c
25
@@ -XXX,XX +XXX,XX @@ static int perform_cow(BlockDriverState *bs, QCowL2Meta *m)
21
@@ -XXX,XX +XXX,XX @@ int qcow2_cluster_zeroize(BlockDriverState *bs, uint64_t offset,
26
assert(start->nb_bytes <= UINT_MAX - end->nb_bytes);
22
/* Caller must pass aligned values, except at image end */
27
assert(start->nb_bytes + end->nb_bytes <= UINT_MAX - data_bytes);
23
assert(QEMU_IS_ALIGNED(offset, s->cluster_size));
28
assert(start->offset + start->nb_bytes <= end->offset);
24
assert(QEMU_IS_ALIGNED(end_offset, s->cluster_size) ||
29
+ assert(!m->data_qiov || m->data_qiov->size == data_bytes);
25
- end_offset == bs->total_sectors << BDRV_SECTOR_BITS);
30
26
+ end_offset >= bs->total_sectors << BDRV_SECTOR_BITS);
31
if (start->nb_bytes == 0 && end->nb_bytes == 0) {
27
32
return 0;
28
/* The zero flag is only supported by version 3 and newer */
33
@@ -XXX,XX +XXX,XX @@ static int perform_cow(BlockDriverState *bs, QCowL2Meta *m)
29
if (s->qcow_version < 3) {
34
/* The part of the buffer where the end region is located */
35
end_buffer = start_buffer + buffer_size - end->nb_bytes;
36
37
- qemu_iovec_init(&qiov, 1);
38
+ qemu_iovec_init(&qiov, 2 + (m->data_qiov ? m->data_qiov->niov : 0));
39
40
qemu_co_mutex_unlock(&s->lock);
41
/* First we read the existing data from both COW regions. We
42
@@ -XXX,XX +XXX,XX @@ static int perform_cow(BlockDriverState *bs, QCowL2Meta *m)
43
}
44
}
45
46
- /* And now we can write everything */
47
- qemu_iovec_reset(&qiov);
48
- qemu_iovec_add(&qiov, start_buffer, start->nb_bytes);
49
- ret = do_perform_cow_write(bs, m->alloc_offset, start->offset, &qiov);
50
- if (ret < 0) {
51
- goto fail;
52
+ /* And now we can write everything. If we have the guest data we
53
+ * can write everything in one single operation */
54
+ if (m->data_qiov) {
55
+ qemu_iovec_reset(&qiov);
56
+ if (start->nb_bytes) {
57
+ qemu_iovec_add(&qiov, start_buffer, start->nb_bytes);
58
+ }
59
+ qemu_iovec_concat(&qiov, m->data_qiov, 0, data_bytes);
60
+ if (end->nb_bytes) {
61
+ qemu_iovec_add(&qiov, end_buffer, end->nb_bytes);
62
+ }
63
+ /* NOTE: we have a write_aio blkdebug event here followed by
64
+ * a cow_write one in do_perform_cow_write(), but there's only
65
+ * one single I/O operation */
66
+ BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
67
+ ret = do_perform_cow_write(bs, m->alloc_offset, start->offset, &qiov);
68
+ } else {
69
+ /* If there's no guest data then write both COW regions separately */
70
+ qemu_iovec_reset(&qiov);
71
+ qemu_iovec_add(&qiov, start_buffer, start->nb_bytes);
72
+ ret = do_perform_cow_write(bs, m->alloc_offset, start->offset, &qiov);
73
+ if (ret < 0) {
74
+ goto fail;
75
+ }
76
+
77
+ qemu_iovec_reset(&qiov);
78
+ qemu_iovec_add(&qiov, end_buffer, end->nb_bytes);
79
+ ret = do_perform_cow_write(bs, m->alloc_offset, end->offset, &qiov);
80
}
81
82
- qemu_iovec_reset(&qiov);
83
- qemu_iovec_add(&qiov, end_buffer, end->nb_bytes);
84
- ret = do_perform_cow_write(bs, m->alloc_offset, end->offset, &qiov);
85
fail:
86
qemu_co_mutex_lock(&s->lock);
87
88
diff --git a/block/qcow2.c b/block/qcow2.c
30
diff --git a/block/qcow2.c b/block/qcow2.c
89
index XXXXXXX..XXXXXXX 100644
31
index XXXXXXX..XXXXXXX 100644
90
--- a/block/qcow2.c
32
--- a/block/qcow2.c
91
+++ b/block/qcow2.c
33
+++ b/block/qcow2.c
92
@@ -XXX,XX +XXX,XX @@ fail:
34
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
93
return ret;
35
94
}
36
bs->supported_zero_flags = header.version >= 3 ?
95
37
BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK : 0;
96
+/* Check if it's possible to merge a write request with the writing of
38
+ bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE;
97
+ * the data from the COW regions */
39
98
+static bool merge_cow(uint64_t offset, unsigned bytes,
40
/* Repair image if dirty */
99
+ QEMUIOVector *hd_qiov, QCowL2Meta *l2meta)
41
if (!(flags & (BDRV_O_CHECK | BDRV_O_INACTIVE)) && !bs->read_only &&
100
+{
42
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
101
+ QCowL2Meta *m;
43
g_assert_not_reached();
44
}
45
46
+ if ((flags & BDRV_REQ_ZERO_WRITE) && offset > old_length) {
47
+ uint64_t zero_start = QEMU_ALIGN_UP(old_length, s->cluster_size);
102
+
48
+
103
+ for (m = l2meta; m != NULL; m = m->next) {
49
+ /*
104
+ /* If both COW regions are empty then there's nothing to merge */
50
+ * Use zero clusters as much as we can. qcow2_cluster_zeroize()
105
+ if (m->cow_start.nb_bytes == 0 && m->cow_end.nb_bytes == 0) {
51
+ * requires a cluster-aligned start. The end may be unaligned if it is
106
+ continue;
52
+ * at the end of the image (which it is here).
53
+ */
54
+ ret = qcow2_cluster_zeroize(bs, zero_start, offset - zero_start, 0);
55
+ if (ret < 0) {
56
+ error_setg_errno(errp, -ret, "Failed to zero out new clusters");
57
+ goto fail;
107
+ }
58
+ }
108
+
59
+
109
+ /* The data (middle) region must be immediately after the
60
+ /* Write explicit zeros for the unaligned head */
110
+ * start region */
61
+ if (zero_start > old_length) {
111
+ if (l2meta_cow_start(m) + m->cow_start.nb_bytes != offset) {
62
+ uint64_t len = zero_start - old_length;
112
+ continue;
63
+ uint8_t *buf = qemu_blockalign0(bs, len);
64
+ QEMUIOVector qiov;
65
+ qemu_iovec_init_buf(&qiov, buf, len);
66
+
67
+ qemu_co_mutex_unlock(&s->lock);
68
+ ret = qcow2_co_pwritev_part(bs, old_length, len, &qiov, 0, 0);
69
+ qemu_co_mutex_lock(&s->lock);
70
+
71
+ qemu_vfree(buf);
72
+ if (ret < 0) {
73
+ error_setg_errno(errp, -ret, "Failed to zero out the new area");
74
+ goto fail;
75
+ }
113
+ }
76
+ }
114
+
115
+ /* The end region must be immediately after the data (middle)
116
+ * region */
117
+ if (m->offset + m->cow_end.offset != offset + bytes) {
118
+ continue;
119
+ }
120
+
121
+ /* Make sure that adding both COW regions to the QEMUIOVector
122
+ * does not exceed IOV_MAX */
123
+ if (hd_qiov->niov > IOV_MAX - 2) {
124
+ continue;
125
+ }
126
+
127
+ m->data_qiov = hd_qiov;
128
+ return true;
129
+ }
77
+ }
130
+
78
+
131
+ return false;
79
if (prealloc != PREALLOC_MODE_OFF) {
132
+}
80
/* Flush metadata before actually changing the image size */
133
+
81
ret = qcow2_write_caches(bs);
134
static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset,
135
uint64_t bytes, QEMUIOVector *qiov,
136
int flags)
137
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset,
138
goto fail;
139
}
140
141
- qemu_co_mutex_unlock(&s->lock);
142
- BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
143
- trace_qcow2_writev_data(qemu_coroutine_self(),
144
- cluster_offset + offset_in_cluster);
145
- ret = bdrv_co_pwritev(bs->file,
146
- cluster_offset + offset_in_cluster,
147
- cur_bytes, &hd_qiov, 0);
148
- qemu_co_mutex_lock(&s->lock);
149
- if (ret < 0) {
150
- goto fail;
151
+ /* If we need to do COW, check if it's possible to merge the
152
+ * writing of the guest data together with that of the COW regions.
153
+ * If it's not possible (or not necessary) then write the
154
+ * guest data now. */
155
+ if (!merge_cow(offset, cur_bytes, &hd_qiov, l2meta)) {
156
+ qemu_co_mutex_unlock(&s->lock);
157
+ BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
158
+ trace_qcow2_writev_data(qemu_coroutine_self(),
159
+ cluster_offset + offset_in_cluster);
160
+ ret = bdrv_co_pwritev(bs->file,
161
+ cluster_offset + offset_in_cluster,
162
+ cur_bytes, &hd_qiov, 0);
163
+ qemu_co_mutex_lock(&s->lock);
164
+ if (ret < 0) {
165
+ goto fail;
166
+ }
167
}
168
169
while (l2meta != NULL) {
170
diff --git a/block/qcow2.h b/block/qcow2.h
171
index XXXXXXX..XXXXXXX 100644
172
--- a/block/qcow2.h
173
+++ b/block/qcow2.h
174
@@ -XXX,XX +XXX,XX @@ typedef struct QCowL2Meta
175
*/
176
Qcow2COWRegion cow_end;
177
178
+ /**
179
+ * The I/O vector with the data from the actual guest write request.
180
+ * If non-NULL, this is meant to be merged together with the data
181
+ * from @cow_start and @cow_end into one single write operation.
182
+ */
183
+ QEMUIOVector *data_qiov;
184
+
185
/** Pointer to next L2Meta of the same write request */
186
struct QCowL2Meta *next;
187
188
--
82
--
189
1.8.3.1
83
2.25.3
190
84
191
85
diff view generated by jsdifflib
1
Now that we stay in coroutine context for the whole request when doing
1
The raw format driver can simply forward the flag and let its bs->file
2
reads or writes, we can add coroutine_fn annotations to many functions
2
child take care of actually providing the zeros.
3
that can do I/O or yield directly.
4
3
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Message-Id: <20200424125448.63318-6-kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
10
---
8
block/qed-cluster.c | 5 +++--
11
block/raw-format.c | 4 +++-
9
block/qed.c | 44 ++++++++++++++++++++++++--------------------
12
1 file changed, 3 insertions(+), 1 deletion(-)
10
block/qed.h | 5 +++--
11
3 files changed, 30 insertions(+), 24 deletions(-)
12
13
13
diff --git a/block/qed-cluster.c b/block/qed-cluster.c
14
diff --git a/block/raw-format.c b/block/raw-format.c
14
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
15
--- a/block/qed-cluster.c
16
--- a/block/raw-format.c
16
+++ b/block/qed-cluster.c
17
+++ b/block/raw-format.c
17
@@ -XXX,XX +XXX,XX @@ static unsigned int qed_count_contiguous_clusters(BDRVQEDState *s,
18
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
18
* On failure QED_CLUSTER_L2 or QED_CLUSTER_L1 is returned for missing L2 or L1
19
19
* table offset, respectively. len is number of contiguous unallocated bytes.
20
s->size = offset;
20
*/
21
offset += s->offset;
21
-int qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
22
- return bdrv_co_truncate(bs->file, offset, exact, prealloc, 0, errp);
22
- size_t *len, uint64_t *img_offset)
23
+ return bdrv_co_truncate(bs->file, offset, exact, prealloc, flags, errp);
23
+int coroutine_fn qed_find_cluster(BDRVQEDState *s, QEDRequest *request,
24
+ uint64_t pos, size_t *len,
25
+ uint64_t *img_offset)
26
{
27
uint64_t l2_offset;
28
uint64_t offset = 0;
29
diff --git a/block/qed.c b/block/qed.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/block/qed.c
32
+++ b/block/qed.c
33
@@ -XXX,XX +XXX,XX @@ int qed_write_header_sync(BDRVQEDState *s)
34
* This function only updates known header fields in-place and does not affect
35
* extra data after the QED header.
36
*/
37
-static int qed_write_header(BDRVQEDState *s)
38
+static int coroutine_fn qed_write_header(BDRVQEDState *s)
39
{
40
/* We must write full sectors for O_DIRECT but cannot necessarily generate
41
* the data following the header if an unrecognized compat feature is
42
@@ -XXX,XX +XXX,XX @@ static void qed_unplug_allocating_write_reqs(BDRVQEDState *s)
43
qemu_co_enter_next(&s->allocating_write_reqs);
44
}
24
}
45
25
46
-static void qed_need_check_timer_entry(void *opaque)
26
static void raw_eject(BlockDriverState *bs, bool eject_flag)
47
+static void coroutine_fn qed_need_check_timer_entry(void *opaque)
27
@@ -XXX,XX +XXX,XX @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
48
{
28
bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
49
BDRVQEDState *s = opaque;
29
((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) &
50
int ret;
30
bs->file->bs->supported_zero_flags);
51
@@ -XXX,XX +XXX,XX @@ static BDRVQEDState *acb_to_s(QEDAIOCB *acb)
31
+ bs->supported_truncate_flags = bs->file->bs->supported_truncate_flags &
52
* This function reads qiov->size bytes starting at pos from the backing file.
32
+ BDRV_REQ_ZERO_WRITE;
53
* If there is no backing file then zeroes are read.
33
54
*/
34
if (bs->probed && !bdrv_is_read_only(bs)) {
55
-static int qed_read_backing_file(BDRVQEDState *s, uint64_t pos,
35
bdrv_refresh_filename(bs->file->bs);
56
- QEMUIOVector *qiov,
57
- QEMUIOVector **backing_qiov)
58
+static int coroutine_fn qed_read_backing_file(BDRVQEDState *s, uint64_t pos,
59
+ QEMUIOVector *qiov,
60
+ QEMUIOVector **backing_qiov)
61
{
62
uint64_t backing_length = 0;
63
size_t size;
64
@@ -XXX,XX +XXX,XX @@ static int qed_read_backing_file(BDRVQEDState *s, uint64_t pos,
65
* @len: Number of bytes
66
* @offset: Byte offset in image file
67
*/
68
-static int qed_copy_from_backing_file(BDRVQEDState *s, uint64_t pos,
69
- uint64_t len, uint64_t offset)
70
+static int coroutine_fn qed_copy_from_backing_file(BDRVQEDState *s,
71
+ uint64_t pos, uint64_t len,
72
+ uint64_t offset)
73
{
74
QEMUIOVector qiov;
75
QEMUIOVector *backing_qiov = NULL;
76
@@ -XXX,XX +XXX,XX @@ out:
77
* The cluster offset may be an allocated byte offset in the image file, the
78
* zero cluster marker, or the unallocated cluster marker.
79
*/
80
-static void qed_update_l2_table(BDRVQEDState *s, QEDTable *table, int index,
81
- unsigned int n, uint64_t cluster)
82
+static void coroutine_fn qed_update_l2_table(BDRVQEDState *s, QEDTable *table,
83
+ int index, unsigned int n,
84
+ uint64_t cluster)
85
{
86
int i;
87
for (i = index; i < index + n; i++) {
88
@@ -XXX,XX +XXX,XX @@ static void qed_update_l2_table(BDRVQEDState *s, QEDTable *table, int index,
89
}
90
}
91
92
-static void qed_aio_complete(QEDAIOCB *acb)
93
+static void coroutine_fn qed_aio_complete(QEDAIOCB *acb)
94
{
95
BDRVQEDState *s = acb_to_s(acb);
96
97
@@ -XXX,XX +XXX,XX @@ static void qed_aio_complete(QEDAIOCB *acb)
98
/**
99
* Update L1 table with new L2 table offset and write it out
100
*/
101
-static int qed_aio_write_l1_update(QEDAIOCB *acb)
102
+static int coroutine_fn qed_aio_write_l1_update(QEDAIOCB *acb)
103
{
104
BDRVQEDState *s = acb_to_s(acb);
105
CachedL2Table *l2_table = acb->request.l2_table;
106
@@ -XXX,XX +XXX,XX @@ static int qed_aio_write_l1_update(QEDAIOCB *acb)
107
/**
108
* Update L2 table with new cluster offsets and write them out
109
*/
110
-static int qed_aio_write_l2_update(QEDAIOCB *acb, uint64_t offset)
111
+static int coroutine_fn qed_aio_write_l2_update(QEDAIOCB *acb, uint64_t offset)
112
{
113
BDRVQEDState *s = acb_to_s(acb);
114
bool need_alloc = acb->find_cluster_ret == QED_CLUSTER_L1;
115
@@ -XXX,XX +XXX,XX @@ static int qed_aio_write_l2_update(QEDAIOCB *acb, uint64_t offset)
116
/**
117
* Write data to the image file
118
*/
119
-static int qed_aio_write_main(QEDAIOCB *acb)
120
+static int coroutine_fn qed_aio_write_main(QEDAIOCB *acb)
121
{
122
BDRVQEDState *s = acb_to_s(acb);
123
uint64_t offset = acb->cur_cluster +
124
@@ -XXX,XX +XXX,XX @@ static int qed_aio_write_main(QEDAIOCB *acb)
125
/**
126
* Populate untouched regions of new data cluster
127
*/
128
-static int qed_aio_write_cow(QEDAIOCB *acb)
129
+static int coroutine_fn qed_aio_write_cow(QEDAIOCB *acb)
130
{
131
BDRVQEDState *s = acb_to_s(acb);
132
uint64_t start, len, offset;
133
@@ -XXX,XX +XXX,XX @@ static bool qed_should_set_need_check(BDRVQEDState *s)
134
*
135
* This path is taken when writing to previously unallocated clusters.
136
*/
137
-static int qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
138
+static int coroutine_fn qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
139
{
140
BDRVQEDState *s = acb_to_s(acb);
141
int ret;
142
@@ -XXX,XX +XXX,XX @@ static int qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
143
*
144
* This path is taken when writing to already allocated clusters.
145
*/
146
-static int qed_aio_write_inplace(QEDAIOCB *acb, uint64_t offset, size_t len)
147
+static int coroutine_fn qed_aio_write_inplace(QEDAIOCB *acb, uint64_t offset,
148
+ size_t len)
149
{
150
/* Allocate buffer for zero writes */
151
if (acb->flags & QED_AIOCB_ZERO) {
152
@@ -XXX,XX +XXX,XX @@ static int qed_aio_write_inplace(QEDAIOCB *acb, uint64_t offset, size_t len)
153
* @offset: Cluster offset in bytes
154
* @len: Length in bytes
155
*/
156
-static int qed_aio_write_data(void *opaque, int ret,
157
- uint64_t offset, size_t len)
158
+static int coroutine_fn qed_aio_write_data(void *opaque, int ret,
159
+ uint64_t offset, size_t len)
160
{
161
QEDAIOCB *acb = opaque;
162
163
@@ -XXX,XX +XXX,XX @@ static int qed_aio_write_data(void *opaque, int ret,
164
* @offset: Cluster offset in bytes
165
* @len: Length in bytes
166
*/
167
-static int qed_aio_read_data(void *opaque, int ret, uint64_t offset, size_t len)
168
+static int coroutine_fn qed_aio_read_data(void *opaque, int ret,
169
+ uint64_t offset, size_t len)
170
{
171
QEDAIOCB *acb = opaque;
172
BDRVQEDState *s = acb_to_s(acb);
173
@@ -XXX,XX +XXX,XX @@ static int qed_aio_read_data(void *opaque, int ret, uint64_t offset, size_t len)
174
/**
175
* Begin next I/O or complete the request
176
*/
177
-static int qed_aio_next_io(QEDAIOCB *acb)
178
+static int coroutine_fn qed_aio_next_io(QEDAIOCB *acb)
179
{
180
BDRVQEDState *s = acb_to_s(acb);
181
uint64_t offset;
182
diff --git a/block/qed.h b/block/qed.h
183
index XXXXXXX..XXXXXXX 100644
184
--- a/block/qed.h
185
+++ b/block/qed.h
186
@@ -XXX,XX +XXX,XX @@ int qed_write_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
187
/**
188
* Cluster functions
189
*/
190
-int qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
191
- size_t *len, uint64_t *img_offset);
192
+int coroutine_fn qed_find_cluster(BDRVQEDState *s, QEDRequest *request,
193
+ uint64_t pos, size_t *len,
194
+ uint64_t *img_offset);
195
196
/**
197
* Consistency check
198
--
36
--
199
1.8.3.1
37
2.25.3
200
38
201
39
diff view generated by jsdifflib
1
This fixes the last place where we degraded from AIO to actual blocking
1
For regular files, we always get BDRV_REQ_ZERO_WRITE behaviour from the
2
synchronous I/O requests. Putting it into a coroutine means that instead
2
OS, so we can advertise the flag and just ignore it.
3
of blocking, the coroutine simply yields while doing I/O.
4
3
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
5
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Reviewed-by: Alberto Garcia <berto@igalia.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Message-Id: <20200424125448.63318-7-kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
10
---
8
block/qed.c | 33 +++++++++++++++++----------------
11
block/file-posix.c | 4 ++++
9
1 file changed, 17 insertions(+), 16 deletions(-)
12
1 file changed, 4 insertions(+)
10
13
11
diff --git a/block/qed.c b/block/qed.c
14
diff --git a/block/file-posix.c b/block/file-posix.c
12
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
13
--- a/block/qed.c
16
--- a/block/file-posix.c
14
+++ b/block/qed.c
17
+++ b/block/file-posix.c
15
@@ -XXX,XX +XXX,XX @@ static void qed_unplug_allocating_write_reqs(BDRVQEDState *s)
18
@@ -XXX,XX +XXX,XX @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
16
qemu_co_enter_next(&s->allocating_write_reqs);
19
#endif
17
}
20
18
21
bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK;
19
-static void qed_clear_need_check(void *opaque, int ret)
22
+ if (S_ISREG(st.st_mode)) {
20
+static void qed_need_check_timer_entry(void *opaque)
23
+ /* When extending regular files, we get zeros from the OS */
21
{
24
+ bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE;
22
BDRVQEDState *s = opaque;
25
+ }
23
+ int ret;
26
ret = 0;
24
27
fail:
25
- if (ret) {
28
if (filename && (bdrv_flags & BDRV_O_TEMPORARY)) {
26
+ /* The timer should only fire when allocating writes have drained */
27
+ assert(!s->allocating_acb);
28
+
29
+ trace_qed_need_check_timer_cb(s);
30
+
31
+ qed_acquire(s);
32
+ qed_plug_allocating_write_reqs(s);
33
+
34
+ /* Ensure writes are on disk before clearing flag */
35
+ ret = bdrv_co_flush(s->bs->file->bs);
36
+ qed_release(s);
37
+ if (ret < 0) {
38
qed_unplug_allocating_write_reqs(s);
39
return;
40
}
41
@@ -XXX,XX +XXX,XX @@ static void qed_clear_need_check(void *opaque, int ret)
42
43
qed_unplug_allocating_write_reqs(s);
44
45
- ret = bdrv_flush(s->bs);
46
+ ret = bdrv_co_flush(s->bs);
47
(void) ret;
48
}
49
50
static void qed_need_check_timer_cb(void *opaque)
51
{
52
- BDRVQEDState *s = opaque;
53
-
54
- /* The timer should only fire when allocating writes have drained */
55
- assert(!s->allocating_acb);
56
-
57
- trace_qed_need_check_timer_cb(s);
58
-
59
- qed_acquire(s);
60
- qed_plug_allocating_write_reqs(s);
61
-
62
- /* Ensure writes are on disk before clearing flag */
63
- bdrv_aio_flush(s->bs->file->bs, qed_clear_need_check, s);
64
- qed_release(s);
65
+ Coroutine *co = qemu_coroutine_create(qed_need_check_timer_entry, opaque);
66
+ qemu_coroutine_enter(co);
67
}
68
69
void qed_acquire(BDRVQEDState *s)
70
--
29
--
71
1.8.3.1
30
2.25.3
72
31
73
32
diff view generated by jsdifflib
1
From: Stefan Hajnoczi <stefanha@redhat.com>
1
When extending the size of an image that has a backing file larger than
2
its old size, make sure that the backing file data doesn't become
3
visible in the guest, but the added area is properly zeroed out.
2
4
3
Calling aio_poll() directly may have been fine previously, but this is
5
Consider the following scenario where the overlay is shorter than its
4
the future, man! The difference between an aio_poll() loop and
6
backing file:
5
BDRV_POLL_WHILE() is that BDRV_POLL_WHILE() releases the AioContext
6
around aio_poll().
7
7
8
This allows the IOThread to run fd handlers or BHs to complete the
8
base.qcow2: AAAAAAAA
9
request. Failure to release the AioContext causes deadlocks.
9
overlay.qcow2: BBBB
10
10
11
Using BDRV_POLL_WHILE() partially fixes a 'savevm' hang with -object
11
When resizing (extending) overlay.qcow2, the new blocks should not stay
12
iothread.
12
unallocated and make the additional As from base.qcow2 visible like
13
before this patch, but zeros should be read.
13
14
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
15
A similar case happens with the various variants of a commit job when an
15
Reviewed-by: Eric Blake <eblake@redhat.com>
16
intermediate file is short (- for unallocated):
16
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
17
18
base.qcow2: A-A-AAAA
19
mid.qcow2: BB-B
20
top.qcow2: C--C--C-
21
22
After commit top.qcow2 to mid.qcow2, the following happens:
23
24
mid.qcow2: CB-C00C0 (correct result)
25
mid.qcow2: CB-C--C- (before this fix)
26
27
Without the fix, blocks that previously read as zeros on top.qcow2
28
suddenly turn into A.
29
30
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
31
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
32
Message-Id: <20200424125448.63318-8-kwolf@redhat.com>
33
Reviewed-by: Max Reitz <mreitz@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
34
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
---
35
---
19
block/io.c | 4 +---
36
block/io.c | 25 +++++++++++++++++++++++++
20
1 file changed, 1 insertion(+), 3 deletions(-)
37
1 file changed, 25 insertions(+)
21
38
22
diff --git a/block/io.c b/block/io.c
39
diff --git a/block/io.c b/block/io.c
23
index XXXXXXX..XXXXXXX 100644
40
index XXXXXXX..XXXXXXX 100644
24
--- a/block/io.c
41
--- a/block/io.c
25
+++ b/block/io.c
42
+++ b/block/io.c
26
@@ -XXX,XX +XXX,XX @@ bdrv_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos,
43
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
27
Coroutine *co = qemu_coroutine_create(bdrv_co_rw_vmstate_entry, &data);
44
goto out;
28
29
bdrv_coroutine_enter(bs, co);
30
- while (data.ret == -EINPROGRESS) {
31
- aio_poll(bdrv_get_aio_context(bs), true);
32
- }
33
+ BDRV_POLL_WHILE(bs, data.ret == -EINPROGRESS);
34
return data.ret;
35
}
45
}
36
}
46
47
+ /*
48
+ * If the image has a backing file that is large enough that it would
49
+ * provide data for the new area, we cannot leave it unallocated because
50
+ * then the backing file content would become visible. Instead, zero-fill
51
+ * the new area.
52
+ *
53
+ * Note that if the image has a backing file, but was opened without the
54
+ * backing file, taking care of keeping things consistent with that backing
55
+ * file is the user's responsibility.
56
+ */
57
+ if (new_bytes && bs->backing) {
58
+ int64_t backing_len;
59
+
60
+ backing_len = bdrv_getlength(backing_bs(bs));
61
+ if (backing_len < 0) {
62
+ ret = backing_len;
63
+ error_setg_errno(errp, -ret, "Could not get backing file size");
64
+ goto out;
65
+ }
66
+
67
+ if (backing_len > old_size) {
68
+ flags |= BDRV_REQ_ZERO_WRITE;
69
+ }
70
+ }
71
+
72
if (drv->bdrv_co_truncate) {
73
if (flags & ~bs->supported_truncate_flags) {
74
error_setg(errp, "Block driver does not support requested flags");
37
--
75
--
38
1.8.3.1
76
2.25.3
39
77
40
78
diff view generated by jsdifflib
1
Now that we process a request in the same coroutine from beginning to
1
We want to keep TEST_IMG for the full path of the main test image, but
2
end and don't drop out of it any more, we can look like a proper
2
filter_testfiles() must be called for other test images before replacing
3
coroutine-based driver and simply call qed_aio_next_io() and get a
3
other things like the image format because the test directory path could
4
return value from it instead of spawning an additional coroutine that
4
contain the format as a substring.
5
reenters the parent when it's done.
5
6
Insert a filter_testfiles() call between both.
6
7
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
11
Message-Id: <20200424125448.63318-9-kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
13
---
10
block/qed.c | 101 +++++++++++++-----------------------------------------------
14
tests/qemu-iotests/iotests.py | 5 +++--
11
block/qed.h | 3 +-
15
1 file changed, 3 insertions(+), 2 deletions(-)
12
2 files changed, 22 insertions(+), 82 deletions(-)
13
16
14
diff --git a/block/qed.c b/block/qed.c
17
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
15
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
16
--- a/block/qed.c
19
--- a/tests/qemu-iotests/iotests.py
17
+++ b/block/qed.c
20
+++ b/tests/qemu-iotests/iotests.py
18
@@ -XXX,XX +XXX,XX @@
21
@@ -XXX,XX +XXX,XX @@ def filter_img_info(output, filename):
19
#include "qapi/qmp/qerror.h"
22
for line in output.split('\n'):
20
#include "sysemu/block-backend.h"
23
if 'disk size' in line or 'actual-size' in line:
21
24
continue
22
-static const AIOCBInfo qed_aiocb_info = {
25
- line = line.replace(filename, 'TEST_IMG') \
23
- .aiocb_size = sizeof(QEDAIOCB),
26
- .replace(imgfmt, 'IMGFMT')
24
-};
27
+ line = line.replace(filename, 'TEST_IMG')
25
-
28
+ line = filter_testfiles(line)
26
static int bdrv_qed_probe(const uint8_t *buf, int buf_size,
29
+ line = line.replace(imgfmt, 'IMGFMT')
27
const char *filename)
30
line = re.sub('iters: [0-9]+', 'iters: XXX', line)
28
{
31
line = re.sub('uuid: [-a-f0-9]+', 'uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX', line)
29
@@ -XXX,XX +XXX,XX @@ static CachedL2Table *qed_new_l2_table(BDRVQEDState *s)
32
line = re.sub('cid: [0-9]+', 'cid: XXXXXXXXXX', line)
30
return l2_table;
31
}
32
33
-static void qed_aio_next_io(QEDAIOCB *acb);
34
-
35
-static void qed_aio_start_io(QEDAIOCB *acb)
36
-{
37
- qed_aio_next_io(acb);
38
-}
39
-
40
static void qed_plug_allocating_write_reqs(BDRVQEDState *s)
41
{
42
assert(!s->allocating_write_reqs_plugged);
43
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn bdrv_qed_co_get_block_status(BlockDriverState *bs,
44
45
static BDRVQEDState *acb_to_s(QEDAIOCB *acb)
46
{
47
- return acb->common.bs->opaque;
48
+ return acb->bs->opaque;
49
}
50
51
/**
52
@@ -XXX,XX +XXX,XX @@ static void qed_update_l2_table(BDRVQEDState *s, QEDTable *table, int index,
53
}
54
}
55
56
-static void qed_aio_complete_bh(void *opaque)
57
-{
58
- QEDAIOCB *acb = opaque;
59
- BDRVQEDState *s = acb_to_s(acb);
60
- BlockCompletionFunc *cb = acb->common.cb;
61
- void *user_opaque = acb->common.opaque;
62
- int ret = acb->bh_ret;
63
-
64
- qemu_aio_unref(acb);
65
-
66
- /* Invoke callback */
67
- qed_acquire(s);
68
- cb(user_opaque, ret);
69
- qed_release(s);
70
-}
71
-
72
-static void qed_aio_complete(QEDAIOCB *acb, int ret)
73
+static void qed_aio_complete(QEDAIOCB *acb)
74
{
75
BDRVQEDState *s = acb_to_s(acb);
76
77
- trace_qed_aio_complete(s, acb, ret);
78
-
79
/* Free resources */
80
qemu_iovec_destroy(&acb->cur_qiov);
81
qed_unref_l2_cache_entry(acb->request.l2_table);
82
@@ -XXX,XX +XXX,XX @@ static void qed_aio_complete(QEDAIOCB *acb, int ret)
83
acb->qiov->iov[0].iov_base = NULL;
84
}
85
86
- /* Arrange for a bh to invoke the completion function */
87
- acb->bh_ret = ret;
88
- aio_bh_schedule_oneshot(bdrv_get_aio_context(acb->common.bs),
89
- qed_aio_complete_bh, acb);
90
-
91
/* Start next allocating write request waiting behind this one. Note that
92
* requests enqueue themselves when they first hit an unallocated cluster
93
* but they wait until the entire request is finished before waking up the
94
@@ -XXX,XX +XXX,XX @@ static int qed_aio_write_inplace(QEDAIOCB *acb, uint64_t offset, size_t len)
95
struct iovec *iov = acb->qiov->iov;
96
97
if (!iov->iov_base) {
98
- iov->iov_base = qemu_try_blockalign(acb->common.bs, iov->iov_len);
99
+ iov->iov_base = qemu_try_blockalign(acb->bs, iov->iov_len);
100
if (iov->iov_base == NULL) {
101
return -ENOMEM;
102
}
103
@@ -XXX,XX +XXX,XX @@ static int qed_aio_read_data(void *opaque, int ret, uint64_t offset, size_t len)
104
{
105
QEDAIOCB *acb = opaque;
106
BDRVQEDState *s = acb_to_s(acb);
107
- BlockDriverState *bs = acb->common.bs;
108
+ BlockDriverState *bs = acb->bs;
109
110
/* Adjust offset into cluster */
111
offset += qed_offset_into_cluster(s, acb->cur_pos);
112
@@ -XXX,XX +XXX,XX @@ static int qed_aio_read_data(void *opaque, int ret, uint64_t offset, size_t len)
113
/**
114
* Begin next I/O or complete the request
115
*/
116
-static void qed_aio_next_io(QEDAIOCB *acb)
117
+static int qed_aio_next_io(QEDAIOCB *acb)
118
{
119
BDRVQEDState *s = acb_to_s(acb);
120
uint64_t offset;
121
@@ -XXX,XX +XXX,XX @@ static void qed_aio_next_io(QEDAIOCB *acb)
122
123
/* Complete request */
124
if (acb->cur_pos >= acb->end_pos) {
125
- qed_aio_complete(acb, 0);
126
- return;
127
+ ret = 0;
128
+ break;
129
}
130
131
/* Find next cluster and start I/O */
132
len = acb->end_pos - acb->cur_pos;
133
ret = qed_find_cluster(s, &acb->request, acb->cur_pos, &len, &offset);
134
if (ret < 0) {
135
- qed_aio_complete(acb, ret);
136
- return;
137
+ break;
138
}
139
140
if (acb->flags & QED_AIOCB_WRITE) {
141
@@ -XXX,XX +XXX,XX @@ static void qed_aio_next_io(QEDAIOCB *acb)
142
}
143
144
if (ret < 0 && ret != -EAGAIN) {
145
- qed_aio_complete(acb, ret);
146
- return;
147
+ break;
148
}
149
}
150
-}
151
152
-typedef struct QEDRequestCo {
153
- Coroutine *co;
154
- bool done;
155
- int ret;
156
-} QEDRequestCo;
157
-
158
-static void qed_co_request_cb(void *opaque, int ret)
159
-{
160
- QEDRequestCo *co = opaque;
161
-
162
- co->done = true;
163
- co->ret = ret;
164
- qemu_coroutine_enter_if_inactive(co->co);
165
+ trace_qed_aio_complete(s, acb, ret);
166
+ qed_aio_complete(acb);
167
+ return ret;
168
}
169
170
static int coroutine_fn qed_co_request(BlockDriverState *bs, int64_t sector_num,
171
QEMUIOVector *qiov, int nb_sectors,
172
int flags)
173
{
174
- QEDRequestCo co = {
175
- .co = qemu_coroutine_self(),
176
- .done = false,
177
+ QEDAIOCB acb = {
178
+ .bs = bs,
179
+ .cur_pos = (uint64_t) sector_num * BDRV_SECTOR_SIZE,
180
+ .end_pos = (sector_num + nb_sectors) * BDRV_SECTOR_SIZE,
181
+ .qiov = qiov,
182
+ .flags = flags,
183
};
184
- QEDAIOCB *acb = qemu_aio_get(&qed_aiocb_info, bs, qed_co_request_cb, &co);
185
-
186
- trace_qed_aio_setup(bs->opaque, acb, sector_num, nb_sectors, &co, flags);
187
+ qemu_iovec_init(&acb.cur_qiov, qiov->niov);
188
189
- acb->flags = flags;
190
- acb->qiov = qiov;
191
- acb->qiov_offset = 0;
192
- acb->cur_pos = (uint64_t)sector_num * BDRV_SECTOR_SIZE;
193
- acb->end_pos = acb->cur_pos + nb_sectors * BDRV_SECTOR_SIZE;
194
- acb->backing_qiov = NULL;
195
- acb->request.l2_table = NULL;
196
- qemu_iovec_init(&acb->cur_qiov, qiov->niov);
197
+ trace_qed_aio_setup(bs->opaque, &acb, sector_num, nb_sectors, NULL, flags);
198
199
/* Start request */
200
- qed_aio_start_io(acb);
201
-
202
- if (!co.done) {
203
- qemu_coroutine_yield();
204
- }
205
-
206
- return co.ret;
207
+ return qed_aio_next_io(&acb);
208
}
209
210
static int coroutine_fn bdrv_qed_co_readv(BlockDriverState *bs,
211
diff --git a/block/qed.h b/block/qed.h
212
index XXXXXXX..XXXXXXX 100644
213
--- a/block/qed.h
214
+++ b/block/qed.h
215
@@ -XXX,XX +XXX,XX @@ enum {
216
};
217
218
typedef struct QEDAIOCB {
219
- BlockAIOCB common;
220
- int bh_ret; /* final return status for completion bh */
221
+ BlockDriverState *bs;
222
QSIMPLEQ_ENTRY(QEDAIOCB) next; /* next request */
223
int flags; /* QED_AIOCB_* bits ORed together */
224
uint64_t end_pos; /* request end on block device, in bytes */
225
--
33
--
226
1.8.3.1
34
2.25.3
227
35
228
36
diff view generated by jsdifflib
1
When qemu is exited, all running jobs should be cancelled successfully.
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
This adds a test for this for all types of block jobs that currently
2
Message-Id: <20200424125448.63318-10-kwolf@redhat.com>
3
exist in qemu.
3
Reviewed-by: Max Reitz <mreitz@redhat.com>
4
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
7
tests/qemu-iotests/274 | 155 +++++++++++++++++++++
8
tests/qemu-iotests/274.out | 268 +++++++++++++++++++++++++++++++++++++
9
tests/qemu-iotests/group | 1 +
10
3 files changed, 424 insertions(+)
11
create mode 100755 tests/qemu-iotests/274
12
create mode 100644 tests/qemu-iotests/274.out
4
13
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
diff --git a/tests/qemu-iotests/274 b/tests/qemu-iotests/274
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
---
8
tests/qemu-iotests/185 | 206 +++++++++++++++++++++++++++++++++++++++++++++
9
tests/qemu-iotests/185.out | 59 +++++++++++++
10
tests/qemu-iotests/group | 1 +
11
3 files changed, 266 insertions(+)
12
create mode 100755 tests/qemu-iotests/185
13
create mode 100644 tests/qemu-iotests/185.out
14
15
diff --git a/tests/qemu-iotests/185 b/tests/qemu-iotests/185
16
new file mode 100755
15
new file mode 100755
17
index XXXXXXX..XXXXXXX
16
index XXXXXXX..XXXXXXX
18
--- /dev/null
17
--- /dev/null
19
+++ b/tests/qemu-iotests/185
18
+++ b/tests/qemu-iotests/274
20
@@ -XXX,XX +XXX,XX @@
19
@@ -XXX,XX +XXX,XX @@
21
+#!/bin/bash
20
+#!/usr/bin/env python3
22
+#
21
+#
23
+# Test exiting qemu while jobs are still running
22
+# Copyright (C) 2019 Red Hat, Inc.
24
+#
25
+# Copyright (C) 2017 Red Hat, Inc.
26
+#
23
+#
27
+# This program is free software; you can redistribute it and/or modify
24
+# This program is free software; you can redistribute it and/or modify
28
+# it under the terms of the GNU General Public License as published by
25
+# it under the terms of the GNU General Public License as published by
29
+# the Free Software Foundation; either version 2 of the License, or
26
+# the Free Software Foundation; either version 2 of the License, or
30
+# (at your option) any later version.
27
+# (at your option) any later version.
...
...
35
+# GNU General Public License for more details.
32
+# GNU General Public License for more details.
36
+#
33
+#
37
+# You should have received a copy of the GNU General Public License
34
+# You should have received a copy of the GNU General Public License
38
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
35
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
39
+#
36
+#
40
+
37
+# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
41
+# creator
38
+#
42
+owner=kwolf@redhat.com
39
+# Some tests for short backing files and short overlays
43
+
40
+
44
+seq=`basename $0`
41
+import iotests
45
+echo "QA output created by $seq"
42
+
46
+
43
+iotests.verify_image_format(supported_fmts=['qcow2'])
47
+here=`pwd`
44
+iotests.verify_platform(['linux'])
48
+status=1 # failure is the default!
45
+
49
+
46
+size_short = 1 * 1024 * 1024
50
+MIG_SOCKET="${TEST_DIR}/migrate"
47
+size_long = 2 * 1024 * 1024
51
+
48
+size_diff = size_long - size_short
52
+_cleanup()
49
+
53
+{
50
+def create_chain() -> None:
54
+ rm -f "${TEST_IMG}.mid"
51
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, base,
55
+ rm -f "${TEST_IMG}.copy"
52
+ str(size_long))
56
+ _cleanup_test_img
53
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', base, mid,
57
+ _cleanup_qemu
54
+ str(size_short))
58
+}
55
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', mid, top,
59
+trap "_cleanup; exit \$status" 0 1 2 3 15
56
+ str(size_long))
60
+
57
+
61
+# get standard environment, filters and checks
58
+ iotests.qemu_io_log('-c', 'write -P 1 0 %d' % size_long, base)
62
+. ./common.rc
59
+
63
+. ./common.filter
60
+def create_vm() -> iotests.VM:
64
+. ./common.qemu
61
+ vm = iotests.VM()
65
+
62
+ vm.add_blockdev('file,filename=%s,node-name=base-file' % base)
66
+_supported_fmt qcow2
63
+ vm.add_blockdev('%s,file=base-file,node-name=base' % iotests.imgfmt)
67
+_supported_proto file
64
+ vm.add_blockdev('file,filename=%s,node-name=mid-file' % mid)
68
+_supported_os Linux
65
+ vm.add_blockdev('%s,file=mid-file,node-name=mid,backing=base'
69
+
66
+ % iotests.imgfmt)
70
+size=64M
67
+ vm.add_drive(top, 'backing=mid,node-name=top')
71
+TEST_IMG="${TEST_IMG}.base" _make_test_img $size
68
+ return vm
72
+
69
+
73
+echo
70
+with iotests.FilePath('base') as base, \
74
+echo === Starting VM ===
71
+ iotests.FilePath('mid') as mid, \
75
+echo
72
+ iotests.FilePath('top') as top:
76
+
73
+
77
+qemu_comm_method="qmp"
74
+ iotests.log('== Commit tests ==')
78
+
75
+
79
+_launch_qemu \
76
+ create_chain()
80
+ -drive file="${TEST_IMG}.base",cache=$CACHEMODE,driver=$IMGFMT,id=disk
77
+
81
+h=$QEMU_HANDLE
78
+ iotests.log('=== Check visible data ===')
82
+_send_qemu_cmd $h "{ 'execute': 'qmp_capabilities' }" 'return'
79
+
83
+
80
+ iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, top)
84
+echo
81
+ iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), top)
85
+echo === Creating backing chain ===
82
+
86
+echo
83
+ iotests.log('=== Checking allocation status ===')
87
+
84
+
88
+_send_qemu_cmd $h \
85
+ iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short,
89
+ "{ 'execute': 'blockdev-snapshot-sync',
86
+ '-c', 'alloc %d %d' % (size_short, size_diff),
90
+ 'arguments': { 'device': 'disk',
87
+ base)
91
+ 'snapshot-file': '$TEST_IMG.mid',
88
+
92
+ 'format': '$IMGFMT',
89
+ iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short,
93
+ 'mode': 'absolute-paths' } }" \
90
+ '-c', 'alloc %d %d' % (size_short, size_diff),
94
+ "return"
91
+ mid)
95
+
92
+
96
+_send_qemu_cmd $h \
93
+ iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short,
97
+ "{ 'execute': 'human-monitor-command',
94
+ '-c', 'alloc %d %d' % (size_short, size_diff),
98
+ 'arguments': { 'command-line':
95
+ top)
99
+ 'qemu-io disk \"write 0 4M\"' } }" \
96
+
100
+ "return"
97
+ iotests.log('=== Checking map ===')
101
+
98
+
102
+_send_qemu_cmd $h \
99
+ iotests.qemu_img_log('map', '--output=json', base)
103
+ "{ 'execute': 'blockdev-snapshot-sync',
100
+ iotests.qemu_img_log('map', '--output=human', base)
104
+ 'arguments': { 'device': 'disk',
101
+ iotests.qemu_img_log('map', '--output=json', mid)
105
+ 'snapshot-file': '$TEST_IMG',
102
+ iotests.qemu_img_log('map', '--output=human', mid)
106
+ 'format': '$IMGFMT',
103
+ iotests.qemu_img_log('map', '--output=json', top)
107
+ 'mode': 'absolute-paths' } }" \
104
+ iotests.qemu_img_log('map', '--output=human', top)
108
+ "return"
105
+
109
+
106
+ iotests.log('=== Testing qemu-img commit (top -> mid) ===')
110
+echo
107
+
111
+echo === Start commit job and exit qemu ===
108
+ iotests.qemu_img_log('commit', top)
112
+echo
109
+ iotests.img_info_log(mid)
113
+
110
+ iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid)
114
+# Note that the reference output intentionally includes the 'offset' field in
111
+ iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid)
115
+# BLOCK_JOB_CANCELLED events for all of the following block jobs. They are
112
+
116
+# predictable and any change in the offsets would hint at a bug in the job
113
+ iotests.log('=== Testing HMP commit (top -> mid) ===')
117
+# throttling code.
114
+
118
+#
115
+ create_chain()
119
+# In order to achieve these predictable offsets, all of the following tests
116
+ with create_vm() as vm:
120
+# use speed=65536. Each job will perform exactly one iteration before it has
117
+ vm.launch()
121
+# to sleep at least for a second, which is plenty of time for the 'quit' QMP
118
+ vm.qmp_log('human-monitor-command', command_line='commit drive0')
122
+# command to be received (after receiving the command, the rest runs
119
+
123
+# synchronously, so jobs can arbitrarily continue or complete).
120
+ iotests.img_info_log(mid)
124
+#
121
+ iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid)
125
+# The buffer size for commit and streaming is 512k (waiting for 8 seconds after
122
+ iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid)
126
+# the first request), for active commit and mirror it's large enough to cover
123
+
127
+# the full 4M, and for backup it's the qcow2 cluster size, which we know is
124
+ iotests.log('=== Testing QMP active commit (top -> mid) ===')
128
+# 64k. As all of these are at least as large as the speed, we are sure that the
125
+
129
+# offset doesn't advance after the first iteration before qemu exits.
126
+ create_chain()
130
+
127
+ with create_vm() as vm:
131
+_send_qemu_cmd $h \
128
+ vm.launch()
132
+ "{ 'execute': 'block-commit',
129
+ vm.qmp_log('block-commit', device='top', base_node='mid',
133
+ 'arguments': { 'device': 'disk',
130
+ job_id='job0', auto_dismiss=False)
134
+ 'base':'$TEST_IMG.base',
131
+ vm.run_job('job0', wait=5)
135
+ 'top': '$TEST_IMG.mid',
132
+
136
+ 'speed': 65536 } }" \
133
+ iotests.img_info_log(mid)
137
+ "return"
134
+ iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid)
138
+
135
+ iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid)
139
+_send_qemu_cmd $h "{ 'execute': 'quit' }" "return"
136
+
140
+wait=1 _cleanup_qemu
137
+
141
+
138
+ iotests.log('== Resize tests ==')
142
+echo
139
+
143
+echo === Start active commit job and exit qemu ===
140
+ # Use different sizes for different allocation modes:
144
+echo
141
+ #
145
+
142
+ # We want to have at least one test where 32 bit truncation in the size of
146
+_launch_qemu \
143
+ # the overlapping area becomes visible. This is covered by the
147
+ -drive file="${TEST_IMG}",cache=$CACHEMODE,driver=$IMGFMT,id=disk
144
+ # prealloc='off' case (1G to 6G is an overlap of 5G).
148
+h=$QEMU_HANDLE
145
+ #
149
+_send_qemu_cmd $h "{ 'execute': 'qmp_capabilities' }" 'return'
146
+ # However, we can only do this for modes that don't preallocate data
150
+
147
+ # because otherwise we might run out of space on the test host.
151
+_send_qemu_cmd $h \
148
+ #
152
+ "{ 'execute': 'block-commit',
149
+ # We also want to test some unaligned combinations.
153
+ 'arguments': { 'device': 'disk',
150
+ for (prealloc, base_size, top_size_old, top_size_new, off) in [
154
+ 'base':'$TEST_IMG.base',
151
+ ('off', '6G', '1G', '8G', '5G'),
155
+ 'speed': 65536 } }" \
152
+ ('metadata', '32G', '30G', '33G', '31G'),
156
+ "return"
153
+ ('falloc', '10M', '5M', '15M', '9M'),
157
+
154
+ ('full', '16M', '8M', '12M', '11M'),
158
+_send_qemu_cmd $h "{ 'execute': 'quit' }" "return"
155
+ ('off', '384k', '253k', '512k', '253k'),
159
+wait=1 _cleanup_qemu
156
+ ('off', '400k', '256k', '512k', '336k'),
160
+
157
+ ('off', '512k', '256k', '500k', '436k')]:
161
+echo
158
+
162
+echo === Start mirror job and exit qemu ===
159
+ iotests.log('=== preallocation=%s ===' % prealloc)
163
+echo
160
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, base, base_size)
164
+
161
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', base, top,
165
+_launch_qemu \
162
+ top_size_old)
166
+ -drive file="${TEST_IMG}",cache=$CACHEMODE,driver=$IMGFMT,id=disk
163
+ iotests.qemu_io_log('-c', 'write -P 1 %s 64k' % off, base)
167
+h=$QEMU_HANDLE
164
+
168
+_send_qemu_cmd $h "{ 'execute': 'qmp_capabilities' }" 'return'
165
+ # After this, top_size_old to base_size should be allocated/zeroed.
169
+
166
+ #
170
+_send_qemu_cmd $h \
167
+ # In theory, leaving base_size to top_size_new unallocated would be
171
+ "{ 'execute': 'drive-mirror',
168
+ # correct, but in practice, if we zero out anything, we zero out
172
+ 'arguments': { 'device': 'disk',
169
+ # everything up to top_size_new.
173
+ 'target': '$TEST_IMG.copy',
170
+ iotests.qemu_img_log('resize', '-f', iotests.imgfmt,
174
+ 'format': '$IMGFMT',
171
+ '--preallocation', prealloc, top, top_size_new)
175
+ 'sync': 'full',
172
+ iotests.qemu_io_log('-c', 'read -P 0 %s 64k' % off, top)
176
+ 'speed': 65536 } }" \
173
+ iotests.qemu_io_log('-c', 'map', top)
177
+ "return"
174
+ iotests.qemu_img_log('map', '--output=json', top)
178
+
175
diff --git a/tests/qemu-iotests/274.out b/tests/qemu-iotests/274.out
179
+_send_qemu_cmd $h "{ 'execute': 'quit' }" "return"
180
+wait=1 _cleanup_qemu
181
+
182
+echo
183
+echo === Start backup job and exit qemu ===
184
+echo
185
+
186
+_launch_qemu \
187
+ -drive file="${TEST_IMG}",cache=$CACHEMODE,driver=$IMGFMT,id=disk
188
+h=$QEMU_HANDLE
189
+_send_qemu_cmd $h "{ 'execute': 'qmp_capabilities' }" 'return'
190
+
191
+_send_qemu_cmd $h \
192
+ "{ 'execute': 'drive-backup',
193
+ 'arguments': { 'device': 'disk',
194
+ 'target': '$TEST_IMG.copy',
195
+ 'format': '$IMGFMT',
196
+ 'sync': 'full',
197
+ 'speed': 65536 } }" \
198
+ "return"
199
+
200
+_send_qemu_cmd $h "{ 'execute': 'quit' }" "return"
201
+wait=1 _cleanup_qemu
202
+
203
+echo
204
+echo === Start streaming job and exit qemu ===
205
+echo
206
+
207
+_launch_qemu \
208
+ -drive file="${TEST_IMG}",cache=$CACHEMODE,driver=$IMGFMT,id=disk
209
+h=$QEMU_HANDLE
210
+_send_qemu_cmd $h "{ 'execute': 'qmp_capabilities' }" 'return'
211
+
212
+_send_qemu_cmd $h \
213
+ "{ 'execute': 'block-stream',
214
+ 'arguments': { 'device': 'disk',
215
+ 'speed': 65536 } }" \
216
+ "return"
217
+
218
+_send_qemu_cmd $h "{ 'execute': 'quit' }" "return"
219
+wait=1 _cleanup_qemu
220
+
221
+_check_test_img
222
+
223
+# success, all done
224
+echo "*** done"
225
+rm -f $seq.full
226
+status=0
227
diff --git a/tests/qemu-iotests/185.out b/tests/qemu-iotests/185.out
228
new file mode 100644
176
new file mode 100644
229
index XXXXXXX..XXXXXXX
177
index XXXXXXX..XXXXXXX
230
--- /dev/null
178
--- /dev/null
231
+++ b/tests/qemu-iotests/185.out
179
+++ b/tests/qemu-iotests/274.out
232
@@ -XXX,XX +XXX,XX @@
180
@@ -XXX,XX +XXX,XX @@
233
+QA output created by 185
181
+== Commit tests ==
234
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
182
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16
235
+
183
+
236
+=== Starting VM ===
184
+Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
237
+
185
+
186
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16
187
+
188
+wrote 2097152/2097152 bytes at offset 0
189
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
190
+
191
+=== Check visible data ===
192
+read 1048576/1048576 bytes at offset 0
193
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
194
+
195
+read 1048576/1048576 bytes at offset 1048576
196
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
197
+
198
+=== Checking allocation status ===
199
+1048576/1048576 bytes allocated at offset 0 bytes
200
+1048576/1048576 bytes allocated at offset 1 MiB
201
+
202
+0/1048576 bytes allocated at offset 0 bytes
203
+0/0 bytes allocated at offset 1 MiB
204
+
205
+0/1048576 bytes allocated at offset 0 bytes
206
+0/1048576 bytes allocated at offset 1 MiB
207
+
208
+=== Checking map ===
209
+[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": 327680}]
210
+
211
+Offset Length Mapped to File
212
+0 0x200000 0x50000 TEST_DIR/PID-base
213
+
214
+[{ "start": 0, "length": 1048576, "depth": 1, "zero": false, "data": true, "offset": 327680}]
215
+
216
+Offset Length Mapped to File
217
+0 0x100000 0x50000 TEST_DIR/PID-base
218
+
219
+[{ "start": 0, "length": 1048576, "depth": 2, "zero": false, "data": true, "offset": 327680},
220
+{ "start": 1048576, "length": 1048576, "depth": 0, "zero": true, "data": false}]
221
+
222
+Offset Length Mapped to File
223
+0 0x100000 0x50000 TEST_DIR/PID-base
224
+
225
+=== Testing qemu-img commit (top -> mid) ===
226
+Image committed.
227
+
228
+image: TEST_IMG
229
+file format: IMGFMT
230
+virtual size: 2 MiB (2097152 bytes)
231
+cluster_size: 65536
232
+backing file: TEST_DIR/PID-base
233
+Format specific information:
234
+ compat: 1.1
235
+ lazy refcounts: false
236
+ refcount bits: 16
237
+ corrupt: false
238
+
239
+read 1048576/1048576 bytes at offset 0
240
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
241
+
242
+read 1048576/1048576 bytes at offset 1048576
243
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
244
+
245
+=== Testing HMP commit (top -> mid) ===
246
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16
247
+
248
+Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
249
+
250
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16
251
+
252
+wrote 2097152/2097152 bytes at offset 0
253
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
254
+
255
+{"execute": "human-monitor-command", "arguments": {"command-line": "commit drive0"}}
256
+{"return": ""}
257
+image: TEST_IMG
258
+file format: IMGFMT
259
+virtual size: 2 MiB (2097152 bytes)
260
+cluster_size: 65536
261
+backing file: TEST_DIR/PID-base
262
+Format specific information:
263
+ compat: 1.1
264
+ lazy refcounts: false
265
+ refcount bits: 16
266
+ corrupt: false
267
+
268
+read 1048576/1048576 bytes at offset 0
269
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
270
+
271
+read 1048576/1048576 bytes at offset 1048576
272
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
273
+
274
+=== Testing QMP active commit (top -> mid) ===
275
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16
276
+
277
+Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
278
+
279
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16
280
+
281
+wrote 2097152/2097152 bytes at offset 0
282
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
283
+
284
+{"execute": "block-commit", "arguments": {"auto-dismiss": false, "base-node": "mid", "device": "top", "job-id": "job0"}}
238
+{"return": {}}
285
+{"return": {}}
239
+
286
+{"execute": "job-complete", "arguments": {"id": "job0"}}
240
+=== Creating backing chain ===
241
+
242
+Formatting 'TEST_DIR/t.qcow2.mid', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.qcow2.base backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
243
+{"return": {}}
287
+{"return": {}}
244
+wrote 4194304/4194304 bytes at offset 0
288
+{"data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
245
+4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
289
+{"data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
246
+{"return": ""}
290
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
247
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.qcow2.mid backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
248
+{"return": {}}
291
+{"return": {}}
249
+
292
+image: TEST_IMG
250
+=== Start commit job and exit qemu ===
293
+file format: IMGFMT
251
+
294
+virtual size: 2 MiB (2097152 bytes)
252
+{"return": {}}
295
+cluster_size: 65536
253
+{"return": {}}
296
+backing file: TEST_DIR/PID-base
254
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
297
+Format specific information:
255
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "disk", "len": 67108864, "offset": 524288, "speed": 65536, "type": "commit"}}
298
+ compat: 1.1
256
+
299
+ lazy refcounts: false
257
+=== Start active commit job and exit qemu ===
300
+ refcount bits: 16
258
+
301
+ corrupt: false
259
+{"return": {}}
302
+
260
+{"return": {}}
303
+read 1048576/1048576 bytes at offset 0
261
+{"return": {}}
304
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
262
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
305
+
263
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "disk", "len": 4194304, "offset": 4194304, "speed": 65536, "type": "commit"}}
306
+read 1048576/1048576 bytes at offset 1048576
264
+
307
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
265
+=== Start mirror job and exit qemu ===
308
+
266
+
309
+== Resize tests ==
267
+{"return": {}}
310
+=== preallocation=off ===
268
+Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
311
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=6442450944 cluster_size=65536 lazy_refcounts=off refcount_bits=16
269
+{"return": {}}
312
+
270
+{"return": {}}
313
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=1073741824 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
271
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
314
+
272
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "disk", "len": 4194304, "offset": 4194304, "speed": 65536, "type": "mirror"}}
315
+wrote 65536/65536 bytes at offset 5368709120
273
+
316
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
274
+=== Start backup job and exit qemu ===
317
+
275
+
318
+Image resized.
276
+{"return": {}}
319
+
277
+Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
320
+read 65536/65536 bytes at offset 5368709120
278
+{"return": {}}
321
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
279
+{"return": {}}
322
+
280
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
323
+1 GiB (0x40000000) bytes not allocated at offset 0 bytes (0x0)
281
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "disk", "len": 67108864, "offset": 65536, "speed": 65536, "type": "backup"}}
324
+7 GiB (0x1c0000000) bytes allocated at offset 1 GiB (0x40000000)
282
+
325
+
283
+=== Start streaming job and exit qemu ===
326
+[{ "start": 0, "length": 1073741824, "depth": 1, "zero": true, "data": false},
284
+
327
+{ "start": 1073741824, "length": 7516192768, "depth": 0, "zero": true, "data": false}]
285
+{"return": {}}
328
+
286
+{"return": {}}
329
+=== preallocation=metadata ===
287
+{"return": {}}
330
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=34359738368 cluster_size=65536 lazy_refcounts=off refcount_bits=16
288
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
331
+
289
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "disk", "len": 67108864, "offset": 524288, "speed": 65536, "type": "stream"}}
332
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=32212254720 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
290
+No errors were found on the image.
333
+
291
+*** done
334
+wrote 65536/65536 bytes at offset 33285996544
335
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
336
+
337
+Image resized.
338
+
339
+read 65536/65536 bytes at offset 33285996544
340
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
341
+
342
+30 GiB (0x780000000) bytes not allocated at offset 0 bytes (0x0)
343
+3 GiB (0xc0000000) bytes allocated at offset 30 GiB (0x780000000)
344
+
345
+[{ "start": 0, "length": 32212254720, "depth": 1, "zero": true, "data": false},
346
+{ "start": 32212254720, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 327680},
347
+{ "start": 32749125632, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 537264128},
348
+{ "start": 33285996544, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 1074200576},
349
+{ "start": 33822867456, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 1611137024},
350
+{ "start": 34359738368, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 2148139008},
351
+{ "start": 34896609280, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 2685075456}]
352
+
353
+=== preallocation=falloc ===
354
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=10485760 cluster_size=65536 lazy_refcounts=off refcount_bits=16
355
+
356
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=5242880 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
357
+
358
+wrote 65536/65536 bytes at offset 9437184
359
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
360
+
361
+Image resized.
362
+
363
+read 65536/65536 bytes at offset 9437184
364
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
365
+
366
+5 MiB (0x500000) bytes not allocated at offset 0 bytes (0x0)
367
+10 MiB (0xa00000) bytes allocated at offset 5 MiB (0x500000)
368
+
369
+[{ "start": 0, "length": 5242880, "depth": 1, "zero": true, "data": false},
370
+{ "start": 5242880, "length": 10485760, "depth": 0, "zero": true, "data": false, "offset": 327680}]
371
+
372
+=== preallocation=full ===
373
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=16777216 cluster_size=65536 lazy_refcounts=off refcount_bits=16
374
+
375
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=8388608 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
376
+
377
+wrote 65536/65536 bytes at offset 11534336
378
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
379
+
380
+Image resized.
381
+
382
+read 65536/65536 bytes at offset 11534336
383
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
384
+
385
+8 MiB (0x800000) bytes not allocated at offset 0 bytes (0x0)
386
+4 MiB (0x400000) bytes allocated at offset 8 MiB (0x800000)
387
+
388
+[{ "start": 0, "length": 8388608, "depth": 1, "zero": true, "data": false},
389
+{ "start": 8388608, "length": 4194304, "depth": 0, "zero": true, "data": false, "offset": 327680}]
390
+
391
+=== preallocation=off ===
392
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=393216 cluster_size=65536 lazy_refcounts=off refcount_bits=16
393
+
394
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=259072 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
395
+
396
+wrote 65536/65536 bytes at offset 259072
397
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
398
+
399
+Image resized.
400
+
401
+read 65536/65536 bytes at offset 259072
402
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
403
+
404
+192 KiB (0x30000) bytes not allocated at offset 0 bytes (0x0)
405
+320 KiB (0x50000) bytes allocated at offset 192 KiB (0x30000)
406
+
407
+[{ "start": 0, "length": 196608, "depth": 1, "zero": true, "data": false},
408
+{ "start": 196608, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": 327680},
409
+{ "start": 262144, "length": 262144, "depth": 0, "zero": true, "data": false}]
410
+
411
+=== preallocation=off ===
412
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=409600 cluster_size=65536 lazy_refcounts=off refcount_bits=16
413
+
414
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=262144 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
415
+
416
+wrote 65536/65536 bytes at offset 344064
417
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
418
+
419
+Image resized.
420
+
421
+read 65536/65536 bytes at offset 344064
422
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
423
+
424
+256 KiB (0x40000) bytes not allocated at offset 0 bytes (0x0)
425
+256 KiB (0x40000) bytes allocated at offset 256 KiB (0x40000)
426
+
427
+[{ "start": 0, "length": 262144, "depth": 1, "zero": true, "data": false},
428
+{ "start": 262144, "length": 262144, "depth": 0, "zero": true, "data": false}]
429
+
430
+=== preallocation=off ===
431
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=524288 cluster_size=65536 lazy_refcounts=off refcount_bits=16
432
+
433
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=262144 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
434
+
435
+wrote 65536/65536 bytes at offset 446464
436
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
437
+
438
+Image resized.
439
+
440
+read 65536/65536 bytes at offset 446464
441
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
442
+
443
+256 KiB (0x40000) bytes not allocated at offset 0 bytes (0x0)
444
+244 KiB (0x3d000) bytes allocated at offset 256 KiB (0x40000)
445
+
446
+[{ "start": 0, "length": 262144, "depth": 1, "zero": true, "data": false},
447
+{ "start": 262144, "length": 249856, "depth": 0, "zero": true, "data": false}]
448
+
292
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
449
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
293
index XXXXXXX..XXXXXXX 100644
450
index XXXXXXX..XXXXXXX 100644
294
--- a/tests/qemu-iotests/group
451
--- a/tests/qemu-iotests/group
295
+++ b/tests/qemu-iotests/group
452
+++ b/tests/qemu-iotests/group
296
@@ -XXX,XX +XXX,XX @@
453
@@ -XXX,XX +XXX,XX @@
297
181 rw auto migration
454
270 rw backing quick
298
182 rw auto quick
455
272 rw
299
183 rw auto migration
456
273 backing quick
300
+185 rw auto
457
+274 rw backing
458
277 rw quick
459
279 rw backing quick
460
280 rw migration quick
301
--
461
--
302
1.8.3.1
462
2.25.3
303
463
304
464
diff view generated by jsdifflib
Deleted patch
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
1
3
AioContext was designed to allow nested acquire/release calls. It uses
4
a recursive mutex so callers don't need to worry about nesting...or so
5
we thought.
6
7
BDRV_POLL_WHILE() is used to wait for block I/O requests. It releases
8
the AioContext temporarily around aio_poll(). This gives IOThreads a
9
chance to acquire the AioContext to process I/O completions.
10
11
It turns out that recursive locking and BDRV_POLL_WHILE() don't mix.
12
BDRV_POLL_WHILE() only releases the AioContext once, so the IOThread
13
will not be able to acquire the AioContext if it was acquired
14
multiple times.
15
16
Instead of trying to release AioContext n times in BDRV_POLL_WHILE(),
17
this patch simply avoids nested locking in save_vmstate(). It's the
18
simplest fix and we should step back to consider the big picture with
19
all the recent changes to block layer threading.
20
21
This patch is the final fix to solve 'savevm' hanging with -object
22
iothread.
23
24
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
25
Reviewed-by: Eric Blake <eblake@redhat.com>
26
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
27
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
28
---
29
migration/savevm.c | 12 +++++++++++-
30
1 file changed, 11 insertions(+), 1 deletion(-)
31
32
diff --git a/migration/savevm.c b/migration/savevm.c
33
index XXXXXXX..XXXXXXX 100644
34
--- a/migration/savevm.c
35
+++ b/migration/savevm.c
36
@@ -XXX,XX +XXX,XX @@ int save_snapshot(const char *name, Error **errp)
37
goto the_end;
38
}
39
40
+ /* The bdrv_all_create_snapshot() call that follows acquires the AioContext
41
+ * for itself. BDRV_POLL_WHILE() does not support nested locking because
42
+ * it only releases the lock once. Therefore synchronous I/O will deadlock
43
+ * unless we release the AioContext before bdrv_all_create_snapshot().
44
+ */
45
+ aio_context_release(aio_context);
46
+ aio_context = NULL;
47
+
48
ret = bdrv_all_create_snapshot(sn, bs, vm_state_size, &bs);
49
if (ret < 0) {
50
error_setg(errp, "Error while creating snapshot on '%s'",
51
@@ -XXX,XX +XXX,XX @@ int save_snapshot(const char *name, Error **errp)
52
ret = 0;
53
54
the_end:
55
- aio_context_release(aio_context);
56
+ if (aio_context) {
57
+ aio_context_release(aio_context);
58
+ }
59
if (saved_vm_running) {
60
vm_start();
61
}
62
--
63
1.8.3.1
64
65
diff view generated by jsdifflib
Deleted patch
1
This adds documentation for the -blockdev options that apply to all
2
nodes independent of the block driver used.
3
1
4
All options that are shared by -blockdev and -drive are now explained in
5
the section for -blockdev. The documentation of -drive mentions that all
6
-blockdev options are accepted as well.
7
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Reviewed-by: Max Reitz <mreitz@redhat.com>
11
---
12
qemu-options.hx | 108 +++++++++++++++++++++++++++++++++++++++++---------------
13
1 file changed, 79 insertions(+), 29 deletions(-)
14
15
diff --git a/qemu-options.hx b/qemu-options.hx
16
index XXXXXXX..XXXXXXX 100644
17
--- a/qemu-options.hx
18
+++ b/qemu-options.hx
19
@@ -XXX,XX +XXX,XX @@ DEF("blockdev", HAS_ARG, QEMU_OPTION_blockdev,
20
" [,read-only=on|off][,detect-zeroes=on|off|unmap]\n"
21
" [,driver specific parameters...]\n"
22
" configure a block backend\n", QEMU_ARCH_ALL)
23
+STEXI
24
+@item -blockdev @var{option}[,@var{option}[,@var{option}[,...]]]
25
+@findex -blockdev
26
+
27
+Define a new block driver node.
28
+
29
+@table @option
30
+@item Valid options for any block driver node:
31
+
32
+@table @code
33
+@item driver
34
+Specifies the block driver to use for the given node.
35
+@item node-name
36
+This defines the name of the block driver node by which it will be referenced
37
+later. The name must be unique, i.e. it must not match the name of a different
38
+block driver node, or (if you use @option{-drive} as well) the ID of a drive.
39
+
40
+If no node name is specified, it is automatically generated. The generated node
41
+name is not intended to be predictable and changes between QEMU invocations.
42
+For the top level, an explicit node name must be specified.
43
+@item read-only
44
+Open the node read-only. Guest write attempts will fail.
45
+@item cache.direct
46
+The host page cache can be avoided with @option{cache.direct=on}. This will
47
+attempt to do disk IO directly to the guest's memory. QEMU may still perform an
48
+internal copy of the data.
49
+@item cache.no-flush
50
+In case you don't care about data integrity over host failures, you can use
51
+@option{cache.no-flush=on}. This option tells QEMU that it never needs to write
52
+any data to the disk but can instead keep things in cache. If anything goes
53
+wrong, like your host losing power, the disk storage getting disconnected
54
+accidentally, etc. your image will most probably be rendered unusable.
55
+@item discard=@var{discard}
56
+@var{discard} is one of "ignore" (or "off") or "unmap" (or "on") and controls
57
+whether @code{discard} (also known as @code{trim} or @code{unmap}) requests are
58
+ignored or passed to the filesystem. Some machine types may not support
59
+discard requests.
60
+@item detect-zeroes=@var{detect-zeroes}
61
+@var{detect-zeroes} is "off", "on" or "unmap" and enables the automatic
62
+conversion of plain zero writes by the OS to driver specific optimized
63
+zero write commands. You may even choose "unmap" if @var{discard} is set
64
+to "unmap" to allow a zero write to be converted to an @code{unmap} operation.
65
+@end table
66
+
67
+@end table
68
+
69
+ETEXI
70
71
DEF("drive", HAS_ARG, QEMU_OPTION_drive,
72
"-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i]\n"
73
@@ -XXX,XX +XXX,XX @@ STEXI
74
@item -drive @var{option}[,@var{option}[,@var{option}[,...]]]
75
@findex -drive
76
77
-Define a new drive. Valid options are:
78
+Define a new drive. This includes creating a block driver node (the backend) as
79
+well as a guest device, and is mostly a shortcut for defining the corresponding
80
+@option{-blockdev} and @option{-device} options.
81
+
82
+@option{-drive} accepts all options that are accepted by @option{-blockdev}. In
83
+addition, it knows the following options:
84
85
@table @option
86
@item file=@var{file}
87
@@ -XXX,XX +XXX,XX @@ These options have the same definition as they have in @option{-hdachs}.
88
@var{snapshot} is "on" or "off" and controls snapshot mode for the given drive
89
(see @option{-snapshot}).
90
@item cache=@var{cache}
91
-@var{cache} is "none", "writeback", "unsafe", "directsync" or "writethrough" and controls how the host cache is used to access block data.
92
+@var{cache} is "none", "writeback", "unsafe", "directsync" or "writethrough"
93
+and controls how the host cache is used to access block data. This is a
94
+shortcut that sets the @option{cache.direct} and @option{cache.no-flush}
95
+options (as in @option{-blockdev}), and additionally @option{cache.writeback},
96
+which provides a default for the @option{write-cache} option of block guest
97
+devices (as in @option{-device}). The modes correspond to the following
98
+settings:
99
+
100
+@c Our texi2pod.pl script doesn't support @multitable, so fall back to using
101
+@c plain ASCII art (well, UTF-8 art really). This looks okay both in the manpage
102
+@c and the HTML output.
103
+@example
104
+@ │ cache.writeback cache.direct cache.no-flush
105
+─────────────┼─────────────────────────────────────────────────
106
+writeback │ on off off
107
+none │ on on off
108
+writethrough │ off off off
109
+directsync │ off on off
110
+unsafe │ on off on
111
+@end example
112
+
113
+The default mode is @option{cache=writeback}.
114
+
115
@item aio=@var{aio}
116
@var{aio} is "threads", or "native" and selects between pthread based disk I/O and native Linux AIO.
117
-@item discard=@var{discard}
118
-@var{discard} is one of "ignore" (or "off") or "unmap" (or "on") and controls whether @dfn{discard} (also known as @dfn{trim} or @dfn{unmap}) requests are ignored or passed to the filesystem. Some machine types may not support discard requests.
119
@item format=@var{format}
120
Specify which disk @var{format} will be used rather than detecting
121
the format. Can be used to specify format=raw to avoid interpreting
122
@@ -XXX,XX +XXX,XX @@ Specify which @var{action} to take on write and read errors. Valid actions are:
123
"report" (report the error to the guest), "enospc" (pause QEMU only if the
124
host disk is full; report the error to the guest otherwise).
125
The default setting is @option{werror=enospc} and @option{rerror=report}.
126
-@item readonly
127
-Open drive @option{file} as read-only. Guest write attempts will fail.
128
@item copy-on-read=@var{copy-on-read}
129
@var{copy-on-read} is "on" or "off" and enables whether to copy read backing
130
file sectors into the image file.
131
-@item detect-zeroes=@var{detect-zeroes}
132
-@var{detect-zeroes} is "off", "on" or "unmap" and enables the automatic
133
-conversion of plain zero writes by the OS to driver specific optimized
134
-zero write commands. You may even choose "unmap" if @var{discard} is set
135
-to "unmap" to allow a zero write to be converted to an UNMAP operation.
136
@item bps=@var{b},bps_rd=@var{r},bps_wr=@var{w}
137
Specify bandwidth throttling limits in bytes per second, either for all request
138
types or for reads or writes only. Small values can lead to timeouts or hangs
139
@@ -XXX,XX +XXX,XX @@ prevent guests from circumventing throttling limits by using many small disks
140
instead of a single larger disk.
141
@end table
142
143
-By default, the @option{cache=writeback} mode is used. It will report data
144
+By default, the @option{cache.writeback=on} mode is used. It will report data
145
writes as completed as soon as the data is present in the host page cache.
146
This is safe as long as your guest OS makes sure to correctly flush disk caches
147
where needed. If your guest OS does not handle volatile disk write caches
148
correctly and your host crashes or loses power, then the guest may experience
149
data corruption.
150
151
-For such guests, you should consider using @option{cache=writethrough}. This
152
+For such guests, you should consider using @option{cache.writeback=off}. This
153
means that the host page cache will be used to read and write data, but write
154
notification will be sent to the guest only after QEMU has made sure to flush
155
each write to the disk. Be aware that this has a major impact on performance.
156
157
-The host page cache can be avoided entirely with @option{cache=none}. This will
158
-attempt to do disk IO directly to the guest's memory. QEMU may still perform
159
-an internal copy of the data. Note that this is considered a writeback mode and
160
-the guest OS must handle the disk write cache correctly in order to avoid data
161
-corruption on host crashes.
162
-
163
-The host page cache can be avoided while only sending write notifications to
164
-the guest when the data has been flushed to the disk using
165
-@option{cache=directsync}.
166
-
167
-In case you don't care about data integrity over host failures, use
168
-@option{cache=unsafe}. This option tells QEMU that it never needs to write any
169
-data to the disk but can instead keep things in cache. If anything goes wrong,
170
-like your host losing power, the disk storage getting disconnected accidentally,
171
-etc. your image will most probably be rendered unusable. When using
172
-the @option{-snapshot} option, unsafe caching is always used.
173
+When using the @option{-snapshot} option, unsafe caching is always used.
174
175
Copy-on-read avoids accessing the same backing file sectors repeatedly and is
176
useful when the backing file is over a slow network. By default copy-on-read
177
--
178
1.8.3.1
179
180
diff view generated by jsdifflib
Deleted patch
1
This documents the driver-specific options for the raw, qcow2 and file
2
block drivers for the man page. For everything else, we refer to the
3
QAPI documentation.
4
1
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
---
9
qemu-options.hx | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
10
1 file changed, 114 insertions(+), 1 deletion(-)
11
12
diff --git a/qemu-options.hx b/qemu-options.hx
13
index XXXXXXX..XXXXXXX 100644
14
--- a/qemu-options.hx
15
+++ b/qemu-options.hx
16
@@ -XXX,XX +XXX,XX @@ STEXI
17
@item -blockdev @var{option}[,@var{option}[,@var{option}[,...]]]
18
@findex -blockdev
19
20
-Define a new block driver node.
21
+Define a new block driver node. Some of the options apply to all block drivers,
22
+other options are only accepted for a specific block driver. See below for a
23
+list of generic options and options for the most common block drivers.
24
+
25
+Options that expect a reference to another node (e.g. @code{file}) can be
26
+given in two ways. Either you specify the node name of an already existing node
27
+(file=@var{node-name}), or you define a new node inline, adding options
28
+for the referenced node after a dot (file.filename=@var{path},file.aio=native).
29
+
30
+A block driver node created with @option{-blockdev} can be used for a guest
31
+device by specifying its node name for the @code{drive} property in a
32
+@option{-device} argument that defines a block device.
33
34
@table @option
35
@item Valid options for any block driver node:
36
@@ -XXX,XX +XXX,XX @@ zero write commands. You may even choose "unmap" if @var{discard} is set
37
to "unmap" to allow a zero write to be converted to an @code{unmap} operation.
38
@end table
39
40
+@item Driver-specific options for @code{file}
41
+
42
+This is the protocol-level block driver for accessing regular files.
43
+
44
+@table @code
45
+@item filename
46
+The path to the image file in the local filesystem
47
+@item aio
48
+Specifies the AIO backend (threads/native, default: threads)
49
+@end table
50
+Example:
51
+@example
52
+-blockdev driver=file,node-name=disk,filename=disk.img
53
+@end example
54
+
55
+@item Driver-specific options for @code{raw}
56
+
57
+This is the image format block driver for raw images. It is usually
58
+stacked on top of a protocol level block driver such as @code{file}.
59
+
60
+@table @code
61
+@item file
62
+Reference to or definition of the data source block driver node
63
+(e.g. a @code{file} driver node)
64
+@end table
65
+Example 1:
66
+@example
67
+-blockdev driver=file,node-name=disk_file,filename=disk.img
68
+-blockdev driver=raw,node-name=disk,file=disk_file
69
+@end example
70
+Example 2:
71
+@example
72
+-blockdev driver=raw,node-name=disk,file.driver=file,file.filename=disk.img
73
+@end example
74
+
75
+@item Driver-specific options for @code{qcow2}
76
+
77
+This is the image format block driver for qcow2 images. It is usually
78
+stacked on top of a protocol level block driver such as @code{file}.
79
+
80
+@table @code
81
+@item file
82
+Reference to or definition of the data source block driver node
83
+(e.g. a @code{file} driver node)
84
+
85
+@item backing
86
+Reference to or definition of the backing file block device (default is taken
87
+from the image file). It is allowed to pass an empty string here in order to
88
+disable the default backing file.
89
+
90
+@item lazy-refcounts
91
+Whether to enable the lazy refcounts feature (on/off; default is taken from the
92
+image file)
93
+
94
+@item cache-size
95
+The maximum total size of the L2 table and refcount block caches in bytes
96
+(default: 1048576 bytes or 8 clusters, whichever is larger)
97
+
98
+@item l2-cache-size
99
+The maximum size of the L2 table cache in bytes
100
+(default: 4/5 of the total cache size)
101
+
102
+@item refcount-cache-size
103
+The maximum size of the refcount block cache in bytes
104
+(default: 1/5 of the total cache size)
105
+
106
+@item cache-clean-interval
107
+Clean unused entries in the L2 and refcount caches. The interval is in seconds.
108
+The default value is 0 and it disables this feature.
109
+
110
+@item pass-discard-request
111
+Whether discard requests to the qcow2 device should be forwarded to the data
112
+source (on/off; default: on if discard=unmap is specified, off otherwise)
113
+
114
+@item pass-discard-snapshot
115
+Whether discard requests for the data source should be issued when a snapshot
116
+operation (e.g. deleting a snapshot) frees clusters in the qcow2 file (on/off;
117
+default: on)
118
+
119
+@item pass-discard-other
120
+Whether discard requests for the data source should be issued on other
121
+occasions where a cluster gets freed (on/off; default: off)
122
+
123
+@item overlap-check
124
+Which overlap checks to perform for writes to the image
125
+(none/constant/cached/all; default: cached). For details or finer
126
+granularity control refer to the QAPI documentation of @code{blockdev-add}.
127
+@end table
128
+
129
+Example 1:
130
+@example
131
+-blockdev driver=file,node-name=my_file,filename=/tmp/disk.qcow2
132
+-blockdev driver=qcow2,node-name=hda,file=my_file,overlap-check=none,cache-size=16777216
133
+@end example
134
+Example 2:
135
+@example
136
+-blockdev driver=qcow2,node-name=disk,file.driver=http,file.filename=http://example.com/image.qcow2
137
+@end example
138
+
139
+@item Driver-specific options for other drivers
140
+Please refer to the QAPI documentation of the @code{blockdev-add} QMP command.
141
+
142
@end table
143
144
ETEXI
145
--
146
1.8.3.1
147
148
diff view generated by jsdifflib
Deleted patch
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
1
3
Old kvm.ko versions only supported a tiny number of ioeventfds so
4
virtio-pci avoids ioeventfds when kvm_has_many_ioeventfds() returns 0.
5
6
Do not check kvm_has_many_ioeventfds() when KVM is disabled since it
7
always returns 0. Since commit 8c56c1a592b5092d91da8d8943c17777d6462a6f
8
("memory: emulate ioeventfd") it has been possible to use ioeventfds in
9
qtest or TCG mode.
10
11
This patch makes -device virtio-blk-pci,iothread=iothread0 work even
12
when KVM is disabled.
13
14
I have tested that virtio-blk-pci works under TCG both with and without
15
iothread.
16
17
Cc: Michael S. Tsirkin <mst@redhat.com>
18
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
19
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
20
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
21
---
22
hw/virtio/virtio-pci.c | 2 +-
23
1 file changed, 1 insertion(+), 1 deletion(-)
24
25
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
26
index XXXXXXX..XXXXXXX 100644
27
--- a/hw/virtio/virtio-pci.c
28
+++ b/hw/virtio/virtio-pci.c
29
@@ -XXX,XX +XXX,XX @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp)
30
bool pcie_port = pci_bus_is_express(pci_dev->bus) &&
31
!pci_bus_is_root(pci_dev->bus);
32
33
- if (!kvm_has_many_ioeventfds()) {
34
+ if (kvm_enabled() && !kvm_has_many_ioeventfds()) {
35
proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD;
36
}
37
38
--
39
1.8.3.1
40
41
diff view generated by jsdifflib
Deleted patch
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
1
3
migration_incoming_state_destroy() uses qemu_fclose() on the vmstate
4
file. Make sure to call it inside an AioContext acquire/release region.
5
6
This fixes an 'qemu: qemu_mutex_unlock: Operation not permitted' abort
7
in loadvm.
8
9
This patch closes the vmstate file before ending the drained region.
10
Previously we closed the vmstate file after ending the drained region.
11
The order does not matter.
12
13
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
16
migration/savevm.c | 2 +-
17
1 file changed, 1 insertion(+), 1 deletion(-)
18
19
diff --git a/migration/savevm.c b/migration/savevm.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/migration/savevm.c
22
+++ b/migration/savevm.c
23
@@ -XXX,XX +XXX,XX @@ int load_snapshot(const char *name, Error **errp)
24
25
aio_context_acquire(aio_context);
26
ret = qemu_loadvm_state(f);
27
+ migration_incoming_state_destroy();
28
aio_context_release(aio_context);
29
30
bdrv_drain_all_end();
31
32
- migration_incoming_state_destroy();
33
if (ret < 0) {
34
error_setg(errp, "Error %d while loading VM state", ret);
35
return ret;
36
--
37
1.8.3.1
38
39
diff view generated by jsdifflib
Deleted patch
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
1
3
Avoid duplicating the QEMU command-line.
4
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
8
tests/qemu-iotests/068 | 15 +++++++++------
9
1 file changed, 9 insertions(+), 6 deletions(-)
10
11
diff --git a/tests/qemu-iotests/068 b/tests/qemu-iotests/068
12
index XXXXXXX..XXXXXXX 100755
13
--- a/tests/qemu-iotests/068
14
+++ b/tests/qemu-iotests/068
15
@@ -XXX,XX +XXX,XX @@ case "$QEMU_DEFAULT_MACHINE" in
16
;;
17
esac
18
19
-# Give qemu some time to boot before saving the VM state
20
-bash -c 'sleep 1; echo -e "savevm 0\nquit"' |\
21
- $QEMU $platform_parm -nographic -monitor stdio -serial none -hda "$TEST_IMG" |\
22
+_qemu()
23
+{
24
+ $QEMU $platform_parm -nographic -monitor stdio -serial none -hda "$TEST_IMG" \
25
+ "$@" |\
26
_filter_qemu | _filter_hmp
27
+}
28
+
29
+# Give qemu some time to boot before saving the VM state
30
+bash -c 'sleep 1; echo -e "savevm 0\nquit"' | _qemu
31
# Now try to continue from that VM state (this should just work)
32
-echo quit |\
33
- $QEMU $platform_parm -nographic -monitor stdio -serial none -hda "$TEST_IMG" -loadvm 0 |\
34
- _filter_qemu | _filter_hmp
35
+echo quit | _qemu -loadvm 0
36
37
# success, all done
38
echo "*** done"
39
--
40
1.8.3.1
41
42
diff view generated by jsdifflib
Deleted patch
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
1
3
Perform the savevm/loadvm test with both iothread on and off. This
4
covers the recently found savevm/loadvm hang when iothread is enabled.
5
6
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
9
tests/qemu-iotests/068 | 23 ++++++++++++++---------
10
tests/qemu-iotests/068.out | 11 ++++++++++-
11
2 files changed, 24 insertions(+), 10 deletions(-)
12
13
diff --git a/tests/qemu-iotests/068 b/tests/qemu-iotests/068
14
index XXXXXXX..XXXXXXX 100755
15
--- a/tests/qemu-iotests/068
16
+++ b/tests/qemu-iotests/068
17
@@ -XXX,XX +XXX,XX @@ _supported_os Linux
18
IMGOPTS="compat=1.1"
19
IMG_SIZE=128K
20
21
-echo
22
-echo "=== Saving and reloading a VM state to/from a qcow2 image ==="
23
-echo
24
-_make_test_img $IMG_SIZE
25
-
26
case "$QEMU_DEFAULT_MACHINE" in
27
s390-ccw-virtio)
28
platform_parm="-no-shutdown"
29
@@ -XXX,XX +XXX,XX @@ _qemu()
30
_filter_qemu | _filter_hmp
31
}
32
33
-# Give qemu some time to boot before saving the VM state
34
-bash -c 'sleep 1; echo -e "savevm 0\nquit"' | _qemu
35
-# Now try to continue from that VM state (this should just work)
36
-echo quit | _qemu -loadvm 0
37
+for extra_args in \
38
+ "" \
39
+ "-object iothread,id=iothread0 -set device.hba0.iothread=iothread0"; do
40
+ echo
41
+ echo "=== Saving and reloading a VM state to/from a qcow2 image ($extra_args) ==="
42
+ echo
43
+
44
+ _make_test_img $IMG_SIZE
45
+
46
+ # Give qemu some time to boot before saving the VM state
47
+ bash -c 'sleep 1; echo -e "savevm 0\nquit"' | _qemu $extra_args
48
+ # Now try to continue from that VM state (this should just work)
49
+ echo quit | _qemu $extra_args -loadvm 0
50
+done
51
52
# success, all done
53
echo "*** done"
54
diff --git a/tests/qemu-iotests/068.out b/tests/qemu-iotests/068.out
55
index XXXXXXX..XXXXXXX 100644
56
--- a/tests/qemu-iotests/068.out
57
+++ b/tests/qemu-iotests/068.out
58
@@ -XXX,XX +XXX,XX @@
59
QA output created by 068
60
61
-=== Saving and reloading a VM state to/from a qcow2 image ===
62
+=== Saving and reloading a VM state to/from a qcow2 image () ===
63
+
64
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072
65
+QEMU X.Y.Z monitor - type 'help' for more information
66
+(qemu) savevm 0
67
+(qemu) quit
68
+QEMU X.Y.Z monitor - type 'help' for more information
69
+(qemu) quit
70
+
71
+=== Saving and reloading a VM state to/from a qcow2 image (-object iothread,id=iothread0 -set device.hba0.iothread=iothread0) ===
72
73
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072
74
QEMU X.Y.Z monitor - type 'help' for more information
75
--
76
1.8.3.1
77
78
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
The BDRV_REQ_ZERO_WRITE is currently implemented in a way that first the
2
image is possibly preallocated and then the zero flag is added to all
3
clusters. This means that a copy-on-write operation may be needed when
4
writing to these clusters, despite having used preallocation, negating
5
one of the major benefits of preallocation.
2
6
3
We already have functions for doing these calculations, so let's use
7
Instead, try to forward the BDRV_REQ_ZERO_WRITE to the protocol driver,
4
them instead of doing everything by hand. This makes the code a bit
8
and if the protocol driver can ensure that the new area reads as zeros,
5
more readable.
9
we can skip setting the zero flag in the qcow2 layer.
6
10
7
Signed-off-by: Alberto Garcia <berto@igalia.com>
11
Unfortunately, the same approach doesn't work for metadata
12
preallocation, so we'll still set the zero flag there.
13
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
Reviewed-by: Max Reitz <mreitz@redhat.com>
16
Message-Id: <20200424142701.67053-1-kwolf@redhat.com>
17
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
19
---
10
block/qcow2-cluster.c | 4 ++--
20
block/qcow2.c | 22 +++++++++++++++++++---
11
block/qcow2.c | 2 +-
21
tests/qemu-iotests/274.out | 4 ++--
12
2 files changed, 3 insertions(+), 3 deletions(-)
22
2 files changed, 21 insertions(+), 5 deletions(-)
13
23
14
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/block/qcow2-cluster.c
17
+++ b/block/qcow2-cluster.c
18
@@ -XXX,XX +XXX,XX @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
19
20
/* find the cluster offset for the given disk offset */
21
22
- l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1);
23
+ l2_index = offset_to_l2_index(s, offset);
24
*cluster_offset = be64_to_cpu(l2_table[l2_index]);
25
26
nb_clusters = size_to_clusters(s, bytes_needed);
27
@@ -XXX,XX +XXX,XX @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
28
29
/* find the cluster offset for the given disk offset */
30
31
- l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1);
32
+ l2_index = offset_to_l2_index(s, offset);
33
34
*new_l2_table = l2_table;
35
*new_l2_index = l2_index;
36
diff --git a/block/qcow2.c b/block/qcow2.c
24
diff --git a/block/qcow2.c b/block/qcow2.c
37
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
38
--- a/block/qcow2.c
26
--- a/block/qcow2.c
39
+++ b/block/qcow2.c
27
+++ b/block/qcow2.c
40
@@ -XXX,XX +XXX,XX @@ static int validate_table_offset(BlockDriverState *bs, uint64_t offset,
28
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
41
}
29
/* Allocate the data area */
42
30
new_file_size = allocation_start +
43
/* Tables must be cluster aligned */
31
nb_new_data_clusters * s->cluster_size;
44
- if (offset & (s->cluster_size - 1)) {
32
- /* Image file grows, so @exact does not matter */
45
+ if (offset_into_cluster(s, offset) != 0) {
33
- ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, 0,
46
return -EINVAL;
34
- errp);
47
}
35
+ /*
48
36
+ * Image file grows, so @exact does not matter.
37
+ *
38
+ * If we need to zero out the new area, try first whether the protocol
39
+ * driver can already take care of this.
40
+ */
41
+ if (flags & BDRV_REQ_ZERO_WRITE) {
42
+ ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc,
43
+ BDRV_REQ_ZERO_WRITE, NULL);
44
+ if (ret >= 0) {
45
+ flags &= ~BDRV_REQ_ZERO_WRITE;
46
+ }
47
+ } else {
48
+ ret = -1;
49
+ }
50
+ if (ret < 0) {
51
+ ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, 0,
52
+ errp);
53
+ }
54
if (ret < 0) {
55
error_prepend(errp, "Failed to resize underlying file: ");
56
qcow2_free_clusters(bs, allocation_start,
57
diff --git a/tests/qemu-iotests/274.out b/tests/qemu-iotests/274.out
58
index XXXXXXX..XXXXXXX 100644
59
--- a/tests/qemu-iotests/274.out
60
+++ b/tests/qemu-iotests/274.out
61
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 9437184
62
10 MiB (0xa00000) bytes allocated at offset 5 MiB (0x500000)
63
64
[{ "start": 0, "length": 5242880, "depth": 1, "zero": true, "data": false},
65
-{ "start": 5242880, "length": 10485760, "depth": 0, "zero": true, "data": false, "offset": 327680}]
66
+{ "start": 5242880, "length": 10485760, "depth": 0, "zero": false, "data": true, "offset": 327680}]
67
68
=== preallocation=full ===
69
Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=16777216 cluster_size=65536 lazy_refcounts=off refcount_bits=16
70
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 11534336
71
4 MiB (0x400000) bytes allocated at offset 8 MiB (0x800000)
72
73
[{ "start": 0, "length": 8388608, "depth": 1, "zero": true, "data": false},
74
-{ "start": 8388608, "length": 4194304, "depth": 0, "zero": true, "data": false, "offset": 327680}]
75
+{ "start": 8388608, "length": 4194304, "depth": 0, "zero": false, "data": true, "offset": 327680}]
76
77
=== preallocation=off ===
78
Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=393216 cluster_size=65536 lazy_refcounts=off refcount_bits=16
49
--
79
--
50
1.8.3.1
80
2.25.3
51
81
52
82
diff view generated by jsdifflib
1
From: Stephen Bates <sbates@raithlin.com>
1
From: Andrzej Jakowski <andrzej.jakowski@linux.intel.com>
2
2
3
Add the ability for the NVMe model to support both the RDS and WDS
3
This patch introduces support for PMR that has been defined as part of NVMe 1.4
4
modes in the Controller Memory Buffer.
4
spec. User can now specify a pmrdev option that should point to HostMemoryBackend.
5
pmrdev memory region will subsequently be exposed as PCI BAR 2 in emulated NVMe
6
device. Guest OS can perform mmio read and writes to the PMR region that will stay
7
persistent across system reboot.
5
8
6
Although not currently supported in the upstreamed Linux kernel a fork
9
Signed-off-by: Andrzej Jakowski <andrzej.jakowski@linux.intel.com>
7
with support exists [1] and user-space test programs that build on
10
Reviewed-by: Klaus Jensen <k.jensen@samsung.com>
8
this also exist [2].
11
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
12
Message-Id: <20200330164656.9348-1-andrzej.jakowski@linux.intel.com>
10
Useful for testing CMB functionality in preperation for real CMB
13
Reviewed-by: Keith Busch <kbusch@kernel.org>
11
enabled NVMe devices (coming soon).
12
13
[1] https://github.com/sbates130272/linux-p2pmem
14
[2] https://github.com/sbates130272/p2pmem-test
15
16
Signed-off-by: Stephen Bates <sbates@raithlin.com>
17
Reviewed-by: Logan Gunthorpe <logang@deltatee.com>
18
Reviewed-by: Keith Busch <keith.busch@intel.com>
19
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
20
---
15
---
21
hw/block/nvme.c | 83 +++++++++++++++++++++++++++++++++++++++------------------
16
hw/block/nvme.h | 2 +
22
hw/block/nvme.h | 1 +
17
include/block/nvme.h | 172 +++++++++++++++++++++++++++++++++++++++++
23
2 files changed, 58 insertions(+), 26 deletions(-)
18
hw/block/nvme.c | 109 ++++++++++++++++++++++++++
19
hw/block/Makefile.objs | 2 +-
20
hw/block/trace-events | 4 +
21
5 files changed, 288 insertions(+), 1 deletion(-)
24
22
23
diff --git a/hw/block/nvme.h b/hw/block/nvme.h
24
index XXXXXXX..XXXXXXX 100644
25
--- a/hw/block/nvme.h
26
+++ b/hw/block/nvme.h
27
@@ -XXX,XX +XXX,XX @@ typedef struct NvmeCtrl {
28
uint64_t timestamp_set_qemu_clock_ms; /* QEMU clock time */
29
30
char *serial;
31
+ HostMemoryBackend *pmrdev;
32
+
33
NvmeNamespace *namespaces;
34
NvmeSQueue **sq;
35
NvmeCQueue **cq;
36
diff --git a/include/block/nvme.h b/include/block/nvme.h
37
index XXXXXXX..XXXXXXX 100644
38
--- a/include/block/nvme.h
39
+++ b/include/block/nvme.h
40
@@ -XXX,XX +XXX,XX @@ typedef struct NvmeBar {
41
uint64_t acq;
42
uint32_t cmbloc;
43
uint32_t cmbsz;
44
+ uint8_t padding[3520]; /* not used by QEMU */
45
+ uint32_t pmrcap;
46
+ uint32_t pmrctl;
47
+ uint32_t pmrsts;
48
+ uint32_t pmrebs;
49
+ uint32_t pmrswtp;
50
+ uint32_t pmrmsc;
51
} NvmeBar;
52
53
enum NvmeCapShift {
54
@@ -XXX,XX +XXX,XX @@ enum NvmeCapShift {
55
CAP_CSS_SHIFT = 37,
56
CAP_MPSMIN_SHIFT = 48,
57
CAP_MPSMAX_SHIFT = 52,
58
+ CAP_PMR_SHIFT = 56,
59
};
60
61
enum NvmeCapMask {
62
@@ -XXX,XX +XXX,XX @@ enum NvmeCapMask {
63
CAP_CSS_MASK = 0xff,
64
CAP_MPSMIN_MASK = 0xf,
65
CAP_MPSMAX_MASK = 0xf,
66
+ CAP_PMR_MASK = 0x1,
67
};
68
69
#define NVME_CAP_MQES(cap) (((cap) >> CAP_MQES_SHIFT) & CAP_MQES_MASK)
70
@@ -XXX,XX +XXX,XX @@ enum NvmeCapMask {
71
<< CAP_MPSMIN_SHIFT)
72
#define NVME_CAP_SET_MPSMAX(cap, val) (cap |= (uint64_t)(val & CAP_MPSMAX_MASK)\
73
<< CAP_MPSMAX_SHIFT)
74
+#define NVME_CAP_SET_PMRS(cap, val) (cap |= (uint64_t)(val & CAP_PMR_MASK)\
75
+ << CAP_PMR_SHIFT)
76
77
enum NvmeCcShift {
78
CC_EN_SHIFT = 0,
79
@@ -XXX,XX +XXX,XX @@ enum NvmeCmbszMask {
80
#define NVME_CMBSZ_GETSIZE(cmbsz) \
81
(NVME_CMBSZ_SZ(cmbsz) * (1 << (12 + 4 * NVME_CMBSZ_SZU(cmbsz))))
82
83
+enum NvmePmrcapShift {
84
+ PMRCAP_RDS_SHIFT = 3,
85
+ PMRCAP_WDS_SHIFT = 4,
86
+ PMRCAP_BIR_SHIFT = 5,
87
+ PMRCAP_PMRTU_SHIFT = 8,
88
+ PMRCAP_PMRWBM_SHIFT = 10,
89
+ PMRCAP_PMRTO_SHIFT = 16,
90
+ PMRCAP_CMSS_SHIFT = 24,
91
+};
92
+
93
+enum NvmePmrcapMask {
94
+ PMRCAP_RDS_MASK = 0x1,
95
+ PMRCAP_WDS_MASK = 0x1,
96
+ PMRCAP_BIR_MASK = 0x7,
97
+ PMRCAP_PMRTU_MASK = 0x3,
98
+ PMRCAP_PMRWBM_MASK = 0xf,
99
+ PMRCAP_PMRTO_MASK = 0xff,
100
+ PMRCAP_CMSS_MASK = 0x1,
101
+};
102
+
103
+#define NVME_PMRCAP_RDS(pmrcap) \
104
+ ((pmrcap >> PMRCAP_RDS_SHIFT) & PMRCAP_RDS_MASK)
105
+#define NVME_PMRCAP_WDS(pmrcap) \
106
+ ((pmrcap >> PMRCAP_WDS_SHIFT) & PMRCAP_WDS_MASK)
107
+#define NVME_PMRCAP_BIR(pmrcap) \
108
+ ((pmrcap >> PMRCAP_BIR_SHIFT) & PMRCAP_BIR_MASK)
109
+#define NVME_PMRCAP_PMRTU(pmrcap) \
110
+ ((pmrcap >> PMRCAP_PMRTU_SHIFT) & PMRCAP_PMRTU_MASK)
111
+#define NVME_PMRCAP_PMRWBM(pmrcap) \
112
+ ((pmrcap >> PMRCAP_PMRWBM_SHIFT) & PMRCAP_PMRWBM_MASK)
113
+#define NVME_PMRCAP_PMRTO(pmrcap) \
114
+ ((pmrcap >> PMRCAP_PMRTO_SHIFT) & PMRCAP_PMRTO_MASK)
115
+#define NVME_PMRCAP_CMSS(pmrcap) \
116
+ ((pmrcap >> PMRCAP_CMSS_SHIFT) & PMRCAP_CMSS_MASK)
117
+
118
+#define NVME_PMRCAP_SET_RDS(pmrcap, val) \
119
+ (pmrcap |= (uint64_t)(val & PMRCAP_RDS_MASK) << PMRCAP_RDS_SHIFT)
120
+#define NVME_PMRCAP_SET_WDS(pmrcap, val) \
121
+ (pmrcap |= (uint64_t)(val & PMRCAP_WDS_MASK) << PMRCAP_WDS_SHIFT)
122
+#define NVME_PMRCAP_SET_BIR(pmrcap, val) \
123
+ (pmrcap |= (uint64_t)(val & PMRCAP_BIR_MASK) << PMRCAP_BIR_SHIFT)
124
+#define NVME_PMRCAP_SET_PMRTU(pmrcap, val) \
125
+ (pmrcap |= (uint64_t)(val & PMRCAP_PMRTU_MASK) << PMRCAP_PMRTU_SHIFT)
126
+#define NVME_PMRCAP_SET_PMRWBM(pmrcap, val) \
127
+ (pmrcap |= (uint64_t)(val & PMRCAP_PMRWBM_MASK) << PMRCAP_PMRWBM_SHIFT)
128
+#define NVME_PMRCAP_SET_PMRTO(pmrcap, val) \
129
+ (pmrcap |= (uint64_t)(val & PMRCAP_PMRTO_MASK) << PMRCAP_PMRTO_SHIFT)
130
+#define NVME_PMRCAP_SET_CMSS(pmrcap, val) \
131
+ (pmrcap |= (uint64_t)(val & PMRCAP_CMSS_MASK) << PMRCAP_CMSS_SHIFT)
132
+
133
+enum NvmePmrctlShift {
134
+ PMRCTL_EN_SHIFT = 0,
135
+};
136
+
137
+enum NvmePmrctlMask {
138
+ PMRCTL_EN_MASK = 0x1,
139
+};
140
+
141
+#define NVME_PMRCTL_EN(pmrctl) ((pmrctl >> PMRCTL_EN_SHIFT) & PMRCTL_EN_MASK)
142
+
143
+#define NVME_PMRCTL_SET_EN(pmrctl, val) \
144
+ (pmrctl |= (uint64_t)(val & PMRCTL_EN_MASK) << PMRCTL_EN_SHIFT)
145
+
146
+enum NvmePmrstsShift {
147
+ PMRSTS_ERR_SHIFT = 0,
148
+ PMRSTS_NRDY_SHIFT = 8,
149
+ PMRSTS_HSTS_SHIFT = 9,
150
+ PMRSTS_CBAI_SHIFT = 12,
151
+};
152
+
153
+enum NvmePmrstsMask {
154
+ PMRSTS_ERR_MASK = 0xff,
155
+ PMRSTS_NRDY_MASK = 0x1,
156
+ PMRSTS_HSTS_MASK = 0x7,
157
+ PMRSTS_CBAI_MASK = 0x1,
158
+};
159
+
160
+#define NVME_PMRSTS_ERR(pmrsts) \
161
+ ((pmrsts >> PMRSTS_ERR_SHIFT) & PMRSTS_ERR_MASK)
162
+#define NVME_PMRSTS_NRDY(pmrsts) \
163
+ ((pmrsts >> PMRSTS_NRDY_SHIFT) & PMRSTS_NRDY_MASK)
164
+#define NVME_PMRSTS_HSTS(pmrsts) \
165
+ ((pmrsts >> PMRSTS_HSTS_SHIFT) & PMRSTS_HSTS_MASK)
166
+#define NVME_PMRSTS_CBAI(pmrsts) \
167
+ ((pmrsts >> PMRSTS_CBAI_SHIFT) & PMRSTS_CBAI_MASK)
168
+
169
+#define NVME_PMRSTS_SET_ERR(pmrsts, val) \
170
+ (pmrsts |= (uint64_t)(val & PMRSTS_ERR_MASK) << PMRSTS_ERR_SHIFT)
171
+#define NVME_PMRSTS_SET_NRDY(pmrsts, val) \
172
+ (pmrsts |= (uint64_t)(val & PMRSTS_NRDY_MASK) << PMRSTS_NRDY_SHIFT)
173
+#define NVME_PMRSTS_SET_HSTS(pmrsts, val) \
174
+ (pmrsts |= (uint64_t)(val & PMRSTS_HSTS_MASK) << PMRSTS_HSTS_SHIFT)
175
+#define NVME_PMRSTS_SET_CBAI(pmrsts, val) \
176
+ (pmrsts |= (uint64_t)(val & PMRSTS_CBAI_MASK) << PMRSTS_CBAI_SHIFT)
177
+
178
+enum NvmePmrebsShift {
179
+ PMREBS_PMRSZU_SHIFT = 0,
180
+ PMREBS_RBB_SHIFT = 4,
181
+ PMREBS_PMRWBZ_SHIFT = 8,
182
+};
183
+
184
+enum NvmePmrebsMask {
185
+ PMREBS_PMRSZU_MASK = 0xf,
186
+ PMREBS_RBB_MASK = 0x1,
187
+ PMREBS_PMRWBZ_MASK = 0xffffff,
188
+};
189
+
190
+#define NVME_PMREBS_PMRSZU(pmrebs) \
191
+ ((pmrebs >> PMREBS_PMRSZU_SHIFT) & PMREBS_PMRSZU_MASK)
192
+#define NVME_PMREBS_RBB(pmrebs) \
193
+ ((pmrebs >> PMREBS_RBB_SHIFT) & PMREBS_RBB_MASK)
194
+#define NVME_PMREBS_PMRWBZ(pmrebs) \
195
+ ((pmrebs >> PMREBS_PMRWBZ_SHIFT) & PMREBS_PMRWBZ_MASK)
196
+
197
+#define NVME_PMREBS_SET_PMRSZU(pmrebs, val) \
198
+ (pmrebs |= (uint64_t)(val & PMREBS_PMRSZU_MASK) << PMREBS_PMRSZU_SHIFT)
199
+#define NVME_PMREBS_SET_RBB(pmrebs, val) \
200
+ (pmrebs |= (uint64_t)(val & PMREBS_RBB_MASK) << PMREBS_RBB_SHIFT)
201
+#define NVME_PMREBS_SET_PMRWBZ(pmrebs, val) \
202
+ (pmrebs |= (uint64_t)(val & PMREBS_PMRWBZ_MASK) << PMREBS_PMRWBZ_SHIFT)
203
+
204
+enum NvmePmrswtpShift {
205
+ PMRSWTP_PMRSWTU_SHIFT = 0,
206
+ PMRSWTP_PMRSWTV_SHIFT = 8,
207
+};
208
+
209
+enum NvmePmrswtpMask {
210
+ PMRSWTP_PMRSWTU_MASK = 0xf,
211
+ PMRSWTP_PMRSWTV_MASK = 0xffffff,
212
+};
213
+
214
+#define NVME_PMRSWTP_PMRSWTU(pmrswtp) \
215
+ ((pmrswtp >> PMRSWTP_PMRSWTU_SHIFT) & PMRSWTP_PMRSWTU_MASK)
216
+#define NVME_PMRSWTP_PMRSWTV(pmrswtp) \
217
+ ((pmrswtp >> PMRSWTP_PMRSWTV_SHIFT) & PMRSWTP_PMRSWTV_MASK)
218
+
219
+#define NVME_PMRSWTP_SET_PMRSWTU(pmrswtp, val) \
220
+ (pmrswtp |= (uint64_t)(val & PMRSWTP_PMRSWTU_MASK) << PMRSWTP_PMRSWTU_SHIFT)
221
+#define NVME_PMRSWTP_SET_PMRSWTV(pmrswtp, val) \
222
+ (pmrswtp |= (uint64_t)(val & PMRSWTP_PMRSWTV_MASK) << PMRSWTP_PMRSWTV_SHIFT)
223
+
224
+enum NvmePmrmscShift {
225
+ PMRMSC_CMSE_SHIFT = 1,
226
+ PMRMSC_CBA_SHIFT = 12,
227
+};
228
+
229
+enum NvmePmrmscMask {
230
+ PMRMSC_CMSE_MASK = 0x1,
231
+ PMRMSC_CBA_MASK = 0xfffffffffffff,
232
+};
233
+
234
+#define NVME_PMRMSC_CMSE(pmrmsc) \
235
+ ((pmrmsc >> PMRMSC_CMSE_SHIFT) & PMRMSC_CMSE_MASK)
236
+#define NVME_PMRMSC_CBA(pmrmsc) \
237
+ ((pmrmsc >> PMRMSC_CBA_SHIFT) & PMRMSC_CBA_MASK)
238
+
239
+#define NVME_PMRMSC_SET_CMSE(pmrmsc, val) \
240
+ (pmrmsc |= (uint64_t)(val & PMRMSC_CMSE_MASK) << PMRMSC_CMSE_SHIFT)
241
+#define NVME_PMRMSC_SET_CBA(pmrmsc, val) \
242
+ (pmrmsc |= (uint64_t)(val & PMRMSC_CBA_MASK) << PMRMSC_CBA_SHIFT)
243
+
244
typedef struct NvmeCmd {
245
uint8_t opcode;
246
uint8_t fuse;
25
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
247
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
26
index XXXXXXX..XXXXXXX 100644
248
index XXXXXXX..XXXXXXX 100644
27
--- a/hw/block/nvme.c
249
--- a/hw/block/nvme.c
28
+++ b/hw/block/nvme.c
250
+++ b/hw/block/nvme.c
29
@@ -XXX,XX +XXX,XX @@
251
@@ -XXX,XX +XXX,XX @@
30
* cmb_size_mb=<cmb_size_mb[optional]>
252
* -drive file=<file>,if=none,id=<drive_id>
253
* -device nvme,drive=<drive_id>,serial=<serial>,id=<id[optional]>, \
254
* cmb_size_mb=<cmb_size_mb[optional]>, \
255
+ * [pmrdev=<mem_backend_file_id>,] \
256
* num_queues=<N[optional]>
31
*
257
*
32
* Note cmb_size_mb denotes size of CMB in MB. CMB is assumed to be at
258
* Note cmb_size_mb denotes size of CMB in MB. CMB is assumed to be at
33
- * offset 0 in BAR2 and supports SQS only for now.
259
* offset 0 in BAR2 and supports only WDS, RDS and SQS for now.
34
+ * offset 0 in BAR2 and supports only WDS, RDS and SQS for now.
260
+ *
261
+ * cmb_size_mb= and pmrdev= options are mutually exclusive due to limitation
262
+ * in available BAR's. cmb_size_mb= will take precedence over pmrdev= when
263
+ * both provided.
264
+ * Enabling pmr emulation can be achieved by pointing to memory-backend-file.
265
+ * For example:
266
+ * -object memory-backend-file,id=<mem_id>,share=on,mem-path=<file_path>, \
267
+ * size=<size> .... -device nvme,...,pmrdev=<mem_id>
35
*/
268
*/
36
269
37
#include "qemu/osdep.h"
270
#include "qemu/osdep.h"
38
@@ -XXX,XX +XXX,XX @@ static void nvme_isr_notify(NvmeCtrl *n, NvmeCQueue *cq)
271
@@ -XXX,XX +XXX,XX @@
272
#include "sysemu/sysemu.h"
273
#include "qapi/error.h"
274
#include "qapi/visitor.h"
275
+#include "sysemu/hostmem.h"
276
#include "sysemu/block-backend.h"
277
+#include "exec/ram_addr.h"
278
279
#include "qemu/log.h"
280
#include "qemu/module.h"
281
@@ -XXX,XX +XXX,XX @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data,
282
NVME_GUEST_ERR(nvme_ub_mmiowr_cmbsz_readonly,
283
"invalid write to read only CMBSZ, ignored");
284
return;
285
+ case 0xE00: /* PMRCAP */
286
+ NVME_GUEST_ERR(nvme_ub_mmiowr_pmrcap_readonly,
287
+ "invalid write to PMRCAP register, ignored");
288
+ return;
289
+ case 0xE04: /* TODO PMRCTL */
290
+ break;
291
+ case 0xE08: /* PMRSTS */
292
+ NVME_GUEST_ERR(nvme_ub_mmiowr_pmrsts_readonly,
293
+ "invalid write to PMRSTS register, ignored");
294
+ return;
295
+ case 0xE0C: /* PMREBS */
296
+ NVME_GUEST_ERR(nvme_ub_mmiowr_pmrebs_readonly,
297
+ "invalid write to PMREBS register, ignored");
298
+ return;
299
+ case 0xE10: /* PMRSWTP */
300
+ NVME_GUEST_ERR(nvme_ub_mmiowr_pmrswtp_readonly,
301
+ "invalid write to PMRSWTP register, ignored");
302
+ return;
303
+ case 0xE14: /* TODO PMRMSC */
304
+ break;
305
default:
306
NVME_GUEST_ERR(nvme_ub_mmiowr_invalid,
307
"invalid MMIO write,"
308
@@ -XXX,XX +XXX,XX @@ static uint64_t nvme_mmio_read(void *opaque, hwaddr addr, unsigned size)
39
}
309
}
310
311
if (addr < sizeof(n->bar)) {
312
+ /*
313
+ * When PMRWBM bit 1 is set then read from
314
+ * from PMRSTS should ensure prior writes
315
+ * made it to persistent media
316
+ */
317
+ if (addr == 0xE08 &&
318
+ (NVME_PMRCAP_PMRWBM(n->bar.pmrcap) & 0x02)) {
319
+ qemu_ram_writeback(n->pmrdev->mr.ram_block,
320
+ 0, n->pmrdev->size);
321
+ }
322
memcpy(&val, ptr + addr, size);
323
} else {
324
NVME_GUEST_ERR(nvme_ub_mmiord_invalid_ofs,
325
@@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
326
error_setg(errp, "serial property not set");
327
return;
328
}
329
+
330
+ if (!n->cmb_size_mb && n->pmrdev) {
331
+ if (host_memory_backend_is_mapped(n->pmrdev)) {
332
+ char *path = object_get_canonical_path_component(OBJECT(n->pmrdev));
333
+ error_setg(errp, "can't use already busy memdev: %s", path);
334
+ g_free(path);
335
+ return;
336
+ }
337
+
338
+ if (!is_power_of_2(n->pmrdev->size)) {
339
+ error_setg(errp, "pmr backend size needs to be power of 2 in size");
340
+ return;
341
+ }
342
+
343
+ host_memory_backend_set_mapped(n->pmrdev, true);
344
+ }
345
+
346
blkconf_blocksizes(&n->conf);
347
if (!blkconf_apply_backend_options(&n->conf, blk_is_read_only(n->conf.blk),
348
false, errp)) {
349
@@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
350
PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64 |
351
PCI_BASE_ADDRESS_MEM_PREFETCH, &n->ctrl_mem);
352
353
+ } else if (n->pmrdev) {
354
+ /* Controller Capabilities register */
355
+ NVME_CAP_SET_PMRS(n->bar.cap, 1);
356
+
357
+ /* PMR Capabities register */
358
+ n->bar.pmrcap = 0;
359
+ NVME_PMRCAP_SET_RDS(n->bar.pmrcap, 0);
360
+ NVME_PMRCAP_SET_WDS(n->bar.pmrcap, 0);
361
+ NVME_PMRCAP_SET_BIR(n->bar.pmrcap, 2);
362
+ NVME_PMRCAP_SET_PMRTU(n->bar.pmrcap, 0);
363
+ /* Turn on bit 1 support */
364
+ NVME_PMRCAP_SET_PMRWBM(n->bar.pmrcap, 0x02);
365
+ NVME_PMRCAP_SET_PMRTO(n->bar.pmrcap, 0);
366
+ NVME_PMRCAP_SET_CMSS(n->bar.pmrcap, 0);
367
+
368
+ /* PMR Control register */
369
+ n->bar.pmrctl = 0;
370
+ NVME_PMRCTL_SET_EN(n->bar.pmrctl, 0);
371
+
372
+ /* PMR Status register */
373
+ n->bar.pmrsts = 0;
374
+ NVME_PMRSTS_SET_ERR(n->bar.pmrsts, 0);
375
+ NVME_PMRSTS_SET_NRDY(n->bar.pmrsts, 0);
376
+ NVME_PMRSTS_SET_HSTS(n->bar.pmrsts, 0);
377
+ NVME_PMRSTS_SET_CBAI(n->bar.pmrsts, 0);
378
+
379
+ /* PMR Elasticity Buffer Size register */
380
+ n->bar.pmrebs = 0;
381
+ NVME_PMREBS_SET_PMRSZU(n->bar.pmrebs, 0);
382
+ NVME_PMREBS_SET_RBB(n->bar.pmrebs, 0);
383
+ NVME_PMREBS_SET_PMRWBZ(n->bar.pmrebs, 0);
384
+
385
+ /* PMR Sustained Write Throughput register */
386
+ n->bar.pmrswtp = 0;
387
+ NVME_PMRSWTP_SET_PMRSWTU(n->bar.pmrswtp, 0);
388
+ NVME_PMRSWTP_SET_PMRSWTV(n->bar.pmrswtp, 0);
389
+
390
+ /* PMR Memory Space Control register */
391
+ n->bar.pmrmsc = 0;
392
+ NVME_PMRMSC_SET_CMSE(n->bar.pmrmsc, 0);
393
+ NVME_PMRMSC_SET_CBA(n->bar.pmrmsc, 0);
394
+
395
+ pci_register_bar(pci_dev, NVME_PMRCAP_BIR(n->bar.pmrcap),
396
+ PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64 |
397
+ PCI_BASE_ADDRESS_MEM_PREFETCH, &n->pmrdev->mr);
398
}
399
400
for (i = 0; i < n->num_namespaces; i++) {
401
@@ -XXX,XX +XXX,XX @@ static void nvme_exit(PCIDevice *pci_dev)
402
if (n->cmb_size_mb) {
403
g_free(n->cmbuf);
404
}
405
+
406
+ if (n->pmrdev) {
407
+ host_memory_backend_set_mapped(n->pmrdev, false);
408
+ }
409
msix_uninit_exclusive_bar(pci_dev);
40
}
410
}
41
411
42
-static uint16_t nvme_map_prp(QEMUSGList *qsg, uint64_t prp1, uint64_t prp2,
412
static Property nvme_props[] = {
43
- uint32_t len, NvmeCtrl *n)
413
DEFINE_BLOCK_PROPERTIES(NvmeCtrl, conf),
44
+static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1,
414
+ DEFINE_PROP_LINK("pmrdev", NvmeCtrl, pmrdev, TYPE_MEMORY_BACKEND,
45
+ uint64_t prp2, uint32_t len, NvmeCtrl *n)
415
+ HostMemoryBackend *),
46
{
416
DEFINE_PROP_STRING("serial", NvmeCtrl, serial),
47
hwaddr trans_len = n->page_size - (prp1 % n->page_size);
417
DEFINE_PROP_UINT32("cmb_size_mb", NvmeCtrl, cmb_size_mb, 0),
48
trans_len = MIN(len, trans_len);
418
DEFINE_PROP_UINT32("num_queues", NvmeCtrl, num_queues, 64),
49
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, uint64_t prp1, uint64_t prp2,
419
diff --git a/hw/block/Makefile.objs b/hw/block/Makefile.objs
50
51
if (!prp1) {
52
return NVME_INVALID_FIELD | NVME_DNR;
53
+ } else if (n->cmbsz && prp1 >= n->ctrl_mem.addr &&
54
+ prp1 < n->ctrl_mem.addr + int128_get64(n->ctrl_mem.size)) {
55
+ qsg->nsg = 0;
56
+ qemu_iovec_init(iov, num_prps);
57
+ qemu_iovec_add(iov, (void *)&n->cmbuf[prp1 - n->ctrl_mem.addr], trans_len);
58
+ } else {
59
+ pci_dma_sglist_init(qsg, &n->parent_obj, num_prps);
60
+ qemu_sglist_add(qsg, prp1, trans_len);
61
}
62
-
63
- pci_dma_sglist_init(qsg, &n->parent_obj, num_prps);
64
- qemu_sglist_add(qsg, prp1, trans_len);
65
len -= trans_len;
66
if (len) {
67
if (!prp2) {
68
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, uint64_t prp1, uint64_t prp2,
69
70
nents = (len + n->page_size - 1) >> n->page_bits;
71
prp_trans = MIN(n->max_prp_ents, nents) * sizeof(uint64_t);
72
- pci_dma_read(&n->parent_obj, prp2, (void *)prp_list, prp_trans);
73
+ nvme_addr_read(n, prp2, (void *)prp_list, prp_trans);
74
while (len != 0) {
75
uint64_t prp_ent = le64_to_cpu(prp_list[i]);
76
77
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, uint64_t prp1, uint64_t prp2,
78
i = 0;
79
nents = (len + n->page_size - 1) >> n->page_bits;
80
prp_trans = MIN(n->max_prp_ents, nents) * sizeof(uint64_t);
81
- pci_dma_read(&n->parent_obj, prp_ent, (void *)prp_list,
82
+ nvme_addr_read(n, prp_ent, (void *)prp_list,
83
prp_trans);
84
prp_ent = le64_to_cpu(prp_list[i]);
85
}
86
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, uint64_t prp1, uint64_t prp2,
87
}
88
89
trans_len = MIN(len, n->page_size);
90
- qemu_sglist_add(qsg, prp_ent, trans_len);
91
+ if (qsg->nsg){
92
+ qemu_sglist_add(qsg, prp_ent, trans_len);
93
+ } else {
94
+ qemu_iovec_add(iov, (void *)&n->cmbuf[prp_ent - n->ctrl_mem.addr], trans_len);
95
+ }
96
len -= trans_len;
97
i++;
98
}
99
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, uint64_t prp1, uint64_t prp2,
100
if (prp2 & (n->page_size - 1)) {
101
goto unmap;
102
}
103
- qemu_sglist_add(qsg, prp2, len);
104
+ if (qsg->nsg) {
105
+ qemu_sglist_add(qsg, prp2, len);
106
+ } else {
107
+ qemu_iovec_add(iov, (void *)&n->cmbuf[prp2 - n->ctrl_mem.addr], trans_len);
108
+ }
109
}
110
}
111
return NVME_SUCCESS;
112
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_dma_read_prp(NvmeCtrl *n, uint8_t *ptr, uint32_t len,
113
uint64_t prp1, uint64_t prp2)
114
{
115
QEMUSGList qsg;
116
+ QEMUIOVector iov;
117
+ uint16_t status = NVME_SUCCESS;
118
119
- if (nvme_map_prp(&qsg, prp1, prp2, len, n)) {
120
+ if (nvme_map_prp(&qsg, &iov, prp1, prp2, len, n)) {
121
return NVME_INVALID_FIELD | NVME_DNR;
122
}
123
- if (dma_buf_read(ptr, len, &qsg)) {
124
+ if (qsg.nsg > 0) {
125
+ if (dma_buf_read(ptr, len, &qsg)) {
126
+ status = NVME_INVALID_FIELD | NVME_DNR;
127
+ }
128
qemu_sglist_destroy(&qsg);
129
- return NVME_INVALID_FIELD | NVME_DNR;
130
+ } else {
131
+ if (qemu_iovec_to_buf(&iov, 0, ptr, len) != len) {
132
+ status = NVME_INVALID_FIELD | NVME_DNR;
133
+ }
134
+ qemu_iovec_destroy(&iov);
135
}
136
- qemu_sglist_destroy(&qsg);
137
- return NVME_SUCCESS;
138
+ return status;
139
}
140
141
static void nvme_post_cqes(void *opaque)
142
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_rw(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
143
return NVME_LBA_RANGE | NVME_DNR;
144
}
145
146
- if (nvme_map_prp(&req->qsg, prp1, prp2, data_size, n)) {
147
+ if (nvme_map_prp(&req->qsg, &req->iov, prp1, prp2, data_size, n)) {
148
block_acct_invalid(blk_get_stats(n->conf.blk), acct);
149
return NVME_INVALID_FIELD | NVME_DNR;
150
}
151
152
- assert((nlb << data_shift) == req->qsg.size);
153
-
154
- req->has_sg = true;
155
dma_acct_start(n->conf.blk, &req->acct, &req->qsg, acct);
156
- req->aiocb = is_write ?
157
- dma_blk_write(n->conf.blk, &req->qsg, data_offset, BDRV_SECTOR_SIZE,
158
- nvme_rw_cb, req) :
159
- dma_blk_read(n->conf.blk, &req->qsg, data_offset, BDRV_SECTOR_SIZE,
160
- nvme_rw_cb, req);
161
+ if (req->qsg.nsg > 0) {
162
+ req->has_sg = true;
163
+ req->aiocb = is_write ?
164
+ dma_blk_write(n->conf.blk, &req->qsg, data_offset, BDRV_SECTOR_SIZE,
165
+ nvme_rw_cb, req) :
166
+ dma_blk_read(n->conf.blk, &req->qsg, data_offset, BDRV_SECTOR_SIZE,
167
+ nvme_rw_cb, req);
168
+ } else {
169
+ req->has_sg = false;
170
+ req->aiocb = is_write ?
171
+ blk_aio_pwritev(n->conf.blk, data_offset, &req->iov, 0, nvme_rw_cb,
172
+ req) :
173
+ blk_aio_preadv(n->conf.blk, data_offset, &req->iov, 0, nvme_rw_cb,
174
+ req);
175
+ }
176
177
return NVME_NO_COMPLETE;
178
}
179
@@ -XXX,XX +XXX,XX @@ static int nvme_init(PCIDevice *pci_dev)
180
NVME_CMBSZ_SET_SQS(n->bar.cmbsz, 1);
181
NVME_CMBSZ_SET_CQS(n->bar.cmbsz, 0);
182
NVME_CMBSZ_SET_LISTS(n->bar.cmbsz, 0);
183
- NVME_CMBSZ_SET_RDS(n->bar.cmbsz, 0);
184
- NVME_CMBSZ_SET_WDS(n->bar.cmbsz, 0);
185
+ NVME_CMBSZ_SET_RDS(n->bar.cmbsz, 1);
186
+ NVME_CMBSZ_SET_WDS(n->bar.cmbsz, 1);
187
NVME_CMBSZ_SET_SZU(n->bar.cmbsz, 2); /* MBs */
188
NVME_CMBSZ_SET_SZ(n->bar.cmbsz, n->cmb_size_mb);
189
190
+ n->cmbloc = n->bar.cmbloc;
191
+ n->cmbsz = n->bar.cmbsz;
192
+
193
n->cmbuf = g_malloc0(NVME_CMBSZ_GETSIZE(n->bar.cmbsz));
194
memory_region_init_io(&n->ctrl_mem, OBJECT(n), &nvme_cmb_ops, n,
195
"nvme-cmb", NVME_CMBSZ_GETSIZE(n->bar.cmbsz));
196
diff --git a/hw/block/nvme.h b/hw/block/nvme.h
197
index XXXXXXX..XXXXXXX 100644
420
index XXXXXXX..XXXXXXX 100644
198
--- a/hw/block/nvme.h
421
--- a/hw/block/Makefile.objs
199
+++ b/hw/block/nvme.h
422
+++ b/hw/block/Makefile.objs
200
@@ -XXX,XX +XXX,XX @@ typedef struct NvmeRequest {
423
@@ -XXX,XX +XXX,XX @@ common-obj-$(CONFIG_PFLASH_CFI02) += pflash_cfi02.o
201
NvmeCqe cqe;
424
common-obj-$(CONFIG_XEN) += xen-block.o
202
BlockAcctCookie acct;
425
common-obj-$(CONFIG_ECC) += ecc.o
203
QEMUSGList qsg;
426
common-obj-$(CONFIG_ONENAND) += onenand.o
204
+ QEMUIOVector iov;
427
-common-obj-$(CONFIG_NVME_PCI) += nvme.o
205
QTAILQ_ENTRY(NvmeRequest)entry;
428
common-obj-$(CONFIG_SWIM) += swim.o
206
} NvmeRequest;
429
207
430
common-obj-$(CONFIG_SH4) += tc58128.o
431
432
obj-$(CONFIG_VIRTIO_BLK) += virtio-blk.o
433
obj-$(CONFIG_VHOST_USER_BLK) += vhost-user-blk.o
434
+obj-$(CONFIG_NVME_PCI) += nvme.o
435
436
obj-y += dataplane/
437
diff --git a/hw/block/trace-events b/hw/block/trace-events
438
index XXXXXXX..XXXXXXX 100644
439
--- a/hw/block/trace-events
440
+++ b/hw/block/trace-events
441
@@ -XXX,XX +XXX,XX @@ nvme_ub_mmiowr_ssreset_w1c_unsupported(void) "attempted to W1C CSTS.NSSRO but CA
442
nvme_ub_mmiowr_ssreset_unsupported(void) "attempted NVM subsystem reset but CAP.NSSRS is zero (not supported)"
443
nvme_ub_mmiowr_cmbloc_reserved(void) "invalid write to reserved CMBLOC when CMBSZ is zero, ignored"
444
nvme_ub_mmiowr_cmbsz_readonly(void) "invalid write to read only CMBSZ, ignored"
445
+nvme_ub_mmiowr_pmrcap_readonly(void) "invalid write to read only PMRCAP, ignored"
446
+nvme_ub_mmiowr_pmrsts_readonly(void) "invalid write to read only PMRSTS, ignored"
447
+nvme_ub_mmiowr_pmrebs_readonly(void) "invalid write to read only PMREBS, ignored"
448
+nvme_ub_mmiowr_pmrswtp_readonly(void) "invalid write to read only PMRSWTP, ignored"
449
nvme_ub_mmiowr_invalid(uint64_t offset, uint64_t data) "invalid MMIO write, offset=0x%"PRIx64", data=0x%"PRIx64""
450
nvme_ub_mmiord_misaligned32(uint64_t offset) "MMIO read not 32-bit aligned, offset=0x%"PRIx64""
451
nvme_ub_mmiord_toosmall(uint64_t offset) "MMIO read smaller than 32-bits, offset=0x%"PRIx64""
208
--
452
--
209
1.8.3.1
453
2.25.3
210
454
211
455
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
Qcow2COWRegion has two attributes:
4
5
- The offset of the COW region from the start of the first cluster
6
touched by the I/O request. Since it's always going to be positive
7
and the maximum request size is at most INT_MAX, we can use a
8
regular unsigned int to store this offset.
9
10
- The size of the COW region in bytes. This is guaranteed to be >= 0,
11
so we should use an unsigned type instead.
12
13
In x86_64 this reduces the size of Qcow2COWRegion from 16 to 8 bytes.
14
It will also help keep some assertions simpler now that we know that
15
there are no negative numbers.
16
17
The prototype of do_perform_cow() is also updated to reflect these
18
changes.
19
20
Signed-off-by: Alberto Garcia <berto@igalia.com>
21
Reviewed-by: Eric Blake <eblake@redhat.com>
22
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
23
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
24
---
25
block/qcow2-cluster.c | 4 ++--
26
block/qcow2.h | 4 ++--
27
2 files changed, 4 insertions(+), 4 deletions(-)
28
29
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/block/qcow2-cluster.c
32
+++ b/block/qcow2-cluster.c
33
@@ -XXX,XX +XXX,XX @@ int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num,
34
static int coroutine_fn do_perform_cow(BlockDriverState *bs,
35
uint64_t src_cluster_offset,
36
uint64_t cluster_offset,
37
- int offset_in_cluster,
38
- int bytes)
39
+ unsigned offset_in_cluster,
40
+ unsigned bytes)
41
{
42
BDRVQcow2State *s = bs->opaque;
43
QEMUIOVector qiov;
44
diff --git a/block/qcow2.h b/block/qcow2.h
45
index XXXXXXX..XXXXXXX 100644
46
--- a/block/qcow2.h
47
+++ b/block/qcow2.h
48
@@ -XXX,XX +XXX,XX @@ typedef struct Qcow2COWRegion {
49
* Offset of the COW region in bytes from the start of the first cluster
50
* touched by the request.
51
*/
52
- uint64_t offset;
53
+ unsigned offset;
54
55
/** Number of bytes to copy */
56
- int nb_bytes;
57
+ unsigned nb_bytes;
58
} Qcow2COWRegion;
59
60
/**
61
--
62
1.8.3.1
63
64
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
Instead of calling perform_cow() twice with a different COW region
4
each time, call it just once and make perform_cow() handle both
5
regions.
6
7
This patch simply moves code around. The next one will do the actual
8
reordering of the COW operations.
9
10
Signed-off-by: Alberto Garcia <berto@igalia.com>
11
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
15
block/qcow2-cluster.c | 36 ++++++++++++++++++++++--------------
16
1 file changed, 22 insertions(+), 14 deletions(-)
17
18
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/block/qcow2-cluster.c
21
+++ b/block/qcow2-cluster.c
22
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn do_perform_cow(BlockDriverState *bs,
23
struct iovec iov;
24
int ret;
25
26
+ if (bytes == 0) {
27
+ return 0;
28
+ }
29
+
30
iov.iov_len = bytes;
31
iov.iov_base = qemu_try_blockalign(bs, iov.iov_len);
32
if (iov.iov_base == NULL) {
33
@@ -XXX,XX +XXX,XX @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
34
return cluster_offset;
35
}
36
37
-static int perform_cow(BlockDriverState *bs, QCowL2Meta *m, Qcow2COWRegion *r)
38
+static int perform_cow(BlockDriverState *bs, QCowL2Meta *m)
39
{
40
BDRVQcow2State *s = bs->opaque;
41
+ Qcow2COWRegion *start = &m->cow_start;
42
+ Qcow2COWRegion *end = &m->cow_end;
43
int ret;
44
45
- if (r->nb_bytes == 0) {
46
+ if (start->nb_bytes == 0 && end->nb_bytes == 0) {
47
return 0;
48
}
49
50
qemu_co_mutex_unlock(&s->lock);
51
- ret = do_perform_cow(bs, m->offset, m->alloc_offset, r->offset, r->nb_bytes);
52
- qemu_co_mutex_lock(&s->lock);
53
-
54
+ ret = do_perform_cow(bs, m->offset, m->alloc_offset,
55
+ start->offset, start->nb_bytes);
56
if (ret < 0) {
57
- return ret;
58
+ goto fail;
59
}
60
61
+ ret = do_perform_cow(bs, m->offset, m->alloc_offset,
62
+ end->offset, end->nb_bytes);
63
+
64
+fail:
65
+ qemu_co_mutex_lock(&s->lock);
66
+
67
/*
68
* Before we update the L2 table to actually point to the new cluster, we
69
* need to be sure that the refcounts have been increased and COW was
70
* handled.
71
*/
72
- qcow2_cache_depends_on_flush(s->l2_table_cache);
73
+ if (ret == 0) {
74
+ qcow2_cache_depends_on_flush(s->l2_table_cache);
75
+ }
76
77
- return 0;
78
+ return ret;
79
}
80
81
int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
82
@@ -XXX,XX +XXX,XX @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
83
}
84
85
/* copy content of unmodified sectors */
86
- ret = perform_cow(bs, m, &m->cow_start);
87
- if (ret < 0) {
88
- goto err;
89
- }
90
-
91
- ret = perform_cow(bs, m, &m->cow_end);
92
+ ret = perform_cow(bs, m);
93
if (ret < 0) {
94
goto err;
95
}
96
--
97
1.8.3.1
98
99
diff view generated by jsdifflib
1
Don't recurse into qed_aio_next_io() and qed_aio_complete() here, but
1
The QMP handler qmp_object_add() and the implementation of --object in
2
just return an error code and let the caller handle it.
2
qemu-storage-daemon can share most of the code. Currently,
3
qemu-storage-daemon calls qmp_object_add(), but this is not correct
4
because different visitors need to be used.
3
5
4
While refactoring qed_aio_write_alloc() to accomodate the change,
6
As a first step towards a fix, make qmp_object_add() a wrapper around a
5
qed_aio_write_zero_cluster() ended up with a single line, so I chose to
7
new function user_creatable_add_dict() that can get an additional
6
inline that line and remove the function completely.
8
parameter. The handling of "props" is only required for compatibility
9
and not required for the qemu-storage-daemon command line, so it stays
10
in qmp_object_add().
7
11
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
---
13
---
11
block/qed.c | 58 +++++++++++++++++++++-------------------------------------
14
include/qom/object_interfaces.h | 12 ++++++++++++
12
1 file changed, 21 insertions(+), 37 deletions(-)
15
qom/object_interfaces.c | 27 +++++++++++++++++++++++++++
16
qom/qom-qmp-cmds.c | 24 +-----------------------
17
3 files changed, 40 insertions(+), 23 deletions(-)
13
18
14
diff --git a/block/qed.c b/block/qed.c
19
diff --git a/include/qom/object_interfaces.h b/include/qom/object_interfaces.h
15
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
16
--- a/block/qed.c
21
--- a/include/qom/object_interfaces.h
17
+++ b/block/qed.c
22
+++ b/include/qom/object_interfaces.h
18
@@ -XXX,XX +XXX,XX @@ static int qed_aio_write_main(QEDAIOCB *acb)
23
@@ -XXX,XX +XXX,XX @@ Object *user_creatable_add_type(const char *type, const char *id,
24
const QDict *qdict,
25
Visitor *v, Error **errp);
26
27
+/**
28
+ * user_creatable_add_dict:
29
+ * @qdict: the object definition
30
+ * @errp: if an error occurs, a pointer to an area to store the error
31
+ *
32
+ * Create an instance of the user creatable object that is defined by
33
+ * @qdict. The object type is taken from the QDict key 'qom-type', its
34
+ * ID from the key 'id'. The remaining entries in @qdict are used to
35
+ * initialize the object properties.
36
+ */
37
+void user_creatable_add_dict(QDict *qdict, Error **errp);
38
+
19
/**
39
/**
20
* Populate untouched regions of new data cluster
40
* user_creatable_add_opts:
21
*/
41
* @opts: the object definition
22
-static void qed_aio_write_cow(void *opaque, int ret)
42
diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c
23
+static int qed_aio_write_cow(QEDAIOCB *acb)
43
index XXXXXXX..XXXXXXX 100644
44
--- a/qom/object_interfaces.c
45
+++ b/qom/object_interfaces.c
46
@@ -XXX,XX +XXX,XX @@
47
#include "qapi/qmp/qerror.h"
48
#include "qapi/qmp/qjson.h"
49
#include "qapi/qmp/qstring.h"
50
+#include "qapi/qobject-input-visitor.h"
51
#include "qom/object_interfaces.h"
52
#include "qemu/help_option.h"
53
#include "qemu/module.h"
54
@@ -XXX,XX +XXX,XX @@ out:
55
return obj;
56
}
57
58
+void user_creatable_add_dict(QDict *qdict, Error **errp)
59
+{
60
+ Visitor *v;
61
+ Object *obj;
62
+ g_autofree char *type = NULL;
63
+ g_autofree char *id = NULL;
64
+
65
+ type = g_strdup(qdict_get_try_str(qdict, "qom-type"));
66
+ if (!type) {
67
+ error_setg(errp, QERR_MISSING_PARAMETER, "qom-type");
68
+ return;
69
+ }
70
+ qdict_del(qdict, "qom-type");
71
+
72
+ id = g_strdup(qdict_get_try_str(qdict, "id"));
73
+ if (!id) {
74
+ error_setg(errp, QERR_MISSING_PARAMETER, "id");
75
+ return;
76
+ }
77
+ qdict_del(qdict, "id");
78
+
79
+ v = qobject_input_visitor_new(QOBJECT(qdict));
80
+ obj = user_creatable_add_type(type, id, qdict, v, errp);
81
+ visit_free(v);
82
+ object_unref(obj);
83
+}
84
85
Object *user_creatable_add_opts(QemuOpts *opts, Error **errp)
24
{
86
{
25
- QEDAIOCB *acb = opaque;
87
diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c
26
BDRVQEDState *s = acb_to_s(acb);
88
index XXXXXXX..XXXXXXX 100644
27
uint64_t start, len, offset;
89
--- a/qom/qom-qmp-cmds.c
28
+ int ret;
90
+++ b/qom/qom-qmp-cmds.c
29
91
@@ -XXX,XX +XXX,XX @@
30
/* Populate front untouched region of new data cluster */
92
#include "qapi/qapi-commands-qom.h"
31
start = qed_start_of_cluster(s, acb->cur_pos);
93
#include "qapi/qmp/qdict.h"
32
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_cow(void *opaque, int ret)
94
#include "qapi/qmp/qerror.h"
33
95
-#include "qapi/qobject-input-visitor.h"
34
trace_qed_aio_write_prefill(s, acb, start, len, acb->cur_cluster);
96
#include "qemu/cutils.h"
35
ret = qed_copy_from_backing_file(s, start, len, acb->cur_cluster);
97
#include "qom/object_interfaces.h"
36
- if (ret) {
98
#include "qom/qom-qobject.h"
37
- qed_aio_complete(acb, ret);
99
@@ -XXX,XX +XXX,XX @@ void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp)
38
- return;
100
{
39
+ if (ret < 0) {
101
QObject *props;
40
+ return ret;
102
QDict *pdict;
41
}
103
- Visitor *v;
42
104
- Object *obj;
43
/* Populate back untouched region of new data cluster */
105
- g_autofree char *type = NULL;
44
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_cow(void *opaque, int ret)
106
- g_autofree char *id = NULL;
45
107
-
46
trace_qed_aio_write_postfill(s, acb, start, len, offset);
108
- type = g_strdup(qdict_get_try_str(qdict, "qom-type"));
47
ret = qed_copy_from_backing_file(s, start, len, offset);
109
- if (!type) {
48
- if (ret) {
110
- error_setg(errp, QERR_MISSING_PARAMETER, "qom-type");
49
- qed_aio_complete(acb, ret);
50
- return;
111
- return;
51
- }
112
- }
113
- qdict_del(qdict, "qom-type");
52
-
114
-
53
- ret = qed_aio_write_main(acb);
115
- id = g_strdup(qdict_get_try_str(qdict, "id"));
54
if (ret < 0) {
116
- if (!id) {
55
- qed_aio_complete(acb, ret);
117
- error_setg(errp, QERR_MISSING_PARAMETER, "id");
56
- return;
57
+ return ret;
58
}
59
- qed_aio_next_io(acb, 0);
60
+
61
+ return qed_aio_write_main(acb);
62
}
63
64
/**
65
@@ -XXX,XX +XXX,XX @@ static bool qed_should_set_need_check(BDRVQEDState *s)
66
return !(s->header.features & QED_F_NEED_CHECK);
67
}
68
69
-static void qed_aio_write_zero_cluster(void *opaque, int ret)
70
-{
71
- QEDAIOCB *acb = opaque;
72
-
73
- if (ret) {
74
- qed_aio_complete(acb, ret);
75
- return;
118
- return;
76
- }
119
- }
77
-
120
- qdict_del(qdict, "id");
78
- ret = qed_aio_write_l2_update(acb, 1);
121
79
- if (ret < 0) {
122
props = qdict_get(qdict, "props");
80
- qed_aio_complete(acb, ret);
123
if (props) {
81
- return;
124
@@ -XXX,XX +XXX,XX @@ void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp)
82
- }
125
qobject_unref(pdict);
83
- qed_aio_next_io(acb, 0);
84
-}
85
-
86
/**
87
* Write new data cluster
88
*
89
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_zero_cluster(void *opaque, int ret)
90
static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
91
{
92
BDRVQEDState *s = acb_to_s(acb);
93
- BlockCompletionFunc *cb;
94
int ret;
95
96
/* Cancel timer when the first allocating request comes in */
97
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
98
qed_aio_start_io(acb);
99
return;
100
}
101
-
102
- cb = qed_aio_write_zero_cluster;
103
} else {
104
- cb = qed_aio_write_cow;
105
acb->cur_cluster = qed_alloc_clusters(s, acb->cur_nclusters);
106
}
126
}
107
127
108
if (qed_should_set_need_check(s)) {
128
- v = qobject_input_visitor_new(QOBJECT(qdict));
109
s->header.features |= QED_F_NEED_CHECK;
129
- obj = user_creatable_add_type(type, id, qdict, v, errp);
110
ret = qed_write_header(s);
130
- visit_free(v);
111
- cb(acb, ret);
131
- object_unref(obj);
112
+ if (ret < 0) {
132
+ user_creatable_add_dict(qdict, errp);
113
+ qed_aio_complete(acb, ret);
114
+ return;
115
+ }
116
+ }
117
+
118
+ if (acb->flags & QED_AIOCB_ZERO) {
119
+ ret = qed_aio_write_l2_update(acb, 1);
120
} else {
121
- cb(acb, 0);
122
+ ret = qed_aio_write_cow(acb);
123
}
124
+ if (ret < 0) {
125
+ qed_aio_complete(acb, ret);
126
+ return;
127
+ }
128
+ qed_aio_next_io(acb, 0);
129
}
133
}
130
134
131
/**
135
void qmp_object_del(const char *id, Error **errp)
132
--
136
--
133
1.8.3.1
137
2.25.3
134
138
135
139
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
After processing the option string with the keyval parser, we get a
2
QDict that contains only strings. This QDict must be fed to a keyval
3
visitor which converts the strings into the right data types.
2
4
3
This patch splits do_perform_cow() into three separate functions to
5
qmp_object_add(), however, uses the normal QObject input visitor, which
4
read, encrypt and write the COW regions.
6
expects a QDict where all properties already have the QType that matches
7
the data type required by the QOM object type.
5
8
6
perform_cow() can now read both regions first, then encrypt them and
9
Change the --object implementation in qemu-storage-daemon so that it
7
finally write them to disk. The memory allocation is also done in
10
doesn't call qmp_object_add(), but calls user_creatable_add_dict()
8
this function now, using one single buffer large enough to hold both
11
directly instead and pass it a new keyval boolean that decides which
9
regions.
12
visitor must be used.
10
13
11
Signed-off-by: Alberto Garcia <berto@igalia.com>
14
Reported-by: Coiby Xu <coiby.xu@gmail.com>
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
16
---
15
block/qcow2-cluster.c | 117 +++++++++++++++++++++++++++++++++++++-------------
17
include/qom/object_interfaces.h | 6 +++++-
16
1 file changed, 87 insertions(+), 30 deletions(-)
18
qemu-storage-daemon.c | 4 +---
19
qom/object_interfaces.c | 8 ++++++--
20
qom/qom-qmp-cmds.c | 2 +-
21
4 files changed, 13 insertions(+), 7 deletions(-)
17
22
18
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
23
diff --git a/include/qom/object_interfaces.h b/include/qom/object_interfaces.h
19
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
20
--- a/block/qcow2-cluster.c
25
--- a/include/qom/object_interfaces.h
21
+++ b/block/qcow2-cluster.c
26
+++ b/include/qom/object_interfaces.h
22
@@ -XXX,XX +XXX,XX @@ int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num,
27
@@ -XXX,XX +XXX,XX @@ Object *user_creatable_add_type(const char *type, const char *id,
23
return 0;
28
/**
29
* user_creatable_add_dict:
30
* @qdict: the object definition
31
+ * @keyval: if true, use a keyval visitor for processing @qdict (i.e.
32
+ * assume that all @qdict values are strings); otherwise, use
33
+ * the normal QObject visitor (i.e. assume all @qdict values
34
+ * have the QType expected by the QOM object type)
35
* @errp: if an error occurs, a pointer to an area to store the error
36
*
37
* Create an instance of the user creatable object that is defined by
38
@@ -XXX,XX +XXX,XX @@ Object *user_creatable_add_type(const char *type, const char *id,
39
* ID from the key 'id'. The remaining entries in @qdict are used to
40
* initialize the object properties.
41
*/
42
-void user_creatable_add_dict(QDict *qdict, Error **errp);
43
+void user_creatable_add_dict(QDict *qdict, bool keyval, Error **errp);
44
45
/**
46
* user_creatable_add_opts:
47
diff --git a/qemu-storage-daemon.c b/qemu-storage-daemon.c
48
index XXXXXXX..XXXXXXX 100644
49
--- a/qemu-storage-daemon.c
50
+++ b/qemu-storage-daemon.c
51
@@ -XXX,XX +XXX,XX @@ static void process_options(int argc, char *argv[])
52
QemuOpts *opts;
53
const char *type;
54
QDict *args;
55
- QObject *ret_data = NULL;
56
57
/* FIXME The keyval parser rejects 'help' arguments, so we must
58
* unconditionall try QemuOpts first. */
59
@@ -XXX,XX +XXX,XX @@ static void process_options(int argc, char *argv[])
60
qemu_opts_del(opts);
61
62
args = keyval_parse(optarg, "qom-type", &error_fatal);
63
- qmp_object_add(args, &ret_data, &error_fatal);
64
+ user_creatable_add_dict(args, true, &error_fatal);
65
qobject_unref(args);
66
- qobject_unref(ret_data);
67
break;
68
}
69
default:
70
diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c
71
index XXXXXXX..XXXXXXX 100644
72
--- a/qom/object_interfaces.c
73
+++ b/qom/object_interfaces.c
74
@@ -XXX,XX +XXX,XX @@ out:
75
return obj;
24
}
76
}
25
77
26
-static int coroutine_fn do_perform_cow(BlockDriverState *bs,
78
-void user_creatable_add_dict(QDict *qdict, Error **errp)
27
- uint64_t src_cluster_offset,
79
+void user_creatable_add_dict(QDict *qdict, bool keyval, Error **errp)
28
- uint64_t cluster_offset,
29
- unsigned offset_in_cluster,
30
- unsigned bytes)
31
+static int coroutine_fn do_perform_cow_read(BlockDriverState *bs,
32
+ uint64_t src_cluster_offset,
33
+ unsigned offset_in_cluster,
34
+ uint8_t *buffer,
35
+ unsigned bytes)
36
{
80
{
37
- BDRVQcow2State *s = bs->opaque;
81
Visitor *v;
38
QEMUIOVector qiov;
82
Object *obj;
39
- struct iovec iov;
83
@@ -XXX,XX +XXX,XX @@ void user_creatable_add_dict(QDict *qdict, Error **errp)
40
+ struct iovec iov = { .iov_base = buffer, .iov_len = bytes };
41
int ret;
42
43
if (bytes == 0) {
44
return 0;
45
}
84
}
46
85
qdict_del(qdict, "id");
47
- iov.iov_len = bytes;
86
48
- iov.iov_base = qemu_try_blockalign(bs, iov.iov_len);
87
- v = qobject_input_visitor_new(QOBJECT(qdict));
49
- if (iov.iov_base == NULL) {
88
+ if (keyval) {
50
- return -ENOMEM;
89
+ v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
51
- }
90
+ } else {
52
-
91
+ v = qobject_input_visitor_new(QOBJECT(qdict));
53
qemu_iovec_init_external(&qiov, &iov, 1);
92
+ }
54
93
obj = user_creatable_add_type(type, id, qdict, v, errp);
55
BLKDBG_EVENT(bs->file, BLKDBG_COW_READ);
94
visit_free(v);
56
95
object_unref(obj);
57
if (!bs->drv) {
96
diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c
58
- ret = -ENOMEDIUM;
97
index XXXXXXX..XXXXXXX 100644
59
- goto out;
98
--- a/qom/qom-qmp-cmds.c
60
+ return -ENOMEDIUM;
99
+++ b/qom/qom-qmp-cmds.c
100
@@ -XXX,XX +XXX,XX @@ void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp)
101
qobject_unref(pdict);
61
}
102
}
62
103
63
/* Call .bdrv_co_readv() directly instead of using the public block-layer
104
- user_creatable_add_dict(qdict, errp);
64
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn do_perform_cow(BlockDriverState *bs,
105
+ user_creatable_add_dict(qdict, false, errp);
65
ret = bs->drv->bdrv_co_preadv(bs, src_cluster_offset + offset_in_cluster,
66
bytes, &qiov, 0);
67
if (ret < 0) {
68
- goto out;
69
+ return ret;
70
}
71
72
- if (bs->encrypted) {
73
+ return 0;
74
+}
75
+
76
+static bool coroutine_fn do_perform_cow_encrypt(BlockDriverState *bs,
77
+ uint64_t src_cluster_offset,
78
+ unsigned offset_in_cluster,
79
+ uint8_t *buffer,
80
+ unsigned bytes)
81
+{
82
+ if (bytes && bs->encrypted) {
83
+ BDRVQcow2State *s = bs->opaque;
84
int64_t sector = (src_cluster_offset + offset_in_cluster)
85
>> BDRV_SECTOR_BITS;
86
assert(s->cipher);
87
assert((offset_in_cluster & ~BDRV_SECTOR_MASK) == 0);
88
assert((bytes & ~BDRV_SECTOR_MASK) == 0);
89
- if (qcow2_encrypt_sectors(s, sector, iov.iov_base, iov.iov_base,
90
+ if (qcow2_encrypt_sectors(s, sector, buffer, buffer,
91
bytes >> BDRV_SECTOR_BITS, true, NULL) < 0) {
92
- ret = -EIO;
93
- goto out;
94
+ return false;
95
}
96
}
97
+ return true;
98
+}
99
+
100
+static int coroutine_fn do_perform_cow_write(BlockDriverState *bs,
101
+ uint64_t cluster_offset,
102
+ unsigned offset_in_cluster,
103
+ uint8_t *buffer,
104
+ unsigned bytes)
105
+{
106
+ QEMUIOVector qiov;
107
+ struct iovec iov = { .iov_base = buffer, .iov_len = bytes };
108
+ int ret;
109
+
110
+ if (bytes == 0) {
111
+ return 0;
112
+ }
113
+
114
+ qemu_iovec_init_external(&qiov, &iov, 1);
115
116
ret = qcow2_pre_write_overlap_check(bs, 0,
117
cluster_offset + offset_in_cluster, bytes);
118
if (ret < 0) {
119
- goto out;
120
+ return ret;
121
}
122
123
BLKDBG_EVENT(bs->file, BLKDBG_COW_WRITE);
124
ret = bdrv_co_pwritev(bs->file, cluster_offset + offset_in_cluster,
125
bytes, &qiov, 0);
126
if (ret < 0) {
127
- goto out;
128
+ return ret;
129
}
130
131
- ret = 0;
132
-out:
133
- qemu_vfree(iov.iov_base);
134
- return ret;
135
+ return 0;
136
}
106
}
137
107
138
108
void qmp_object_del(const char *id, Error **errp)
139
@@ -XXX,XX +XXX,XX @@ static int perform_cow(BlockDriverState *bs, QCowL2Meta *m)
140
BDRVQcow2State *s = bs->opaque;
141
Qcow2COWRegion *start = &m->cow_start;
142
Qcow2COWRegion *end = &m->cow_end;
143
+ unsigned buffer_size;
144
+ uint8_t *start_buffer, *end_buffer;
145
int ret;
146
147
+ assert(start->nb_bytes <= UINT_MAX - end->nb_bytes);
148
+
149
if (start->nb_bytes == 0 && end->nb_bytes == 0) {
150
return 0;
151
}
152
153
+ /* Reserve a buffer large enough to store the data from both the
154
+ * start and end COW regions. Add some padding in the middle if
155
+ * necessary to make sure that the end region is optimally aligned */
156
+ buffer_size = QEMU_ALIGN_UP(start->nb_bytes, bdrv_opt_mem_align(bs)) +
157
+ end->nb_bytes;
158
+ start_buffer = qemu_try_blockalign(bs, buffer_size);
159
+ if (start_buffer == NULL) {
160
+ return -ENOMEM;
161
+ }
162
+ /* The part of the buffer where the end region is located */
163
+ end_buffer = start_buffer + buffer_size - end->nb_bytes;
164
+
165
qemu_co_mutex_unlock(&s->lock);
166
- ret = do_perform_cow(bs, m->offset, m->alloc_offset,
167
- start->offset, start->nb_bytes);
168
+ /* First we read the existing data from both COW regions */
169
+ ret = do_perform_cow_read(bs, m->offset, start->offset,
170
+ start_buffer, start->nb_bytes);
171
if (ret < 0) {
172
goto fail;
173
}
174
175
- ret = do_perform_cow(bs, m->offset, m->alloc_offset,
176
- end->offset, end->nb_bytes);
177
+ ret = do_perform_cow_read(bs, m->offset, end->offset,
178
+ end_buffer, end->nb_bytes);
179
+ if (ret < 0) {
180
+ goto fail;
181
+ }
182
+
183
+ /* Encrypt the data if necessary before writing it */
184
+ if (bs->encrypted) {
185
+ if (!do_perform_cow_encrypt(bs, m->offset, start->offset,
186
+ start_buffer, start->nb_bytes) ||
187
+ !do_perform_cow_encrypt(bs, m->offset, end->offset,
188
+ end_buffer, end->nb_bytes)) {
189
+ ret = -EIO;
190
+ goto fail;
191
+ }
192
+ }
193
+
194
+ /* And now we can write everything */
195
+ ret = do_perform_cow_write(bs, m->alloc_offset, start->offset,
196
+ start_buffer, start->nb_bytes);
197
+ if (ret < 0) {
198
+ goto fail;
199
+ }
200
201
+ ret = do_perform_cow_write(bs, m->alloc_offset, end->offset,
202
+ end_buffer, end->nb_bytes);
203
fail:
204
qemu_co_mutex_lock(&s->lock);
205
206
@@ -XXX,XX +XXX,XX @@ fail:
207
qcow2_cache_depends_on_flush(s->l2_table_cache);
208
}
209
210
+ qemu_vfree(start_buffer);
211
return ret;
212
}
213
214
--
109
--
215
1.8.3.1
110
2.25.3
216
111
217
112
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
Instead of passing a single buffer pointer to do_perform_cow_write(),
4
pass a QEMUIOVector. This will allow us to merge the write requests
5
for the COW regions and the actual data into a single one.
6
7
Although do_perform_cow_read() does not strictly need to change its
8
API, we're doing it here as well for consistency.
9
10
Signed-off-by: Alberto Garcia <berto@igalia.com>
11
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
14
block/qcow2-cluster.c | 51 ++++++++++++++++++++++++---------------------------
15
1 file changed, 24 insertions(+), 27 deletions(-)
16
17
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/block/qcow2-cluster.c
20
+++ b/block/qcow2-cluster.c
21
@@ -XXX,XX +XXX,XX @@ int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num,
22
static int coroutine_fn do_perform_cow_read(BlockDriverState *bs,
23
uint64_t src_cluster_offset,
24
unsigned offset_in_cluster,
25
- uint8_t *buffer,
26
- unsigned bytes)
27
+ QEMUIOVector *qiov)
28
{
29
- QEMUIOVector qiov;
30
- struct iovec iov = { .iov_base = buffer, .iov_len = bytes };
31
int ret;
32
33
- if (bytes == 0) {
34
+ if (qiov->size == 0) {
35
return 0;
36
}
37
38
- qemu_iovec_init_external(&qiov, &iov, 1);
39
-
40
BLKDBG_EVENT(bs->file, BLKDBG_COW_READ);
41
42
if (!bs->drv) {
43
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn do_perform_cow_read(BlockDriverState *bs,
44
* which can lead to deadlock when block layer copy-on-read is enabled.
45
*/
46
ret = bs->drv->bdrv_co_preadv(bs, src_cluster_offset + offset_in_cluster,
47
- bytes, &qiov, 0);
48
+ qiov->size, qiov, 0);
49
if (ret < 0) {
50
return ret;
51
}
52
@@ -XXX,XX +XXX,XX @@ static bool coroutine_fn do_perform_cow_encrypt(BlockDriverState *bs,
53
static int coroutine_fn do_perform_cow_write(BlockDriverState *bs,
54
uint64_t cluster_offset,
55
unsigned offset_in_cluster,
56
- uint8_t *buffer,
57
- unsigned bytes)
58
+ QEMUIOVector *qiov)
59
{
60
- QEMUIOVector qiov;
61
- struct iovec iov = { .iov_base = buffer, .iov_len = bytes };
62
int ret;
63
64
- if (bytes == 0) {
65
+ if (qiov->size == 0) {
66
return 0;
67
}
68
69
- qemu_iovec_init_external(&qiov, &iov, 1);
70
-
71
ret = qcow2_pre_write_overlap_check(bs, 0,
72
- cluster_offset + offset_in_cluster, bytes);
73
+ cluster_offset + offset_in_cluster, qiov->size);
74
if (ret < 0) {
75
return ret;
76
}
77
78
BLKDBG_EVENT(bs->file, BLKDBG_COW_WRITE);
79
ret = bdrv_co_pwritev(bs->file, cluster_offset + offset_in_cluster,
80
- bytes, &qiov, 0);
81
+ qiov->size, qiov, 0);
82
if (ret < 0) {
83
return ret;
84
}
85
@@ -XXX,XX +XXX,XX @@ static int perform_cow(BlockDriverState *bs, QCowL2Meta *m)
86
unsigned data_bytes = end->offset - (start->offset + start->nb_bytes);
87
bool merge_reads;
88
uint8_t *start_buffer, *end_buffer;
89
+ QEMUIOVector qiov;
90
int ret;
91
92
assert(start->nb_bytes <= UINT_MAX - end->nb_bytes);
93
@@ -XXX,XX +XXX,XX @@ static int perform_cow(BlockDriverState *bs, QCowL2Meta *m)
94
/* The part of the buffer where the end region is located */
95
end_buffer = start_buffer + buffer_size - end->nb_bytes;
96
97
+ qemu_iovec_init(&qiov, 1);
98
+
99
qemu_co_mutex_unlock(&s->lock);
100
/* First we read the existing data from both COW regions. We
101
* either read the whole region in one go, or the start and end
102
* regions separately. */
103
if (merge_reads) {
104
- ret = do_perform_cow_read(bs, m->offset, start->offset,
105
- start_buffer, buffer_size);
106
+ qemu_iovec_add(&qiov, start_buffer, buffer_size);
107
+ ret = do_perform_cow_read(bs, m->offset, start->offset, &qiov);
108
} else {
109
- ret = do_perform_cow_read(bs, m->offset, start->offset,
110
- start_buffer, start->nb_bytes);
111
+ qemu_iovec_add(&qiov, start_buffer, start->nb_bytes);
112
+ ret = do_perform_cow_read(bs, m->offset, start->offset, &qiov);
113
if (ret < 0) {
114
goto fail;
115
}
116
117
- ret = do_perform_cow_read(bs, m->offset, end->offset,
118
- end_buffer, end->nb_bytes);
119
+ qemu_iovec_reset(&qiov);
120
+ qemu_iovec_add(&qiov, end_buffer, end->nb_bytes);
121
+ ret = do_perform_cow_read(bs, m->offset, end->offset, &qiov);
122
}
123
if (ret < 0) {
124
goto fail;
125
@@ -XXX,XX +XXX,XX @@ static int perform_cow(BlockDriverState *bs, QCowL2Meta *m)
126
}
127
128
/* And now we can write everything */
129
- ret = do_perform_cow_write(bs, m->alloc_offset, start->offset,
130
- start_buffer, start->nb_bytes);
131
+ qemu_iovec_reset(&qiov);
132
+ qemu_iovec_add(&qiov, start_buffer, start->nb_bytes);
133
+ ret = do_perform_cow_write(bs, m->alloc_offset, start->offset, &qiov);
134
if (ret < 0) {
135
goto fail;
136
}
137
138
- ret = do_perform_cow_write(bs, m->alloc_offset, end->offset,
139
- end_buffer, end->nb_bytes);
140
+ qemu_iovec_reset(&qiov);
141
+ qemu_iovec_add(&qiov, end_buffer, end->nb_bytes);
142
+ ret = do_perform_cow_write(bs, m->alloc_offset, end->offset, &qiov);
143
fail:
144
qemu_co_mutex_lock(&s->lock);
145
146
@@ -XXX,XX +XXX,XX @@ fail:
147
}
148
149
qemu_vfree(start_buffer);
150
+ qemu_iovec_destroy(&qiov);
151
return ret;
152
}
153
154
--
155
1.8.3.1
156
157
diff view generated by jsdifflib
Deleted patch
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Reviewed-by: Eric Blake <eblake@redhat.com>
3
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
4
---
5
block/qed-cluster.c | 94 ++++++++++++++++++-----------------------------------
6
block/qed-table.c | 15 +++------
7
block/qed.h | 3 +-
8
3 files changed, 36 insertions(+), 76 deletions(-)
9
1
10
diff --git a/block/qed-cluster.c b/block/qed-cluster.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/block/qed-cluster.c
13
+++ b/block/qed-cluster.c
14
@@ -XXX,XX +XXX,XX @@ static unsigned int qed_count_contiguous_clusters(BDRVQEDState *s,
15
return i - index;
16
}
17
18
-typedef struct {
19
- BDRVQEDState *s;
20
- uint64_t pos;
21
- size_t len;
22
-
23
- QEDRequest *request;
24
-
25
- /* User callback */
26
- QEDFindClusterFunc *cb;
27
- void *opaque;
28
-} QEDFindClusterCB;
29
-
30
-static void qed_find_cluster_cb(void *opaque, int ret)
31
-{
32
- QEDFindClusterCB *find_cluster_cb = opaque;
33
- BDRVQEDState *s = find_cluster_cb->s;
34
- QEDRequest *request = find_cluster_cb->request;
35
- uint64_t offset = 0;
36
- size_t len = 0;
37
- unsigned int index;
38
- unsigned int n;
39
-
40
- qed_acquire(s);
41
- if (ret) {
42
- goto out;
43
- }
44
-
45
- index = qed_l2_index(s, find_cluster_cb->pos);
46
- n = qed_bytes_to_clusters(s,
47
- qed_offset_into_cluster(s, find_cluster_cb->pos) +
48
- find_cluster_cb->len);
49
- n = qed_count_contiguous_clusters(s, request->l2_table->table,
50
- index, n, &offset);
51
-
52
- if (qed_offset_is_unalloc_cluster(offset)) {
53
- ret = QED_CLUSTER_L2;
54
- } else if (qed_offset_is_zero_cluster(offset)) {
55
- ret = QED_CLUSTER_ZERO;
56
- } else if (qed_check_cluster_offset(s, offset)) {
57
- ret = QED_CLUSTER_FOUND;
58
- } else {
59
- ret = -EINVAL;
60
- }
61
-
62
- len = MIN(find_cluster_cb->len, n * s->header.cluster_size -
63
- qed_offset_into_cluster(s, find_cluster_cb->pos));
64
-
65
-out:
66
- find_cluster_cb->cb(find_cluster_cb->opaque, ret, offset, len);
67
- qed_release(s);
68
- g_free(find_cluster_cb);
69
-}
70
-
71
/**
72
* Find the offset of a data cluster
73
*
74
@@ -XXX,XX +XXX,XX @@ out:
75
void qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
76
size_t len, QEDFindClusterFunc *cb, void *opaque)
77
{
78
- QEDFindClusterCB *find_cluster_cb;
79
uint64_t l2_offset;
80
+ uint64_t offset = 0;
81
+ unsigned int index;
82
+ unsigned int n;
83
+ int ret;
84
85
/* Limit length to L2 boundary. Requests are broken up at the L2 boundary
86
* so that a request acts on one L2 table at a time.
87
@@ -XXX,XX +XXX,XX @@ void qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
88
return;
89
}
90
91
- find_cluster_cb = g_malloc(sizeof(*find_cluster_cb));
92
- find_cluster_cb->s = s;
93
- find_cluster_cb->pos = pos;
94
- find_cluster_cb->len = len;
95
- find_cluster_cb->cb = cb;
96
- find_cluster_cb->opaque = opaque;
97
- find_cluster_cb->request = request;
98
+ ret = qed_read_l2_table(s, request, l2_offset);
99
+ qed_acquire(s);
100
+ if (ret) {
101
+ goto out;
102
+ }
103
+
104
+ index = qed_l2_index(s, pos);
105
+ n = qed_bytes_to_clusters(s,
106
+ qed_offset_into_cluster(s, pos) + len);
107
+ n = qed_count_contiguous_clusters(s, request->l2_table->table,
108
+ index, n, &offset);
109
+
110
+ if (qed_offset_is_unalloc_cluster(offset)) {
111
+ ret = QED_CLUSTER_L2;
112
+ } else if (qed_offset_is_zero_cluster(offset)) {
113
+ ret = QED_CLUSTER_ZERO;
114
+ } else if (qed_check_cluster_offset(s, offset)) {
115
+ ret = QED_CLUSTER_FOUND;
116
+ } else {
117
+ ret = -EINVAL;
118
+ }
119
+
120
+ len = MIN(len,
121
+ n * s->header.cluster_size - qed_offset_into_cluster(s, pos));
122
123
- qed_read_l2_table(s, request, l2_offset,
124
- qed_find_cluster_cb, find_cluster_cb);
125
+out:
126
+ cb(opaque, ret, offset, len);
127
+ qed_release(s);
128
}
129
diff --git a/block/qed-table.c b/block/qed-table.c
130
index XXXXXXX..XXXXXXX 100644
131
--- a/block/qed-table.c
132
+++ b/block/qed-table.c
133
@@ -XXX,XX +XXX,XX @@ int qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index,
134
return ret;
135
}
136
137
-void qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset,
138
- BlockCompletionFunc *cb, void *opaque)
139
+int qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset)
140
{
141
int ret;
142
143
@@ -XXX,XX +XXX,XX @@ void qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset,
144
/* Check for cached L2 entry */
145
request->l2_table = qed_find_l2_cache_entry(&s->l2_cache, offset);
146
if (request->l2_table) {
147
- cb(opaque, 0);
148
- return;
149
+ return 0;
150
}
151
152
request->l2_table = qed_alloc_l2_cache_entry(&s->l2_cache);
153
@@ -XXX,XX +XXX,XX @@ void qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset,
154
}
155
qed_release(s);
156
157
- cb(opaque, ret);
158
+ return ret;
159
}
160
161
int qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request, uint64_t offset)
162
{
163
- int ret = -EINPROGRESS;
164
-
165
- qed_read_l2_table(s, request, offset, qed_sync_cb, &ret);
166
- BDRV_POLL_WHILE(s->bs, ret == -EINPROGRESS);
167
-
168
- return ret;
169
+ return qed_read_l2_table(s, request, offset);
170
}
171
172
void qed_write_l2_table(BDRVQEDState *s, QEDRequest *request,
173
diff --git a/block/qed.h b/block/qed.h
174
index XXXXXXX..XXXXXXX 100644
175
--- a/block/qed.h
176
+++ b/block/qed.h
177
@@ -XXX,XX +XXX,XX @@ int qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index,
178
unsigned int n);
179
int qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
180
uint64_t offset);
181
-void qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset,
182
- BlockCompletionFunc *cb, void *opaque);
183
+int qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset);
184
void qed_write_l2_table(BDRVQEDState *s, QEDRequest *request,
185
unsigned int index, unsigned int n, bool flush,
186
BlockCompletionFunc *cb, void *opaque);
187
--
188
1.8.3.1
189
190
diff view generated by jsdifflib
Deleted patch
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
3
---
4
block/qed-cluster.c | 39 ++++++++++++++++++++++-----------------
5
block/qed.c | 24 +++++++++++-------------
6
block/qed.h | 4 ++--
7
3 files changed, 35 insertions(+), 32 deletions(-)
8
1
9
diff --git a/block/qed-cluster.c b/block/qed-cluster.c
10
index XXXXXXX..XXXXXXX 100644
11
--- a/block/qed-cluster.c
12
+++ b/block/qed-cluster.c
13
@@ -XXX,XX +XXX,XX @@ static unsigned int qed_count_contiguous_clusters(BDRVQEDState *s,
14
* @s: QED state
15
* @request: L2 cache entry
16
* @pos: Byte position in device
17
- * @len: Number of bytes
18
- * @cb: Completion function
19
- * @opaque: User data for completion function
20
+ * @len: Number of bytes (may be shortened on return)
21
+ * @img_offset: Contains offset in the image file on success
22
*
23
* This function translates a position in the block device to an offset in the
24
- * image file. It invokes the cb completion callback to report back the
25
- * translated offset or unallocated range in the image file.
26
+ * image file. The translated offset or unallocated range in the image file is
27
+ * reported back in *img_offset and *len.
28
*
29
* If the L2 table exists, request->l2_table points to the L2 table cache entry
30
* and the caller must free the reference when they are finished. The cache
31
* entry is exposed in this way to avoid callers having to read the L2 table
32
* again later during request processing. If request->l2_table is non-NULL it
33
* will be unreferenced before taking on the new cache entry.
34
+ *
35
+ * On success QED_CLUSTER_FOUND is returned and img_offset/len are a contiguous
36
+ * range in the image file.
37
+ *
38
+ * On failure QED_CLUSTER_L2 or QED_CLUSTER_L1 is returned for missing L2 or L1
39
+ * table offset, respectively. len is number of contiguous unallocated bytes.
40
*/
41
-void qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
42
- size_t len, QEDFindClusterFunc *cb, void *opaque)
43
+int qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
44
+ size_t *len, uint64_t *img_offset)
45
{
46
uint64_t l2_offset;
47
uint64_t offset = 0;
48
@@ -XXX,XX +XXX,XX @@ void qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
49
/* Limit length to L2 boundary. Requests are broken up at the L2 boundary
50
* so that a request acts on one L2 table at a time.
51
*/
52
- len = MIN(len, (((pos >> s->l1_shift) + 1) << s->l1_shift) - pos);
53
+ *len = MIN(*len, (((pos >> s->l1_shift) + 1) << s->l1_shift) - pos);
54
55
l2_offset = s->l1_table->offsets[qed_l1_index(s, pos)];
56
if (qed_offset_is_unalloc_cluster(l2_offset)) {
57
- cb(opaque, QED_CLUSTER_L1, 0, len);
58
- return;
59
+ *img_offset = 0;
60
+ return QED_CLUSTER_L1;
61
}
62
if (!qed_check_table_offset(s, l2_offset)) {
63
- cb(opaque, -EINVAL, 0, 0);
64
- return;
65
+ *img_offset = *len = 0;
66
+ return -EINVAL;
67
}
68
69
ret = qed_read_l2_table(s, request, l2_offset);
70
@@ -XXX,XX +XXX,XX @@ void qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
71
}
72
73
index = qed_l2_index(s, pos);
74
- n = qed_bytes_to_clusters(s,
75
- qed_offset_into_cluster(s, pos) + len);
76
+ n = qed_bytes_to_clusters(s, qed_offset_into_cluster(s, pos) + *len);
77
n = qed_count_contiguous_clusters(s, request->l2_table->table,
78
index, n, &offset);
79
80
@@ -XXX,XX +XXX,XX @@ void qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
81
ret = -EINVAL;
82
}
83
84
- len = MIN(len,
85
- n * s->header.cluster_size - qed_offset_into_cluster(s, pos));
86
+ *len = MIN(*len,
87
+ n * s->header.cluster_size - qed_offset_into_cluster(s, pos));
88
89
out:
90
- cb(opaque, ret, offset, len);
91
+ *img_offset = offset;
92
qed_release(s);
93
+ return ret;
94
}
95
diff --git a/block/qed.c b/block/qed.c
96
index XXXXXXX..XXXXXXX 100644
97
--- a/block/qed.c
98
+++ b/block/qed.c
99
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn bdrv_qed_co_get_block_status(BlockDriverState *bs,
100
.file = file,
101
};
102
QEDRequest request = { .l2_table = NULL };
103
+ uint64_t offset;
104
+ int ret;
105
106
- qed_find_cluster(s, &request, cb.pos, len, qed_is_allocated_cb, &cb);
107
+ ret = qed_find_cluster(s, &request, cb.pos, &len, &offset);
108
+ qed_is_allocated_cb(&cb, ret, offset, len);
109
110
- /* Now sleep if the callback wasn't invoked immediately */
111
- while (cb.status == BDRV_BLOCK_OFFSET_MASK) {
112
- cb.co = qemu_coroutine_self();
113
- qemu_coroutine_yield();
114
- }
115
+ /* The callback was invoked immediately */
116
+ assert(cb.status != BDRV_BLOCK_OFFSET_MASK);
117
118
qed_unref_l2_cache_entry(request.l2_table);
119
120
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_inplace(QEDAIOCB *acb, uint64_t offset, size_t len)
121
* or -errno
122
* @offset: Cluster offset in bytes
123
* @len: Length in bytes
124
- *
125
- * Callback from qed_find_cluster().
126
*/
127
static void qed_aio_write_data(void *opaque, int ret,
128
uint64_t offset, size_t len)
129
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_data(void *opaque, int ret,
130
* or -errno
131
* @offset: Cluster offset in bytes
132
* @len: Length in bytes
133
- *
134
- * Callback from qed_find_cluster().
135
*/
136
static void qed_aio_read_data(void *opaque, int ret,
137
uint64_t offset, size_t len)
138
@@ -XXX,XX +XXX,XX @@ static void qed_aio_next_io(QEDAIOCB *acb, int ret)
139
BDRVQEDState *s = acb_to_s(acb);
140
QEDFindClusterFunc *io_fn = (acb->flags & QED_AIOCB_WRITE) ?
141
qed_aio_write_data : qed_aio_read_data;
142
+ uint64_t offset;
143
+ size_t len;
144
145
trace_qed_aio_next_io(s, acb, ret, acb->cur_pos + acb->cur_qiov.size);
146
147
@@ -XXX,XX +XXX,XX @@ static void qed_aio_next_io(QEDAIOCB *acb, int ret)
148
}
149
150
/* Find next cluster and start I/O */
151
- qed_find_cluster(s, &acb->request,
152
- acb->cur_pos, acb->end_pos - acb->cur_pos,
153
- io_fn, acb);
154
+ len = acb->end_pos - acb->cur_pos;
155
+ ret = qed_find_cluster(s, &acb->request, acb->cur_pos, &len, &offset);
156
+ io_fn(acb, ret, offset, len);
157
}
158
159
static BlockAIOCB *qed_aio_setup(BlockDriverState *bs,
160
diff --git a/block/qed.h b/block/qed.h
161
index XXXXXXX..XXXXXXX 100644
162
--- a/block/qed.h
163
+++ b/block/qed.h
164
@@ -XXX,XX +XXX,XX @@ int qed_write_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
165
/**
166
* Cluster functions
167
*/
168
-void qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
169
- size_t len, QEDFindClusterFunc *cb, void *opaque);
170
+int qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
171
+ size_t *len, uint64_t *img_offset);
172
173
/**
174
* Consistency check
175
--
176
1.8.3.1
177
178
diff view generated by jsdifflib
Deleted patch
1
With this change, qed_aio_write_prefill() and qed_aio_write_postfill()
2
collapse into a single function. This is reflected by a rename of the
3
combined function to qed_aio_write_cow().
4
1
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
---
9
block/qed.c | 57 +++++++++++++++++++++++----------------------------------
10
1 file changed, 23 insertions(+), 34 deletions(-)
11
12
diff --git a/block/qed.c b/block/qed.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/block/qed.c
15
+++ b/block/qed.c
16
@@ -XXX,XX +XXX,XX @@ static int qed_read_backing_file(BDRVQEDState *s, uint64_t pos,
17
* @pos: Byte position in device
18
* @len: Number of bytes
19
* @offset: Byte offset in image file
20
- * @cb: Completion function
21
- * @opaque: User data for completion function
22
*/
23
-static void qed_copy_from_backing_file(BDRVQEDState *s, uint64_t pos,
24
- uint64_t len, uint64_t offset,
25
- BlockCompletionFunc *cb,
26
- void *opaque)
27
+static int qed_copy_from_backing_file(BDRVQEDState *s, uint64_t pos,
28
+ uint64_t len, uint64_t offset)
29
{
30
QEMUIOVector qiov;
31
QEMUIOVector *backing_qiov = NULL;
32
@@ -XXX,XX +XXX,XX @@ static void qed_copy_from_backing_file(BDRVQEDState *s, uint64_t pos,
33
34
/* Skip copy entirely if there is no work to do */
35
if (len == 0) {
36
- cb(opaque, 0);
37
- return;
38
+ return 0;
39
}
40
41
iov = (struct iovec) {
42
@@ -XXX,XX +XXX,XX @@ static void qed_copy_from_backing_file(BDRVQEDState *s, uint64_t pos,
43
ret = 0;
44
out:
45
qemu_vfree(iov.iov_base);
46
- cb(opaque, ret);
47
+ return ret;
48
}
49
50
/**
51
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_main(void *opaque, int ret)
52
}
53
54
/**
55
- * Populate back untouched region of new data cluster
56
+ * Populate untouched regions of new data cluster
57
*/
58
-static void qed_aio_write_postfill(void *opaque, int ret)
59
+static void qed_aio_write_cow(void *opaque, int ret)
60
{
61
QEDAIOCB *acb = opaque;
62
BDRVQEDState *s = acb_to_s(acb);
63
- uint64_t start = acb->cur_pos + acb->cur_qiov.size;
64
- uint64_t len =
65
- qed_start_of_cluster(s, start + s->header.cluster_size - 1) - start;
66
- uint64_t offset = acb->cur_cluster +
67
- qed_offset_into_cluster(s, acb->cur_pos) +
68
- acb->cur_qiov.size;
69
+ uint64_t start, len, offset;
70
+
71
+ /* Populate front untouched region of new data cluster */
72
+ start = qed_start_of_cluster(s, acb->cur_pos);
73
+ len = qed_offset_into_cluster(s, acb->cur_pos);
74
75
+ trace_qed_aio_write_prefill(s, acb, start, len, acb->cur_cluster);
76
+ ret = qed_copy_from_backing_file(s, start, len, acb->cur_cluster);
77
if (ret) {
78
qed_aio_complete(acb, ret);
79
return;
80
}
81
82
- trace_qed_aio_write_postfill(s, acb, start, len, offset);
83
- qed_copy_from_backing_file(s, start, len, offset,
84
- qed_aio_write_main, acb);
85
-}
86
+ /* Populate back untouched region of new data cluster */
87
+ start = acb->cur_pos + acb->cur_qiov.size;
88
+ len = qed_start_of_cluster(s, start + s->header.cluster_size - 1) - start;
89
+ offset = acb->cur_cluster +
90
+ qed_offset_into_cluster(s, acb->cur_pos) +
91
+ acb->cur_qiov.size;
92
93
-/**
94
- * Populate front untouched region of new data cluster
95
- */
96
-static void qed_aio_write_prefill(void *opaque, int ret)
97
-{
98
- QEDAIOCB *acb = opaque;
99
- BDRVQEDState *s = acb_to_s(acb);
100
- uint64_t start = qed_start_of_cluster(s, acb->cur_pos);
101
- uint64_t len = qed_offset_into_cluster(s, acb->cur_pos);
102
+ trace_qed_aio_write_postfill(s, acb, start, len, offset);
103
+ ret = qed_copy_from_backing_file(s, start, len, offset);
104
105
- trace_qed_aio_write_prefill(s, acb, start, len, acb->cur_cluster);
106
- qed_copy_from_backing_file(s, start, len, acb->cur_cluster,
107
- qed_aio_write_postfill, acb);
108
+ qed_aio_write_main(acb, ret);
109
}
110
111
/**
112
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
113
114
cb = qed_aio_write_zero_cluster;
115
} else {
116
- cb = qed_aio_write_prefill;
117
+ cb = qed_aio_write_cow;
118
acb->cur_cluster = qed_alloc_clusters(s, acb->cur_nclusters);
119
}
120
121
--
122
1.8.3.1
123
124
diff view generated by jsdifflib
Deleted patch
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
3
---
4
block/qed.c | 32 ++++++++++++--------------------
5
1 file changed, 12 insertions(+), 20 deletions(-)
6
1
7
diff --git a/block/qed.c b/block/qed.c
8
index XXXXXXX..XXXXXXX 100644
9
--- a/block/qed.c
10
+++ b/block/qed.c
11
@@ -XXX,XX +XXX,XX @@ int qed_write_header_sync(BDRVQEDState *s)
12
* This function only updates known header fields in-place and does not affect
13
* extra data after the QED header.
14
*/
15
-static void qed_write_header(BDRVQEDState *s, BlockCompletionFunc cb,
16
- void *opaque)
17
+static int qed_write_header(BDRVQEDState *s)
18
{
19
/* We must write full sectors for O_DIRECT but cannot necessarily generate
20
* the data following the header if an unrecognized compat feature is
21
@@ -XXX,XX +XXX,XX @@ static void qed_write_header(BDRVQEDState *s, BlockCompletionFunc cb,
22
ret = 0;
23
out:
24
qemu_vfree(buf);
25
- cb(opaque, ret);
26
+ return ret;
27
}
28
29
static uint64_t qed_max_image_size(uint32_t cluster_size, uint32_t table_size)
30
@@ -XXX,XX +XXX,XX @@ static void qed_unplug_allocating_write_reqs(BDRVQEDState *s)
31
}
32
}
33
34
-static void qed_finish_clear_need_check(void *opaque, int ret)
35
-{
36
- /* Do nothing */
37
-}
38
-
39
-static void qed_flush_after_clear_need_check(void *opaque, int ret)
40
-{
41
- BDRVQEDState *s = opaque;
42
-
43
- bdrv_aio_flush(s->bs, qed_finish_clear_need_check, s);
44
-
45
- /* No need to wait until flush completes */
46
- qed_unplug_allocating_write_reqs(s);
47
-}
48
-
49
static void qed_clear_need_check(void *opaque, int ret)
50
{
51
BDRVQEDState *s = opaque;
52
@@ -XXX,XX +XXX,XX @@ static void qed_clear_need_check(void *opaque, int ret)
53
}
54
55
s->header.features &= ~QED_F_NEED_CHECK;
56
- qed_write_header(s, qed_flush_after_clear_need_check, s);
57
+ ret = qed_write_header(s);
58
+ (void) ret;
59
+
60
+ qed_unplug_allocating_write_reqs(s);
61
+
62
+ ret = bdrv_flush(s->bs);
63
+ (void) ret;
64
}
65
66
static void qed_need_check_timer_cb(void *opaque)
67
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
68
{
69
BDRVQEDState *s = acb_to_s(acb);
70
BlockCompletionFunc *cb;
71
+ int ret;
72
73
/* Cancel timer when the first allocating request comes in */
74
if (QSIMPLEQ_EMPTY(&s->allocating_write_reqs)) {
75
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
76
77
if (qed_should_set_need_check(s)) {
78
s->header.features |= QED_F_NEED_CHECK;
79
- qed_write_header(s, cb, acb);
80
+ ret = qed_write_header(s);
81
+ cb(acb, ret);
82
} else {
83
cb(acb, 0);
84
}
85
--
86
1.8.3.1
87
88
diff view generated by jsdifflib
Deleted patch
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
3
---
4
block/qed-table.c | 47 ++++++++++++-----------------------------------
5
block/qed.c | 12 +++++++-----
6
block/qed.h | 8 +++-----
7
3 files changed, 22 insertions(+), 45 deletions(-)
8
1
9
diff --git a/block/qed-table.c b/block/qed-table.c
10
index XXXXXXX..XXXXXXX 100644
11
--- a/block/qed-table.c
12
+++ b/block/qed-table.c
13
@@ -XXX,XX +XXX,XX @@ out:
14
* @index: Index of first element
15
* @n: Number of elements
16
* @flush: Whether or not to sync to disk
17
- * @cb: Completion function
18
- * @opaque: Argument for completion function
19
*/
20
-static void qed_write_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
21
- unsigned int index, unsigned int n, bool flush,
22
- BlockCompletionFunc *cb, void *opaque)
23
+static int qed_write_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
24
+ unsigned int index, unsigned int n, bool flush)
25
{
26
unsigned int sector_mask = BDRV_SECTOR_SIZE / sizeof(uint64_t) - 1;
27
unsigned int start, end, i;
28
@@ -XXX,XX +XXX,XX @@ static void qed_write_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
29
ret = 0;
30
out:
31
qemu_vfree(new_table);
32
- cb(opaque, ret);
33
-}
34
-
35
-/**
36
- * Propagate return value from async callback
37
- */
38
-static void qed_sync_cb(void *opaque, int ret)
39
-{
40
- *(int *)opaque = ret;
41
+ return ret;
42
}
43
44
int qed_read_l1_table_sync(BDRVQEDState *s)
45
@@ -XXX,XX +XXX,XX @@ int qed_read_l1_table_sync(BDRVQEDState *s)
46
return qed_read_table(s, s->header.l1_table_offset, s->l1_table);
47
}
48
49
-void qed_write_l1_table(BDRVQEDState *s, unsigned int index, unsigned int n,
50
- BlockCompletionFunc *cb, void *opaque)
51
+int qed_write_l1_table(BDRVQEDState *s, unsigned int index, unsigned int n)
52
{
53
BLKDBG_EVENT(s->bs->file, BLKDBG_L1_UPDATE);
54
- qed_write_table(s, s->header.l1_table_offset,
55
- s->l1_table, index, n, false, cb, opaque);
56
+ return qed_write_table(s, s->header.l1_table_offset,
57
+ s->l1_table, index, n, false);
58
}
59
60
int qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index,
61
unsigned int n)
62
{
63
- int ret = -EINPROGRESS;
64
-
65
- qed_write_l1_table(s, index, n, qed_sync_cb, &ret);
66
- BDRV_POLL_WHILE(s->bs, ret == -EINPROGRESS);
67
-
68
- return ret;
69
+ return qed_write_l1_table(s, index, n);
70
}
71
72
int qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset)
73
@@ -XXX,XX +XXX,XX @@ int qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request, uint64_t offset
74
return qed_read_l2_table(s, request, offset);
75
}
76
77
-void qed_write_l2_table(BDRVQEDState *s, QEDRequest *request,
78
- unsigned int index, unsigned int n, bool flush,
79
- BlockCompletionFunc *cb, void *opaque)
80
+int qed_write_l2_table(BDRVQEDState *s, QEDRequest *request,
81
+ unsigned int index, unsigned int n, bool flush)
82
{
83
BLKDBG_EVENT(s->bs->file, BLKDBG_L2_UPDATE);
84
- qed_write_table(s, request->l2_table->offset,
85
- request->l2_table->table, index, n, flush, cb, opaque);
86
+ return qed_write_table(s, request->l2_table->offset,
87
+ request->l2_table->table, index, n, flush);
88
}
89
90
int qed_write_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
91
unsigned int index, unsigned int n, bool flush)
92
{
93
- int ret = -EINPROGRESS;
94
-
95
- qed_write_l2_table(s, request, index, n, flush, qed_sync_cb, &ret);
96
- BDRV_POLL_WHILE(s->bs, ret == -EINPROGRESS);
97
-
98
- return ret;
99
+ return qed_write_l2_table(s, request, index, n, flush);
100
}
101
diff --git a/block/qed.c b/block/qed.c
102
index XXXXXXX..XXXXXXX 100644
103
--- a/block/qed.c
104
+++ b/block/qed.c
105
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_l1_update(void *opaque, int ret)
106
index = qed_l1_index(s, acb->cur_pos);
107
s->l1_table->offsets[index] = acb->request.l2_table->offset;
108
109
- qed_write_l1_table(s, index, 1, qed_commit_l2_update, acb);
110
+ ret = qed_write_l1_table(s, index, 1);
111
+ qed_commit_l2_update(acb, ret);
112
}
113
114
/**
115
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_l2_update(QEDAIOCB *acb, int ret, uint64_t offset)
116
117
if (need_alloc) {
118
/* Write out the whole new L2 table */
119
- qed_write_l2_table(s, &acb->request, 0, s->table_nelems, true,
120
- qed_aio_write_l1_update, acb);
121
+ ret = qed_write_l2_table(s, &acb->request, 0, s->table_nelems, true);
122
+ qed_aio_write_l1_update(acb, ret);
123
} else {
124
/* Write out only the updated part of the L2 table */
125
- qed_write_l2_table(s, &acb->request, index, acb->cur_nclusters, false,
126
- qed_aio_next_io_cb, acb);
127
+ ret = qed_write_l2_table(s, &acb->request, index, acb->cur_nclusters,
128
+ false);
129
+ qed_aio_next_io(acb, ret);
130
}
131
return;
132
133
diff --git a/block/qed.h b/block/qed.h
134
index XXXXXXX..XXXXXXX 100644
135
--- a/block/qed.h
136
+++ b/block/qed.h
137
@@ -XXX,XX +XXX,XX @@ void qed_commit_l2_cache_entry(L2TableCache *l2_cache, CachedL2Table *l2_table);
138
* Table I/O functions
139
*/
140
int qed_read_l1_table_sync(BDRVQEDState *s);
141
-void qed_write_l1_table(BDRVQEDState *s, unsigned int index, unsigned int n,
142
- BlockCompletionFunc *cb, void *opaque);
143
+int qed_write_l1_table(BDRVQEDState *s, unsigned int index, unsigned int n);
144
int qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index,
145
unsigned int n);
146
int qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
147
uint64_t offset);
148
int qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset);
149
-void qed_write_l2_table(BDRVQEDState *s, QEDRequest *request,
150
- unsigned int index, unsigned int n, bool flush,
151
- BlockCompletionFunc *cb, void *opaque);
152
+int qed_write_l2_table(BDRVQEDState *s, QEDRequest *request,
153
+ unsigned int index, unsigned int n, bool flush);
154
int qed_write_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
155
unsigned int index, unsigned int n, bool flush);
156
157
--
158
1.8.3.1
159
160
diff view generated by jsdifflib
Deleted patch
1
Note that this code is generally not running in coroutine context, so
2
this is an actual blocking synchronous operation. We'll fix this in a
3
moment.
4
1
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
---
8
block/qed.c | 61 +++++++++++++++++++------------------------------------------
9
1 file changed, 19 insertions(+), 42 deletions(-)
10
11
diff --git a/block/qed.c b/block/qed.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/block/qed.c
14
+++ b/block/qed.c
15
@@ -XXX,XX +XXX,XX @@ static void qed_aio_start_io(QEDAIOCB *acb)
16
qed_aio_next_io(acb, 0);
17
}
18
19
-static void qed_aio_next_io_cb(void *opaque, int ret)
20
-{
21
- QEDAIOCB *acb = opaque;
22
-
23
- qed_aio_next_io(acb, ret);
24
-}
25
-
26
static void qed_plug_allocating_write_reqs(BDRVQEDState *s)
27
{
28
assert(!s->allocating_write_reqs_plugged);
29
@@ -XXX,XX +XXX,XX @@ err:
30
qed_aio_complete(acb, ret);
31
}
32
33
-static void qed_aio_write_l2_update_cb(void *opaque, int ret)
34
-{
35
- QEDAIOCB *acb = opaque;
36
- qed_aio_write_l2_update(acb, ret, acb->cur_cluster);
37
-}
38
-
39
-/**
40
- * Flush new data clusters before updating the L2 table
41
- *
42
- * This flush is necessary when a backing file is in use. A crash during an
43
- * allocating write could result in empty clusters in the image. If the write
44
- * only touched a subregion of the cluster, then backing image sectors have
45
- * been lost in the untouched region. The solution is to flush after writing a
46
- * new data cluster and before updating the L2 table.
47
- */
48
-static void qed_aio_write_flush_before_l2_update(void *opaque, int ret)
49
-{
50
- QEDAIOCB *acb = opaque;
51
- BDRVQEDState *s = acb_to_s(acb);
52
-
53
- if (!bdrv_aio_flush(s->bs->file->bs, qed_aio_write_l2_update_cb, opaque)) {
54
- qed_aio_complete(acb, -EIO);
55
- }
56
-}
57
-
58
/**
59
* Write data to the image file
60
*/
61
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_main(void *opaque, int ret)
62
BDRVQEDState *s = acb_to_s(acb);
63
uint64_t offset = acb->cur_cluster +
64
qed_offset_into_cluster(s, acb->cur_pos);
65
- BlockCompletionFunc *next_fn;
66
67
trace_qed_aio_write_main(s, acb, ret, offset, acb->cur_qiov.size);
68
69
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_main(void *opaque, int ret)
70
return;
71
}
72
73
+ BLKDBG_EVENT(s->bs->file, BLKDBG_WRITE_AIO);
74
+ ret = bdrv_pwritev(s->bs->file, offset, &acb->cur_qiov);
75
+ if (ret >= 0) {
76
+ ret = 0;
77
+ }
78
+
79
if (acb->find_cluster_ret == QED_CLUSTER_FOUND) {
80
- next_fn = qed_aio_next_io_cb;
81
+ qed_aio_next_io(acb, ret);
82
} else {
83
if (s->bs->backing) {
84
- next_fn = qed_aio_write_flush_before_l2_update;
85
- } else {
86
- next_fn = qed_aio_write_l2_update_cb;
87
+ /*
88
+ * Flush new data clusters before updating the L2 table
89
+ *
90
+ * This flush is necessary when a backing file is in use. A crash
91
+ * during an allocating write could result in empty clusters in the
92
+ * image. If the write only touched a subregion of the cluster,
93
+ * then backing image sectors have been lost in the untouched
94
+ * region. The solution is to flush after writing a new data
95
+ * cluster and before updating the L2 table.
96
+ */
97
+ ret = bdrv_flush(s->bs->file->bs);
98
}
99
+ qed_aio_write_l2_update(acb, ret, acb->cur_cluster);
100
}
101
-
102
- BLKDBG_EVENT(s->bs->file, BLKDBG_WRITE_AIO);
103
- bdrv_aio_writev(s->bs->file, offset / BDRV_SECTOR_SIZE,
104
- &acb->cur_qiov, acb->cur_qiov.size / BDRV_SECTOR_SIZE,
105
- next_fn, acb);
106
}
107
108
/**
109
--
110
1.8.3.1
111
112
diff view generated by jsdifflib
Deleted patch
1
qed_commit_l2_update() is unconditionally called at the end of
2
qed_aio_write_l1_update(). Inline it.
3
1
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
6
---
7
block/qed.c | 36 ++++++++++++++----------------------
8
1 file changed, 14 insertions(+), 22 deletions(-)
9
10
diff --git a/block/qed.c b/block/qed.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/block/qed.c
13
+++ b/block/qed.c
14
@@ -XXX,XX +XXX,XX @@ static void qed_aio_complete(QEDAIOCB *acb, int ret)
15
}
16
17
/**
18
- * Commit the current L2 table to the cache
19
+ * Update L1 table with new L2 table offset and write it out
20
*/
21
-static void qed_commit_l2_update(void *opaque, int ret)
22
+static void qed_aio_write_l1_update(void *opaque, int ret)
23
{
24
QEDAIOCB *acb = opaque;
25
BDRVQEDState *s = acb_to_s(acb);
26
CachedL2Table *l2_table = acb->request.l2_table;
27
uint64_t l2_offset = l2_table->offset;
28
+ int index;
29
+
30
+ if (ret) {
31
+ qed_aio_complete(acb, ret);
32
+ return;
33
+ }
34
35
+ index = qed_l1_index(s, acb->cur_pos);
36
+ s->l1_table->offsets[index] = l2_table->offset;
37
+
38
+ ret = qed_write_l1_table(s, index, 1);
39
+
40
+ /* Commit the current L2 table to the cache */
41
qed_commit_l2_cache_entry(&s->l2_cache, l2_table);
42
43
/* This is guaranteed to succeed because we just committed the entry to the
44
@@ -XXX,XX +XXX,XX @@ static void qed_commit_l2_update(void *opaque, int ret)
45
qed_aio_next_io(acb, ret);
46
}
47
48
-/**
49
- * Update L1 table with new L2 table offset and write it out
50
- */
51
-static void qed_aio_write_l1_update(void *opaque, int ret)
52
-{
53
- QEDAIOCB *acb = opaque;
54
- BDRVQEDState *s = acb_to_s(acb);
55
- int index;
56
-
57
- if (ret) {
58
- qed_aio_complete(acb, ret);
59
- return;
60
- }
61
-
62
- index = qed_l1_index(s, acb->cur_pos);
63
- s->l1_table->offsets[index] = acb->request.l2_table->offset;
64
-
65
- ret = qed_write_l1_table(s, index, 1);
66
- qed_commit_l2_update(acb, ret);
67
-}
68
69
/**
70
* Update L2 table with new cluster offsets and write them out
71
--
72
1.8.3.1
73
74
diff view generated by jsdifflib
Deleted patch
1
Don't recurse into qed_aio_next_io() and qed_aio_complete() here, but
2
just return an error code and let the caller handle it.
3
1
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
6
---
7
block/qed.c | 19 +++++++++----------
8
1 file changed, 9 insertions(+), 10 deletions(-)
9
10
diff --git a/block/qed.c b/block/qed.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/block/qed.c
13
+++ b/block/qed.c
14
@@ -XXX,XX +XXX,XX @@ static void qed_aio_complete(QEDAIOCB *acb, int ret)
15
/**
16
* Update L1 table with new L2 table offset and write it out
17
*/
18
-static void qed_aio_write_l1_update(void *opaque, int ret)
19
+static int qed_aio_write_l1_update(QEDAIOCB *acb)
20
{
21
- QEDAIOCB *acb = opaque;
22
BDRVQEDState *s = acb_to_s(acb);
23
CachedL2Table *l2_table = acb->request.l2_table;
24
uint64_t l2_offset = l2_table->offset;
25
- int index;
26
-
27
- if (ret) {
28
- qed_aio_complete(acb, ret);
29
- return;
30
- }
31
+ int index, ret;
32
33
index = qed_l1_index(s, acb->cur_pos);
34
s->l1_table->offsets[index] = l2_table->offset;
35
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_l1_update(void *opaque, int ret)
36
acb->request.l2_table = qed_find_l2_cache_entry(&s->l2_cache, l2_offset);
37
assert(acb->request.l2_table != NULL);
38
39
- qed_aio_next_io(acb, ret);
40
+ return ret;
41
}
42
43
44
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_l2_update(QEDAIOCB *acb, int ret, uint64_t offset)
45
if (need_alloc) {
46
/* Write out the whole new L2 table */
47
ret = qed_write_l2_table(s, &acb->request, 0, s->table_nelems, true);
48
- qed_aio_write_l1_update(acb, ret);
49
+ if (ret) {
50
+ goto err;
51
+ }
52
+ ret = qed_aio_write_l1_update(acb);
53
+ qed_aio_next_io(acb, ret);
54
+
55
} else {
56
/* Write out only the updated part of the L2 table */
57
ret = qed_write_l2_table(s, &acb->request, index, acb->cur_nclusters,
58
--
59
1.8.3.1
60
61
diff view generated by jsdifflib
Deleted patch
1
Don't recurse into qed_aio_next_io() and qed_aio_complete() here, but
2
just return an error code and let the caller handle it.
3
1
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
6
---
7
block/qed.c | 43 ++++++++++++++++++++++++++-----------------
8
1 file changed, 26 insertions(+), 17 deletions(-)
9
10
diff --git a/block/qed.c b/block/qed.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/block/qed.c
13
+++ b/block/qed.c
14
@@ -XXX,XX +XXX,XX @@ static int qed_aio_write_l1_update(QEDAIOCB *acb)
15
/**
16
* Update L2 table with new cluster offsets and write them out
17
*/
18
-static void qed_aio_write_l2_update(QEDAIOCB *acb, int ret, uint64_t offset)
19
+static int qed_aio_write_l2_update(QEDAIOCB *acb, uint64_t offset)
20
{
21
BDRVQEDState *s = acb_to_s(acb);
22
bool need_alloc = acb->find_cluster_ret == QED_CLUSTER_L1;
23
- int index;
24
-
25
- if (ret) {
26
- goto err;
27
- }
28
+ int index, ret;
29
30
if (need_alloc) {
31
qed_unref_l2_cache_entry(acb->request.l2_table);
32
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_l2_update(QEDAIOCB *acb, int ret, uint64_t offset)
33
/* Write out the whole new L2 table */
34
ret = qed_write_l2_table(s, &acb->request, 0, s->table_nelems, true);
35
if (ret) {
36
- goto err;
37
+ return ret;
38
}
39
- ret = qed_aio_write_l1_update(acb);
40
- qed_aio_next_io(acb, ret);
41
-
42
+ return qed_aio_write_l1_update(acb);
43
} else {
44
/* Write out only the updated part of the L2 table */
45
ret = qed_write_l2_table(s, &acb->request, index, acb->cur_nclusters,
46
false);
47
- qed_aio_next_io(acb, ret);
48
+ if (ret) {
49
+ return ret;
50
+ }
51
}
52
- return;
53
-
54
-err:
55
- qed_aio_complete(acb, ret);
56
+ return 0;
57
}
58
59
/**
60
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_main(void *opaque, int ret)
61
*/
62
ret = bdrv_flush(s->bs->file->bs);
63
}
64
- qed_aio_write_l2_update(acb, ret, acb->cur_cluster);
65
+ if (ret) {
66
+ goto err;
67
+ }
68
+ ret = qed_aio_write_l2_update(acb, acb->cur_cluster);
69
+ if (ret) {
70
+ goto err;
71
+ }
72
+ qed_aio_next_io(acb, 0);
73
}
74
+ return;
75
+
76
+err:
77
+ qed_aio_complete(acb, ret);
78
}
79
80
/**
81
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_zero_cluster(void *opaque, int ret)
82
return;
83
}
84
85
- qed_aio_write_l2_update(acb, 0, 1);
86
+ ret = qed_aio_write_l2_update(acb, 1);
87
+ if (ret < 0) {
88
+ qed_aio_complete(acb, ret);
89
+ return;
90
+ }
91
+ qed_aio_next_io(acb, 0);
92
}
93
94
/**
95
--
96
1.8.3.1
97
98
diff view generated by jsdifflib
Deleted patch
1
Don't recurse into qed_aio_next_io() and qed_aio_complete() here, but
2
just return an error code and let the caller handle it.
3
1
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
6
---
7
block/qed.c | 43 ++++++++++++++++++++-----------------------
8
1 file changed, 20 insertions(+), 23 deletions(-)
9
10
diff --git a/block/qed.c b/block/qed.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/block/qed.c
13
+++ b/block/qed.c
14
@@ -XXX,XX +XXX,XX @@ static bool qed_should_set_need_check(BDRVQEDState *s)
15
*
16
* This path is taken when writing to previously unallocated clusters.
17
*/
18
-static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
19
+static int qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
20
{
21
BDRVQEDState *s = acb_to_s(acb);
22
int ret;
23
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
24
}
25
if (acb != QSIMPLEQ_FIRST(&s->allocating_write_reqs) ||
26
s->allocating_write_reqs_plugged) {
27
- return; /* wait for existing request to finish */
28
+ return -EINPROGRESS; /* wait for existing request to finish */
29
}
30
31
acb->cur_nclusters = qed_bytes_to_clusters(s,
32
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
33
if (acb->flags & QED_AIOCB_ZERO) {
34
/* Skip ahead if the clusters are already zero */
35
if (acb->find_cluster_ret == QED_CLUSTER_ZERO) {
36
- qed_aio_start_io(acb);
37
- return;
38
+ return 0;
39
}
40
} else {
41
acb->cur_cluster = qed_alloc_clusters(s, acb->cur_nclusters);
42
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
43
s->header.features |= QED_F_NEED_CHECK;
44
ret = qed_write_header(s);
45
if (ret < 0) {
46
- qed_aio_complete(acb, ret);
47
- return;
48
+ return ret;
49
}
50
}
51
52
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
53
ret = qed_aio_write_cow(acb);
54
}
55
if (ret < 0) {
56
- qed_aio_complete(acb, ret);
57
- return;
58
+ return ret;
59
}
60
- qed_aio_next_io(acb, 0);
61
+ return 0;
62
}
63
64
/**
65
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
66
*
67
* This path is taken when writing to already allocated clusters.
68
*/
69
-static void qed_aio_write_inplace(QEDAIOCB *acb, uint64_t offset, size_t len)
70
+static int qed_aio_write_inplace(QEDAIOCB *acb, uint64_t offset, size_t len)
71
{
72
- int ret;
73
-
74
/* Allocate buffer for zero writes */
75
if (acb->flags & QED_AIOCB_ZERO) {
76
struct iovec *iov = acb->qiov->iov;
77
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_inplace(QEDAIOCB *acb, uint64_t offset, size_t len)
78
if (!iov->iov_base) {
79
iov->iov_base = qemu_try_blockalign(acb->common.bs, iov->iov_len);
80
if (iov->iov_base == NULL) {
81
- qed_aio_complete(acb, -ENOMEM);
82
- return;
83
+ return -ENOMEM;
84
}
85
memset(iov->iov_base, 0, iov->iov_len);
86
}
87
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_inplace(QEDAIOCB *acb, uint64_t offset, size_t len)
88
qemu_iovec_concat(&acb->cur_qiov, acb->qiov, acb->qiov_offset, len);
89
90
/* Do the actual write */
91
- ret = qed_aio_write_main(acb);
92
- if (ret < 0) {
93
- qed_aio_complete(acb, ret);
94
- return;
95
- }
96
- qed_aio_next_io(acb, 0);
97
+ return qed_aio_write_main(acb);
98
}
99
100
/**
101
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_data(void *opaque, int ret,
102
103
switch (ret) {
104
case QED_CLUSTER_FOUND:
105
- qed_aio_write_inplace(acb, offset, len);
106
+ ret = qed_aio_write_inplace(acb, offset, len);
107
break;
108
109
case QED_CLUSTER_L2:
110
case QED_CLUSTER_L1:
111
case QED_CLUSTER_ZERO:
112
- qed_aio_write_alloc(acb, len);
113
+ ret = qed_aio_write_alloc(acb, len);
114
break;
115
116
default:
117
- qed_aio_complete(acb, ret);
118
+ assert(ret < 0);
119
break;
120
}
121
+
122
+ if (ret < 0) {
123
+ if (ret != -EINPROGRESS) {
124
+ qed_aio_complete(acb, ret);
125
+ }
126
+ return;
127
+ }
128
+ qed_aio_next_io(acb, 0);
129
}
130
131
/**
132
--
133
1.8.3.1
134
135
diff view generated by jsdifflib
Deleted patch
1
All callers pass ret = 0, so we can just remove it.
2
1
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
5
---
6
block/qed.c | 17 ++++++-----------
7
1 file changed, 6 insertions(+), 11 deletions(-)
8
9
diff --git a/block/qed.c b/block/qed.c
10
index XXXXXXX..XXXXXXX 100644
11
--- a/block/qed.c
12
+++ b/block/qed.c
13
@@ -XXX,XX +XXX,XX @@ static CachedL2Table *qed_new_l2_table(BDRVQEDState *s)
14
return l2_table;
15
}
16
17
-static void qed_aio_next_io(QEDAIOCB *acb, int ret);
18
+static void qed_aio_next_io(QEDAIOCB *acb);
19
20
static void qed_aio_start_io(QEDAIOCB *acb)
21
{
22
- qed_aio_next_io(acb, 0);
23
+ qed_aio_next_io(acb);
24
}
25
26
static void qed_plug_allocating_write_reqs(BDRVQEDState *s)
27
@@ -XXX,XX +XXX,XX @@ static int qed_aio_read_data(void *opaque, int ret, uint64_t offset, size_t len)
28
/**
29
* Begin next I/O or complete the request
30
*/
31
-static void qed_aio_next_io(QEDAIOCB *acb, int ret)
32
+static void qed_aio_next_io(QEDAIOCB *acb)
33
{
34
BDRVQEDState *s = acb_to_s(acb);
35
uint64_t offset;
36
size_t len;
37
+ int ret;
38
39
- trace_qed_aio_next_io(s, acb, ret, acb->cur_pos + acb->cur_qiov.size);
40
+ trace_qed_aio_next_io(s, acb, 0, acb->cur_pos + acb->cur_qiov.size);
41
42
if (acb->backing_qiov) {
43
qemu_iovec_destroy(acb->backing_qiov);
44
@@ -XXX,XX +XXX,XX @@ static void qed_aio_next_io(QEDAIOCB *acb, int ret)
45
acb->backing_qiov = NULL;
46
}
47
48
- /* Handle I/O error */
49
- if (ret) {
50
- qed_aio_complete(acb, ret);
51
- return;
52
- }
53
-
54
acb->qiov_offset += acb->cur_qiov.size;
55
acb->cur_pos += acb->cur_qiov.size;
56
qemu_iovec_reset(&acb->cur_qiov);
57
@@ -XXX,XX +XXX,XX @@ static void qed_aio_next_io(QEDAIOCB *acb, int ret)
58
}
59
return;
60
}
61
- qed_aio_next_io(acb, 0);
62
+ qed_aio_next_io(acb);
63
}
64
65
static BlockAIOCB *qed_aio_setup(BlockDriverState *bs,
66
--
67
1.8.3.1
68
69
diff view generated by jsdifflib
Deleted patch
1
Most of the qed code is now synchronous and matches the coroutine model.
2
One notable exception is the serialisation between requests which can
3
still schedule a callback. Before we can replace this with coroutine
4
locks, let's convert the driver's external interfaces to the coroutine
5
versions.
6
1
7
We need to be careful to handle both requests that call the completion
8
callback directly from the calling coroutine (i.e. fully synchronous
9
code) and requests that involve some callback, so that we need to yield
10
and wait for the completion callback coming from outside the coroutine.
11
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Reviewed-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
14
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
15
---
16
block/qed.c | 97 ++++++++++++++++++++++++++-----------------------------------
17
1 file changed, 42 insertions(+), 55 deletions(-)
18
19
diff --git a/block/qed.c b/block/qed.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/block/qed.c
22
+++ b/block/qed.c
23
@@ -XXX,XX +XXX,XX @@ static void qed_aio_next_io(QEDAIOCB *acb)
24
}
25
}
26
27
-static BlockAIOCB *qed_aio_setup(BlockDriverState *bs,
28
- int64_t sector_num,
29
- QEMUIOVector *qiov, int nb_sectors,
30
- BlockCompletionFunc *cb,
31
- void *opaque, int flags)
32
+typedef struct QEDRequestCo {
33
+ Coroutine *co;
34
+ bool done;
35
+ int ret;
36
+} QEDRequestCo;
37
+
38
+static void qed_co_request_cb(void *opaque, int ret)
39
{
40
- QEDAIOCB *acb = qemu_aio_get(&qed_aiocb_info, bs, cb, opaque);
41
+ QEDRequestCo *co = opaque;
42
43
- trace_qed_aio_setup(bs->opaque, acb, sector_num, nb_sectors,
44
- opaque, flags);
45
+ co->done = true;
46
+ co->ret = ret;
47
+ qemu_coroutine_enter_if_inactive(co->co);
48
+}
49
+
50
+static int coroutine_fn qed_co_request(BlockDriverState *bs, int64_t sector_num,
51
+ QEMUIOVector *qiov, int nb_sectors,
52
+ int flags)
53
+{
54
+ QEDRequestCo co = {
55
+ .co = qemu_coroutine_self(),
56
+ .done = false,
57
+ };
58
+ QEDAIOCB *acb = qemu_aio_get(&qed_aiocb_info, bs, qed_co_request_cb, &co);
59
+
60
+ trace_qed_aio_setup(bs->opaque, acb, sector_num, nb_sectors, &co, flags);
61
62
acb->flags = flags;
63
acb->qiov = qiov;
64
@@ -XXX,XX +XXX,XX @@ static BlockAIOCB *qed_aio_setup(BlockDriverState *bs,
65
66
/* Start request */
67
qed_aio_start_io(acb);
68
- return &acb->common;
69
-}
70
71
-static BlockAIOCB *bdrv_qed_aio_readv(BlockDriverState *bs,
72
- int64_t sector_num,
73
- QEMUIOVector *qiov, int nb_sectors,
74
- BlockCompletionFunc *cb,
75
- void *opaque)
76
-{
77
- return qed_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
78
+ if (!co.done) {
79
+ qemu_coroutine_yield();
80
+ }
81
+
82
+ return co.ret;
83
}
84
85
-static BlockAIOCB *bdrv_qed_aio_writev(BlockDriverState *bs,
86
- int64_t sector_num,
87
- QEMUIOVector *qiov, int nb_sectors,
88
- BlockCompletionFunc *cb,
89
- void *opaque)
90
+static int coroutine_fn bdrv_qed_co_readv(BlockDriverState *bs,
91
+ int64_t sector_num, int nb_sectors,
92
+ QEMUIOVector *qiov)
93
{
94
- return qed_aio_setup(bs, sector_num, qiov, nb_sectors, cb,
95
- opaque, QED_AIOCB_WRITE);
96
+ return qed_co_request(bs, sector_num, qiov, nb_sectors, 0);
97
}
98
99
-typedef struct {
100
- Coroutine *co;
101
- int ret;
102
- bool done;
103
-} QEDWriteZeroesCB;
104
-
105
-static void coroutine_fn qed_co_pwrite_zeroes_cb(void *opaque, int ret)
106
+static int coroutine_fn bdrv_qed_co_writev(BlockDriverState *bs,
107
+ int64_t sector_num, int nb_sectors,
108
+ QEMUIOVector *qiov)
109
{
110
- QEDWriteZeroesCB *cb = opaque;
111
-
112
- cb->done = true;
113
- cb->ret = ret;
114
- if (cb->co) {
115
- aio_co_wake(cb->co);
116
- }
117
+ return qed_co_request(bs, sector_num, qiov, nb_sectors, QED_AIOCB_WRITE);
118
}
119
120
static int coroutine_fn bdrv_qed_co_pwrite_zeroes(BlockDriverState *bs,
121
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_pwrite_zeroes(BlockDriverState *bs,
122
int count,
123
BdrvRequestFlags flags)
124
{
125
- BlockAIOCB *blockacb;
126
BDRVQEDState *s = bs->opaque;
127
- QEDWriteZeroesCB cb = { .done = false };
128
QEMUIOVector qiov;
129
struct iovec iov;
130
131
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_pwrite_zeroes(BlockDriverState *bs,
132
iov.iov_len = count;
133
134
qemu_iovec_init_external(&qiov, &iov, 1);
135
- blockacb = qed_aio_setup(bs, offset >> BDRV_SECTOR_BITS, &qiov,
136
- count >> BDRV_SECTOR_BITS,
137
- qed_co_pwrite_zeroes_cb, &cb,
138
- QED_AIOCB_WRITE | QED_AIOCB_ZERO);
139
- if (!blockacb) {
140
- return -EIO;
141
- }
142
- if (!cb.done) {
143
- cb.co = qemu_coroutine_self();
144
- qemu_coroutine_yield();
145
- }
146
- assert(cb.done);
147
- return cb.ret;
148
+ return qed_co_request(bs, offset >> BDRV_SECTOR_BITS, &qiov,
149
+ count >> BDRV_SECTOR_BITS,
150
+ QED_AIOCB_WRITE | QED_AIOCB_ZERO);
151
}
152
153
static int bdrv_qed_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
154
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_qed = {
155
.bdrv_create = bdrv_qed_create,
156
.bdrv_has_zero_init = bdrv_has_zero_init_1,
157
.bdrv_co_get_block_status = bdrv_qed_co_get_block_status,
158
- .bdrv_aio_readv = bdrv_qed_aio_readv,
159
- .bdrv_aio_writev = bdrv_qed_aio_writev,
160
+ .bdrv_co_readv = bdrv_qed_co_readv,
161
+ .bdrv_co_writev = bdrv_qed_co_writev,
162
.bdrv_co_pwrite_zeroes = bdrv_qed_co_pwrite_zeroes,
163
.bdrv_truncate = bdrv_qed_truncate,
164
.bdrv_getlength = bdrv_qed_getlength,
165
--
166
1.8.3.1
167
168
diff view generated by jsdifflib
Deleted patch
1
From: "sochin.jiang" <sochin.jiang@huawei.com>
2
1
3
img_commit could fall into an infinite loop calling run_block_job() if
4
its blockjob fails on any I/O error, fix this already known problem.
5
6
Signed-off-by: sochin.jiang <sochin.jiang@huawei.com>
7
Message-id: 1497509253-28941-1-git-send-email-sochin.jiang@huawei.com
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
---
10
blockjob.c | 4 ++--
11
include/block/blockjob.h | 18 ++++++++++++++++++
12
qemu-img.c | 20 +++++++++++++-------
13
3 files changed, 33 insertions(+), 9 deletions(-)
14
15
diff --git a/blockjob.c b/blockjob.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/blockjob.c
18
+++ b/blockjob.c
19
@@ -XXX,XX +XXX,XX @@ static void block_job_resume(BlockJob *job)
20
block_job_enter(job);
21
}
22
23
-static void block_job_ref(BlockJob *job)
24
+void block_job_ref(BlockJob *job)
25
{
26
++job->refcnt;
27
}
28
@@ -XXX,XX +XXX,XX @@ static void block_job_attached_aio_context(AioContext *new_context,
29
void *opaque);
30
static void block_job_detach_aio_context(void *opaque);
31
32
-static void block_job_unref(BlockJob *job)
33
+void block_job_unref(BlockJob *job)
34
{
35
if (--job->refcnt == 0) {
36
BlockDriverState *bs = blk_bs(job->blk);
37
diff --git a/include/block/blockjob.h b/include/block/blockjob.h
38
index XXXXXXX..XXXXXXX 100644
39
--- a/include/block/blockjob.h
40
+++ b/include/block/blockjob.h
41
@@ -XXX,XX +XXX,XX @@ void block_job_iostatus_reset(BlockJob *job);
42
BlockJobTxn *block_job_txn_new(void);
43
44
/**
45
+ * block_job_ref:
46
+ *
47
+ * Add a reference to BlockJob refcnt, it will be decreased with
48
+ * block_job_unref, and then be freed if it comes to be the last
49
+ * reference.
50
+ */
51
+void block_job_ref(BlockJob *job);
52
+
53
+/**
54
+ * block_job_unref:
55
+ *
56
+ * Release a reference that was previously acquired with block_job_ref
57
+ * or block_job_create. If it's the last reference to the object, it will be
58
+ * freed.
59
+ */
60
+void block_job_unref(BlockJob *job);
61
+
62
+/**
63
* block_job_txn_unref:
64
*
65
* Release a reference that was previously acquired with block_job_txn_add_job
66
diff --git a/qemu-img.c b/qemu-img.c
67
index XXXXXXX..XXXXXXX 100644
68
--- a/qemu-img.c
69
+++ b/qemu-img.c
70
@@ -XXX,XX +XXX,XX @@ static void common_block_job_cb(void *opaque, int ret)
71
static void run_block_job(BlockJob *job, Error **errp)
72
{
73
AioContext *aio_context = blk_get_aio_context(job->blk);
74
+ int ret = 0;
75
76
- /* FIXME In error cases, the job simply goes away and we access a dangling
77
- * pointer below. */
78
aio_context_acquire(aio_context);
79
+ block_job_ref(job);
80
do {
81
aio_poll(aio_context, true);
82
qemu_progress_print(job->len ?
83
((float)job->offset / job->len * 100.f) : 0.0f, 0);
84
- } while (!job->ready);
85
+ } while (!job->ready && !job->completed);
86
87
- block_job_complete_sync(job, errp);
88
+ if (!job->completed) {
89
+ ret = block_job_complete_sync(job, errp);
90
+ } else {
91
+ ret = job->ret;
92
+ }
93
+ block_job_unref(job);
94
aio_context_release(aio_context);
95
96
- /* A block job may finish instantaneously without publishing any progress,
97
- * so just signal completion here */
98
- qemu_progress_print(100.f, 0);
99
+ /* publish completion progress only when success */
100
+ if (!ret) {
101
+ qemu_progress_print(100.f, 0);
102
+ }
103
}
104
105
static int img_commit(int argc, char **argv)
106
--
107
1.8.3.1
108
109
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
The bs->exact_filename field may not be sufficient to store the full
4
blkdebug node filename. In this case, we should not generate a filename
5
at all instead of an unusable one.
6
7
Cc: qemu-stable@nongnu.org
8
Reported-by: Qu Wenruo <quwenruo@cn.fujitsu.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
Message-id: 20170613172006.19685-2-mreitz@redhat.com
11
Reviewed-by: Alberto Garcia <berto@igalia.com>
12
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
---
15
block/blkdebug.c | 10 +++++++---
16
1 file changed, 7 insertions(+), 3 deletions(-)
17
18
diff --git a/block/blkdebug.c b/block/blkdebug.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/block/blkdebug.c
21
+++ b/block/blkdebug.c
22
@@ -XXX,XX +XXX,XX @@ static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options)
23
}
24
25
if (!force_json && bs->file->bs->exact_filename[0]) {
26
- snprintf(bs->exact_filename, sizeof(bs->exact_filename),
27
- "blkdebug:%s:%s", s->config_file ?: "",
28
- bs->file->bs->exact_filename);
29
+ int ret = snprintf(bs->exact_filename, sizeof(bs->exact_filename),
30
+ "blkdebug:%s:%s", s->config_file ?: "",
31
+ bs->file->bs->exact_filename);
32
+ if (ret >= sizeof(bs->exact_filename)) {
33
+ /* An overflow makes the filename unusable, so do not report any */
34
+ bs->exact_filename[0] = 0;
35
+ }
36
}
37
38
opts = qdict_new();
39
--
40
1.8.3.1
41
42
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
The bs->exact_filename field may not be sufficient to store the full
4
blkverify node filename. In this case, we should not generate a filename
5
at all instead of an unusable one.
6
7
Cc: qemu-stable@nongnu.org
8
Reported-by: Qu Wenruo <quwenruo@cn.fujitsu.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
Message-id: 20170613172006.19685-3-mreitz@redhat.com
11
Reviewed-by: Alberto Garcia <berto@igalia.com>
12
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
---
15
block/blkverify.c | 12 ++++++++----
16
1 file changed, 8 insertions(+), 4 deletions(-)
17
18
diff --git a/block/blkverify.c b/block/blkverify.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/block/blkverify.c
21
+++ b/block/blkverify.c
22
@@ -XXX,XX +XXX,XX @@ static void blkverify_refresh_filename(BlockDriverState *bs, QDict *options)
23
if (bs->file->bs->exact_filename[0]
24
&& s->test_file->bs->exact_filename[0])
25
{
26
- snprintf(bs->exact_filename, sizeof(bs->exact_filename),
27
- "blkverify:%s:%s",
28
- bs->file->bs->exact_filename,
29
- s->test_file->bs->exact_filename);
30
+ int ret = snprintf(bs->exact_filename, sizeof(bs->exact_filename),
31
+ "blkverify:%s:%s",
32
+ bs->file->bs->exact_filename,
33
+ s->test_file->bs->exact_filename);
34
+ if (ret >= sizeof(bs->exact_filename)) {
35
+ /* An overflow makes the filename unusable, so do not report any */
36
+ bs->exact_filename[0] = 0;
37
+ }
38
}
39
}
40
41
--
42
1.8.3.1
43
44
diff view generated by jsdifflib