1
The following changes since commit 6d8e75d41c58892ccc5d4ad61c4da476684c1c83:
1
The following changes since commit 16aaacb307ed607b9780c12702c44f0fe52edc7e:
2
2
3
Merge remote-tracking branch 'remotes/rth/tags/pull-axp-20190519' into staging (2019-05-20 11:38:36 +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
6
7
git://repo.or.cz/qemu/kevin.git tags/for-upstream
7
git://repo.or.cz/qemu/kevin.git tags/for-upstream
8
8
9
for you to fetch changes up to c423a6af592cf36b4f149c54e2966dd0016b7e96:
9
for you to fetch changes up to eaae29ef89d498d0eac553c77b554f310a47f809:
10
10
11
iotests: Make 245 faster and more reliable (2019-05-20 17:08:57 +0200)
11
qemu-storage-daemon: Fix non-string --object properties (2020-04-30 17:51:07 +0200)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block layer patches:
14
Block layer patches:
15
15
16
- block: AioContext management, part 1
16
- Fix resize (extending) of short overlays
17
- qmp: forbid qmp_cont in RUN_STATE_FINISH_MIGRATE
17
- nvme: introduce PMR support from NVMe 1.4 spec
18
- nvme: fix copy direction in DMA reads going to CMB
18
- qemu-storage-daemon: Fix non-string --object properties
19
- file-posix: Fix block status for unaligned raw images with O_DIRECT
20
- file-posix: Fix xfs_write_zeroes() after EOF
21
- Documentation and iotests improvements
22
19
23
----------------------------------------------------------------
20
----------------------------------------------------------------
24
Alberto Garcia (2):
21
Alberto Garcia (1):
25
qcow2: Define and use QCOW2_COMPRESSED_SECTOR_SIZE
22
qcow2: Add incompatibility note between backing files and raw external data files
26
block: Use BDRV_REQUEST_MAX_BYTES instead of BDRV_REQUEST_MAX_SECTORS
27
23
28
Kevin Wolf (10):
24
Andrzej Jakowski (1):
29
block: Add bdrv_try_set_aio_context()
25
nvme: introduce PMR support from NVMe 1.4 spec
30
block: Make bdrv_attach/detach_aio_context() static
31
block: Move recursion to bdrv_set_aio_context()
32
block: Propagate AioContext change to parents
33
test-block-iothread: Test AioContext propagation through the tree
34
block: Implement .(can_)set_aio_ctx for BlockBackend
35
block: Add blk_set_allow_aio_context_change()
36
blockjob: Propagate AioContext change to all job nodes
37
blockjob: Remove AioContext notifiers
38
test-block-iothread: Test AioContext propagation for block jobs
39
26
40
Klaus Birkelund Jensen (1):
27
Kevin Wolf (12):
41
nvme: fix copy direction in DMA reads going to CMB
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
42
40
43
Max Reitz (9):
41
Paolo Bonzini (1):
44
block/file-posix: Truncate in xfs_write_zeroes()
42
qemu-iotests: allow qcow2 external discarded clusters to contain stale data
45
block/file-posix: Unaligned O_DIRECT block-status
46
iotests: Test unaligned raw images with O_DIRECT
47
qemu-img.texi: Be specific about JSON object types
48
qemu-img.texi: Describe human-readable info output
49
block: Improve "Block node is read-only" message
50
iotests.py: Let assert_qmp() accept an array
51
iotests.py: Fix VM.run_job
52
iotests: Make 245 faster and more reliable
53
43
54
Vladimir Sementsov-Ogievskiy (2):
44
docs/interop/qcow2.txt | 3 +
55
qmp: forbid qmp_cont in RUN_STATE_FINISH_MIGRATE
45
hw/block/nvme.h | 2 +
56
iotest: fix 169: do not run qmp_cont in RUN_STATE_FINISH_MIGRATE
46
include/block/block.h | 5 +-
47
include/block/block_int.h | 10 +-
48
include/block/nvme.h | 172 ++++++++++++++++++++++++++
49
include/qom/object_interfaces.h | 16 +++
50
include/sysemu/block-backend.h | 2 +-
51
block.c | 3 +-
52
block/block-backend.c | 4 +-
53
block/commit.c | 4 +-
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
57
96
58
block/qcow2.h | 4 +
59
include/block/block.h | 10 ++
60
include/block/block_int.h | 25 +----
61
include/sysemu/block-backend.h | 1 +
62
block.c | 174 +++++++++++++++++++++++++++++++----
63
block/backup.c | 8 --
64
block/block-backend.c | 55 ++++++++++-
65
block/file-posix.c | 29 ++++++
66
block/io.c | 6 +-
67
block/mirror.c | 10 +-
68
block/qcow2-cluster.c | 5 +-
69
block/qcow2-refcount.c | 25 ++---
70
block/qcow2.c | 3 +-
71
blockjob.c | 77 ++++++++--------
72
hw/block/nvme.c | 2 +-
73
qemu-io-cmds.c | 7 +-
74
qmp.c | 3 +
75
tests/test-block-iothread.c | 202 +++++++++++++++++++++++++++++++++++++++++
76
qemu-img.texi | 52 ++++++++++-
77
tests/qemu-iotests/169 | 7 +-
78
tests/qemu-iotests/221 | 4 +
79
tests/qemu-iotests/245 | 22 +++--
80
tests/qemu-iotests/245.out | 12 +++
81
tests/qemu-iotests/253 | 84 +++++++++++++++++
82
tests/qemu-iotests/253.out | 14 +++
83
tests/qemu-iotests/group | 1 +
84
tests/qemu-iotests/iotests.py | 20 +++-
85
27 files changed, 728 insertions(+), 134 deletions(-)
86
create mode 100755 tests/qemu-iotests/253
87
create mode 100644 tests/qemu-iotests/253.out
88
97
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
qmp_cont in RUN_STATE_FINISH_MIGRATE may lead to moving vm to
3
Backing files and raw external data files are mutually exclusive.
4
RUN_STATE_RUNNING, before actual migration finish. So, when migration
4
The documentation of the raw external data bit (in autoclear_features)
5
thread will try to go to RUN_STATE_POSTMIGRATE, assuming transition
5
already indicates that, but we should also mention it on the other
6
RUN_STATE_FINISH_MIGRATE->RUN_STATE_POSTMIGRATE, it will crash, as
6
side.
7
current state is RUN_STATE_RUNNING, and transition
8
RUN_STATE_RUNNING->RUN_STATE_POSTMIGRATE is forbidden.
9
7
10
Reported-by: Max Reitz <mreitz@redhat.com>
8
Suggested-by: Eric Blake <eblake@redhat.com>
11
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
Signed-off-by: Alberto Garcia <berto@igalia.com>
12
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
10
Message-Id: <20200410121816.8334-1-berto@igalia.com>
11
Reviewed-by: Eric Blake <eblake@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
13
---
15
qmp.c | 3 +++
14
docs/interop/qcow2.txt | 3 +++
16
1 file changed, 3 insertions(+)
15
1 file changed, 3 insertions(+)
17
16
18
diff --git a/qmp.c b/qmp.c
17
diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt
19
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
20
--- a/qmp.c
19
--- a/docs/interop/qcow2.txt
21
+++ b/qmp.c
20
+++ b/docs/interop/qcow2.txt
22
@@ -XXX,XX +XXX,XX @@ void qmp_cont(Error **errp)
21
@@ -XXX,XX +XXX,XX @@ The first cluster of a qcow2 image contains the file header:
23
return;
22
is stored (NB: The string is not null terminated). 0 if the
24
} else if (runstate_check(RUN_STATE_SUSPENDED)) {
23
image doesn't have a backing file.
25
return;
24
26
+ } else if (runstate_check(RUN_STATE_FINISH_MIGRATE)) {
25
+ Note: backing files are incompatible with raw external data
27
+ error_setg(errp, "Migration is not finalized yet");
26
+ files (auto-clear feature bit 1).
28
+ return;
27
+
29
}
28
16 - 19: backing_file_size
30
29
Length of the backing file name in bytes. Must not be
31
for (blk = blk_next(NULL); blk; blk = blk_next(blk)) {
30
longer than 1023 bytes. Undefined if the image doesn't have
32
--
31
--
33
2.20.1
32
2.25.3
34
33
35
34
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
Sometimes, 245 fails for me because some stream job has already finished
3
Test 244 checks the expected behavior of qcow2 external data files
4
while the test expects it to still be active. (With -c none, it fails
4
with respect to zero and discarded clusters. Filesystems however
5
basically every time.) The most reliable way to fix this is to simply
5
are free to ignore discard requests, and this seems to be the
6
set auto_finalize=false so the job will remain in the block graph as
6
case for overlayfs. Relax the tests to skip checks on the
7
long as we need it. This allows us to drop the rate limiting, too,
7
external data file for discarded areas, which implies not using
8
which makes the test faster.
8
qemu-img compare in the data_file_raw=on case.
9
9
10
The only problem with this is that there is a single place that yields a
10
This fixes docker tests on RHEL8.
11
different error message depending on whether the stream job is still
12
copying data (so COR is enabled) or not (COR has been disabled, but the
13
job still has the WRITE_UNCHANGED permission on the target node). We
14
can easily address that by expecting either error message.
15
11
16
Note that we do not need auto_finalize=false (or rate limiting) for the
12
Cc: Kevin Wolf <kwolf@redhat.com>
17
active commit job, because It never completes without an explicit
13
Cc: qemu-block@nongnu.org
18
block-job-complete anyway.
14
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
19
15
Message-Id: <20200409191006.24429-1-pbonzini@redhat.com>
20
Signed-off-by: Max Reitz <mreitz@redhat.com>
21
Reviewed-by: Alberto Garcia <berto@igalia.com>
22
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
23
---
17
---
24
tests/qemu-iotests/245 | 22 ++++++++++++++--------
18
tests/qemu-iotests/244 | 10 ++++++++--
25
tests/qemu-iotests/245.out | 12 ++++++++++++
19
tests/qemu-iotests/244.out | 9 ++++++---
26
2 files changed, 26 insertions(+), 8 deletions(-)
20
2 files changed, 14 insertions(+), 5 deletions(-)
27
21
28
diff --git a/tests/qemu-iotests/245 b/tests/qemu-iotests/245
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
29
index XXXXXXX..XXXXXXX 100644
52
index XXXXXXX..XXXXXXX 100644
30
--- a/tests/qemu-iotests/245
53
--- a/tests/qemu-iotests/244.out
31
+++ b/tests/qemu-iotests/245
54
+++ b/tests/qemu-iotests/244.out
32
@@ -XXX,XX +XXX,XX @@ class TestBlockdevReopen(iotests.QMPTestCase):
55
@@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 0
33
56
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
34
# hd2 <- hd0
57
read 1048576/1048576 bytes at offset 1048576
35
result = self.vm.qmp('block-stream', conv_keys = True, job_id = 'stream0',
58
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
36
- device = 'hd0', base_node = 'hd2', speed = 512 * 1024)
59
-read 2097152/2097152 bytes at offset 2097152
37
+ device = 'hd0', base_node = 'hd2',
60
-2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
38
+ auto_finalize = False)
61
read 1048576/1048576 bytes at offset 4194304
39
self.assert_qmp(result, 'return', {})
62
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
40
63
read 1048576/1048576 bytes at offset 5242880
41
# We can't remove hd2 while the stream job is ongoing
64
@@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 1048576
42
@@ -XXX,XX +XXX,XX @@ class TestBlockdevReopen(iotests.QMPTestCase):
65
read 4194304/4194304 bytes at offset 2097152
43
opts['backing'] = None
66
4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
44
self.reopen(opts, {}, "Cannot change 'backing' link from 'hd0' to 'hd1'")
67
45
68
-Images are identical.
46
- self.wait_until_completed(drive = 'stream0')
69
+read 1048576/1048576 bytes at offset 0
47
+ self.vm.run_job('stream0', auto_finalize = False, auto_dismiss = True)
70
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
48
71
+read 1048576/1048576 bytes at offset 1048576
49
# Reopen the chain during a block-stream job (from hd2 to hd1)
72
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
50
def test_block_stream_4(self):
73
+read 3145728/3145728 bytes at offset 3145728
51
@@ -XXX,XX +XXX,XX @@ class TestBlockdevReopen(iotests.QMPTestCase):
74
+3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
52
75
qcow2 file size after I/O: 327680
53
# hd1 <- hd0
76
54
result = self.vm.qmp('block-stream', conv_keys = True, job_id = 'stream0',
77
=== bdrv_co_block_status test for file and offset=0 ===
55
- device = 'hd1', speed = 512 * 1024)
56
+ device = 'hd1', auto_finalize = False)
57
self.assert_qmp(result, 'return', {})
58
59
# We can't reopen with the original options because that would
60
# make hd1 read-only and block-stream requires it to be read-write
61
- self.reopen(opts, {}, "Can't set node 'hd1' to r/o with copy-on-read enabled")
62
+ # (Which error message appears depends on whether the stream job is
63
+ # already done with copying at this point.)
64
+ self.reopen(opts, {},
65
+ ["Can't set node 'hd1' to r/o with copy-on-read enabled",
66
+ "Cannot make block node read-only, there is a writer on it"])
67
68
# We can't remove hd2 while the stream job is ongoing
69
opts['backing']['backing'] = None
70
@@ -XXX,XX +XXX,XX @@ class TestBlockdevReopen(iotests.QMPTestCase):
71
opts['backing'] = None
72
self.reopen(opts)
73
74
- self.wait_until_completed(drive = 'stream0')
75
+ self.vm.run_job('stream0', auto_finalize = False, auto_dismiss = True)
76
77
# Reopen the chain during a block-commit job (from hd0 to hd2)
78
def test_block_commit_1(self):
79
@@ -XXX,XX +XXX,XX @@ class TestBlockdevReopen(iotests.QMPTestCase):
80
self.assert_qmp(result, 'return', {})
81
82
result = self.vm.qmp('block-commit', conv_keys = True, job_id = 'commit0',
83
- device = 'hd0', speed = 1024 * 1024)
84
+ device = 'hd0')
85
self.assert_qmp(result, 'return', {})
86
87
# We can't remove hd2 while the commit job is ongoing
88
@@ -XXX,XX +XXX,XX @@ class TestBlockdevReopen(iotests.QMPTestCase):
89
self.assert_qmp(result, 'return', {})
90
91
result = self.vm.qmp('block-commit', conv_keys = True, job_id = 'commit0',
92
- device = 'hd0', top_node = 'hd1', speed = 1024 * 1024)
93
+ device = 'hd0', top_node = 'hd1',
94
+ auto_finalize = False)
95
self.assert_qmp(result, 'return', {})
96
97
# We can't remove hd2 while the commit job is ongoing
98
@@ -XXX,XX +XXX,XX @@ class TestBlockdevReopen(iotests.QMPTestCase):
99
self.reopen(opts, {}, "Cannot change backing link if 'hd0' has an implicit backing file")
100
101
# hd2 <- hd0
102
- self.wait_until_completed(drive = 'commit0')
103
+ self.vm.run_job('commit0', auto_finalize = False, auto_dismiss = True)
104
105
self.assert_qmp(self.get_node('hd0'), 'ro', False)
106
self.assertEqual(self.get_node('hd1'), None)
107
diff --git a/tests/qemu-iotests/245.out b/tests/qemu-iotests/245.out
108
index XXXXXXX..XXXXXXX 100644
109
--- a/tests/qemu-iotests/245.out
110
+++ b/tests/qemu-iotests/245.out
111
@@ -XXX,XX +XXX,XX @@
112
Ran 18 tests
113
114
OK
115
+{"execute": "job-finalize", "arguments": {"id": "commit0"}}
116
+{"return": {}}
117
+{"data": {"id": "commit0", "type": "commit"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
118
+{"data": {"device": "commit0", "len": 3145728, "offset": 3145728, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
119
+{"execute": "job-finalize", "arguments": {"id": "stream0"}}
120
+{"return": {}}
121
+{"data": {"id": "stream0", "type": "stream"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
122
+{"data": {"device": "stream0", "len": 3145728, "offset": 3145728, "speed": 0, "type": "stream"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
123
+{"execute": "job-finalize", "arguments": {"id": "stream0"}}
124
+{"return": {}}
125
+{"data": {"id": "stream0", "type": "stream"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
126
+{"data": {"device": "stream0", "len": 3145728, "offset": 3145728, "speed": 0, "type": "stream"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
127
--
78
--
128
2.20.1
79
2.25.3
129
80
130
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
Currently, qemu crashes whenever someone queries the block status of an
3
BlockDriverState that allows drivers to advertise support for request
4
unaligned image tail of an O_DIRECT image:
4
flags in the context of truncate.
5
$ echo > foo
5
6
$ qemu-img map --image-opts driver=file,filename=foo,cache.direct=on
6
For now, we always pass 0 and no drivers declare support for any flag.
7
Offset Length Mapped to File
7
8
qemu-img: block/io.c:2093: bdrv_co_block_status: Assertion `*pnum &&
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
QEMU_IS_ALIGNED(*pnum, align) && align > offset - aligned_offset'
9
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10
failed.
10
Reviewed-by: Alberto Garcia <berto@igalia.com>
11
11
Reviewed-by: Max Reitz <mreitz@redhat.com>
12
This is because bdrv_co_block_status() checks that the result returned
12
Message-Id: <20200424125448.63318-2-kwolf@redhat.com>
13
by the driver's implementation is aligned to the request_alignment, but
14
file-posix can fail to do so, which is actually mentioned in a comment
15
there: "[...] possibly including a partial sector at EOF".
16
17
Fix this by rounding up those partial sectors.
18
19
There are two possible alternative fixes:
20
(1) We could refuse to open unaligned image files with O_DIRECT
21
altogether. That sounds reasonable until you realize that qcow2
22
does necessarily not fill up its metadata clusters, and that nobody
23
runs qemu-img create with O_DIRECT. Therefore, unpreallocated qcow2
24
files usually have an unaligned image tail.
25
26
(2) bdrv_co_block_status() could ignore unaligned tails. It actually
27
throws away everything past the EOF already, so that sounds
28
reasonable.
29
Unfortunately, the block layer knows file lengths only with a
30
granularity of BDRV_SECTOR_SIZE, so bdrv_co_block_status() usually
31
would have to guess whether its file length information is inexact
32
or whether the driver is broken.
33
34
Fixing what raw_co_block_status() returns is the safest thing to do.
35
36
There seems to be no other block driver that sets request_alignment and
37
does not make sure that it always returns aligned values.
38
39
Cc: qemu-stable@nongnu.org
40
Signed-off-by: Max Reitz <mreitz@redhat.com>
41
Reviewed-by: Eric Blake <eblake@redhat.com>
42
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
43
---
14
---
44
block/file-posix.c | 16 ++++++++++++++++
15
include/block/block_int.h | 10 +++++++++-
45
1 file changed, 16 insertions(+)
16
block/crypto.c | 3 ++-
46
17
block/file-posix.c | 2 +-
18
block/file-win32.c | 2 +-
19
block/gluster.c | 1 +
20
block/io.c | 8 +++++++-
21
block/iscsi.c | 2 +-
22
block/nfs.c | 3 ++-
23
block/qcow2.c | 2 +-
24
block/qed.c | 1 +
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 =
47
diff --git a/block/file-posix.c b/block/file-posix.c
74
diff --git a/block/file-posix.c b/block/file-posix.c
48
index XXXXXXX..XXXXXXX 100644
75
index XXXXXXX..XXXXXXX 100644
49
--- a/block/file-posix.c
76
--- a/block/file-posix.c
50
+++ b/block/file-posix.c
77
+++ b/block/file-posix.c
51
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_block_status(BlockDriverState *bs,
78
@@ -XXX,XX +XXX,XX @@ raw_regular_truncate(BlockDriverState *bs, int fd, int64_t offset,
52
off_t data = 0, hole = 0;
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;
53
int ret;
122
int ret;
54
123
55
+ assert(QEMU_IS_ALIGNED(offset | bytes, bs->bl.request_alignment));
124
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
56
+
125
}
57
ret = fd_open(bs);
126
58
if (ret < 0) {
127
if (drv->bdrv_co_truncate) {
59
return ret;
128
- ret = drv->bdrv_co_truncate(bs, offset, exact, prealloc, errp);
60
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_block_status(BlockDriverState *bs,
129
+ if (flags & ~bs->supported_truncate_flags) {
61
/* On a data extent, compute bytes to the end of the extent,
130
+ error_setg(errp, "Block driver does not support requested flags");
62
* possibly including a partial sector at EOF. */
131
+ ret = -ENOTSUP;
63
*pnum = MIN(bytes, hole - offset);
132
+ goto out;
64
+
65
+ /*
66
+ * We are not allowed to return partial sectors, though, so
67
+ * round up if necessary.
68
+ */
69
+ if (!QEMU_IS_ALIGNED(*pnum, bs->bl.request_alignment)) {
70
+ int64_t file_length = raw_getlength(bs);
71
+ if (file_length > 0) {
72
+ /* Ignore errors, this is just a safeguard */
73
+ assert(hole == file_length);
74
+ }
75
+ *pnum = ROUND_UP(*pnum, bs->bl.request_alignment);
76
+ }
133
+ }
77
+
134
+ ret = drv->bdrv_co_truncate(bs, offset, exact, prealloc, flags, errp);
78
ret = BDRV_BLOCK_DATA;
135
} else if (bs->file && drv->is_filter) {
136
ret = bdrv_co_truncate(bs->file, offset, exact, prealloc, errp);
79
} else {
137
} else {
80
/* On a hole, compute bytes to the beginning of the next extent. */
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;
151
diff --git a/block/nfs.c b/block/nfs.c
152
index XXXXXXX..XXXXXXX 100644
153
--- a/block/nfs.c
154
+++ b/block/nfs.c
155
@@ -XXX,XX +XXX,XX @@ static int64_t nfs_get_allocated_file_size(BlockDriverState *bs)
156
157
static int coroutine_fn
158
nfs_file_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
159
- PreallocMode prealloc, Error **errp)
160
+ PreallocMode prealloc, BdrvRequestFlags flags,
161
+ Error **errp)
162
{
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;
215
diff --git a/block/sheepdog.c b/block/sheepdog.c
216
index XXXXXXX..XXXXXXX 100644
217
--- a/block/sheepdog.c
218
+++ b/block/sheepdog.c
219
@@ -XXX,XX +XXX,XX @@ static int64_t sd_getlength(BlockDriverState *bs)
220
221
static int coroutine_fn sd_co_truncate(BlockDriverState *bs, int64_t offset,
222
bool exact, PreallocMode prealloc,
223
- Error **errp)
224
+ BdrvRequestFlags flags, Error **errp)
225
{
226
BDRVSheepdogState *s = bs->opaque;
227
int ret, fd;
228
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num,
229
230
assert(!flags);
231
if (offset > s->inode.vdi_size) {
232
- ret = sd_co_truncate(bs, offset, false, PREALLOC_MODE_OFF, NULL);
233
+ ret = sd_co_truncate(bs, offset, false, PREALLOC_MODE_OFF, 0, NULL);
234
if (ret < 0) {
235
return ret;
236
}
237
diff --git a/block/ssh.c b/block/ssh.c
238
index XXXXXXX..XXXXXXX 100644
239
--- a/block/ssh.c
240
+++ b/block/ssh.c
241
@@ -XXX,XX +XXX,XX @@ static int64_t ssh_getlength(BlockDriverState *bs)
242
243
static int coroutine_fn ssh_co_truncate(BlockDriverState *bs, int64_t offset,
244
bool exact, PreallocMode prealloc,
245
- Error **errp)
246
+ BdrvRequestFlags flags, Error **errp)
247
{
248
BDRVSSHState *s = bs->opaque;
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
}
81
--
264
--
82
2.20.1
265
2.25.3
83
266
84
267
diff view generated by jsdifflib
1
bdrv_try_set_aio_context() currently fails if a BlockBackend is attached
1
Now that block drivers can support flags for .bdrv_co_truncate, expose
2
to a node because it doesn't implement the BdrvChildRole callbacks for
2
the parameter in the node level interfaces bdrv_co_truncate() and
3
AioContext management.
3
bdrv_truncate().
4
5
We can allow changing the AioContext of monitor-owned BlockBackends as
6
long as no device is attached to them.
7
8
When setting the AioContext of the root node of a BlockBackend, we now
9
need to pass blk->root as an ignored child because we don't want the
10
root node to recursively call back into BlockBackend and execute
11
blk_do_set_aio_context() a second time.
12
4
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@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>
14
---
11
---
15
block/block-backend.c | 45 +++++++++++++++++++++++++++++++++++++++++--
12
include/block/block.h | 5 +++--
16
1 file changed, 43 insertions(+), 2 deletions(-)
13
block/block-backend.c | 2 +-
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(-)
17
26
27
diff --git a/include/block/block.h b/include/block/block.h
28
index XXXXXXX..XXXXXXX 100644
29
--- a/include/block/block.h
30
+++ b/include/block/block.h
31
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
32
void bdrv_refresh_filename(BlockDriverState *bs);
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);
18
diff --git a/block/block-backend.c b/block/block-backend.c
44
diff --git a/block/block-backend.c b/block/block-backend.c
19
index XXXXXXX..XXXXXXX 100644
45
index XXXXXXX..XXXXXXX 100644
20
--- a/block/block-backend.c
46
--- a/block/block-backend.c
21
+++ b/block/block-backend.c
47
+++ b/block/block-backend.c
22
@@ -XXX,XX +XXX,XX @@ static void blk_root_drained_end(BdrvChild *child);
48
@@ -XXX,XX +XXX,XX @@ int blk_truncate(BlockBackend *blk, int64_t offset, bool exact,
23
static void blk_root_change_media(BdrvChild *child, bool load);
49
return -ENOMEDIUM;
24
static void blk_root_resize(BdrvChild *child);
50
}
25
51
26
+static bool blk_root_can_set_aio_ctx(BdrvChild *child, AioContext *ctx,
52
- return bdrv_truncate(blk->root, offset, exact, prealloc, errp);
27
+ GSList **ignore, Error **errp);
53
+ return bdrv_truncate(blk->root, offset, exact, prealloc, 0, errp);
28
+static void blk_root_set_aio_ctx(BdrvChild *child, AioContext *ctx,
54
}
29
+ GSList **ignore);
55
30
+
56
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
31
static char *blk_root_get_parent_desc(BdrvChild *child)
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)
32
{
81
{
33
BlockBackend *blk = child->opaque;
82
BlockDriverState *bs = child->bs;
34
@@ -XXX,XX +XXX,XX @@ static const BdrvChildRole child_root = {
83
BlockDriver *drv = bs->drv;
35
84
BdrvTrackedRequest req;
36
.attach = blk_root_attach,
85
- BdrvRequestFlags flags = 0;
37
.detach = blk_root_detach,
86
int64_t old_size, new_bytes;
38
+
87
int ret;
39
+ .can_set_aio_ctx = blk_root_can_set_aio_ctx,
88
40
+ .set_aio_ctx = blk_root_set_aio_ctx,
89
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
41
};
90
}
91
ret = drv->bdrv_co_truncate(bs, offset, exact, prealloc, flags, errp);
92
} else if (bs->file && drv->is_filter) {
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);
253
if (ret < 0) {
254
error_report_err(local_err);
255
goto fail;
256
diff --git a/block/raw-format.c b/block/raw-format.c
257
index XXXXXXX..XXXXXXX 100644
258
--- a/block/raw-format.c
259
+++ b/block/raw-format.c
260
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
261
262
s->size = offset;
263
offset += s->offset;
264
- return bdrv_co_truncate(bs->file, offset, exact, prealloc, errp);
265
+ return bdrv_co_truncate(bs->file, offset, exact, prealloc, 0, errp);
266
}
267
268
static void raw_eject(BlockDriverState *bs, bool eject_flag)
269
diff --git a/block/vhdx-log.c b/block/vhdx-log.c
270
index XXXXXXX..XXXXXXX 100644
271
--- a/block/vhdx-log.c
272
+++ b/block/vhdx-log.c
273
@@ -XXX,XX +XXX,XX @@ static int vhdx_log_flush(BlockDriverState *bs, BDRVVHDXState *s,
274
goto exit;
275
}
276
ret = bdrv_truncate(bs->file, new_file_size, false,
277
- PREALLOC_MODE_OFF, NULL);
278
+ PREALLOC_MODE_OFF, 0, NULL);
279
if (ret < 0) {
280
goto exit;
281
}
282
diff --git a/block/vhdx.c b/block/vhdx.c
283
index XXXXXXX..XXXXXXX 100644
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
}
42
293
43
/*
294
/*
44
@@ -XXX,XX +XXX,XX @@ static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb)
295
diff --git a/block/vmdk.c b/block/vmdk.c
45
return blk_get_aio_context(blk_acb->blk);
296
index XXXXXXX..XXXXXXX 100644
46
}
297
--- a/block/vmdk.c
47
298
+++ b/block/vmdk.c
48
-void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
299
@@ -XXX,XX +XXX,XX @@ vmdk_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
49
+static void blk_do_set_aio_context(BlockBackend *blk, AioContext *new_context,
300
}
50
+ bool update_root_node)
301
length = QEMU_ALIGN_UP(length, BDRV_SECTOR_SIZE);
51
{
302
ret = bdrv_truncate(s->extents[i].file, length, false,
52
BlockDriverState *bs = blk_bs(blk);
303
- PREALLOC_MODE_OFF, NULL);
53
ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
304
+ PREALLOC_MODE_OFF, 0, NULL);
54
@@ -XXX,XX +XXX,XX @@ void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
305
if (ret < 0) {
55
throttle_group_attach_aio_context(tgm, new_context);
306
return ret;
56
bdrv_drained_end(bs);
307
}
57
}
308
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
58
- bdrv_set_aio_context(bs, new_context);
309
index XXXXXXX..XXXXXXX 100644
59
+ if (update_root_node) {
310
--- a/tests/test-block-iothread.c
60
+ GSList *ignore = g_slist_prepend(NULL, blk->root);
311
+++ b/tests/test-block-iothread.c
61
+ bdrv_set_aio_context_ignore(bs, new_context, &ignore);
312
@@ -XXX,XX +XXX,XX @@ static void test_sync_op_truncate(BdrvChild *c)
62
+ g_slist_free(ignore);
313
int ret;
63
+ }
314
64
}
315
/* Normal success path */
65
}
316
- ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, NULL);
66
317
+ ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, 0, NULL);
67
+void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
318
g_assert_cmpint(ret, ==, 0);
68
+{
319
69
+ blk_do_set_aio_context(blk, new_context, true);
320
/* Early error: Negative offset */
70
+}
321
- ret = bdrv_truncate(c, -2, false, PREALLOC_MODE_OFF, NULL);
71
+
322
+ ret = bdrv_truncate(c, -2, false, PREALLOC_MODE_OFF, 0, NULL);
72
+static bool blk_root_can_set_aio_ctx(BdrvChild *child, AioContext *ctx,
323
g_assert_cmpint(ret, ==, -EINVAL);
73
+ GSList **ignore, Error **errp)
324
74
+{
325
/* Error: Read-only image */
75
+ BlockBackend *blk = child->opaque;
326
c->bs->read_only = true;
76
+
327
c->bs->open_flags &= ~BDRV_O_RDWR;
77
+ /* Only manually created BlockBackends that are not attached to anything
328
78
+ * can change their AioContext without updating their user. */
329
- ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, NULL);
79
+ if (!blk->name || blk->dev) {
330
+ ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, 0, NULL);
80
+ /* TODO Add BB name/QOM path */
331
g_assert_cmpint(ret, ==, -EACCES);
81
+ error_setg(errp, "Cannot change iothread of active block backend");
332
82
+ return false;
333
c->bs->read_only = false;
83
+ }
84
+
85
+ return true;
86
+}
87
+
88
+static void blk_root_set_aio_ctx(BdrvChild *child, AioContext *ctx,
89
+ GSList **ignore)
90
+{
91
+ BlockBackend *blk = child->opaque;
92
+ blk_do_set_aio_context(blk, ctx, false);
93
+}
94
+
95
void blk_add_aio_context_notifier(BlockBackend *blk,
96
void (*attached_aio_context)(AioContext *new_context, void *opaque),
97
void (*detach_aio_context)(void *opaque), void *opaque)
98
--
334
--
99
2.20.1
335
2.25.3
100
336
101
337
diff view generated by jsdifflib
1
Some users (like block jobs) can tolerate an AioContext change for their
1
Now that node level interface bdrv_truncate() supports passing request
2
BlockBackend. Add a function that tells the BlockBackend that it can
2
flags to the block driver, expose this on the BlockBackend level, too.
3
allow changes.
3
4
4
Signed-off-by: Kevin Wolf <kwolf@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-4-kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
10
---
7
include/sysemu/block-backend.h | 1 +
11
include/sysemu/block-backend.h | 2 +-
8
block/block-backend.c | 10 ++++++++++
12
block.c | 3 ++-
9
2 files changed, 11 insertions(+)
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(-)
10
27
11
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
28
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
12
index XXXXXXX..XXXXXXX 100644
29
index XXXXXXX..XXXXXXX 100644
13
--- a/include/sysemu/block-backend.h
30
--- a/include/sysemu/block-backend.h
14
+++ b/include/sysemu/block-backend.h
31
+++ b/include/sysemu/block-backend.h
15
@@ -XXX,XX +XXX,XX @@ int blk_set_perm(BlockBackend *blk, uint64_t perm, uint64_t shared_perm,
32
@@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_pwrite_zeroes(BlockBackend *blk, int64_t offset,
16
void blk_get_perm(BlockBackend *blk, uint64_t *perm, uint64_t *shared_perm);
33
int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf,
17
34
int bytes);
18
void blk_set_allow_write_beyond_eof(BlockBackend *blk, bool allow);
35
int blk_truncate(BlockBackend *blk, int64_t offset, bool exact,
19
+void blk_set_allow_aio_context_change(BlockBackend *blk, bool allow);
36
- PreallocMode prealloc, Error **errp);
20
void blk_iostatus_enable(BlockBackend *blk);
37
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp);
21
bool blk_iostatus_is_enabled(const BlockBackend *blk);
38
int blk_pdiscard(BlockBackend *blk, int64_t offset, int bytes);
22
BlockDeviceIoStatus blk_iostatus(const BlockBackend *blk);
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;
23
diff --git a/block/block-backend.c b/block/block-backend.c
55
diff --git a/block/block-backend.c b/block/block-backend.c
24
index XXXXXXX..XXXXXXX 100644
56
index XXXXXXX..XXXXXXX 100644
25
--- a/block/block-backend.c
57
--- a/block/block-backend.c
26
+++ b/block/block-backend.c
58
+++ b/block/block-backend.c
27
@@ -XXX,XX +XXX,XX @@ struct BlockBackend {
59
@@ -XXX,XX +XXX,XX @@ int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf,
28
uint64_t shared_perm;
29
bool disable_perm;
30
31
+ bool allow_aio_context_change;
32
bool allow_write_beyond_eof;
33
34
NotifierList remove_bs_notifiers, insert_bs_notifiers;
35
@@ -XXX,XX +XXX,XX @@ void blk_set_allow_write_beyond_eof(BlockBackend *blk, bool allow)
36
blk->allow_write_beyond_eof = allow;
37
}
60
}
38
61
39
+void blk_set_allow_aio_context_change(BlockBackend *blk, bool allow)
62
int blk_truncate(BlockBackend *blk, int64_t offset, bool exact,
40
+{
63
- PreallocMode prealloc, Error **errp)
41
+ blk->allow_aio_context_change = allow;
64
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp)
42
+}
43
+
44
static int blk_check_byte_request(BlockBackend *blk, int64_t offset,
45
size_t size)
46
{
65
{
47
@@ -XXX,XX +XXX,XX @@ static bool blk_root_can_set_aio_ctx(BdrvChild *child, AioContext *ctx,
66
if (!blk_is_available(blk)) {
48
{
67
error_setg(errp, "No medium inserted");
49
BlockBackend *blk = child->opaque;
68
return -ENOMEDIUM;
50
69
}
51
+ if (blk->allow_aio_context_change) {
70
52
+ return true;
71
- return bdrv_truncate(blk->root, offset, exact, prealloc, 0, errp);
53
+ }
72
+ return bdrv_truncate(blk->root, offset, exact, prealloc, flags, errp);
54
+
73
}
55
/* Only manually created BlockBackends that are not attached to anything
74
56
* can change their AioContext without updating their user. */
75
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
57
if (!blk->name || blk->dev) {
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;
146
diff --git a/block/qed.c b/block/qed.c
147
index XXXXXXX..XXXXXXX 100644
148
--- a/block/qed.c
149
+++ b/block/qed.c
150
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_create(BlockdevCreateOptions *opts,
151
* The QED format associates file length with allocation status,
152
* so a new file (which is empty) must have a length of 0.
153
*/
154
- ret = blk_truncate(blk, 0, true, PREALLOC_MODE_OFF, errp);
155
+ ret = blk_truncate(blk, 0, true, PREALLOC_MODE_OFF, 0, errp);
156
if (ret < 0) {
157
goto out;
158
}
159
diff --git a/block/vdi.c b/block/vdi.c
160
index XXXXXXX..XXXXXXX 100644
161
--- a/block/vdi.c
162
+++ b/block/vdi.c
163
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
164
165
if (image_type == VDI_TYPE_STATIC) {
166
ret = blk_truncate(blk, offset + blocks * block_size, false,
167
- PREALLOC_MODE_OFF, errp);
168
+ PREALLOC_MODE_OFF, 0, errp);
169
if (ret < 0) {
170
error_prepend(errp, "Failed to statically allocate file");
171
goto exit;
172
diff --git a/block/vhdx.c b/block/vhdx.c
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);
233
if (ret < 0) {
234
return ret;
235
}
236
diff --git a/blockdev.c b/blockdev.c
237
index XXXXXXX..XXXXXXX 100644
238
--- a/blockdev.c
239
+++ b/blockdev.c
240
@@ -XXX,XX +XXX,XX @@ void qmp_block_resize(bool has_device, const char *device,
241
}
242
243
bdrv_drained_begin(bs);
244
- ret = blk_truncate(blk, size, false, PREALLOC_MODE_OFF, errp);
245
+ ret = blk_truncate(blk, size, false, PREALLOC_MODE_OFF, 0, errp);
246
bdrv_drained_end(bs);
247
248
out:
249
diff --git a/qemu-img.c b/qemu-img.c
250
index XXXXXXX..XXXXXXX 100644
251
--- a/qemu-img.c
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);
274
return ret;
58
--
275
--
59
2.20.1
276
2.25.3
60
277
61
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
When an L2 table entry points to a compressed cluster the space used
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
by the data is specified in 512-byte sectors. This size is independent
8
Message-Id: <20200424125448.63318-5-kwolf@redhat.com>
5
from BDRV_SECTOR_SIZE and is specific to the qcow2 file format.
9
Reviewed-by: Eric Blake <eblake@redhat.com>
6
10
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
The QCOW2_COMPRESSED_SECTOR_SIZE constant defined in this patch makes
8
this explicit.
9
10
Signed-off-by: Alberto Garcia <berto@igalia.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
12
---
13
block/qcow2.h | 4 ++++
13
block/qcow2-cluster.c | 2 +-
14
block/qcow2-cluster.c | 5 +++--
14
block/qcow2.c | 34 ++++++++++++++++++++++++++++++++++
15
block/qcow2-refcount.c | 25 ++++++++++++++-----------
15
2 files changed, 35 insertions(+), 1 deletion(-)
16
block/qcow2.c | 3 ++-
17
4 files changed, 23 insertions(+), 14 deletions(-)
18
16
19
diff --git a/block/qcow2.h b/block/qcow2.h
20
index XXXXXXX..XXXXXXX 100644
21
--- a/block/qcow2.h
22
+++ b/block/qcow2.h
23
@@ -XXX,XX +XXX,XX @@
24
#define MIN_CLUSTER_BITS 9
25
#define MAX_CLUSTER_BITS 21
26
27
+/* Defined in the qcow2 spec (compressed cluster descriptor) */
28
+#define QCOW2_COMPRESSED_SECTOR_SIZE 512U
29
+#define QCOW2_COMPRESSED_SECTOR_MASK (~(QCOW2_COMPRESSED_SECTOR_SIZE - 1))
30
+
31
/* Must be at least 2 to cover COW */
32
#define MIN_L2_CACHE_SIZE 2 /* cache entries */
33
34
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
35
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
36
--- a/block/qcow2-cluster.c
19
--- a/block/qcow2-cluster.c
37
+++ b/block/qcow2-cluster.c
20
+++ b/block/qcow2-cluster.c
38
@@ -XXX,XX +XXX,XX @@ int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
21
@@ -XXX,XX +XXX,XX @@ int qcow2_cluster_zeroize(BlockDriverState *bs, uint64_t offset,
39
return cluster_offset;
22
/* Caller must pass aligned values, except at image end */
40
}
23
assert(QEMU_IS_ALIGNED(offset, s->cluster_size));
41
24
assert(QEMU_IS_ALIGNED(end_offset, s->cluster_size) ||
42
- nb_csectors = ((cluster_offset + compressed_size - 1) >> 9) -
25
- end_offset == bs->total_sectors << BDRV_SECTOR_BITS);
43
- (cluster_offset >> 9);
26
+ end_offset >= bs->total_sectors << BDRV_SECTOR_BITS);
44
+ nb_csectors =
27
45
+ (cluster_offset + compressed_size - 1) / QCOW2_COMPRESSED_SECTOR_SIZE -
28
/* The zero flag is only supported by version 3 and newer */
46
+ (cluster_offset / QCOW2_COMPRESSED_SECTOR_SIZE);
29
if (s->qcow_version < 3) {
47
48
cluster_offset |= QCOW_OFLAG_COMPRESSED |
49
((uint64_t)nb_csectors << s->csize_shift);
50
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
51
index XXXXXXX..XXXXXXX 100644
52
--- a/block/qcow2-refcount.c
53
+++ b/block/qcow2-refcount.c
54
@@ -XXX,XX +XXX,XX @@ void qcow2_free_any_clusters(BlockDriverState *bs, uint64_t l2_entry,
55
switch (ctype) {
56
case QCOW2_CLUSTER_COMPRESSED:
57
{
58
- int nb_csectors;
59
- nb_csectors = ((l2_entry >> s->csize_shift) &
60
- s->csize_mask) + 1;
61
- qcow2_free_clusters(bs,
62
- (l2_entry & s->cluster_offset_mask) & ~511,
63
- nb_csectors * 512, type);
64
+ int64_t offset = (l2_entry & s->cluster_offset_mask)
65
+ & QCOW2_COMPRESSED_SECTOR_MASK;
66
+ int size = QCOW2_COMPRESSED_SECTOR_SIZE *
67
+ (((l2_entry >> s->csize_shift) & s->csize_mask) + 1);
68
+ qcow2_free_clusters(bs, offset, size, type);
69
}
70
break;
71
case QCOW2_CLUSTER_NORMAL:
72
@@ -XXX,XX +XXX,XX @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
73
nb_csectors = ((entry >> s->csize_shift) &
74
s->csize_mask) + 1;
75
if (addend != 0) {
76
+ uint64_t coffset = (entry & s->cluster_offset_mask)
77
+ & QCOW2_COMPRESSED_SECTOR_MASK;
78
ret = update_refcount(
79
- bs, (entry & s->cluster_offset_mask) & ~511,
80
- nb_csectors * 512, abs(addend), addend < 0,
81
+ bs, coffset,
82
+ nb_csectors * QCOW2_COMPRESSED_SECTOR_SIZE,
83
+ abs(addend), addend < 0,
84
QCOW2_DISCARD_SNAPSHOT);
85
if (ret < 0) {
86
goto fail;
87
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
88
nb_csectors = ((l2_entry >> s->csize_shift) &
89
s->csize_mask) + 1;
90
l2_entry &= s->cluster_offset_mask;
91
- ret = qcow2_inc_refcounts_imrt(bs, res,
92
- refcount_table, refcount_table_size,
93
- l2_entry & ~511, nb_csectors * 512);
94
+ ret = qcow2_inc_refcounts_imrt(
95
+ bs, res, refcount_table, refcount_table_size,
96
+ l2_entry & QCOW2_COMPRESSED_SECTOR_MASK,
97
+ nb_csectors * QCOW2_COMPRESSED_SECTOR_SIZE);
98
if (ret < 0) {
99
goto fail;
100
}
101
diff --git a/block/qcow2.c b/block/qcow2.c
30
diff --git a/block/qcow2.c b/block/qcow2.c
102
index XXXXXXX..XXXXXXX 100644
31
index XXXXXXX..XXXXXXX 100644
103
--- a/block/qcow2.c
32
--- a/block/qcow2.c
104
+++ b/block/qcow2.c
33
+++ b/block/qcow2.c
105
@@ -XXX,XX +XXX,XX @@ qcow2_co_preadv_compressed(BlockDriverState *bs,
34
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
106
35
107
coffset = file_cluster_offset & s->cluster_offset_mask;
36
bs->supported_zero_flags = header.version >= 3 ?
108
nb_csectors = ((file_cluster_offset >> s->csize_shift) & s->csize_mask) + 1;
37
BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK : 0;
109
- csize = nb_csectors * 512 - (coffset & 511);
38
+ bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE;
110
+ csize = nb_csectors * QCOW2_COMPRESSED_SECTOR_SIZE -
39
111
+ (coffset & ~QCOW2_COMPRESSED_SECTOR_MASK);
40
/* Repair image if dirty */
112
41
if (!(flags & (BDRV_O_CHECK | BDRV_O_INACTIVE)) && !bs->read_only &&
113
buf = g_try_malloc(csize);
42
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
114
if (!buf) {
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);
48
+
49
+ /*
50
+ * Use zero clusters as much as we can. qcow2_cluster_zeroize()
51
+ * requires a cluster-aligned start. The end may be unaligned if it is
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;
58
+ }
59
+
60
+ /* Write explicit zeros for the unaligned head */
61
+ if (zero_start > old_length) {
62
+ uint64_t len = zero_start - old_length;
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
+ }
76
+ }
77
+ }
78
+
79
if (prealloc != PREALLOC_MODE_OFF) {
80
/* Flush metadata before actually changing the image size */
81
ret = qcow2_write_caches(bs);
115
--
82
--
116
2.20.1
83
2.25.3
117
84
118
85
diff view generated by jsdifflib
1
The raw format driver can simply forward the flag and let its bs->file
2
child take care of actually providing the zeros.
3
4
Signed-off-by: Kevin Wolf <kwolf@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>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
---
10
---
3
tests/test-block-iothread.c | 71 +++++++++++++++++++++++++++++++++++++
11
block/raw-format.c | 4 +++-
4
1 file changed, 71 insertions(+)
12
1 file changed, 3 insertions(+), 1 deletion(-)
5
13
6
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
14
diff --git a/block/raw-format.c b/block/raw-format.c
7
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
8
--- a/tests/test-block-iothread.c
16
--- a/block/raw-format.c
9
+++ b/tests/test-block-iothread.c
17
+++ b/block/raw-format.c
10
@@ -XXX,XX +XXX,XX @@ static void test_propagate_diamond(void)
18
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
11
bdrv_unref(bs_a);
19
20
s->size = offset;
21
offset += s->offset;
22
- return bdrv_co_truncate(bs->file, offset, exact, prealloc, 0, errp);
23
+ return bdrv_co_truncate(bs->file, offset, exact, prealloc, flags, errp);
12
}
24
}
13
25
14
+static void test_propagate_mirror(void)
26
static void raw_eject(BlockDriverState *bs, bool eject_flag)
15
+{
27
@@ -XXX,XX +XXX,XX @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
16
+ IOThread *iothread = iothread_new();
28
bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
17
+ AioContext *ctx = iothread_get_aio_context(iothread);
29
((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) &
18
+ AioContext *main_ctx = qemu_get_aio_context();
30
bs->file->bs->supported_zero_flags);
19
+ BlockDriverState *src, *target;
31
+ bs->supported_truncate_flags = bs->file->bs->supported_truncate_flags &
20
+ BlockBackend *blk;
32
+ BDRV_REQ_ZERO_WRITE;
21
+ Job *job;
33
22
+ Error *local_err = NULL;
34
if (bs->probed && !bdrv_is_read_only(bs)) {
23
+
35
bdrv_refresh_filename(bs->file->bs);
24
+ /* Create src and target*/
25
+ src = bdrv_new_open_driver(&bdrv_test, "src", BDRV_O_RDWR, &error_abort);
26
+ target = bdrv_new_open_driver(&bdrv_test, "target", BDRV_O_RDWR,
27
+ &error_abort);
28
+
29
+ /* Start a mirror job */
30
+ mirror_start("job0", src, target, NULL, JOB_DEFAULT, 0, 0, 0,
31
+ MIRROR_SYNC_MODE_NONE, MIRROR_OPEN_BACKING_CHAIN,
32
+ BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT,
33
+ false, "filter_node", MIRROR_COPY_MODE_BACKGROUND,
34
+ &error_abort);
35
+ job = job_get("job0");
36
+
37
+ /* Change the AioContext of src */
38
+ bdrv_try_set_aio_context(src, ctx, &error_abort);
39
+ g_assert(bdrv_get_aio_context(src) == ctx);
40
+ g_assert(bdrv_get_aio_context(target) == ctx);
41
+ g_assert(job->aio_context == ctx);
42
+
43
+ /* Change the AioContext of target */
44
+ aio_context_acquire(ctx);
45
+ bdrv_try_set_aio_context(target, main_ctx, &error_abort);
46
+ aio_context_release(ctx);
47
+ g_assert(bdrv_get_aio_context(src) == main_ctx);
48
+ g_assert(bdrv_get_aio_context(target) == main_ctx);
49
+
50
+ /* With a BlockBackend on src, changing target must fail */
51
+ blk = blk_new(0, BLK_PERM_ALL);
52
+ blk_insert_bs(blk, src, &error_abort);
53
+
54
+ bdrv_try_set_aio_context(target, ctx, &local_err);
55
+ g_assert(local_err);
56
+ error_free(local_err);
57
+
58
+ g_assert(blk_get_aio_context(blk) == main_ctx);
59
+ g_assert(bdrv_get_aio_context(src) == main_ctx);
60
+ g_assert(bdrv_get_aio_context(target) == main_ctx);
61
+
62
+ /* ...unless we explicitly allow it */
63
+ aio_context_acquire(ctx);
64
+ blk_set_allow_aio_context_change(blk, true);
65
+ bdrv_try_set_aio_context(target, ctx, &error_abort);
66
+ aio_context_release(ctx);
67
+
68
+ g_assert(blk_get_aio_context(blk) == ctx);
69
+ g_assert(bdrv_get_aio_context(src) == ctx);
70
+ g_assert(bdrv_get_aio_context(target) == ctx);
71
+
72
+ job_cancel_sync_all();
73
+
74
+ aio_context_acquire(ctx);
75
+ blk_set_aio_context(blk, main_ctx);
76
+ bdrv_try_set_aio_context(target, main_ctx, &error_abort);
77
+ aio_context_release(ctx);
78
+
79
+ blk_unref(blk);
80
+ bdrv_unref(src);
81
+ bdrv_unref(target);
82
+}
83
+
84
int main(int argc, char **argv)
85
{
86
int i;
87
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
88
g_test_add_func("/attach/blockjob", test_attach_blockjob);
89
g_test_add_func("/propagate/basic", test_propagate_basic);
90
g_test_add_func("/propagate/diamond", test_propagate_diamond);
91
+ g_test_add_func("/propagate/mirror", test_propagate_mirror);
92
93
return g_test_run();
94
}
95
--
36
--
96
2.20.1
37
2.25.3
97
38
98
39
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
For regular files, we always get BDRV_REQ_ZERO_WRITE behaviour from the
2
OS, so we can advertise the flag and just ignore it.
2
3
3
XFS_IOC_ZERO_RANGE does not increase the file length:
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
$ touch foo
5
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
5
$ xfs_io -c 'zero 0 65536' foo
6
Reviewed-by: Alberto Garcia <berto@igalia.com>
6
$ stat -c "size=%s, blocks=%b" foo
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
size=0, blocks=128
8
Message-Id: <20200424125448.63318-7-kwolf@redhat.com>
8
9
We do want writes beyond the EOF to automatically increase the file
10
length, however. This is evidenced by the fact that iotest 061 is
11
broken on XFS since qcow2's check implementation checks for blocks
12
beyond the EOF.
13
14
Reported-by: Kevin Wolf <kwolf@redhat.com>
15
Signed-off-by: Max Reitz <mreitz@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
---
10
---
18
block/file-posix.c | 13 +++++++++++++
11
block/file-posix.c | 4 ++++
19
1 file changed, 13 insertions(+)
12
1 file changed, 4 insertions(+)
20
13
21
diff --git a/block/file-posix.c b/block/file-posix.c
14
diff --git a/block/file-posix.c b/block/file-posix.c
22
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
23
--- a/block/file-posix.c
16
--- a/block/file-posix.c
24
+++ b/block/file-posix.c
17
+++ b/block/file-posix.c
25
@@ -XXX,XX +XXX,XX @@ out:
18
@@ -XXX,XX +XXX,XX @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
26
#ifdef CONFIG_XFS
19
#endif
27
static int xfs_write_zeroes(BDRVRawState *s, int64_t offset, uint64_t bytes)
20
28
{
21
bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK;
29
+ int64_t len;
22
+ if (S_ISREG(st.st_mode)) {
30
struct xfs_flock64 fl;
23
+ /* When extending regular files, we get zeros from the OS */
31
int err;
24
+ bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE;
32
33
+ len = lseek(s->fd, 0, SEEK_END);
34
+ if (len < 0) {
35
+ return -errno;
36
+ }
25
+ }
37
+
26
ret = 0;
38
+ if (offset + bytes > len) {
27
fail:
39
+ /* XFS_IOC_ZERO_RANGE does not increase the file length */
28
if (filename && (bdrv_flags & BDRV_O_TEMPORARY)) {
40
+ if (ftruncate(s->fd, offset + bytes) < 0) {
41
+ return -errno;
42
+ }
43
+ }
44
+
45
memset(&fl, 0, sizeof(fl));
46
fl.l_whence = SEEK_SET;
47
fl.l_start = offset;
48
--
29
--
49
2.20.1
30
2.25.3
50
31
51
32
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.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
There are a few places in which we turn a number of bytes into sectors
5
Consider the following scenario where the overlay is shorter than its
4
in order to compare the result against BDRV_REQUEST_MAX_SECTORS
6
backing file:
5
instead of using BDRV_REQUEST_MAX_BYTES directly.
6
7
7
Signed-off-by: Alberto Garcia <berto@igalia.com>
8
base.qcow2: AAAAAAAA
8
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
9
overlay.qcow2: BBBB
10
11
When resizing (extending) overlay.qcow2, the new blocks should not stay
12
unallocated and make the additional As from base.qcow2 visible like
13
before this patch, but zeros should be read.
14
15
A similar case happens with the various variants of a commit job when an
16
intermediate file is short (- for unallocated):
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>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
34
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
35
---
11
block/io.c | 6 +++---
36
block/io.c | 25 +++++++++++++++++++++++++
12
qemu-io-cmds.c | 7 +++----
37
1 file changed, 25 insertions(+)
13
2 files changed, 6 insertions(+), 7 deletions(-)
14
38
15
diff --git a/block/io.c b/block/io.c
39
diff --git a/block/io.c b/block/io.c
16
index XXXXXXX..XXXXXXX 100644
40
index XXXXXXX..XXXXXXX 100644
17
--- a/block/io.c
41
--- a/block/io.c
18
+++ b/block/io.c
42
+++ b/block/io.c
19
@@ -XXX,XX +XXX,XX @@ static bool coroutine_fn wait_serialising_requests(BdrvTrackedRequest *self)
43
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
20
static int bdrv_check_byte_request(BlockDriverState *bs, int64_t offset,
44
goto out;
21
size_t size)
22
{
23
- if (size > BDRV_REQUEST_MAX_SECTORS << BDRV_SECTOR_BITS) {
24
+ if (size > BDRV_REQUEST_MAX_BYTES) {
25
return -EIO;
26
}
45
}
27
46
28
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_driver_preadv(BlockDriverState *bs,
47
+ /*
29
48
+ * If the image has a backing file that is large enough that it would
30
assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
49
+ * provide data for the new area, we cannot leave it unallocated because
31
assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
50
+ * then the backing file content would become visible. Instead, zero-fill
32
- assert((bytes >> BDRV_SECTOR_BITS) <= BDRV_REQUEST_MAX_SECTORS);
51
+ * the new area.
33
+ assert(bytes <= BDRV_REQUEST_MAX_BYTES);
52
+ *
34
assert(drv->bdrv_co_readv);
53
+ * Note that if the image has a backing file, but was opened without the
35
54
+ * backing file, taking care of keeping things consistent with that backing
36
return drv->bdrv_co_readv(bs, sector_num, nb_sectors, qiov);
55
+ * file is the user's responsibility.
37
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs,
56
+ */
38
57
+ if (new_bytes && bs->backing) {
39
assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
58
+ int64_t backing_len;
40
assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
59
+
41
- assert((bytes >> BDRV_SECTOR_BITS) <= BDRV_REQUEST_MAX_SECTORS);
60
+ backing_len = bdrv_getlength(backing_bs(bs));
42
+ assert(bytes <= BDRV_REQUEST_MAX_BYTES);
61
+ if (backing_len < 0) {
43
62
+ ret = backing_len;
44
assert(drv->bdrv_co_writev);
63
+ error_setg_errno(errp, -ret, "Could not get backing file size");
45
ret = drv->bdrv_co_writev(bs, sector_num, nb_sectors, qiov,
64
+ goto out;
46
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
65
+ }
47
index XXXXXXX..XXXXXXX 100644
66
+
48
--- a/qemu-io-cmds.c
67
+ if (backing_len > old_size) {
49
+++ b/qemu-io-cmds.c
68
+ flags |= BDRV_REQ_ZERO_WRITE;
50
@@ -XXX,XX +XXX,XX @@ static int do_write_compressed(BlockBackend *blk, char *buf, int64_t offset,
69
+ }
51
{
70
+ }
52
int ret;
71
+
53
72
if (drv->bdrv_co_truncate) {
54
- if (bytes >> 9 > BDRV_REQUEST_MAX_SECTORS) {
73
if (flags & ~bs->supported_truncate_flags) {
55
+ if (bytes > BDRV_REQUEST_MAX_BYTES) {
74
error_setg(errp, "Block driver does not support requested flags");
56
return -ERANGE;
57
}
58
59
@@ -XXX,XX +XXX,XX @@ static int discard_f(BlockBackend *blk, int argc, char **argv)
60
if (bytes < 0) {
61
print_cvtnum_err(bytes, argv[optind]);
62
return bytes;
63
- } else if (bytes >> BDRV_SECTOR_BITS > BDRV_REQUEST_MAX_SECTORS) {
64
+ } else if (bytes > BDRV_REQUEST_MAX_BYTES) {
65
printf("length cannot exceed %"PRIu64", given %s\n",
66
- (uint64_t)BDRV_REQUEST_MAX_SECTORS << BDRV_SECTOR_BITS,
67
- argv[optind]);
68
+ (uint64_t)BDRV_REQUEST_MAX_BYTES, argv[optind]);
69
return -EINVAL;
70
}
71
72
--
75
--
73
2.20.1
76
2.25.3
74
77
75
78
diff view generated by jsdifflib
Deleted patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
1
3
qmp_cont fails if vm in RUN_STATE_FINISH_MIGRATE, so let's wait for
4
final RUN_STATE_POSTMIGRATE. Also, while being here, check qmp_cont
5
result.
6
7
Reported-by: Max Reitz <mreitz@redhat.com>
8
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
Tested-by: Max Reitz <mreitz@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
12
tests/qemu-iotests/169 | 7 ++++++-
13
1 file changed, 6 insertions(+), 1 deletion(-)
14
15
diff --git a/tests/qemu-iotests/169 b/tests/qemu-iotests/169
16
index XXXXXXX..XXXXXXX 100755
17
--- a/tests/qemu-iotests/169
18
+++ b/tests/qemu-iotests/169
19
@@ -XXX,XX +XXX,XX @@ class TestDirtyBitmapMigration(iotests.QMPTestCase):
20
event = self.vm_a.event_wait('MIGRATION')
21
if event['data']['status'] == 'completed':
22
break
23
+ while True:
24
+ result = self.vm_a.qmp('query-status')
25
+ if (result['return']['status'] == 'postmigrate'):
26
+ break
27
28
# test that bitmap is still here
29
removed = (not migrate_bitmaps) and persistent
30
self.check_bitmap(self.vm_a, False if removed else sha256)
31
32
- self.vm_a.qmp('cont')
33
+ result = self.vm_a.qmp('cont')
34
+ self.assert_qmp(result, 'return', {})
35
36
# test that bitmap is still here after invalidation
37
self.check_bitmap(self.vm_a, sha256)
38
--
39
2.20.1
40
41
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
We want to keep TEST_IMG for the full path of the main test image, but
2
filter_testfiles() must be called for other test images before replacing
3
other things like the image format because the test directory path could
4
contain the format as a substring.
2
5
3
log() is in the current module, there is no need to prefix it. In fact,
6
Insert a filter_testfiles() call between both.
4
doing so may make VM.run_job() unusable in tests that never use
5
iotests.log() themselves.
6
7
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Reviewed-by: Alberto Garcia <berto@igalia.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>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
13
---
11
tests/qemu-iotests/iotests.py | 2 +-
14
tests/qemu-iotests/iotests.py | 5 +++--
12
1 file changed, 1 insertion(+), 1 deletion(-)
15
1 file changed, 3 insertions(+), 2 deletions(-)
13
16
14
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
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/tests/qemu-iotests/iotests.py
19
--- a/tests/qemu-iotests/iotests.py
17
+++ b/tests/qemu-iotests/iotests.py
20
+++ b/tests/qemu-iotests/iotests.py
18
@@ -XXX,XX +XXX,XX @@ class VM(qtest.QEMUQtestMachine):
21
@@ -XXX,XX +XXX,XX @@ def filter_img_info(output, filename):
19
elif status == 'null':
22
for line in output.split('\n'):
20
return error
23
if 'disk size' in line or 'actual-size' in line:
21
else:
24
continue
22
- iotests.log(ev)
25
- line = line.replace(filename, 'TEST_IMG') \
23
+ log(ev)
26
- .replace(imgfmt, 'IMGFMT')
24
27
+ line = line.replace(filename, 'TEST_IMG')
25
def node_info(self, node_name):
28
+ line = filter_testfiles(line)
26
nodes = self.qmp('query-named-block-nodes')
29
+ line = line.replace(imgfmt, 'IMGFMT')
30
line = re.sub('iters: [0-9]+', 'iters: XXX', line)
31
line = re.sub('uuid: [-a-f0-9]+', 'uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX', line)
32
line = re.sub('cid: [0-9]+', 'cid: XXXXXXXXXX', line)
27
--
33
--
28
2.20.1
34
2.25.3
29
35
30
36
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
2
Message-Id: <20200424125448.63318-10-kwolf@redhat.com>
3
We already have 221 for accesses through the page cache, but it is
3
Reviewed-by: Max Reitz <mreitz@redhat.com>
4
better to create a new file for O_DIRECT instead of integrating those
4
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
5
test cases into 221. This way, we can make use of
6
_supported_cache_modes (and _default_cache_mode) so the test is
7
automatically skipped on filesystems that do not support O_DIRECT.
8
9
As part of the split, add _supported_cache_modes to 221. With that, it
10
no longer fails when run with -c none or -c directsync.
11
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
Reviewed-by: Eric Blake <eblake@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
6
---
16
tests/qemu-iotests/221 | 4 ++
7
tests/qemu-iotests/274 | 155 +++++++++++++++++++++
17
tests/qemu-iotests/253 | 84 ++++++++++++++++++++++++++++++++++++++
8
tests/qemu-iotests/274.out | 268 +++++++++++++++++++++++++++++++++++++
18
tests/qemu-iotests/253.out | 14 +++++++
9
tests/qemu-iotests/group | 1 +
19
tests/qemu-iotests/group | 1 +
10
3 files changed, 424 insertions(+)
20
4 files changed, 103 insertions(+)
11
create mode 100755 tests/qemu-iotests/274
21
create mode 100755 tests/qemu-iotests/253
12
create mode 100644 tests/qemu-iotests/274.out
22
create mode 100644 tests/qemu-iotests/253.out
23
13
24
diff --git a/tests/qemu-iotests/221 b/tests/qemu-iotests/221
14
diff --git a/tests/qemu-iotests/274 b/tests/qemu-iotests/274
25
index XXXXXXX..XXXXXXX 100755
26
--- a/tests/qemu-iotests/221
27
+++ b/tests/qemu-iotests/221
28
@@ -XXX,XX +XXX,XX @@
29
#!/usr/bin/env bash
30
#
31
# Test qemu-img vs. unaligned images
32
+# (See also 253, which is the O_DIRECT version)
33
#
34
# Copyright (C) 2018-2019 Red Hat, Inc.
35
#
36
@@ -XXX,XX +XXX,XX @@ _supported_fmt raw
37
_supported_proto file
38
_supported_os Linux
39
40
+_default_cache_mode writeback
41
+_supported_cache_modes writeback writethrough unsafe
42
+
43
echo
44
echo "=== Check mapping of unaligned raw image ==="
45
echo
46
diff --git a/tests/qemu-iotests/253 b/tests/qemu-iotests/253
47
new file mode 100755
15
new file mode 100755
48
index XXXXXXX..XXXXXXX
16
index XXXXXXX..XXXXXXX
49
--- /dev/null
17
--- /dev/null
50
+++ b/tests/qemu-iotests/253
18
+++ b/tests/qemu-iotests/274
51
@@ -XXX,XX +XXX,XX @@
19
@@ -XXX,XX +XXX,XX @@
52
+#!/usr/bin/env bash
20
+#!/usr/bin/env python3
53
+#
54
+# Test qemu-img vs. unaligned images; O_DIRECT version
55
+# (Originates from 221)
56
+#
21
+#
57
+# Copyright (C) 2019 Red Hat, Inc.
22
+# Copyright (C) 2019 Red Hat, Inc.
58
+#
23
+#
59
+# 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
60
+# 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
...
...
67
+# GNU General Public License for more details.
32
+# GNU General Public License for more details.
68
+#
33
+#
69
+# 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
70
+# 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/>.
71
+#
36
+#
72
+
37
+# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
73
+seq="$(basename $0)"
38
+#
74
+echo "QA output created by $seq"
39
+# Some tests for short backing files and short overlays
75
+
40
+
76
+status=1 # failure is the default!
41
+import iotests
77
+
42
+
78
+_cleanup()
43
+iotests.verify_image_format(supported_fmts=['qcow2'])
79
+{
44
+iotests.verify_platform(['linux'])
80
+ _cleanup_test_img
45
+
81
+}
46
+size_short = 1 * 1024 * 1024
82
+trap "_cleanup; exit \$status" 0 1 2 3 15
47
+size_long = 2 * 1024 * 1024
83
+
48
+size_diff = size_long - size_short
84
+# get standard environment, filters and checks
49
+
85
+. ./common.rc
50
+def create_chain() -> None:
86
+. ./common.filter
51
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, base,
87
+
52
+ str(size_long))
88
+_supported_fmt raw
53
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', base, mid,
89
+_supported_proto file
54
+ str(size_short))
90
+_supported_os Linux
55
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', mid, top,
91
+
56
+ str(size_long))
92
+_default_cache_mode none
57
+
93
+_supported_cache_modes none directsync
58
+ iotests.qemu_io_log('-c', 'write -P 1 0 %d' % size_long, base)
94
+
59
+
95
+echo
60
+def create_vm() -> iotests.VM:
96
+echo "=== Check mapping of unaligned raw image ==="
61
+ vm = iotests.VM()
97
+echo
62
+ vm.add_blockdev('file,filename=%s,node-name=base-file' % base)
98
+
63
+ vm.add_blockdev('%s,file=base-file,node-name=base' % iotests.imgfmt)
99
+# We do not know how large a physical sector is, but it is certainly
64
+ vm.add_blockdev('file,filename=%s,node-name=mid-file' % mid)
100
+# going to be a factor of 1 MB
65
+ vm.add_blockdev('%s,file=mid-file,node-name=mid,backing=base'
101
+size=$((1 * 1024 * 1024 - 1))
66
+ % iotests.imgfmt)
102
+
67
+ vm.add_drive(top, 'backing=mid,node-name=top')
103
+# qemu-img create rounds size up to BDRV_SECTOR_SIZE
68
+ return vm
104
+_make_test_img $size
69
+
105
+$QEMU_IMG map --output=json --image-opts \
70
+with iotests.FilePath('base') as base, \
106
+ "driver=$IMGFMT,file.driver=file,file.filename=$TEST_IMG,cache.direct=on" \
71
+ iotests.FilePath('mid') as mid, \
107
+ | _filter_qemu_img_map
72
+ iotests.FilePath('top') as top:
108
+
73
+
109
+# so we resize it and check again
74
+ iotests.log('== Commit tests ==')
110
+truncate --size=$size "$TEST_IMG"
75
+
111
+$QEMU_IMG map --output=json --image-opts \
76
+ create_chain()
112
+ "driver=$IMGFMT,file.driver=file,file.filename=$TEST_IMG,cache.direct=on" \
77
+
113
+ | _filter_qemu_img_map
78
+ iotests.log('=== Check visible data ===')
114
+
79
+
115
+# qemu-io with O_DIRECT always writes whole physical sectors. Again,
80
+ iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, top)
116
+# we do not know how large a physical sector is, so we just start
81
+ iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), top)
117
+# writing from a 64 kB boundary, which should always be aligned.
82
+
118
+offset=$((1 * 1024 * 1024 - 64 * 1024))
83
+ iotests.log('=== Checking allocation status ===')
119
+$QEMU_IO -c "w $offset $((size - offset))" "$TEST_IMG" | _filter_qemu_io
84
+
120
+$QEMU_IMG map --output=json --image-opts \
85
+ iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short,
121
+ "driver=$IMGFMT,file.driver=file,file.filename=$TEST_IMG,cache.direct=on" \
86
+ '-c', 'alloc %d %d' % (size_short, size_diff),
122
+ | _filter_qemu_img_map
87
+ base)
123
+
88
+
124
+# Resize it and check again -- contrary to 221, we may not get partial
89
+ iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short,
125
+# sectors here, so there should be only two areas (one zero, one
90
+ '-c', 'alloc %d %d' % (size_short, size_diff),
126
+# data).
91
+ mid)
127
+truncate --size=$size "$TEST_IMG"
92
+
128
+$QEMU_IMG map --output=json --image-opts \
93
+ iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short,
129
+ "driver=$IMGFMT,file.driver=file,file.filename=$TEST_IMG,cache.direct=on" \
94
+ '-c', 'alloc %d %d' % (size_short, size_diff),
130
+ | _filter_qemu_img_map
95
+ top)
131
+
96
+
132
+# success, all done
97
+ iotests.log('=== Checking map ===')
133
+echo '*** done'
98
+
134
+rm -f $seq.full
99
+ iotests.qemu_img_log('map', '--output=json', base)
135
+status=0
100
+ iotests.qemu_img_log('map', '--output=human', base)
136
diff --git a/tests/qemu-iotests/253.out b/tests/qemu-iotests/253.out
101
+ iotests.qemu_img_log('map', '--output=json', mid)
102
+ iotests.qemu_img_log('map', '--output=human', mid)
103
+ iotests.qemu_img_log('map', '--output=json', top)
104
+ iotests.qemu_img_log('map', '--output=human', top)
105
+
106
+ iotests.log('=== Testing qemu-img commit (top -> mid) ===')
107
+
108
+ iotests.qemu_img_log('commit', top)
109
+ iotests.img_info_log(mid)
110
+ iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid)
111
+ iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid)
112
+
113
+ iotests.log('=== Testing HMP commit (top -> mid) ===')
114
+
115
+ create_chain()
116
+ with create_vm() as vm:
117
+ vm.launch()
118
+ vm.qmp_log('human-monitor-command', command_line='commit drive0')
119
+
120
+ iotests.img_info_log(mid)
121
+ iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid)
122
+ iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid)
123
+
124
+ iotests.log('=== Testing QMP active commit (top -> mid) ===')
125
+
126
+ create_chain()
127
+ with create_vm() as vm:
128
+ vm.launch()
129
+ vm.qmp_log('block-commit', device='top', base_node='mid',
130
+ job_id='job0', auto_dismiss=False)
131
+ vm.run_job('job0', wait=5)
132
+
133
+ iotests.img_info_log(mid)
134
+ iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid)
135
+ iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid)
136
+
137
+
138
+ iotests.log('== Resize tests ==')
139
+
140
+ # Use different sizes for different allocation modes:
141
+ #
142
+ # We want to have at least one test where 32 bit truncation in the size of
143
+ # the overlapping area becomes visible. This is covered by the
144
+ # prealloc='off' case (1G to 6G is an overlap of 5G).
145
+ #
146
+ # However, we can only do this for modes that don't preallocate data
147
+ # because otherwise we might run out of space on the test host.
148
+ #
149
+ # We also want to test some unaligned combinations.
150
+ for (prealloc, base_size, top_size_old, top_size_new, off) in [
151
+ ('off', '6G', '1G', '8G', '5G'),
152
+ ('metadata', '32G', '30G', '33G', '31G'),
153
+ ('falloc', '10M', '5M', '15M', '9M'),
154
+ ('full', '16M', '8M', '12M', '11M'),
155
+ ('off', '384k', '253k', '512k', '253k'),
156
+ ('off', '400k', '256k', '512k', '336k'),
157
+ ('off', '512k', '256k', '500k', '436k')]:
158
+
159
+ iotests.log('=== preallocation=%s ===' % prealloc)
160
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, base, base_size)
161
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', base, top,
162
+ top_size_old)
163
+ iotests.qemu_io_log('-c', 'write -P 1 %s 64k' % off, base)
164
+
165
+ # After this, top_size_old to base_size should be allocated/zeroed.
166
+ #
167
+ # In theory, leaving base_size to top_size_new unallocated would be
168
+ # correct, but in practice, if we zero out anything, we zero out
169
+ # everything up to top_size_new.
170
+ iotests.qemu_img_log('resize', '-f', iotests.imgfmt,
171
+ '--preallocation', prealloc, top, top_size_new)
172
+ iotests.qemu_io_log('-c', 'read -P 0 %s 64k' % off, top)
173
+ iotests.qemu_io_log('-c', 'map', top)
174
+ iotests.qemu_img_log('map', '--output=json', top)
175
diff --git a/tests/qemu-iotests/274.out b/tests/qemu-iotests/274.out
137
new file mode 100644
176
new file mode 100644
138
index XXXXXXX..XXXXXXX
177
index XXXXXXX..XXXXXXX
139
--- /dev/null
178
--- /dev/null
140
+++ b/tests/qemu-iotests/253.out
179
+++ b/tests/qemu-iotests/274.out
141
@@ -XXX,XX +XXX,XX @@
180
@@ -XXX,XX +XXX,XX @@
142
+QA output created by 253
181
+== Commit tests ==
143
+
182
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16
144
+=== Check mapping of unaligned raw image ===
183
+
145
+
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
146
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048575
185
+
147
+[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
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
148
+[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
187
+
149
+wrote 65535/65535 bytes at offset 983040
188
+wrote 2097152/2097152 bytes at offset 0
150
+63.999 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
189
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
151
+[{ "start": 0, "length": 983040, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
190
+
152
+{ "start": 983040, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": OFFSET}]
191
+=== Check visible data ===
153
+[{ "start": 0, "length": 983040, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
192
+read 1048576/1048576 bytes at offset 0
154
+{ "start": 983040, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": OFFSET}]
193
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
155
+*** done
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"}}
285
+{"return": {}}
286
+{"execute": "job-complete", "arguments": {"id": "job0"}}
287
+{"return": {}}
288
+{"data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
289
+{"data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
290
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
291
+{"return": {}}
292
+image: TEST_IMG
293
+file format: IMGFMT
294
+virtual size: 2 MiB (2097152 bytes)
295
+cluster_size: 65536
296
+backing file: TEST_DIR/PID-base
297
+Format specific information:
298
+ compat: 1.1
299
+ lazy refcounts: false
300
+ refcount bits: 16
301
+ corrupt: false
302
+
303
+read 1048576/1048576 bytes at offset 0
304
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
305
+
306
+read 1048576/1048576 bytes at offset 1048576
307
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
308
+
309
+== Resize tests ==
310
+=== preallocation=off ===
311
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=6442450944 cluster_size=65536 lazy_refcounts=off refcount_bits=16
312
+
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
314
+
315
+wrote 65536/65536 bytes at offset 5368709120
316
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
317
+
318
+Image resized.
319
+
320
+read 65536/65536 bytes at offset 5368709120
321
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
322
+
323
+1 GiB (0x40000000) bytes not allocated at offset 0 bytes (0x0)
324
+7 GiB (0x1c0000000) bytes allocated at offset 1 GiB (0x40000000)
325
+
326
+[{ "start": 0, "length": 1073741824, "depth": 1, "zero": true, "data": false},
327
+{ "start": 1073741824, "length": 7516192768, "depth": 0, "zero": true, "data": false}]
328
+
329
+=== preallocation=metadata ===
330
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=34359738368 cluster_size=65536 lazy_refcounts=off refcount_bits=16
331
+
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
333
+
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
+
156
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
157
index XXXXXXX..XXXXXXX 100644
450
index XXXXXXX..XXXXXXX 100644
158
--- a/tests/qemu-iotests/group
451
--- a/tests/qemu-iotests/group
159
+++ b/tests/qemu-iotests/group
452
+++ b/tests/qemu-iotests/group
160
@@ -XXX,XX +XXX,XX @@
453
@@ -XXX,XX +XXX,XX @@
161
248 rw auto quick
454
270 rw backing quick
162
249 rw auto quick
455
272 rw
163
252 rw auto backing quick
456
273 backing quick
164
+253 rw auto quick
457
+274 rw backing
458
277 rw quick
459
279 rw backing quick
460
280 rw migration quick
165
--
461
--
166
2.20.1
462
2.25.3
167
463
168
464
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.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
Sometimes we cannot tell which error message qemu will emit, and we do
7
Instead, try to forward the BDRV_REQ_ZERO_WRITE to the protocol driver,
4
not care. With this change, we can then just pass an array of all
8
and if the protocol driver can ensure that the new area reads as zeros,
5
possible messages to assert_qmp() and it will choose the right one.
9
we can skip setting the zero flag in the qcow2 layer.
6
10
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
Unfortunately, the same approach doesn't work for metadata
8
Reviewed-by: Alberto Garcia <berto@igalia.com>
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>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
19
---
11
tests/qemu-iotests/iotests.py | 18 ++++++++++++++++--
20
block/qcow2.c | 22 +++++++++++++++++++---
12
1 file changed, 16 insertions(+), 2 deletions(-)
21
tests/qemu-iotests/274.out | 4 ++--
22
2 files changed, 21 insertions(+), 5 deletions(-)
13
23
14
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
24
diff --git a/block/qcow2.c b/block/qcow2.c
15
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
16
--- a/tests/qemu-iotests/iotests.py
26
--- a/block/qcow2.c
17
+++ b/tests/qemu-iotests/iotests.py
27
+++ b/block/qcow2.c
18
@@ -XXX,XX +XXX,XX @@ class QMPTestCase(unittest.TestCase):
28
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
19
self.fail('path "%s" has value "%s"' % (path, str(result)))
29
/* Allocate the data area */
20
30
new_file_size = allocation_start +
21
def assert_qmp(self, d, path, value):
31
nb_new_data_clusters * s->cluster_size;
22
- '''Assert that the value for a specific path in a QMP dict matches'''
32
- /* Image file grows, so @exact does not matter */
23
+ '''Assert that the value for a specific path in a QMP dict
33
- ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, 0,
24
+ matches. When given a list of values, assert that any of
34
- errp);
25
+ them matches.'''
35
+ /*
26
+
36
+ * Image file grows, so @exact does not matter.
27
result = self.dictpath(d, path)
37
+ *
28
- self.assertEqual(result, value, 'values not equal "%s" and "%s"' % (str(result), str(value)))
38
+ * If we need to zero out the new area, try first whether the protocol
29
+
39
+ * driver can already take care of this.
30
+ # [] makes no sense as a list of valid values, so treat it as
40
+ */
31
+ # an actual single value.
41
+ if (flags & BDRV_REQ_ZERO_WRITE) {
32
+ if isinstance(value, list) and value != []:
42
+ ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc,
33
+ for v in value:
43
+ BDRV_REQ_ZERO_WRITE, NULL);
34
+ if result == v:
44
+ if (ret >= 0) {
35
+ return
45
+ flags &= ~BDRV_REQ_ZERO_WRITE;
36
+ self.fail('no match for "%s" in %s' % (str(result), str(value)))
46
+ }
37
+ else:
47
+ } else {
38
+ self.assertEqual(result, value,
48
+ ret = -1;
39
+ 'values not equal "%s" and "%s"'
49
+ }
40
+ % (str(result), str(value)))
50
+ if (ret < 0) {
41
51
+ ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, 0,
42
def assert_no_active_block_jobs(self):
52
+ errp);
43
result = self.vm.qmp('query-block-jobs')
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
44
--
79
--
45
2.20.1
80
2.25.3
46
81
47
82
diff view generated by jsdifflib
1
From: Klaus Birkelund Jensen <klaus@birkelund.eu>
1
From: Andrzej Jakowski <andrzej.jakowski@linux.intel.com>
2
2
3
`nvme_dma_read_prp` erronously used `qemu_iovec_*to*_buf` instead of
3
This patch introduces support for PMR that has been defined as part of NVMe 1.4
4
`qemu_iovec_*from*_buf` when the request involved the controller memory
4
spec. User can now specify a pmrdev option that should point to HostMemoryBackend.
5
buffer.
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.
6
8
7
Signed-off-by: Klaus Birkelund Jensen <klaus.jensen@cnexlabs.com>
9
Signed-off-by: Andrzej Jakowski <andrzej.jakowski@linux.intel.com>
8
Reviewed-by: Kenneth Heitke <kenneth.heitke@intel.com>
10
Reviewed-by: Klaus Jensen <k.jensen@samsung.com>
11
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Message-Id: <20200330164656.9348-1-andrzej.jakowski@linux.intel.com>
13
Reviewed-by: Keith Busch <kbusch@kernel.org>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
15
---
11
hw/block/nvme.c | 2 +-
16
hw/block/nvme.h | 2 +
12
1 file changed, 1 insertion(+), 1 deletion(-)
17
include/block/nvme.h | 172 +++++++++++++++++++++++++++++++++++++++++
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(-)
13
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;
14
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
15
index XXXXXXX..XXXXXXX 100644
248
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/block/nvme.c
249
--- a/hw/block/nvme.c
17
+++ b/hw/block/nvme.c
250
+++ b/hw/block/nvme.c
18
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_dma_read_prp(NvmeCtrl *n, uint8_t *ptr, uint32_t len,
251
@@ -XXX,XX +XXX,XX @@
19
}
252
* -drive file=<file>,if=none,id=<drive_id>
20
qemu_sglist_destroy(&qsg);
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]>
257
*
258
* Note cmb_size_mb denotes size of CMB in MB. CMB is assumed to be at
259
* 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>
268
*/
269
270
#include "qemu/osdep.h"
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)
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);
21
} else {
323
} else {
22
- if (unlikely(qemu_iovec_to_buf(&iov, 0, ptr, len) != len)) {
324
NVME_GUEST_ERR(nvme_ub_mmiord_invalid_ofs,
23
+ if (unlikely(qemu_iovec_from_buf(&iov, 0, ptr, len) != len)) {
325
@@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
24
trace_nvme_err_invalid_dma();
326
error_setg(errp, "serial property not set");
25
status = NVME_INVALID_FIELD | NVME_DNR;
327
return;
26
}
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);
410
}
411
412
static Property nvme_props[] = {
413
DEFINE_BLOCK_PROPERTIES(NvmeCtrl, conf),
414
+ DEFINE_PROP_LINK("pmrdev", NvmeCtrl, pmrdev, TYPE_MEMORY_BACKEND,
415
+ HostMemoryBackend *),
416
DEFINE_PROP_STRING("serial", NvmeCtrl, serial),
417
DEFINE_PROP_UINT32("cmb_size_mb", NvmeCtrl, cmb_size_mb, 0),
418
DEFINE_PROP_UINT32("num_queues", NvmeCtrl, num_queues, 64),
419
diff --git a/hw/block/Makefile.objs b/hw/block/Makefile.objs
420
index XXXXXXX..XXXXXXX 100644
421
--- a/hw/block/Makefile.objs
422
+++ b/hw/block/Makefile.objs
423
@@ -XXX,XX +XXX,XX @@ common-obj-$(CONFIG_PFLASH_CFI02) += pflash_cfi02.o
424
common-obj-$(CONFIG_XEN) += xen-block.o
425
common-obj-$(CONFIG_ECC) += ecc.o
426
common-obj-$(CONFIG_ONENAND) += onenand.o
427
-common-obj-$(CONFIG_NVME_PCI) += nvme.o
428
common-obj-$(CONFIG_SWIM) += swim.o
429
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""
27
--
452
--
28
2.20.1
453
2.25.3
29
454
30
455
diff view generated by jsdifflib
Deleted patch
1
Eventually, we want to make sure that all parents and all children of a
2
node are in the same AioContext as the node itself. This means that
3
changing the AioContext may fail because one of the other involved
4
parties (e.g. a guest device that was configured with an iothread)
5
cannot allow switching to a different AioContext.
6
1
7
Introduce a set of functions that allow to first check whether all
8
involved nodes can switch to a new context and only then do the actual
9
switch. The check recursively covers children and parents.
10
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
13
include/block/block.h | 8 ++++
14
include/block/block_int.h | 3 ++
15
block.c | 92 +++++++++++++++++++++++++++++++++++++++
16
3 files changed, 103 insertions(+)
17
18
diff --git a/include/block/block.h b/include/block/block.h
19
index XXXXXXX..XXXXXXX 100644
20
--- a/include/block/block.h
21
+++ b/include/block/block.h
22
@@ -XXX,XX +XXX,XX @@ void bdrv_coroutine_enter(BlockDriverState *bs, Coroutine *co);
23
* This function must be called with iothread lock held.
24
*/
25
void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context);
26
+int bdrv_try_set_aio_context(BlockDriverState *bs, AioContext *ctx,
27
+ Error **errp);
28
+int bdrv_child_try_set_aio_context(BlockDriverState *bs, AioContext *ctx,
29
+ BdrvChild *ignore_child, Error **errp);
30
+bool bdrv_child_can_set_aio_context(BdrvChild *c, AioContext *ctx,
31
+ GSList **ignore, Error **errp);
32
+bool bdrv_can_set_aio_context(BlockDriverState *bs, AioContext *ctx,
33
+ GSList **ignore, Error **errp);
34
int bdrv_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz);
35
int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo);
36
37
diff --git a/include/block/block_int.h b/include/block/block_int.h
38
index XXXXXXX..XXXXXXX 100644
39
--- a/include/block/block_int.h
40
+++ b/include/block/block_int.h
41
@@ -XXX,XX +XXX,XX @@ struct BdrvChildRole {
42
* can update its reference. */
43
int (*update_filename)(BdrvChild *child, BlockDriverState *new_base,
44
const char *filename, Error **errp);
45
+
46
+ bool (*can_set_aio_ctx)(BdrvChild *child, AioContext *ctx,
47
+ GSList **ignore, Error **errp);
48
};
49
50
extern const BdrvChildRole child_file;
51
diff --git a/block.c b/block.c
52
index XXXXXXX..XXXXXXX 100644
53
--- a/block.c
54
+++ b/block.c
55
@@ -XXX,XX +XXX,XX @@ static int bdrv_child_cb_inactivate(BdrvChild *child)
56
return 0;
57
}
58
59
+static bool bdrv_child_cb_can_set_aio_ctx(BdrvChild *child, AioContext *ctx,
60
+ GSList **ignore, Error **errp)
61
+{
62
+ BlockDriverState *bs = child->opaque;
63
+ return bdrv_can_set_aio_context(bs, ctx, ignore, errp);
64
+}
65
+
66
/*
67
* Returns the options and flags that a temporary snapshot should get, based on
68
* the originally requested flags (the originally requested image will have
69
@@ -XXX,XX +XXX,XX @@ const BdrvChildRole child_file = {
70
.attach = bdrv_child_cb_attach,
71
.detach = bdrv_child_cb_detach,
72
.inactivate = bdrv_child_cb_inactivate,
73
+ .can_set_aio_ctx = bdrv_child_cb_can_set_aio_ctx,
74
};
75
76
/*
77
@@ -XXX,XX +XXX,XX @@ const BdrvChildRole child_format = {
78
.attach = bdrv_child_cb_attach,
79
.detach = bdrv_child_cb_detach,
80
.inactivate = bdrv_child_cb_inactivate,
81
+ .can_set_aio_ctx = bdrv_child_cb_can_set_aio_ctx,
82
};
83
84
static void bdrv_backing_attach(BdrvChild *c)
85
@@ -XXX,XX +XXX,XX @@ const BdrvChildRole child_backing = {
86
.drained_end = bdrv_child_cb_drained_end,
87
.inactivate = bdrv_child_cb_inactivate,
88
.update_filename = bdrv_backing_update_filename,
89
+ .can_set_aio_ctx = bdrv_child_cb_can_set_aio_ctx,
90
};
91
92
static int bdrv_open_flags(BlockDriverState *bs, int flags)
93
@@ -XXX,XX +XXX,XX @@ void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
94
aio_context_release(new_context);
95
}
96
97
+static bool bdrv_parent_can_set_aio_context(BdrvChild *c, AioContext *ctx,
98
+ GSList **ignore, Error **errp)
99
+{
100
+ if (g_slist_find(*ignore, c)) {
101
+ return true;
102
+ }
103
+ *ignore = g_slist_prepend(*ignore, c);
104
+
105
+ /* A BdrvChildRole that doesn't handle AioContext changes cannot
106
+ * tolerate any AioContext changes */
107
+ if (!c->role->can_set_aio_ctx) {
108
+ char *user = bdrv_child_user_desc(c);
109
+ error_setg(errp, "Changing iothreads is not supported by %s", user);
110
+ g_free(user);
111
+ return false;
112
+ }
113
+ if (!c->role->can_set_aio_ctx(c, ctx, ignore, errp)) {
114
+ assert(!errp || *errp);
115
+ return false;
116
+ }
117
+ return true;
118
+}
119
+
120
+bool bdrv_child_can_set_aio_context(BdrvChild *c, AioContext *ctx,
121
+ GSList **ignore, Error **errp)
122
+{
123
+ if (g_slist_find(*ignore, c)) {
124
+ return true;
125
+ }
126
+ *ignore = g_slist_prepend(*ignore, c);
127
+ return bdrv_can_set_aio_context(c->bs, ctx, ignore, errp);
128
+}
129
+
130
+/* @ignore will accumulate all visited BdrvChild object. The caller is
131
+ * responsible for freeing the list afterwards. */
132
+bool bdrv_can_set_aio_context(BlockDriverState *bs, AioContext *ctx,
133
+ GSList **ignore, Error **errp)
134
+{
135
+ BdrvChild *c;
136
+
137
+ if (bdrv_get_aio_context(bs) == ctx) {
138
+ return true;
139
+ }
140
+
141
+ QLIST_FOREACH(c, &bs->parents, next_parent) {
142
+ if (!bdrv_parent_can_set_aio_context(c, ctx, ignore, errp)) {
143
+ return false;
144
+ }
145
+ }
146
+ QLIST_FOREACH(c, &bs->children, next) {
147
+ if (!bdrv_child_can_set_aio_context(c, ctx, ignore, errp)) {
148
+ return false;
149
+ }
150
+ }
151
+
152
+ return true;
153
+}
154
+
155
+int bdrv_child_try_set_aio_context(BlockDriverState *bs, AioContext *ctx,
156
+ BdrvChild *ignore_child, Error **errp)
157
+{
158
+ GSList *ignore;
159
+ bool ret;
160
+
161
+ ignore = ignore_child ? g_slist_prepend(NULL, ignore_child) : NULL;
162
+ ret = bdrv_can_set_aio_context(bs, ctx, &ignore, errp);
163
+ g_slist_free(ignore);
164
+
165
+ if (!ret) {
166
+ return -EPERM;
167
+ }
168
+
169
+ bdrv_set_aio_context(bs, ctx);
170
+ return 0;
171
+}
172
+
173
+int bdrv_try_set_aio_context(BlockDriverState *bs, AioContext *ctx,
174
+ Error **errp)
175
+{
176
+ return bdrv_child_try_set_aio_context(bs, ctx, NULL, errp);
177
+}
178
+
179
void bdrv_add_aio_context_notifier(BlockDriverState *bs,
180
void (*attached_aio_context)(AioContext *new_context, void *opaque),
181
void (*detach_aio_context)(void *opaque), void *opaque)
182
--
183
2.20.1
184
185
diff view generated by jsdifflib
Deleted patch
1
Since commit b97511c7bc8, there is no reason for block drivers any more
2
to call these functions (see the function comment in block_int.h). They
3
are now just internal helper functions for bdrv_set_aio_context()
4
and can be made static.
5
1
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
8
include/block/block_int.h | 21 ---------------------
9
block.c | 6 +++---
10
2 files changed, 3 insertions(+), 24 deletions(-)
11
12
diff --git a/include/block/block_int.h b/include/block/block_int.h
13
index XXXXXXX..XXXXXXX 100644
14
--- a/include/block/block_int.h
15
+++ b/include/block/block_int.h
16
@@ -XXX,XX +XXX,XX @@ void bdrv_parse_filename_strip_prefix(const char *filename, const char *prefix,
17
void bdrv_add_before_write_notifier(BlockDriverState *bs,
18
NotifierWithReturn *notifier);
19
20
-/**
21
- * bdrv_detach_aio_context:
22
- *
23
- * May be called from .bdrv_detach_aio_context() to detach children from the
24
- * current #AioContext. This is only needed by block drivers that manage their
25
- * own children. Both ->file and ->backing are automatically handled and
26
- * block drivers should not call this function on them explicitly.
27
- */
28
-void bdrv_detach_aio_context(BlockDriverState *bs);
29
-
30
-/**
31
- * bdrv_attach_aio_context:
32
- *
33
- * May be called from .bdrv_attach_aio_context() to attach children to the new
34
- * #AioContext. This is only needed by block drivers that manage their own
35
- * children. Both ->file and ->backing are automatically handled and block
36
- * drivers should not call this function on them explicitly.
37
- */
38
-void bdrv_attach_aio_context(BlockDriverState *bs,
39
- AioContext *new_context);
40
-
41
/**
42
* bdrv_add_aio_context_notifier:
43
*
44
diff --git a/block.c b/block.c
45
index XXXXXXX..XXXXXXX 100644
46
--- a/block.c
47
+++ b/block.c
48
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_remove_aio_context_notifier(BdrvAioNotifier *ban)
49
g_free(ban);
50
}
51
52
-void bdrv_detach_aio_context(BlockDriverState *bs)
53
+static void bdrv_detach_aio_context(BlockDriverState *bs)
54
{
55
BdrvAioNotifier *baf, *baf_tmp;
56
BdrvChild *child;
57
@@ -XXX,XX +XXX,XX @@ void bdrv_detach_aio_context(BlockDriverState *bs)
58
bs->aio_context = NULL;
59
}
60
61
-void bdrv_attach_aio_context(BlockDriverState *bs,
62
- AioContext *new_context)
63
+static void bdrv_attach_aio_context(BlockDriverState *bs,
64
+ AioContext *new_context)
65
{
66
BdrvAioNotifier *ban, *ban_tmp;
67
BdrvChild *child;
68
--
69
2.20.1
70
71
diff view generated by jsdifflib
Deleted patch
1
Instead of having two recursions, in bdrv_attach_aio_context() and in
2
bdrv_detach_aio_context(), just having one recursion is enough. Said
3
functions are only about a single node now.
4
1
5
It is important that the recursion doesn't happen between detaching and
6
attaching a context to the current node because the nested call will
7
drain the node, and draining with a NULL context would segfault.
8
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
block.c | 15 +++++++--------
12
1 file changed, 7 insertions(+), 8 deletions(-)
13
14
diff --git a/block.c b/block.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/block.c
17
+++ b/block.c
18
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_remove_aio_context_notifier(BdrvAioNotifier *ban)
19
static void bdrv_detach_aio_context(BlockDriverState *bs)
20
{
21
BdrvAioNotifier *baf, *baf_tmp;
22
- BdrvChild *child;
23
24
assert(!bs->walking_aio_notifiers);
25
bs->walking_aio_notifiers = true;
26
@@ -XXX,XX +XXX,XX @@ static void bdrv_detach_aio_context(BlockDriverState *bs)
27
if (bs->drv && bs->drv->bdrv_detach_aio_context) {
28
bs->drv->bdrv_detach_aio_context(bs);
29
}
30
- QLIST_FOREACH(child, &bs->children, next) {
31
- bdrv_detach_aio_context(child->bs);
32
- }
33
34
if (bs->quiesce_counter) {
35
aio_enable_external(bs->aio_context);
36
@@ -XXX,XX +XXX,XX @@ static void bdrv_attach_aio_context(BlockDriverState *bs,
37
AioContext *new_context)
38
{
39
BdrvAioNotifier *ban, *ban_tmp;
40
- BdrvChild *child;
41
42
if (bs->quiesce_counter) {
43
aio_disable_external(new_context);
44
@@ -XXX,XX +XXX,XX @@ static void bdrv_attach_aio_context(BlockDriverState *bs,
45
46
bs->aio_context = new_context;
47
48
- QLIST_FOREACH(child, &bs->children, next) {
49
- bdrv_attach_aio_context(child->bs, new_context);
50
- }
51
if (bs->drv && bs->drv->bdrv_attach_aio_context) {
52
bs->drv->bdrv_attach_aio_context(bs, new_context);
53
}
54
@@ -XXX,XX +XXX,XX @@ static void bdrv_attach_aio_context(BlockDriverState *bs,
55
* the same as the current context of bs). */
56
void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
57
{
58
+ BdrvChild *child;
59
+
60
if (bdrv_get_aio_context(bs) == new_context) {
61
return;
62
}
63
64
bdrv_drained_begin(bs);
65
+
66
+ QLIST_FOREACH(child, &bs->children, next) {
67
+ bdrv_set_aio_context(child->bs, new_context);
68
+ }
69
+
70
bdrv_detach_aio_context(bs);
71
72
/* This function executes in the old AioContext so acquire the new one in
73
--
74
2.20.1
75
76
diff view generated by jsdifflib
1
Block jobs require that all of the nodes the job is using are in the
1
The QMP handler qmp_object_add() and the implementation of --object in
2
same AioContext. Therefore all BdrvChild objects of the job propagate
2
qemu-storage-daemon can share most of the code. Currently,
3
.(can_)set_aio_context to all other job nodes, so that the switch is
3
qemu-storage-daemon calls qmp_object_add(), but this is not correct
4
checked and performed consistently even if both nodes are in different
4
because different visitors need to be used.
5
subtrees.
5
6
As a first step towards a fix, make qmp_object_add() a wrapper around a
7
new function user_creatable_add_dict() that can get an additional
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().
6
11
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
13
---
9
block/backup.c | 8 --------
14
include/qom/object_interfaces.h | 12 ++++++++++++
10
block/mirror.c | 10 +---------
15
qom/object_interfaces.c | 27 +++++++++++++++++++++++++++
11
blockjob.c | 34 ++++++++++++++++++++++++++++++++++
16
qom/qom-qmp-cmds.c | 24 +-----------------------
12
3 files changed, 35 insertions(+), 17 deletions(-)
17
3 files changed, 40 insertions(+), 23 deletions(-)
13
18
14
diff --git a/block/backup.c b/block/backup.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/backup.c
21
--- a/include/qom/object_interfaces.h
17
+++ b/block/backup.c
22
+++ b/include/qom/object_interfaces.h
18
@@ -XXX,XX +XXX,XX @@ static void backup_clean(Job *job)
23
@@ -XXX,XX +XXX,XX @@ Object *user_creatable_add_type(const char *type, const char *id,
19
s->target = NULL;
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
+
39
/**
40
* user_creatable_add_opts:
41
* @opts: the object definition
42
diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c
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;
20
}
56
}
21
57
22
-static void backup_attached_aio_context(BlockJob *job, AioContext *aio_context)
58
+void user_creatable_add_dict(QDict *qdict, Error **errp)
23
-{
59
+{
24
- BackupBlockJob *s = container_of(job, BackupBlockJob, common);
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)
86
{
87
diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c
88
index XXXXXXX..XXXXXXX 100644
89
--- a/qom/qom-qmp-cmds.c
90
+++ b/qom/qom-qmp-cmds.c
91
@@ -XXX,XX +XXX,XX @@
92
#include "qapi/qapi-commands-qom.h"
93
#include "qapi/qmp/qdict.h"
94
#include "qapi/qmp/qerror.h"
95
-#include "qapi/qobject-input-visitor.h"
96
#include "qemu/cutils.h"
97
#include "qom/object_interfaces.h"
98
#include "qom/qom-qobject.h"
99
@@ -XXX,XX +XXX,XX @@ void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp)
100
{
101
QObject *props;
102
QDict *pdict;
103
- Visitor *v;
104
- Object *obj;
105
- g_autofree char *type = NULL;
106
- g_autofree char *id = NULL;
25
-
107
-
26
- blk_set_aio_context(s->target, aio_context);
108
- type = g_strdup(qdict_get_try_str(qdict, "qom-type"));
27
-}
109
- if (!type) {
110
- error_setg(errp, QERR_MISSING_PARAMETER, "qom-type");
111
- return;
112
- }
113
- qdict_del(qdict, "qom-type");
28
-
114
-
29
void backup_do_checkpoint(BlockJob *job, Error **errp)
115
- id = g_strdup(qdict_get_try_str(qdict, "id"));
30
{
116
- if (!id) {
31
BackupBlockJob *backup_job = container_of(job, BackupBlockJob, common);
117
- error_setg(errp, QERR_MISSING_PARAMETER, "id");
32
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver backup_job_driver = {
118
- return;
33
.abort = backup_abort,
119
- }
34
.clean = backup_clean,
120
- qdict_del(qdict, "id");
35
},
121
36
- .attached_aio_context = backup_attached_aio_context,
122
props = qdict_get(qdict, "props");
37
.drain = backup_drain,
123
if (props) {
38
};
124
@@ -XXX,XX +XXX,XX @@ void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp)
39
125
qobject_unref(pdict);
40
diff --git a/block/mirror.c b/block/mirror.c
126
}
41
index XXXXXXX..XXXXXXX 100644
127
42
--- a/block/mirror.c
128
- v = qobject_input_visitor_new(QOBJECT(qdict));
43
+++ b/block/mirror.c
129
- obj = user_creatable_add_type(type, id, qdict, v, errp);
44
@@ -XXX,XX +XXX,XX @@ static bool mirror_drained_poll(BlockJob *job)
130
- visit_free(v);
45
return !!s->in_flight;
131
- object_unref(obj);
132
+ user_creatable_add_dict(qdict, errp);
46
}
133
}
47
134
48
-static void mirror_attached_aio_context(BlockJob *job, AioContext *new_context)
135
void qmp_object_del(const char *id, Error **errp)
49
-{
50
- MirrorBlockJob *s = container_of(job, MirrorBlockJob, common);
51
-
52
- blk_set_aio_context(s->target, new_context);
53
-}
54
-
55
static void mirror_drain(BlockJob *job)
56
{
57
MirrorBlockJob *s = container_of(job, MirrorBlockJob, common);
58
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver mirror_job_driver = {
59
.complete = mirror_complete,
60
},
61
.drained_poll = mirror_drained_poll,
62
- .attached_aio_context = mirror_attached_aio_context,
63
.drain = mirror_drain,
64
};
65
66
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver commit_active_job_driver = {
67
.complete = mirror_complete,
68
},
69
.drained_poll = mirror_drained_poll,
70
- .attached_aio_context = mirror_attached_aio_context,
71
.drain = mirror_drain,
72
};
73
74
@@ -XXX,XX +XXX,XX @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
75
* ensure that. */
76
blk_set_force_allow_inactivate(s->target);
77
}
78
+ blk_set_allow_aio_context_change(s->target, true);
79
80
s->replaces = g_strdup(replaces);
81
s->on_source_error = on_source_error;
82
diff --git a/blockjob.c b/blockjob.c
83
index XXXXXXX..XXXXXXX 100644
84
--- a/blockjob.c
85
+++ b/blockjob.c
86
@@ -XXX,XX +XXX,XX @@ static void child_job_drained_end(BdrvChild *c)
87
job_resume(&job->job);
88
}
89
90
+static bool child_job_can_set_aio_ctx(BdrvChild *c, AioContext *ctx,
91
+ GSList **ignore, Error **errp)
92
+{
93
+ BlockJob *job = c->opaque;
94
+ GSList *l;
95
+
96
+ for (l = job->nodes; l; l = l->next) {
97
+ BdrvChild *sibling = l->data;
98
+ if (!bdrv_child_can_set_aio_context(sibling, ctx, ignore, errp)) {
99
+ return false;
100
+ }
101
+ }
102
+ return true;
103
+}
104
+
105
+static void child_job_set_aio_ctx(BdrvChild *c, AioContext *ctx,
106
+ GSList **ignore)
107
+{
108
+ BlockJob *job = c->opaque;
109
+ GSList *l;
110
+
111
+ for (l = job->nodes; l; l = l->next) {
112
+ BdrvChild *sibling = l->data;
113
+ if (g_slist_find(*ignore, sibling)) {
114
+ continue;
115
+ }
116
+ *ignore = g_slist_prepend(*ignore, sibling);
117
+ bdrv_set_aio_context_ignore(sibling->bs, ctx, ignore);
118
+ }
119
+}
120
+
121
static const BdrvChildRole child_job = {
122
.get_parent_desc = child_job_get_parent_desc,
123
.drained_begin = child_job_drained_begin,
124
.drained_poll = child_job_drained_poll,
125
.drained_end = child_job_drained_end,
126
+ .can_set_aio_ctx = child_job_can_set_aio_ctx,
127
+ .set_aio_ctx = child_job_set_aio_ctx,
128
.stay_at_node = true,
129
};
130
131
@@ -XXX,XX +XXX,XX @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
132
133
blk_add_aio_context_notifier(blk, block_job_attached_aio_context,
134
block_job_detach_aio_context, job);
135
+ blk_set_allow_aio_context_change(blk, true);
136
137
/* Only set speed when necessary to avoid NotSupported error */
138
if (speed != 0) {
139
--
136
--
140
2.20.1
137
2.25.3
141
138
142
139
diff view generated by jsdifflib
1
All block nodes and users in any connected component of the block graph
1
After processing the option string with the keyval parser, we get a
2
must be in the same AioContext, so changing the AioContext of one node
2
QDict that contains only strings. This QDict must be fed to a keyval
3
must not only change all of its children, but all of its parents (and
3
visitor which converts the strings into the right data types.
4
in turn their children etc.) as well.
5
4
5
qmp_object_add(), however, uses the normal QObject input visitor, which
6
expects a QDict where all properties already have the QType that matches
7
the data type required by the QOM object type.
8
9
Change the --object implementation in qemu-storage-daemon so that it
10
doesn't call qmp_object_add(), but calls user_creatable_add_dict()
11
directly instead and pass it a new keyval boolean that decides which
12
visitor must be used.
13
14
Reported-by: Coiby Xu <coiby.xu@gmail.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
16
---
8
include/block/block.h | 2 ++
17
include/qom/object_interfaces.h | 6 +++++-
9
include/block/block_int.h | 1 +
18
qemu-storage-daemon.c | 4 +---
10
block.c | 48 ++++++++++++++++++++++++++++++++++-----
19
qom/object_interfaces.c | 8 ++++++--
11
3 files changed, 45 insertions(+), 6 deletions(-)
20
qom/qom-qmp-cmds.c | 2 +-
21
4 files changed, 13 insertions(+), 7 deletions(-)
12
22
13
diff --git a/include/block/block.h b/include/block/block.h
23
diff --git a/include/qom/object_interfaces.h b/include/qom/object_interfaces.h
14
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
15
--- a/include/block/block.h
25
--- a/include/qom/object_interfaces.h
16
+++ b/include/block/block.h
26
+++ b/include/qom/object_interfaces.h
17
@@ -XXX,XX +XXX,XX @@ void bdrv_coroutine_enter(BlockDriverState *bs, Coroutine *co);
27
@@ -XXX,XX +XXX,XX @@ Object *user_creatable_add_type(const char *type, const char *id,
18
* This function must be called with iothread lock held.
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.
19
*/
41
*/
20
void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context);
42
-void user_creatable_add_dict(QDict *qdict, Error **errp);
21
+void bdrv_set_aio_context_ignore(BlockDriverState *bs,
43
+void user_creatable_add_dict(QDict *qdict, bool keyval, Error **errp);
22
+ AioContext *new_context, GSList **ignore);
44
23
int bdrv_try_set_aio_context(BlockDriverState *bs, AioContext *ctx,
45
/**
24
Error **errp);
46
* user_creatable_add_opts:
25
int bdrv_child_try_set_aio_context(BlockDriverState *bs, AioContext *ctx,
47
diff --git a/qemu-storage-daemon.c b/qemu-storage-daemon.c
26
diff --git a/include/block/block_int.h b/include/block/block_int.h
27
index XXXXXXX..XXXXXXX 100644
48
index XXXXXXX..XXXXXXX 100644
28
--- a/include/block/block_int.h
49
--- a/qemu-storage-daemon.c
29
+++ b/include/block/block_int.h
50
+++ b/qemu-storage-daemon.c
30
@@ -XXX,XX +XXX,XX @@ struct BdrvChildRole {
51
@@ -XXX,XX +XXX,XX @@ static void process_options(int argc, char *argv[])
31
52
QemuOpts *opts;
32
bool (*can_set_aio_ctx)(BdrvChild *child, AioContext *ctx,
53
const char *type;
33
GSList **ignore, Error **errp);
54
QDict *args;
34
+ void (*set_aio_ctx)(BdrvChild *child, AioContext *ctx, GSList **ignore);
55
- QObject *ret_data = NULL;
35
};
56
36
57
/* FIXME The keyval parser rejects 'help' arguments, so we must
37
extern const BdrvChildRole child_file;
58
* unconditionall try QemuOpts first. */
38
diff --git a/block.c b/block.c
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
39
index XXXXXXX..XXXXXXX 100644
71
index XXXXXXX..XXXXXXX 100644
40
--- a/block.c
72
--- a/qom/object_interfaces.c
41
+++ b/block.c
73
+++ b/qom/object_interfaces.c
42
@@ -XXX,XX +XXX,XX @@ static bool bdrv_child_cb_can_set_aio_ctx(BdrvChild *child, AioContext *ctx,
74
@@ -XXX,XX +XXX,XX @@ out:
43
return bdrv_can_set_aio_context(bs, ctx, ignore, errp);
75
return obj;
44
}
76
}
45
77
46
+static void bdrv_child_cb_set_aio_ctx(BdrvChild *child, AioContext *ctx,
78
-void user_creatable_add_dict(QDict *qdict, Error **errp)
47
+ GSList **ignore)
79
+void user_creatable_add_dict(QDict *qdict, bool keyval, Error **errp)
48
+{
80
{
49
+ BlockDriverState *bs = child->opaque;
81
Visitor *v;
50
+ return bdrv_set_aio_context_ignore(bs, ctx, ignore);
82
Object *obj;
51
+}
83
@@ -XXX,XX +XXX,XX @@ void user_creatable_add_dict(QDict *qdict, Error **errp)
52
+
84
}
53
/*
85
qdict_del(qdict, "id");
54
* Returns the options and flags that a temporary snapshot should get, based on
86
55
* the originally requested flags (the originally requested image will have
87
- v = qobject_input_visitor_new(QOBJECT(qdict));
56
@@ -XXX,XX +XXX,XX @@ const BdrvChildRole child_file = {
88
+ if (keyval) {
57
.detach = bdrv_child_cb_detach,
89
+ v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
58
.inactivate = bdrv_child_cb_inactivate,
90
+ } else {
59
.can_set_aio_ctx = bdrv_child_cb_can_set_aio_ctx,
91
+ v = qobject_input_visitor_new(QOBJECT(qdict));
60
+ .set_aio_ctx = bdrv_child_cb_set_aio_ctx,
92
+ }
61
};
93
obj = user_creatable_add_type(type, id, qdict, v, errp);
62
94
visit_free(v);
63
/*
95
object_unref(obj);
64
@@ -XXX,XX +XXX,XX @@ const BdrvChildRole child_format = {
96
diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c
65
.detach = bdrv_child_cb_detach,
97
index XXXXXXX..XXXXXXX 100644
66
.inactivate = bdrv_child_cb_inactivate,
98
--- a/qom/qom-qmp-cmds.c
67
.can_set_aio_ctx = bdrv_child_cb_can_set_aio_ctx,
99
+++ b/qom/qom-qmp-cmds.c
68
+ .set_aio_ctx = bdrv_child_cb_set_aio_ctx,
100
@@ -XXX,XX +XXX,XX @@ void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp)
69
};
101
qobject_unref(pdict);
70
102
}
71
static void bdrv_backing_attach(BdrvChild *c)
103
72
@@ -XXX,XX +XXX,XX @@ const BdrvChildRole child_backing = {
104
- user_creatable_add_dict(qdict, errp);
73
.inactivate = bdrv_child_cb_inactivate,
105
+ user_creatable_add_dict(qdict, false, errp);
74
.update_filename = bdrv_backing_update_filename,
75
.can_set_aio_ctx = bdrv_child_cb_can_set_aio_ctx,
76
+ .set_aio_ctx = bdrv_child_cb_set_aio_ctx,
77
};
78
79
static int bdrv_open_flags(BlockDriverState *bs, int flags)
80
@@ -XXX,XX +XXX,XX @@ static void bdrv_attach_aio_context(BlockDriverState *bs,
81
bs->walking_aio_notifiers = false;
82
}
106
}
83
107
84
-/* The caller must own the AioContext lock for the old AioContext of bs, but it
108
void qmp_object_del(const char *id, Error **errp)
85
- * must not own the AioContext lock for new_context (unless new_context is
86
- * the same as the current context of bs). */
87
-void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
88
+/* @ignore will accumulate all visited BdrvChild object. The caller is
89
+ * responsible for freeing the list afterwards. */
90
+void bdrv_set_aio_context_ignore(BlockDriverState *bs,
91
+ AioContext *new_context, GSList **ignore)
92
{
93
BdrvChild *child;
94
95
@@ -XXX,XX +XXX,XX @@ void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
96
bdrv_drained_begin(bs);
97
98
QLIST_FOREACH(child, &bs->children, next) {
99
- bdrv_set_aio_context(child->bs, new_context);
100
+ if (g_slist_find(*ignore, child)) {
101
+ continue;
102
+ }
103
+ *ignore = g_slist_prepend(*ignore, child);
104
+ bdrv_set_aio_context_ignore(child->bs, new_context, ignore);
105
+ }
106
+ QLIST_FOREACH(child, &bs->parents, next_parent) {
107
+ if (g_slist_find(*ignore, child)) {
108
+ continue;
109
+ }
110
+ if (child->role->set_aio_ctx) {
111
+ *ignore = g_slist_prepend(*ignore, child);
112
+ child->role->set_aio_ctx(child, new_context, ignore);
113
+ }
114
}
115
116
bdrv_detach_aio_context(bs);
117
@@ -XXX,XX +XXX,XX @@ void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
118
aio_context_release(new_context);
119
}
120
121
+/* The caller must own the AioContext lock for the old AioContext of bs, but it
122
+ * must not own the AioContext lock for new_context (unless new_context is
123
+ * the same as the current context of bs). */
124
+void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
125
+{
126
+ GSList *ignore_list = NULL;
127
+ bdrv_set_aio_context_ignore(bs, new_context, &ignore_list);
128
+ g_slist_free(ignore_list);
129
+}
130
+
131
static bool bdrv_parent_can_set_aio_context(BdrvChild *c, AioContext *ctx,
132
GSList **ignore, Error **errp)
133
{
134
@@ -XXX,XX +XXX,XX @@ int bdrv_child_try_set_aio_context(BlockDriverState *bs, AioContext *ctx,
135
return -EPERM;
136
}
137
138
- bdrv_set_aio_context(bs, ctx);
139
+ ignore = ignore_child ? g_slist_prepend(NULL, ignore_child) : NULL;
140
+ bdrv_set_aio_context_ignore(bs, ctx, &ignore);
141
+ g_slist_free(ignore);
142
+
143
return 0;
144
}
145
146
--
109
--
147
2.20.1
110
2.25.3
148
111
149
112
diff view generated by jsdifflib
Deleted patch
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
---
3
tests/test-block-iothread.c | 131 ++++++++++++++++++++++++++++++++++++
4
1 file changed, 131 insertions(+)
5
1
6
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
7
index XXXXXXX..XXXXXXX 100644
8
--- a/tests/test-block-iothread.c
9
+++ b/tests/test-block-iothread.c
10
@@ -XXX,XX +XXX,XX @@
11
#include "block/blockjob_int.h"
12
#include "sysemu/block-backend.h"
13
#include "qapi/error.h"
14
+#include "qapi/qmp/qdict.h"
15
#include "iothread.h"
16
17
static int coroutine_fn bdrv_test_co_prwv(BlockDriverState *bs,
18
@@ -XXX,XX +XXX,XX @@ static void test_attach_blockjob(void)
19
blk_unref(blk);
20
}
21
22
+/*
23
+ * Test that changing the AioContext for one node in a tree (here through blk)
24
+ * changes all other nodes as well:
25
+ *
26
+ * blk
27
+ * |
28
+ * | bs_verify [blkverify]
29
+ * | / \
30
+ * | / \
31
+ * bs_a [bdrv_test] bs_b [bdrv_test]
32
+ *
33
+ */
34
+static void test_propagate_basic(void)
35
+{
36
+ IOThread *iothread = iothread_new();
37
+ AioContext *ctx = iothread_get_aio_context(iothread);
38
+ BlockBackend *blk;
39
+ BlockDriverState *bs_a, *bs_b, *bs_verify;
40
+ QDict *options;
41
+
42
+ /* Create bs_a and its BlockBackend */
43
+ blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
44
+ bs_a = bdrv_new_open_driver(&bdrv_test, "bs_a", BDRV_O_RDWR, &error_abort);
45
+ blk_insert_bs(blk, bs_a, &error_abort);
46
+
47
+ /* Create bs_b */
48
+ bs_b = bdrv_new_open_driver(&bdrv_test, "bs_b", BDRV_O_RDWR, &error_abort);
49
+
50
+ /* Create blkverify filter that references both bs_a and bs_b */
51
+ options = qdict_new();
52
+ qdict_put_str(options, "driver", "blkverify");
53
+ qdict_put_str(options, "test", "bs_a");
54
+ qdict_put_str(options, "raw", "bs_b");
55
+
56
+ bs_verify = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
57
+
58
+ /* Switch the AioContext */
59
+ blk_set_aio_context(blk, ctx);
60
+ g_assert(blk_get_aio_context(blk) == ctx);
61
+ g_assert(bdrv_get_aio_context(bs_a) == ctx);
62
+ g_assert(bdrv_get_aio_context(bs_verify) == ctx);
63
+ g_assert(bdrv_get_aio_context(bs_b) == ctx);
64
+
65
+ /* Switch the AioContext back */
66
+ ctx = qemu_get_aio_context();
67
+ blk_set_aio_context(blk, ctx);
68
+ g_assert(blk_get_aio_context(blk) == ctx);
69
+ g_assert(bdrv_get_aio_context(bs_a) == ctx);
70
+ g_assert(bdrv_get_aio_context(bs_verify) == ctx);
71
+ g_assert(bdrv_get_aio_context(bs_b) == ctx);
72
+
73
+ bdrv_unref(bs_verify);
74
+ bdrv_unref(bs_b);
75
+ bdrv_unref(bs_a);
76
+ blk_unref(blk);
77
+}
78
+
79
+/*
80
+ * Test that diamonds in the graph don't lead to endless recursion:
81
+ *
82
+ * blk
83
+ * |
84
+ * bs_verify [blkverify]
85
+ * / \
86
+ * / \
87
+ * bs_b [raw] bs_c[raw]
88
+ * \ /
89
+ * \ /
90
+ * bs_a [bdrv_test]
91
+ */
92
+static void test_propagate_diamond(void)
93
+{
94
+ IOThread *iothread = iothread_new();
95
+ AioContext *ctx = iothread_get_aio_context(iothread);
96
+ BlockBackend *blk;
97
+ BlockDriverState *bs_a, *bs_b, *bs_c, *bs_verify;
98
+ QDict *options;
99
+
100
+ /* Create bs_a */
101
+ bs_a = bdrv_new_open_driver(&bdrv_test, "bs_a", BDRV_O_RDWR, &error_abort);
102
+
103
+ /* Create bs_b and bc_c */
104
+ options = qdict_new();
105
+ qdict_put_str(options, "driver", "raw");
106
+ qdict_put_str(options, "file", "bs_a");
107
+ qdict_put_str(options, "node-name", "bs_b");
108
+ bs_b = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
109
+
110
+ options = qdict_new();
111
+ qdict_put_str(options, "driver", "raw");
112
+ qdict_put_str(options, "file", "bs_a");
113
+ qdict_put_str(options, "node-name", "bs_c");
114
+ bs_c = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
115
+
116
+ /* Create blkverify filter that references both bs_b and bs_c */
117
+ options = qdict_new();
118
+ qdict_put_str(options, "driver", "blkverify");
119
+ qdict_put_str(options, "test", "bs_b");
120
+ qdict_put_str(options, "raw", "bs_c");
121
+
122
+ bs_verify = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
123
+ blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
124
+ blk_insert_bs(blk, bs_verify, &error_abort);
125
+
126
+ /* Switch the AioContext */
127
+ blk_set_aio_context(blk, ctx);
128
+ g_assert(blk_get_aio_context(blk) == ctx);
129
+ g_assert(bdrv_get_aio_context(bs_verify) == ctx);
130
+ g_assert(bdrv_get_aio_context(bs_a) == ctx);
131
+ g_assert(bdrv_get_aio_context(bs_b) == ctx);
132
+ g_assert(bdrv_get_aio_context(bs_c) == ctx);
133
+
134
+ /* Switch the AioContext back */
135
+ ctx = qemu_get_aio_context();
136
+ blk_set_aio_context(blk, ctx);
137
+ g_assert(blk_get_aio_context(blk) == ctx);
138
+ g_assert(bdrv_get_aio_context(bs_verify) == ctx);
139
+ g_assert(bdrv_get_aio_context(bs_a) == ctx);
140
+ g_assert(bdrv_get_aio_context(bs_b) == ctx);
141
+ g_assert(bdrv_get_aio_context(bs_c) == ctx);
142
+
143
+ blk_unref(blk);
144
+ bdrv_unref(bs_verify);
145
+ bdrv_unref(bs_c);
146
+ bdrv_unref(bs_b);
147
+ bdrv_unref(bs_a);
148
+}
149
+
150
int main(int argc, char **argv)
151
{
152
int i;
153
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
154
}
155
156
g_test_add_func("/attach/blockjob", test_attach_blockjob);
157
+ g_test_add_func("/propagate/basic", test_propagate_basic);
158
+ g_test_add_func("/propagate/diamond", test_propagate_diamond);
159
160
return g_test_run();
161
}
162
--
163
2.20.1
164
165
diff view generated by jsdifflib
Deleted patch
1
The notifiers made sure that the job is quiesced and that the
2
job->aio_context field is updated. The first part is unnecessary today
3
since bdrv_set_aio_context_ignore() drains the block node, and this
4
means drainig the block job, too. The second part can be done in the
5
.set_aio_ctx callback of the block job BdrvChildRole.
6
1
7
The notifiers were problematic because they poll the AioContext while
8
the graph is in an inconsistent state with some nodes already in the new
9
context, but others still in the old context. So removing the notifiers
10
not only simplifies the code, but actually makes the code safer.
11
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
14
blockjob.c | 43 ++-----------------------------------------
15
1 file changed, 2 insertions(+), 41 deletions(-)
16
17
diff --git a/blockjob.c b/blockjob.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/blockjob.c
20
+++ b/blockjob.c
21
@@ -XXX,XX +XXX,XX @@ BlockJob *block_job_get(const char *id)
22
}
23
}
24
25
-static void block_job_attached_aio_context(AioContext *new_context,
26
- void *opaque);
27
-static void block_job_detach_aio_context(void *opaque);
28
-
29
void block_job_free(Job *job)
30
{
31
BlockJob *bjob = container_of(job, BlockJob, job);
32
@@ -XXX,XX +XXX,XX @@ void block_job_free(Job *job)
33
34
bs->job = NULL;
35
block_job_remove_all_bdrv(bjob);
36
- blk_remove_aio_context_notifier(bjob->blk,
37
- block_job_attached_aio_context,
38
- block_job_detach_aio_context, bjob);
39
blk_unref(bjob->blk);
40
error_free(bjob->blocker);
41
}
42
43
-static void block_job_attached_aio_context(AioContext *new_context,
44
- void *opaque)
45
-{
46
- BlockJob *job = opaque;
47
- const JobDriver *drv = job->job.driver;
48
- BlockJobDriver *bjdrv = container_of(drv, BlockJobDriver, job_driver);
49
-
50
- job->job.aio_context = new_context;
51
- if (bjdrv->attached_aio_context) {
52
- bjdrv->attached_aio_context(job, new_context);
53
- }
54
-
55
- job_resume(&job->job);
56
-}
57
-
58
void block_job_drain(Job *job)
59
{
60
BlockJob *bjob = container_of(job, BlockJob, job);
61
@@ -XXX,XX +XXX,XX @@ void block_job_drain(Job *job)
62
}
63
}
64
65
-static void block_job_detach_aio_context(void *opaque)
66
-{
67
- BlockJob *job = opaque;
68
-
69
- /* In case the job terminates during aio_poll()... */
70
- job_ref(&job->job);
71
-
72
- job_pause(&job->job);
73
-
74
- while (!job->job.paused && !job_is_completed(&job->job)) {
75
- job_drain(&job->job);
76
- }
77
-
78
- job->job.aio_context = NULL;
79
- job_unref(&job->job);
80
-}
81
-
82
static char *child_job_get_parent_desc(BdrvChild *c)
83
{
84
BlockJob *job = c->opaque;
85
@@ -XXX,XX +XXX,XX @@ static void child_job_set_aio_ctx(BdrvChild *c, AioContext *ctx,
86
*ignore = g_slist_prepend(*ignore, sibling);
87
bdrv_set_aio_context_ignore(sibling->bs, ctx, ignore);
88
}
89
+
90
+ job->job.aio_context = ctx;
91
}
92
93
static const BdrvChildRole child_job = {
94
@@ -XXX,XX +XXX,XX @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
95
96
bdrv_op_unblock(bs, BLOCK_OP_TYPE_DATAPLANE, job->blocker);
97
98
- blk_add_aio_context_notifier(blk, block_job_attached_aio_context,
99
- block_job_detach_aio_context, job);
100
blk_set_allow_aio_context_change(blk, true);
101
102
/* Only set speed when necessary to avoid NotSupported error */
103
--
104
2.20.1
105
106
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
Just writing that --output=json outputs JSON information does not really
4
help; we should also make a note of what QAPI type the result object
5
has. (The map subcommand does not emit a QAPI-typed object, but its
6
section already describes the object structure well enough.)
7
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
qemu-img.texi | 11 ++++++++---
12
1 file changed, 8 insertions(+), 3 deletions(-)
13
14
diff --git a/qemu-img.texi b/qemu-img.texi
15
index XXXXXXX..XXXXXXX 100644
16
--- a/qemu-img.texi
17
+++ b/qemu-img.texi
18
@@ -XXX,XX +XXX,XX @@ overridden with a pattern byte specified by @var{pattern}.
19
20
Perform a consistency check on the disk image @var{filename}. The command can
21
output in the format @var{ofmt} which is either @code{human} or @code{json}.
22
+The JSON output is an object of QAPI type @code{ImageCheck}.
23
24
If @code{-r} is specified, qemu-img tries to repair any inconsistencies found
25
during the check. @code{-r leaks} repairs only cluster leaks, whereas
26
@@ -XXX,XX +XXX,XX @@ The size syntax is similar to dd(1)'s size syntax.
27
Give information about the disk image @var{filename}. Use it in
28
particular to know the size reserved on disk which can be different
29
from the displayed size. If VM snapshots are stored in the disk image,
30
-they are displayed too. The command can output in the format @var{ofmt}
31
-which is either @code{human} or @code{json}.
32
+they are displayed too.
33
34
If a disk image has a backing file chain, information about each disk image in
35
the chain can be recursively enumerated by using the option @code{--backing-chain}.
36
@@ -XXX,XX +XXX,XX @@ To enumerate information about each disk image in the above chain, starting from
37
qemu-img info --backing-chain snap2.qcow2
38
@end example
39
40
+The command can output in the format @var{ofmt} which is either @code{human} or
41
+@code{json}. The JSON output is an object of QAPI type @code{ImageInfo}; with
42
+@code{--backing-chain}, it is an array of @code{ImageInfo} objects.
43
+
44
@item map [--object @var{objectdef}] [--image-opts] [-f @var{fmt}] [--output=@var{ofmt}] [-U] @var{filename}
45
46
Dump the metadata of image @var{filename} and its backing file chain.
47
@@ -XXX,XX +XXX,XX @@ Calculate the file size required for a new image. This information can be used
48
to size logical volumes or SAN LUNs appropriately for the image that will be
49
placed in them. The values reported are guaranteed to be large enough to fit
50
the image. The command can output in the format @var{ofmt} which is either
51
-@code{human} or @code{json}.
52
+@code{human} or @code{json}. The JSON output is an object of QAPI type
53
+@code{BlockMeasureInfo}.
54
55
If the size @var{N} is given then act as if creating a new empty image file
56
using @command{qemu-img create}. If @var{filename} is given then act as if
57
--
58
2.20.1
59
60
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
Ideally, it should be self-explanatory. However, keys like "disk size"
4
arguably really are not self-explanatory. In any case, there is no harm
5
in going into a some more detail here.
6
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
10
qemu-img.texi | 41 +++++++++++++++++++++++++++++++++++++++++
11
1 file changed, 41 insertions(+)
12
13
diff --git a/qemu-img.texi b/qemu-img.texi
14
index XXXXXXX..XXXXXXX 100644
15
--- a/qemu-img.texi
16
+++ b/qemu-img.texi
17
@@ -XXX,XX +XXX,XX @@ The command can output in the format @var{ofmt} which is either @code{human} or
18
@code{json}. The JSON output is an object of QAPI type @code{ImageInfo}; with
19
@code{--backing-chain}, it is an array of @code{ImageInfo} objects.
20
21
+@code{--output=human} reports the following information (for every image in the
22
+chain):
23
+@table @var
24
+@item image
25
+The image file name
26
+
27
+@item file format
28
+The image format
29
+
30
+@item virtual size
31
+The size of the guest disk
32
+
33
+@item disk size
34
+How much space the image file occupies on the host file system (may be shown as
35
+0 if this information is unavailable, e.g. because there is no file system)
36
+
37
+@item cluster_size
38
+Cluster size of the image format, if applicable
39
+
40
+@item encrypted
41
+Whether the image is encrypted (only present if so)
42
+
43
+@item cleanly shut down
44
+This is shown as @code{no} if the image is dirty and will have to be
45
+auto-repaired the next time it is opened in qemu.
46
+
47
+@item backing file
48
+The backing file name, if present
49
+
50
+@item backing file format
51
+The format of the backing file, if the image enforces it
52
+
53
+@item Snapshot list
54
+A list of all internal snapshots
55
+
56
+@item Format specific information
57
+Further information whose structure depends on the image format. This section
58
+is a textual representation of the respective @code{ImageInfoSpecific*} QAPI
59
+object (e.g. @code{ImageInfoSpecificQCow2} for qcow2 images).
60
+@end table
61
+
62
@item map [--object @var{objectdef}] [--image-opts] [-f @var{fmt}] [--output=@var{ofmt}] [-U] @var{filename}
63
64
Dump the metadata of image @var{filename} and its backing file chain.
65
--
66
2.20.1
67
68
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
This message does not make any sense when it appears as the response to
4
making an R/W node read-only. We should detect that case and emit a
5
different message, then.
6
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
Reviewed-by: Alberto Garcia <berto@igalia.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
block.c | 17 ++++++++++++++++-
12
1 file changed, 16 insertions(+), 1 deletion(-)
13
14
diff --git a/block.c b/block.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/block.c
17
+++ b/block.c
18
@@ -XXX,XX +XXX,XX @@ static int bdrv_child_check_perm(BdrvChild *c, BlockReopenQueue *q,
19
GSList *ignore_children, Error **errp);
20
static void bdrv_child_abort_perm_update(BdrvChild *c);
21
static void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared);
22
+static void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm,
23
+ uint64_t *shared_perm);
24
25
typedef struct BlockReopenQueueEntry {
26
bool prepared;
27
@@ -XXX,XX +XXX,XX @@ static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q,
28
if ((cumulative_perms & (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED)) &&
29
!bdrv_is_writable_after_reopen(bs, q))
30
{
31
- error_setg(errp, "Block node is read-only");
32
+ if (!bdrv_is_writable_after_reopen(bs, NULL)) {
33
+ error_setg(errp, "Block node is read-only");
34
+ } else {
35
+ uint64_t current_perms, current_shared;
36
+ bdrv_get_cumulative_perm(bs, &current_perms, &current_shared);
37
+ if (current_perms & (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED)) {
38
+ error_setg(errp, "Cannot make block node read-only, there is "
39
+ "a writer on it");
40
+ } else {
41
+ error_setg(errp, "Cannot make block node read-only and create "
42
+ "a writer on it");
43
+ }
44
+ }
45
+
46
return -EPERM;
47
}
48
49
--
50
2.20.1
51
52
diff view generated by jsdifflib