1
The following changes since commit 9436e082de18b2fb2ceed2e9d1beef641ae64f23:
1
The following changes since commit ad88e4252f09c2956b99c90de39e95bab2e8e7af:
2
2
3
MAINTAINERS: clarify some of the tags (2018-11-19 11:19:23 +0000)
3
Merge remote-tracking branch 'remotes/amarkovic/tags/mips-queue-jun-1-2019' into staging (2019-06-03 10:25:12 +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 6d0a4a0fb5c8f10c8eb68b52cfda0082b00ae963:
9
for you to fetch changes up to 9593db8ccd27800ce4a17f1d5b735b9130c541a2:
10
10
11
iotests: Test file-posix locking and reopen (2018-11-19 14:32:04 +0100)
11
iotests: Fix duplicated diff output on failure (2019-06-03 16:33:20 +0200)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block layer patches:
14
Block layer patches:
15
15
16
- file-posix: Fix shared permission locks after reopen
16
- block: AioContext management, part 2
17
- block: Fix error path for failed .bdrv_reopen_prepare
17
- Avoid recursive block_status call (i.e. lseek() calls) if possible
18
- qcow2: Catch invalid allocations when the image becomes too large
18
- linux-aio: Drop unused BlockAIOCB submission method
19
- vvfat/fdc/nvme: Fix segfaults and leaks
19
- nvme: add Get/Set Feature Timestamp support
20
- Fix crash on commit job start with active I/O on base node
21
- Fix crash in bdrv_drained_end
22
- Fix integer overflow in qcow2 discard
20
23
21
----------------------------------------------------------------
24
----------------------------------------------------------------
22
Eric Blake (3):
25
John Snow (1):
23
qcow2: Document some maximum size constraints
26
blockdev: fix missed target unref for drive-backup
24
qcow2: Don't allow overflow during cluster allocation
25
iotests: Add new test 220 for max compressed cluster offset
26
27
27
Kevin Wolf (1):
28
Julia Suvorova (1):
28
vvfat: Fix memory leak
29
block/linux-aio: Drop unused BlockAIOCB submission method
29
30
30
Li Qiang (1):
31
Kenneth Heitke (1):
31
nvme: fix oob access issue(CVE-2018-16847)
32
nvme: add Get/Set Feature Timestamp support
32
33
33
Mark Cave-Ayland (1):
34
Kevin Wolf (19):
34
fdc: fix segfault in fdctrl_stop_transfer() when DMA is disabled
35
block: Drain source node in bdrv_replace_node()
36
iotests: Test commit job start with concurrent I/O
37
test-block-iothread: Check filter node in test_propagate_mirror
38
nbd-server: Call blk_set_allow_aio_context_change()
39
block: Add Error to blk_set_aio_context()
40
block: Add BlockBackend.ctx
41
block: Add qdev_prop_drive_iothread property type
42
scsi-disk: Use qdev_prop_drive_iothread
43
block: Adjust AioContexts when attaching nodes
44
test-block-iothread: Test adding parent to iothread node
45
test-block-iothread: BlockBackend AioContext across root node change
46
block: Move node without parents to main AioContext
47
blockdev: Use bdrv_try_set_aio_context() for monitor commands
48
block: Remove wrong bdrv_set_aio_context() calls
49
virtio-scsi-test: Test attaching new overlay with iothreads
50
iotests: Attach new devices to node in non-default iothread
51
test-bdrv-drain: Use bdrv_try_set_aio_context()
52
block: Remove bdrv_set_aio_context()
53
iotests: Fix duplicated diff output on failure
35
54
36
Max Reitz (3):
55
Max Reitz (2):
37
block: Always abort reopen after prepare succeeded
56
block/io: Delay decrementing the quiesce_counter
38
file-posix: Fix shared locks on reopen commit
57
iotests: Test cancelling a job and closing the VM
39
iotests: Test file-posix locking and reopen
40
58
41
docs/interop/qcow2.txt | 38 +++++++++++++++++-
59
Vladimir Sementsov-Ogievskiy (4):
42
block/qcow2.h | 6 +++
60
tests/perf: Test lseek influence on qcow2 block-status
43
block.c | 12 ++++++
61
block: avoid recursive block_status call if possible
44
block/file-posix.c | 2 +-
62
block/qcow2-refcount: add trace-point to qcow2_process_discards
45
block/qcow2-refcount.c | 20 ++++++----
63
block/io: bdrv_pdiscard: support int64_t bytes parameter
46
block/vvfat.c | 6 +--
47
hw/block/fdc.c | 2 +-
48
hw/block/nvme.c | 7 ++++
49
tests/qemu-iotests/182 | 71 ++++++++++++++++++++++++++++++++++
50
tests/qemu-iotests/182.out | 9 +++++
51
tests/qemu-iotests/220 | 96 ++++++++++++++++++++++++++++++++++++++++++++++
52
tests/qemu-iotests/220.out | 54 ++++++++++++++++++++++++++
53
tests/qemu-iotests/group | 1 +
54
13 files changed, 310 insertions(+), 14 deletions(-)
55
create mode 100755 tests/qemu-iotests/220
56
create mode 100644 tests/qemu-iotests/220.out
57
64
65
docs/devel/multiple-iothreads.txt | 4 +-
66
block/qcow2.h | 4 +
67
hw/block/nvme.h | 2 +
68
include/block/block.h | 21 ++---
69
include/block/block_int.h | 1 +
70
include/block/nvme.h | 2 +
71
include/block/raw-aio.h | 3 -
72
include/hw/block/block.h | 7 +-
73
include/hw/qdev-properties.h | 3 +
74
include/hw/scsi/scsi.h | 1 +
75
include/sysemu/block-backend.h | 5 +-
76
tests/libqtest.h | 11 +++
77
block.c | 79 ++++++++++++-----
78
block/backup.c | 3 +-
79
block/block-backend.c | 47 ++++++----
80
block/commit.c | 13 +--
81
block/crypto.c | 3 +-
82
block/io.c | 28 +++---
83
block/linux-aio.c | 72 +++------------
84
block/mirror.c | 4 +-
85
block/parallels.c | 3 +-
86
block/qcow.c | 3 +-
87
block/qcow2-refcount.c | 39 ++++++++-
88
block/qcow2.c | 17 +++-
89
block/qed.c | 3 +-
90
block/sheepdog.c | 3 +-
91
block/vdi.c | 3 +-
92
block/vhdx.c | 3 +-
93
block/vmdk.c | 3 +-
94
block/vpc.c | 3 +-
95
blockdev.c | 61 +++++++------
96
blockjob.c | 12 ++-
97
hmp.c | 3 +-
98
hw/block/dataplane/virtio-blk.c | 12 ++-
99
hw/block/dataplane/xen-block.c | 6 +-
100
hw/block/fdc.c | 2 +-
101
hw/block/nvme.c | 106 +++++++++++++++++++++-
102
hw/block/xen-block.c | 2 +-
103
hw/core/qdev-properties-system.c | 41 ++++++++-
104
hw/ide/qdev.c | 2 +-
105
hw/scsi/scsi-disk.c | 24 +++--
106
hw/scsi/virtio-scsi.c | 25 +++---
107
migration/block.c | 3 +-
108
nbd/server.c | 6 +-
109
qemu-img.c | 6 +-
110
tests/libqtest.c | 19 ++++
111
tests/test-bdrv-drain.c | 50 ++++++-----
112
tests/test-bdrv-graph-mod.c | 5 +-
113
tests/test-block-backend.c | 6 +-
114
tests/test-block-iothread.c | 104 ++++++++++++++++++----
115
tests/test-blockjob.c | 2 +-
116
tests/test-throttle.c | 6 +-
117
tests/virtio-scsi-test.c | 62 +++++++++++++
118
block/trace-events | 3 +
119
hw/block/trace-events | 2 +
120
tests/perf/block/qcow2/convert-blockstatus | 71 +++++++++++++++
121
tests/qemu-iotests/051 | 24 +++++
122
tests/qemu-iotests/051.out | 3 +
123
tests/qemu-iotests/051.pc.out | 27 ++++++
124
tests/qemu-iotests/102 | 2 +-
125
tests/qemu-iotests/102.out | 3 +-
126
tests/qemu-iotests/141.out | 2 +-
127
tests/qemu-iotests/144.out | 2 +-
128
tests/qemu-iotests/240 | 21 +++++
129
tests/qemu-iotests/240.out | 15 +++-
130
tests/qemu-iotests/255 | 135 +++++++++++++++++++++++++++++
131
tests/qemu-iotests/255.out | 40 +++++++++
132
tests/qemu-iotests/check | 1 -
133
tests/qemu-iotests/group | 1 +
134
tests/qemu-iotests/iotests.py | 10 ++-
135
70 files changed, 1048 insertions(+), 272 deletions(-)
136
create mode 100755 tests/perf/block/qcow2/convert-blockstatus
137
create mode 100755 tests/qemu-iotests/255
138
create mode 100644 tests/qemu-iotests/255.out
139
diff view generated by jsdifflib
New patch
1
Instead of just asserting that no requests are in flight in
2
bdrv_replace_node(), which is a requirement that most callers ignore, we
3
can just drain the source node right there. This fixes at least starting
4
a commit job while I/O is active on the backing chain, but probably
5
other callers, too.
1
6
7
Having requests in flight on the target node isn't a problem because the
8
target just gets new parents, but the call path of running requests
9
isn't modified. So we can just drop this assertion without a replacement.
10
11
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1711643
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Reviewed-by: Max Reitz <mreitz@redhat.com>
14
---
15
block.c | 7 ++++---
16
1 file changed, 4 insertions(+), 3 deletions(-)
17
18
diff --git a/block.c b/block.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/block.c
21
+++ b/block.c
22
@@ -XXX,XX +XXX,XX @@ void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
23
uint64_t perm = 0, shared = BLK_PERM_ALL;
24
int ret;
25
26
- assert(!atomic_read(&from->in_flight));
27
- assert(!atomic_read(&to->in_flight));
28
-
29
/* Make sure that @from doesn't go away until we have successfully attached
30
* all of its parents to @to. */
31
bdrv_ref(from);
32
33
+ assert(qemu_get_current_aio_context() == qemu_get_aio_context());
34
+ bdrv_drained_begin(from);
35
+
36
/* Put all parents into @list and calculate their cumulative permissions */
37
QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) {
38
assert(c->bs == from);
39
@@ -XXX,XX +XXX,XX @@ void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
40
41
out:
42
g_slist_free(list);
43
+ bdrv_drained_end(from);
44
bdrv_unref(from);
45
}
46
47
--
48
2.20.1
49
50
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
This tests that concurrent requests are correctly drained before making
2
graph modifications instead of running into assertions in
3
bdrv_replace_node().
2
4
3
If you have a capable file system (tmpfs is good, ext4 not so much;
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
run ./check with TEST_DIR pointing to a good location so as not
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
5
to skip the test), it's actually possible to create a qcow2 file
7
---
6
that expands to a sparse 512T image with just over 38M of content.
8
tests/qemu-iotests/255 | 83 +++++++++++++++++++++++++++++++++++
7
The test is not the world's fastest (qemu crawling through 256M
9
tests/qemu-iotests/255.out | 16 +++++++
8
bits of refcount table to find the next cluster to allocate takes
10
tests/qemu-iotests/group | 1 +
9
several seconds, as does qemu-img check reporting millions of
11
tests/qemu-iotests/iotests.py | 10 ++++-
10
leaked clusters); but it DOES catch the problem that the previous
12
4 files changed, 109 insertions(+), 1 deletion(-)
11
patch just fixed where writing a compressed cluster to a full
13
create mode 100755 tests/qemu-iotests/255
12
image ended up overwriting the wrong cluster.
14
create mode 100644 tests/qemu-iotests/255.out
13
15
14
Suggested-by: Max Reitz <mreitz@redhat.com>
16
diff --git a/tests/qemu-iotests/255 b/tests/qemu-iotests/255
15
Signed-off-by: Eric Blake <eblake@redhat.com>
16
Reviewed-by: Alberto Garcia <berto@igalia.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
---
19
tests/qemu-iotests/220 | 96 ++++++++++++++++++++++++++++++++++++++
20
tests/qemu-iotests/220.out | 54 +++++++++++++++++++++
21
tests/qemu-iotests/group | 1 +
22
3 files changed, 151 insertions(+)
23
create mode 100755 tests/qemu-iotests/220
24
create mode 100644 tests/qemu-iotests/220.out
25
26
diff --git a/tests/qemu-iotests/220 b/tests/qemu-iotests/220
27
new file mode 100755
17
new file mode 100755
28
index XXXXXXX..XXXXXXX
18
index XXXXXXX..XXXXXXX
29
--- /dev/null
19
--- /dev/null
30
+++ b/tests/qemu-iotests/220
20
+++ b/tests/qemu-iotests/255
31
@@ -XXX,XX +XXX,XX @@
21
@@ -XXX,XX +XXX,XX @@
32
+#!/bin/bash
22
+#!/usr/bin/env python
33
+#
23
+#
34
+# max limits on compression in huge qcow2 files
24
+# Test commit job graph modifications while requests are active
35
+#
25
+#
36
+# Copyright (C) 2018 Red Hat, Inc.
26
+# Copyright (C) 2019 Red Hat, Inc.
27
+#
28
+# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
37
+#
29
+#
38
+# This program is free software; you can redistribute it and/or modify
30
+# This program is free software; you can redistribute it and/or modify
39
+# it under the terms of the GNU General Public License as published by
31
+# it under the terms of the GNU General Public License as published by
40
+# the Free Software Foundation; either version 2 of the License, or
32
+# the Free Software Foundation; either version 2 of the License, or
41
+# (at your option) any later version.
33
+# (at your option) any later version.
...
...
47
+#
39
+#
48
+# You should have received a copy of the GNU General Public License
40
+# You should have received a copy of the GNU General Public License
49
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
41
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
50
+#
42
+#
51
+
43
+
52
+seq=$(basename $0)
44
+import iotests
53
+echo "QA output created by $seq"
45
+from iotests import imgfmt
54
+
46
+
55
+status=1 # failure is the default!
47
+iotests.verify_image_format(supported_fmts=['qcow2'])
56
+
48
+
57
+_cleanup()
49
+def blockdev_create(vm, options):
58
+{
50
+ result = vm.qmp_log('blockdev-create',
59
+ _cleanup_test_img
51
+ filters=[iotests.filter_qmp_testfiles],
60
+}
52
+ job_id='job0', options=options)
61
+trap "_cleanup; exit \$status" 0 1 2 3 15
62
+
53
+
63
+# get standard environment, filters and checks
54
+ if 'return' in result:
64
+. ./common.rc
55
+ assert result['return'] == {}
65
+. ./common.filter
56
+ vm.run_job('job0')
66
+. ./common.pattern
57
+ iotests.log("")
67
+
58
+
68
+_supported_fmt qcow2
59
+with iotests.FilePath('t.qcow2') as disk_path, \
69
+_supported_proto file
60
+ iotests.FilePath('t.qcow2.mid') as mid_path, \
70
+_supported_os Linux
61
+ iotests.FilePath('t.qcow2.base') as base_path, \
62
+ iotests.VM() as vm:
71
+
63
+
72
+echo "== Creating huge file =="
64
+ iotests.log("=== Create backing chain and start VM ===")
65
+ iotests.log("")
73
+
66
+
74
+# Sanity check: We require a file system that permits the creation
67
+ size = 128 * 1024 * 1024
75
+# of a HUGE (but very sparse) file. tmpfs works, ext4 does not.
68
+ size_str = str(size)
76
+if ! truncate --size=513T "$TEST_IMG"; then
77
+ _notrun "file system on $TEST_DIR does not support large enough files"
78
+fi
79
+rm "$TEST_IMG"
80
+IMGOPTS='cluster_size=2M,refcount_bits=1' _make_test_img 513T
81
+
69
+
82
+echo "== Populating refcounts =="
70
+ iotests.create_image(base_path, size)
83
+# We want an image with 256M refcounts * 2M clusters = 512T referenced.
71
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, mid_path, size_str)
84
+# Each 2M cluster holds 16M refcounts; the refcount table initially uses
72
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, disk_path, size_str)
85
+# 1 refblock, so we need to add 15 more. The refcount table lives at 2M,
86
+# first refblock at 4M, L2 at 6M, so our remaining additions start at 8M.
87
+# Then, for each refblock, mark it as fully populated.
88
+to_hex() {
89
+ printf %016x\\n $1 | sed 's/\(..\)/\\x\1/g'
90
+}
91
+truncate --size=38m "$TEST_IMG"
92
+entry=$((0x200000))
93
+$QEMU_IO_PROG -f raw -c "w -P 0xff 4m 2m" "$TEST_IMG" | _filter_qemu_io
94
+for i in {1..15}; do
95
+ offs=$((0x600000 + i*0x200000))
96
+ poke_file "$TEST_IMG" $((i*8 + entry)) $(to_hex $offs)
97
+ $QEMU_IO_PROG -f raw -c "w -P 0xff $offs 2m" "$TEST_IMG" | _filter_qemu_io
98
+done
99
+
73
+
100
+echo "== Checking file before =="
74
+ # Create a backing chain like this:
101
+# FIXME: 'qemu-img check' doesn't diagnose refcounts beyond the end of
75
+ # base <- [throttled: bps-read=4096] <- mid <- overlay
102
+# the file as leaked clusters
103
+_check_test_img 2>&1 | sed '/^Leaked cluster/d'
104
+stat -c 'image size %s' "$TEST_IMG"
105
+
76
+
106
+echo "== Trying to write compressed cluster =="
77
+ vm.add_object('throttle-group,x-bps-read=4096,id=throttle0')
107
+# Given our file size, the next available cluster at 512T lies beyond the
78
+ vm.add_blockdev('file,filename=%s,node-name=base' % (base_path))
108
+# maximum offset that a compressed 2M cluster can reside in
79
+ vm.add_blockdev('throttle,throttle-group=throttle0,file=base,node-name=throttled')
109
+$QEMU_IO_PROG -c 'w -c 0 2m' "$TEST_IMG" | _filter_qemu_io
80
+ vm.add_blockdev('file,filename=%s,node-name=mid-file' % (mid_path))
110
+# The attempt failed, but ended up allocating a new refblock
81
+ vm.add_blockdev('qcow2,file=mid-file,node-name=mid,backing=throttled')
111
+stat -c 'image size %s' "$TEST_IMG"
82
+ vm.add_drive_raw('if=none,id=overlay,driver=qcow2,file=%s,backing=mid' % (disk_path))
112
+
83
+
113
+echo "== Writing normal cluster =="
84
+ vm.launch()
114
+# The failed write should not corrupt the image, so a normal write succeeds
115
+$QEMU_IO_PROG -c 'w 0 2m' "$TEST_IMG" | _filter_qemu_io
116
+
85
+
117
+echo "== Checking file after =="
86
+ iotests.log("=== Start background read requests ===")
118
+# qemu-img now sees the millions of leaked clusters, thanks to the allocations
87
+ iotests.log("")
119
+# at 512T. Undo many of our faked references to speed up the check.
120
+$QEMU_IO_PROG -f raw -c "w -z 5m 1m" -c "w -z 8m 30m" "$TEST_IMG" |
121
+ _filter_qemu_io
122
+_check_test_img 2>&1 | sed '/^Leaked cluster/d'
123
+
88
+
124
+# success, all done
89
+ def start_requests():
125
+echo "*** done"
90
+ vm.hmp_qemu_io('overlay', 'aio_read 0 4k')
126
+rm -f $seq.full
91
+ vm.hmp_qemu_io('overlay', 'aio_read 0 4k')
127
+status=0
92
+
128
diff --git a/tests/qemu-iotests/220.out b/tests/qemu-iotests/220.out
93
+ start_requests()
94
+
95
+ iotests.log("=== Run a commit job ===")
96
+ iotests.log("")
97
+
98
+ result = vm.qmp_log('block-commit', job_id='job0', auto_finalize=False,
99
+ device='overlay', top_node='mid')
100
+
101
+ vm.run_job('job0', auto_finalize=False, pre_finalize=start_requests,
102
+ auto_dismiss=True)
103
+
104
+ vm.shutdown()
105
diff --git a/tests/qemu-iotests/255.out b/tests/qemu-iotests/255.out
129
new file mode 100644
106
new file mode 100644
130
index XXXXXXX..XXXXXXX
107
index XXXXXXX..XXXXXXX
131
--- /dev/null
108
--- /dev/null
132
+++ b/tests/qemu-iotests/220.out
109
+++ b/tests/qemu-iotests/255.out
133
@@ -XXX,XX +XXX,XX @@
110
@@ -XXX,XX +XXX,XX @@
134
+QA output created by 220
111
+=== Create backing chain and start VM ===
135
+== Creating huge file ==
136
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=564049465049088
137
+== Populating refcounts ==
138
+wrote 2097152/2097152 bytes at offset 4194304
139
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
140
+wrote 2097152/2097152 bytes at offset 8388608
141
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
142
+wrote 2097152/2097152 bytes at offset 10485760
143
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
144
+wrote 2097152/2097152 bytes at offset 12582912
145
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
146
+wrote 2097152/2097152 bytes at offset 14680064
147
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
148
+wrote 2097152/2097152 bytes at offset 16777216
149
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
150
+wrote 2097152/2097152 bytes at offset 18874368
151
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
152
+wrote 2097152/2097152 bytes at offset 20971520
153
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
154
+wrote 2097152/2097152 bytes at offset 23068672
155
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
156
+wrote 2097152/2097152 bytes at offset 25165824
157
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
158
+wrote 2097152/2097152 bytes at offset 27262976
159
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
160
+wrote 2097152/2097152 bytes at offset 29360128
161
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
162
+wrote 2097152/2097152 bytes at offset 31457280
163
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
164
+wrote 2097152/2097152 bytes at offset 33554432
165
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
166
+wrote 2097152/2097152 bytes at offset 35651584
167
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
168
+wrote 2097152/2097152 bytes at offset 37748736
169
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
170
+== Checking file before ==
171
+No errors were found on the image.
172
+image size 39845888
173
+== Trying to write compressed cluster ==
174
+write failed: Input/output error
175
+image size 562949957615616
176
+== Writing normal cluster ==
177
+wrote 2097152/2097152 bytes at offset 0
178
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
179
+== Checking file after ==
180
+wrote 1048576/1048576 bytes at offset 5242880
181
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
182
+wrote 31457280/31457280 bytes at offset 8388608
183
+30 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
184
+
112
+
185
+8388589 leaked clusters were found on the image.
113
+Formatting 'TEST_DIR/PID-t.qcow2.mid', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16
186
+This means waste of disk space, but no harm to data.
114
+
187
+*** done
115
+Formatting 'TEST_DIR/PID-t.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16
116
+
117
+=== Start background read requests ===
118
+
119
+=== Run a commit job ===
120
+
121
+{"execute": "block-commit", "arguments": {"auto-finalize": false, "device": "overlay", "job-id": "job0", "top-node": "mid"}}
122
+{"return": {}}
123
+{"execute": "job-finalize", "arguments": {"id": "job0"}}
124
+{"return": {}}
125
+{"data": {"id": "job0", "type": "commit"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
126
+{"data": {"device": "job0", "len": 134217728, "offset": 134217728, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
188
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
127
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
189
index XXXXXXX..XXXXXXX 100644
128
index XXXXXXX..XXXXXXX 100644
190
--- a/tests/qemu-iotests/group
129
--- a/tests/qemu-iotests/group
191
+++ b/tests/qemu-iotests/group
130
+++ b/tests/qemu-iotests/group
192
@@ -XXX,XX +XXX,XX @@
131
@@ -XXX,XX +XXX,XX @@
193
217 rw auto quick
132
252 rw auto backing quick
194
218 rw auto quick
133
253 rw auto quick
195
219 rw auto
134
254 rw auto backing quick
196
+220 rw auto
135
+255 rw auto quick
197
221 rw auto quick
136
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
198
222 rw auto quick
137
index XXXXXXX..XXXXXXX 100644
199
223 rw auto quick
138
--- a/tests/qemu-iotests/iotests.py
139
+++ b/tests/qemu-iotests/iotests.py
140
@@ -XXX,XX +XXX,XX @@ def qemu_img_pipe(*args):
141
sys.stderr.write('qemu-img received signal %i: %s\n' % (-exitcode, ' '.join(qemu_img_args + list(args))))
142
return subp.communicate()[0]
143
144
+def qemu_img_log(*args):
145
+ result = qemu_img_pipe(*args)
146
+ log(result, filters=[filter_testfiles])
147
+ return result
148
+
149
def img_info_log(filename, filter_path=None, imgopts=False, extra_args=[]):
150
args = [ 'info' ]
151
if imgopts:
152
@@ -XXX,XX +XXX,XX @@ class VM(qtest.QEMUQtestMachine):
153
return result
154
155
# Returns None on success, and an error string on failure
156
- def run_job(self, job, auto_finalize=True, auto_dismiss=False):
157
+ def run_job(self, job, auto_finalize=True, auto_dismiss=False,
158
+ pre_finalize=None):
159
error = None
160
while True:
161
for ev in self.get_qmp_events_filtered(wait=True):
162
@@ -XXX,XX +XXX,XX @@ class VM(qtest.QEMUQtestMachine):
163
error = j['error']
164
log('Job failed: %s' % (j['error']))
165
elif status == 'pending' and not auto_finalize:
166
+ if pre_finalize:
167
+ pre_finalize()
168
self.qmp_log('job-finalize', id=job)
169
elif status == 'concluded' and not auto_dismiss:
170
self.qmp_log('job-dismiss', id=job)
200
--
171
--
201
2.19.1
172
2.20.1
202
173
203
174
diff view generated by jsdifflib
1
Don't leak 'cluster' in the mapping == NULL case. Found by Coverity
1
From: John Snow <jsnow@redhat.com>
2
(CID 1055918).
3
2
4
Fixes: 8d9401c2791ee2d2805b741b1ee3006041edcd3e
3
If the bitmap can't be used for whatever reason, we skip putting down
4
the reference. Fix that.
5
6
In practice, this means that if you attempt to gracefully exit QEMU
7
after a backup command being rejected, bdrv_close_all will fail and
8
tell you some unpleasant things via assert().
9
10
Reported-by: aihua liang <aliang@redhat.com>
11
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1703916
12
Signed-off-by: John Snow <jsnow@redhat.com>
13
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
7
Reviewed-by: Liam Merwick <liam.merwick@oracle.com>
8
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
9
---
15
---
10
block/vvfat.c | 6 +++---
16
blockdev.c | 13 ++++++-------
11
1 file changed, 3 insertions(+), 3 deletions(-)
17
1 file changed, 6 insertions(+), 7 deletions(-)
12
18
13
diff --git a/block/vvfat.c b/block/vvfat.c
19
diff --git a/blockdev.c b/blockdev.c
14
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
15
--- a/block/vvfat.c
21
--- a/blockdev.c
16
+++ b/block/vvfat.c
22
+++ b/blockdev.c
17
@@ -XXX,XX +XXX,XX @@ static int commit_one_file(BDRVVVFATState* s,
23
@@ -XXX,XX +XXX,XX @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn,
18
uint32_t first_cluster = c;
24
if (set_backing_hd) {
19
mapping_t* mapping = find_mapping_for_cluster(s, c);
25
bdrv_set_backing_hd(target_bs, source, &local_err);
20
uint32_t size = filesize_of_direntry(direntry);
26
if (local_err) {
21
- char* cluster = g_malloc(s->cluster_size);
27
- bdrv_unref(target_bs);
22
+ char *cluster;
28
- goto out;
23
uint32_t i;
29
+ goto unref;
24
int fd = 0;
25
26
@@ -XXX,XX +XXX,XX @@ static int commit_one_file(BDRVVVFATState* s,
27
if (fd < 0) {
28
fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
29
strerror(errno), errno);
30
- g_free(cluster);
31
return fd;
32
}
33
if (offset > 0) {
34
if (lseek(fd, offset, SEEK_SET) != offset) {
35
qemu_close(fd);
36
- g_free(cluster);
37
return -3;
38
}
30
}
39
}
31
}
40
32
41
+ cluster = g_malloc(s->cluster_size);
33
@@ -XXX,XX +XXX,XX @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn,
42
+
34
bmap = bdrv_find_dirty_bitmap(bs, backup->bitmap);
43
while (offset < size) {
35
if (!bmap) {
44
uint32_t c1;
36
error_setg(errp, "Bitmap '%s' could not be found", backup->bitmap);
45
int rest_size = (size - offset > s->cluster_size ?
37
- bdrv_unref(target_bs);
38
- goto out;
39
+ goto unref;
40
}
41
if (bdrv_dirty_bitmap_check(bmap, BDRV_BITMAP_DEFAULT, errp)) {
42
- goto out;
43
+ goto unref;
44
}
45
}
46
if (!backup->auto_finalize) {
47
@@ -XXX,XX +XXX,XX @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn,
48
backup->sync, bmap, backup->compress,
49
backup->on_source_error, backup->on_target_error,
50
job_flags, NULL, NULL, txn, &local_err);
51
- bdrv_unref(target_bs);
52
if (local_err != NULL) {
53
error_propagate(errp, local_err);
54
- goto out;
55
+ goto unref;
56
}
57
58
+unref:
59
+ bdrv_unref(target_bs);
60
out:
61
aio_context_release(aio_context);
62
return job;
46
--
63
--
47
2.19.1
64
2.20.1
48
65
49
66
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
Block layer may recursively check block_status in file child of qcow2,
4
if qcow2 driver returned DATA. There are several test cases to check
5
influence of lseek on block_status performance. To see real difference
6
run on tmpfs.
7
8
Tests originally created by Kevin, I just refactored and put them
9
together into one executable file with simple output.
10
11
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
14
tests/perf/block/qcow2/convert-blockstatus | 71 ++++++++++++++++++++++
15
1 file changed, 71 insertions(+)
16
create mode 100755 tests/perf/block/qcow2/convert-blockstatus
17
18
diff --git a/tests/perf/block/qcow2/convert-blockstatus b/tests/perf/block/qcow2/convert-blockstatus
19
new file mode 100755
20
index XXXXXXX..XXXXXXX
21
--- /dev/null
22
+++ b/tests/perf/block/qcow2/convert-blockstatus
23
@@ -XXX,XX +XXX,XX @@
24
+#!/bin/bash
25
+#
26
+# Test lseek influence on qcow2 block-status
27
+#
28
+# Block layer may recursively check block_status in file child of qcow2, if
29
+# qcow2 driver returned DATA. There are several test cases to check influence
30
+# of lseek on block_status performance. To see real difference run on tmpfs.
31
+#
32
+# Copyright (c) 2019 Virtuozzo International GmbH. All rights reserved.
33
+#
34
+# Tests originally written by Kevin Wolf
35
+#
36
+# This program is free software; you can redistribute it and/or modify
37
+# it under the terms of the GNU General Public License as published by
38
+# the Free Software Foundation; either version 2 of the License, or
39
+# (at your option) any later version.
40
+#
41
+# This program is distributed in the hope that it will be useful,
42
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
43
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
44
+# GNU General Public License for more details.
45
+#
46
+# You should have received a copy of the GNU General Public License
47
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
48
+#
49
+
50
+if [ "$#" -lt 1 ]; then
51
+ echo "Usage: $0 SOURCE_FILE"
52
+ exit 1
53
+fi
54
+
55
+ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/../../../.." >/dev/null 2>&1 && pwd )"
56
+QEMU_IMG="$ROOT_DIR/qemu-img"
57
+QEMU_IO="$ROOT_DIR/qemu-io"
58
+
59
+size=1G
60
+src="$1"
61
+
62
+# test-case plain
63
+
64
+(
65
+$QEMU_IMG create -f qcow2 "$src" $size
66
+for i in $(seq 16384 -1 0); do
67
+ echo "write $((i * 65536)) 64k"
68
+done | $QEMU_IO "$src"
69
+) > /dev/null
70
+
71
+echo -n "plain: "
72
+/usr/bin/time -f %e $QEMU_IMG convert -n "$src" null-co://
73
+
74
+# test-case forward
75
+
76
+(
77
+$QEMU_IMG create -f qcow2 "$src" $size
78
+for i in $(seq 0 2 16384); do
79
+ echo "write $((i * 65536)) 64k"
80
+done | $QEMU_IO "$src"
81
+for i in $(seq 1 2 16384); do
82
+ echo "write $((i * 65536)) 64k"
83
+done | $QEMU_IO "$src"
84
+) > /dev/null
85
+
86
+echo -n "forward: "
87
+/usr/bin/time -f %e $QEMU_IMG convert -n "$src" null-co://
88
+
89
+# test-case prealloc
90
+
91
+$QEMU_IMG create -f qcow2 -o preallocation=metadata "$src" $size > /dev/null
92
+
93
+echo -n "prealloc: "
94
+/usr/bin/time -f %e $QEMU_IMG convert -n "$src" null-co://
95
--
96
2.20.1
97
98
diff view generated by jsdifflib
New patch
1
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
3
drv_co_block_status digs bs->file for additional, more accurate search
4
for hole inside region, reported as DATA by bs since 5daa74a6ebc.
5
6
This accuracy is not free: assume we have qcow2 disk. Actually, qcow2
7
knows, where are holes and where is data. But every block_status
8
request calls lseek additionally. Assume a big disk, full of
9
data, in any iterative copying block job (or img convert) we'll call
10
lseek(HOLE) on every iteration, and each of these lseeks will have to
11
iterate through all metadata up to the end of file. It's obviously
12
ineffective behavior. And for many scenarios we don't need this lseek
13
at all.
14
15
However, lseek is needed when we have metadata-preallocated image.
16
17
So, let's detect metadata-preallocation case and don't dig qcow2's
18
protocol file in other cases.
19
20
The idea is to compare allocation size in POV of filesystem with
21
allocations size in POV of Qcow2 (by refcounts). If allocation in fs is
22
significantly lower, consider it as metadata-preallocation case.
23
24
102 iotest changed, as our detector can't detect shrinked file as
25
metadata-preallocation, which don't seem to be wrong, as with metadata
26
preallocation we always have valid file length.
27
28
Two other iotests have a slight change in their QMP output sequence:
29
Active 'block-commit' returns earlier because the job coroutine yields
30
earlier on a blocking operation. This operation is loading the refcount
31
blocks in qcow2_detect_metadata_preallocation().
32
33
Suggested-by: Denis V. Lunev <den@openvz.org>
34
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
35
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
36
---
37
block/qcow2.h | 4 ++++
38
include/block/block.h | 8 +++++++-
39
block/io.c | 9 ++++++++-
40
block/qcow2-refcount.c | 32 ++++++++++++++++++++++++++++++++
41
block/qcow2.c | 11 +++++++++++
42
tests/qemu-iotests/102 | 2 +-
43
tests/qemu-iotests/102.out | 3 ++-
44
tests/qemu-iotests/141.out | 2 +-
45
tests/qemu-iotests/144.out | 2 +-
46
9 files changed, 67 insertions(+), 6 deletions(-)
47
48
diff --git a/block/qcow2.h b/block/qcow2.h
49
index XXXXXXX..XXXXXXX 100644
50
--- a/block/qcow2.h
51
+++ b/block/qcow2.h
52
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVQcow2State {
53
int nb_threads;
54
55
BdrvChild *data_file;
56
+
57
+ bool metadata_preallocation_checked;
58
+ bool metadata_preallocation;
59
} BDRVQcow2State;
60
61
typedef struct Qcow2COWRegion {
62
@@ -XXX,XX +XXX,XX @@ int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order,
63
void *cb_opaque, Error **errp);
64
int qcow2_shrink_reftable(BlockDriverState *bs);
65
int64_t qcow2_get_last_cluster(BlockDriverState *bs, int64_t size);
66
+int qcow2_detect_metadata_preallocation(BlockDriverState *bs);
67
68
/* qcow2-cluster.c functions */
69
int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
70
diff --git a/include/block/block.h b/include/block/block.h
71
index XXXXXXX..XXXXXXX 100644
72
--- a/include/block/block.h
73
+++ b/include/block/block.h
74
@@ -XXX,XX +XXX,XX @@ typedef struct HDGeometry {
75
* BDRV_BLOCK_EOF: the returned pnum covers through end of file for this
76
* layer, set by block layer
77
*
78
- * Internal flag:
79
+ * Internal flags:
80
* BDRV_BLOCK_RAW: for use by passthrough drivers, such as raw, to request
81
* that the block layer recompute the answer from the returned
82
* BDS; must be accompanied by just BDRV_BLOCK_OFFSET_VALID.
83
+ * BDRV_BLOCK_RECURSE: request that the block layer will recursively search for
84
+ * zeroes in file child of current block node inside
85
+ * returned region. Only valid together with both
86
+ * BDRV_BLOCK_DATA and BDRV_BLOCK_OFFSET_VALID. Should not
87
+ * appear with BDRV_BLOCK_ZERO.
88
*
89
* If BDRV_BLOCK_OFFSET_VALID is set, the map parameter represents the
90
* host offset within the returned BDS that is allocated for the
91
@@ -XXX,XX +XXX,XX @@ typedef struct HDGeometry {
92
#define BDRV_BLOCK_RAW 0x08
93
#define BDRV_BLOCK_ALLOCATED 0x10
94
#define BDRV_BLOCK_EOF 0x20
95
+#define BDRV_BLOCK_RECURSE 0x40
96
#define BDRV_BLOCK_OFFSET_MASK BDRV_SECTOR_MASK
97
98
typedef QSIMPLEQ_HEAD(BlockReopenQueue, BlockReopenQueueEntry) BlockReopenQueue;
99
diff --git a/block/io.c b/block/io.c
100
index XXXXXXX..XXXXXXX 100644
101
--- a/block/io.c
102
+++ b/block/io.c
103
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_block_status(BlockDriverState *bs,
104
*/
105
assert(*pnum && QEMU_IS_ALIGNED(*pnum, align) &&
106
align > offset - aligned_offset);
107
+ if (ret & BDRV_BLOCK_RECURSE) {
108
+ assert(ret & BDRV_BLOCK_DATA);
109
+ assert(ret & BDRV_BLOCK_OFFSET_VALID);
110
+ assert(!(ret & BDRV_BLOCK_ZERO));
111
+ }
112
+
113
*pnum -= offset - aligned_offset;
114
if (*pnum > bytes) {
115
*pnum = bytes;
116
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_block_status(BlockDriverState *bs,
117
}
118
}
119
120
- if (want_zero && local_file && local_file != bs &&
121
+ if (want_zero && ret & BDRV_BLOCK_RECURSE &&
122
+ local_file && local_file != bs &&
123
(ret & BDRV_BLOCK_DATA) && !(ret & BDRV_BLOCK_ZERO) &&
124
(ret & BDRV_BLOCK_OFFSET_VALID)) {
125
int64_t file_pnum;
126
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
127
index XXXXXXX..XXXXXXX 100644
128
--- a/block/qcow2-refcount.c
129
+++ b/block/qcow2-refcount.c
130
@@ -XXX,XX +XXX,XX @@ int64_t qcow2_get_last_cluster(BlockDriverState *bs, int64_t size)
131
"There are no references in the refcount table.");
132
return -EIO;
133
}
134
+
135
+int qcow2_detect_metadata_preallocation(BlockDriverState *bs)
136
+{
137
+ BDRVQcow2State *s = bs->opaque;
138
+ int64_t i, end_cluster, cluster_count = 0, threshold;
139
+ int64_t file_length, real_allocation, real_clusters;
140
+
141
+ file_length = bdrv_getlength(bs->file->bs);
142
+ if (file_length < 0) {
143
+ return file_length;
144
+ }
145
+
146
+ real_allocation = bdrv_get_allocated_file_size(bs->file->bs);
147
+ if (real_allocation < 0) {
148
+ return real_allocation;
149
+ }
150
+
151
+ real_clusters = real_allocation / s->cluster_size;
152
+ threshold = MAX(real_clusters * 10 / 9, real_clusters + 2);
153
+
154
+ end_cluster = size_to_clusters(s, file_length);
155
+ for (i = 0; i < end_cluster && cluster_count < threshold; i++) {
156
+ uint64_t refcount;
157
+ int ret = qcow2_get_refcount(bs, i, &refcount);
158
+ if (ret < 0) {
159
+ return ret;
160
+ }
161
+ cluster_count += !!refcount;
162
+ }
163
+
164
+ return cluster_count >= threshold;
165
+}
166
diff --git a/block/qcow2.c b/block/qcow2.c
167
index XXXXXXX..XXXXXXX 100644
168
--- a/block/qcow2.c
169
+++ b/block/qcow2.c
170
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
171
unsigned int bytes;
172
int status = 0;
173
174
+ if (!s->metadata_preallocation_checked) {
175
+ ret = qcow2_detect_metadata_preallocation(bs);
176
+ s->metadata_preallocation = (ret == 1);
177
+ s->metadata_preallocation_checked = true;
178
+ }
179
+
180
bytes = MIN(INT_MAX, count);
181
qemu_co_mutex_lock(&s->lock);
182
ret = qcow2_get_cluster_offset(bs, offset, &bytes, &cluster_offset);
183
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
184
} else if (ret != QCOW2_CLUSTER_UNALLOCATED) {
185
status |= BDRV_BLOCK_DATA;
186
}
187
+ if (s->metadata_preallocation && (status & BDRV_BLOCK_DATA) &&
188
+ (status & BDRV_BLOCK_OFFSET_VALID))
189
+ {
190
+ status |= BDRV_BLOCK_RECURSE;
191
+ }
192
return status;
193
}
194
195
diff --git a/tests/qemu-iotests/102 b/tests/qemu-iotests/102
196
index XXXXXXX..XXXXXXX 100755
197
--- a/tests/qemu-iotests/102
198
+++ b/tests/qemu-iotests/102
199
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c 'write 0 64k' "$TEST_IMG" | _filter_qemu_io
200
$QEMU_IMG resize -f raw --shrink "$TEST_IMG" $((5 * 64 * 1024))
201
202
$QEMU_IO -c map "$TEST_IMG"
203
-$QEMU_IMG map "$TEST_IMG"
204
+$QEMU_IMG map "$TEST_IMG" | _filter_qemu_img_map
205
206
echo
207
echo '=== Testing map on an image file truncated outside of qemu ==='
208
diff --git a/tests/qemu-iotests/102.out b/tests/qemu-iotests/102.out
209
index XXXXXXX..XXXXXXX 100644
210
--- a/tests/qemu-iotests/102.out
211
+++ b/tests/qemu-iotests/102.out
212
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 0
213
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
214
Image resized.
215
64 KiB (0x10000) bytes allocated at offset 0 bytes (0x0)
216
-Offset Length Mapped to File
217
+Offset Length File
218
+0 0x10000 TEST_DIR/t.IMGFMT
219
220
=== Testing map on an image file truncated outside of qemu ===
221
222
diff --git a/tests/qemu-iotests/141.out b/tests/qemu-iotests/141.out
223
index XXXXXXX..XXXXXXX 100644
224
--- a/tests/qemu-iotests/141.out
225
+++ b/tests/qemu-iotests/141.out
226
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.
227
{"return": {}}
228
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}}
229
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}}
230
+{"return": {}}
231
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job0"}}
232
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}}
233
-{"return": {}}
234
{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: commit"}}
235
{"return": {}}
236
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job0"}}
237
diff --git a/tests/qemu-iotests/144.out b/tests/qemu-iotests/144.out
238
index XXXXXXX..XXXXXXX 100644
239
--- a/tests/qemu-iotests/144.out
240
+++ b/tests/qemu-iotests/144.out
241
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/tmp.qcow2', fmt=qcow2 size=536870912 backing_file=TEST_DIR/
242
243
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "virtio0"}}
244
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "virtio0"}}
245
+{"return": {}}
246
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "virtio0"}}
247
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "virtio0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}}
248
{"return": {}}
249
-{"return": {}}
250
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "virtio0"}}
251
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "virtio0"}}
252
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "virtio0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}}
253
--
254
2.20.1
255
256
diff view generated by jsdifflib
New patch
1
From: Max Reitz <mreitz@redhat.com>
1
2
3
When ending a drained section, bdrv_do_drained_end() currently first
4
decrements the quiesce_counter, and only then actually ends the drain.
5
6
The bdrv_drain_invoke(bs, false) call may cause graph changes. Say the
7
graph change involves replacing an existing BB's ("blk") BDS
8
(blk_bs(blk)) by @bs. Let us introducing the following values:
9
- bs_oqc = old_quiesce_counter
10
(so bs->quiesce_counter == bs_oqc - 1)
11
- obs_qc = blk_bs(blk)->quiesce_counter (before bdrv_drain_invoke())
12
13
Let us assume there is no blk_pread_unthrottled() involved, so
14
blk->quiesce_counter == obs_qc (before bdrv_drain_invoke()).
15
16
Now replacing blk_bs(blk) by @bs will reduce blk->quiesce_counter by
17
obs_qc (making it 0) and increase it by bs_oqc-1 (making it bs_oqc-1).
18
19
bdrv_drain_invoke() returns and we invoke bdrv_parent_drained_end().
20
This will decrement blk->quiesce_counter by one, so it would be -1 --
21
were there not an assertion against that in blk_root_drained_end().
22
23
We therefore have to keep the quiesce_counter up at least until
24
bdrv_drain_invoke() returns, so that bdrv_parent_drained_end() does the
25
right thing for the parents @bs got during bdrv_drain_invoke().
26
27
But let us delay it even further, namely until bdrv_parent_drained_end()
28
returns, because then it mirrors bdrv_do_drained_begin(): There, we
29
first increment the quiesce_counter, then begin draining the parents,
30
and then call bdrv_drain_invoke(). It makes sense to let
31
bdrv_do_drained_end() unravel this exactly in reverse.
32
33
Signed-off-by: Max Reitz <mreitz@redhat.com>
34
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
35
---
36
block/io.c | 3 ++-
37
1 file changed, 2 insertions(+), 1 deletion(-)
38
39
diff --git a/block/io.c b/block/io.c
40
index XXXXXXX..XXXXXXX 100644
41
--- a/block/io.c
42
+++ b/block/io.c
43
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
44
return;
45
}
46
assert(bs->quiesce_counter > 0);
47
- old_quiesce_counter = atomic_fetch_dec(&bs->quiesce_counter);
48
49
/* Re-enable things in child-to-parent order */
50
bdrv_drain_invoke(bs, false);
51
bdrv_parent_drained_end(bs, parent, ignore_bds_parents);
52
+
53
+ old_quiesce_counter = atomic_fetch_dec(&bs->quiesce_counter);
54
if (old_quiesce_counter == 1) {
55
aio_enable_external(bdrv_get_aio_context(bs));
56
}
57
--
58
2.20.1
59
60
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
From: Max Reitz <mreitz@redhat.com>
2
2
3
s->locked_shared_perm is the set of bits locked in the file, which is
3
This patch adds a test where we cancel a throttled mirror job and
4
the inverse of the permissions actually shared. So we need to pass them
4
immediately close the VM before it can be cancelled. Doing so will
5
as they are to raw_apply_lock_bytes() instead of inverting them again.
5
invoke bdrv_drain_all() while the mirror job tries to drain the
6
throttled node. When bdrv_drain_all_end() tries to lift its drain on
7
the throttle node, the job will exit and replace the current root node
8
of the BB drive0 (which is the job's filter node) by the throttle node.
9
Before the previous patch, this replacement did not increase drive0's
10
quiesce_counter by a sufficient amount, so when
11
bdrv_parent_drained_end() (invoked by bdrv_do_drained_end(), invoked by
12
bdrv_drain_all_end()) tried to end the drain on all of the throttle
13
node's parents, it decreased drive0's quiesce_counter below 0 -- which
14
fails an assertion.
6
15
7
Reported-by: Alberto Garcia <berto@igalia.com>
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
Reviewed-by: Alberto Garcia <berto@igalia.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
18
---
12
block/file-posix.c | 2 +-
19
tests/qemu-iotests/255 | 52 ++++++++++++++++++++++++++++++++++++++
13
1 file changed, 1 insertion(+), 1 deletion(-)
20
tests/qemu-iotests/255.out | 24 ++++++++++++++++++
21
2 files changed, 76 insertions(+)
14
22
15
diff --git a/block/file-posix.c b/block/file-posix.c
23
diff --git a/tests/qemu-iotests/255 b/tests/qemu-iotests/255
24
index XXXXXXX..XXXXXXX 100755
25
--- a/tests/qemu-iotests/255
26
+++ b/tests/qemu-iotests/255
27
@@ -XXX,XX +XXX,XX @@ def blockdev_create(vm, options):
28
vm.run_job('job0')
29
iotests.log("")
30
31
+iotests.log('Finishing a commit job with background reads')
32
+iotests.log('============================================')
33
+iotests.log('')
34
+
35
with iotests.FilePath('t.qcow2') as disk_path, \
36
iotests.FilePath('t.qcow2.mid') as mid_path, \
37
iotests.FilePath('t.qcow2.base') as base_path, \
38
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.qcow2') as disk_path, \
39
auto_dismiss=True)
40
41
vm.shutdown()
42
+
43
+iotests.log('')
44
+iotests.log('Closing the VM while a job is being cancelled')
45
+iotests.log('=============================================')
46
+iotests.log('')
47
+
48
+with iotests.FilePath('src.qcow2') as src_path, \
49
+ iotests.FilePath('dst.qcow2') as dst_path, \
50
+ iotests.VM() as vm:
51
+
52
+ iotests.log('=== Create images and start VM ===')
53
+ iotests.log('')
54
+
55
+ size = 128 * 1024 * 1024
56
+ size_str = str(size)
57
+
58
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, src_path, size_str)
59
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, dst_path, size_str)
60
+
61
+ iotests.log(iotests.qemu_io('-f', iotests.imgfmt, '-c', 'write 0 1M',
62
+ src_path),
63
+ filters=[iotests.filter_test_dir, iotests.filter_qemu_io])
64
+
65
+ vm.add_object('throttle-group,x-bps-read=4096,id=throttle0')
66
+
67
+ vm.add_blockdev('file,node-name=src-file,filename=%s' % (src_path))
68
+ vm.add_blockdev('%s,node-name=src,file=src-file' % (iotests.imgfmt))
69
+
70
+ vm.add_blockdev('file,node-name=dst-file,filename=%s' % (dst_path))
71
+ vm.add_blockdev('%s,node-name=dst,file=dst-file' % (iotests.imgfmt))
72
+
73
+ vm.add_blockdev('throttle,node-name=src-throttled,' +
74
+ 'throttle-group=throttle0,file=src')
75
+
76
+ vm.add_device('virtio-blk,drive=src-throttled')
77
+
78
+ vm.launch()
79
+
80
+ iotests.log('=== Start a mirror job ===')
81
+ iotests.log('')
82
+
83
+ vm.qmp_log('blockdev-mirror', job_id='job0', device='src-throttled',
84
+ target='dst', sync='full')
85
+
86
+ vm.qmp_log('block-job-cancel', device='job0')
87
+ vm.qmp_log('quit')
88
+
89
+ vm.shutdown()
90
diff --git a/tests/qemu-iotests/255.out b/tests/qemu-iotests/255.out
16
index XXXXXXX..XXXXXXX 100644
91
index XXXXXXX..XXXXXXX 100644
17
--- a/block/file-posix.c
92
--- a/tests/qemu-iotests/255.out
18
+++ b/block/file-posix.c
93
+++ b/tests/qemu-iotests/255.out
19
@@ -XXX,XX +XXX,XX @@ static void raw_reopen_commit(BDRVReopenState *state)
94
@@ -XXX,XX +XXX,XX @@
20
95
+Finishing a commit job with background reads
21
/* Copy locks to the new fd before closing the old one. */
96
+============================================
22
raw_apply_lock_bytes(NULL, rs->fd, s->locked_perm,
97
+
23
- ~s->locked_shared_perm, false, &local_err);
98
=== Create backing chain and start VM ===
24
+ s->locked_shared_perm, false, &local_err);
99
25
if (local_err) {
100
Formatting 'TEST_DIR/PID-t.qcow2.mid', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16
26
/* shouldn't fail in a sane host, but report it just in case. */
101
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/PID-t.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 l
27
error_report_err(local_err);
102
{"return": {}}
103
{"data": {"id": "job0", "type": "commit"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
104
{"data": {"device": "job0", "len": 134217728, "offset": 134217728, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
105
+
106
+Closing the VM while a job is being cancelled
107
+=============================================
108
+
109
+=== Create images and start VM ===
110
+
111
+Formatting 'TEST_DIR/PID-src.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16
112
+
113
+Formatting 'TEST_DIR/PID-dst.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16
114
+
115
+wrote 1048576/1048576 bytes at offset 0
116
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
117
+
118
+=== Start a mirror job ===
119
+
120
+{"execute": "blockdev-mirror", "arguments": {"device": "src-throttled", "job-id": "job0", "sync": "full", "target": "dst"}}
121
+{"return": {}}
122
+{"execute": "block-job-cancel", "arguments": {"device": "job0"}}
123
+{"return": {}}
124
+{"execute": "quit", "arguments": {}}
125
+{"return": {}}
28
--
126
--
29
2.19.1
127
2.20.1
30
128
31
129
diff view generated by jsdifflib
New patch
1
From: Julia Suvorova <jusual@mail.ru>
1
2
3
Callback-based laio_submit() and laio_cancel() were left after
4
rewriting Linux AIO backend to coroutines in hope that they would be
5
used in other code that could bypass coroutines. They can be safely
6
removed because they have not been used since that time.
7
8
Signed-off-by: Julia Suvorova <jusual@mail.ru>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
12
include/block/raw-aio.h | 3 --
13
block/linux-aio.c | 72 ++++++-----------------------------------
14
2 files changed, 10 insertions(+), 65 deletions(-)
15
16
diff --git a/include/block/raw-aio.h b/include/block/raw-aio.h
17
index XXXXXXX..XXXXXXX 100644
18
--- a/include/block/raw-aio.h
19
+++ b/include/block/raw-aio.h
20
@@ -XXX,XX +XXX,XX @@ LinuxAioState *laio_init(Error **errp);
21
void laio_cleanup(LinuxAioState *s);
22
int coroutine_fn laio_co_submit(BlockDriverState *bs, LinuxAioState *s, int fd,
23
uint64_t offset, QEMUIOVector *qiov, int type);
24
-BlockAIOCB *laio_submit(BlockDriverState *bs, LinuxAioState *s, int fd,
25
- int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
26
- BlockCompletionFunc *cb, void *opaque, int type);
27
void laio_detach_aio_context(LinuxAioState *s, AioContext *old_context);
28
void laio_attach_aio_context(LinuxAioState *s, AioContext *new_context);
29
void laio_io_plug(BlockDriverState *bs, LinuxAioState *s);
30
diff --git a/block/linux-aio.c b/block/linux-aio.c
31
index XXXXXXX..XXXXXXX 100644
32
--- a/block/linux-aio.c
33
+++ b/block/linux-aio.c
34
@@ -XXX,XX +XXX,XX @@
35
#define MAX_EVENTS 128
36
37
struct qemu_laiocb {
38
- BlockAIOCB common;
39
Coroutine *co;
40
LinuxAioState *ctx;
41
struct iocb iocb;
42
@@ -XXX,XX +XXX,XX @@ static inline ssize_t io_event_ret(struct io_event *ev)
43
}
44
45
/*
46
- * Completes an AIO request (calls the callback and frees the ACB).
47
+ * Completes an AIO request.
48
*/
49
static void qemu_laio_process_completion(struct qemu_laiocb *laiocb)
50
{
51
@@ -XXX,XX +XXX,XX @@ static void qemu_laio_process_completion(struct qemu_laiocb *laiocb)
52
}
53
54
laiocb->ret = ret;
55
- if (laiocb->co) {
56
- /* If the coroutine is already entered it must be in ioq_submit() and
57
- * will notice laio->ret has been filled in when it eventually runs
58
- * later. Coroutines cannot be entered recursively so avoid doing
59
- * that!
60
- */
61
- if (!qemu_coroutine_entered(laiocb->co)) {
62
- aio_co_wake(laiocb->co);
63
- }
64
- } else {
65
- laiocb->common.cb(laiocb->common.opaque, ret);
66
- qemu_aio_unref(laiocb);
67
+
68
+ /*
69
+ * If the coroutine is already entered it must be in ioq_submit() and
70
+ * will notice laio->ret has been filled in when it eventually runs
71
+ * later. Coroutines cannot be entered recursively so avoid doing
72
+ * that!
73
+ */
74
+ if (!qemu_coroutine_entered(laiocb->co)) {
75
+ aio_co_wake(laiocb->co);
76
}
77
}
78
79
@@ -XXX,XX +XXX,XX @@ static bool qemu_laio_poll_cb(void *opaque)
80
return true;
81
}
82
83
-static void laio_cancel(BlockAIOCB *blockacb)
84
-{
85
- struct qemu_laiocb *laiocb = (struct qemu_laiocb *)blockacb;
86
- struct io_event event;
87
- int ret;
88
-
89
- if (laiocb->ret != -EINPROGRESS) {
90
- return;
91
- }
92
- ret = io_cancel(laiocb->ctx->ctx, &laiocb->iocb, &event);
93
- laiocb->ret = -ECANCELED;
94
- if (ret != 0) {
95
- /* iocb is not cancelled, cb will be called by the event loop later */
96
- return;
97
- }
98
-
99
- laiocb->common.cb(laiocb->common.opaque, laiocb->ret);
100
-}
101
-
102
-static const AIOCBInfo laio_aiocb_info = {
103
- .aiocb_size = sizeof(struct qemu_laiocb),
104
- .cancel_async = laio_cancel,
105
-};
106
-
107
static void ioq_init(LaioQueue *io_q)
108
{
109
QSIMPLEQ_INIT(&io_q->pending);
110
@@ -XXX,XX +XXX,XX @@ int coroutine_fn laio_co_submit(BlockDriverState *bs, LinuxAioState *s, int fd,
111
return laiocb.ret;
112
}
113
114
-BlockAIOCB *laio_submit(BlockDriverState *bs, LinuxAioState *s, int fd,
115
- int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
116
- BlockCompletionFunc *cb, void *opaque, int type)
117
-{
118
- struct qemu_laiocb *laiocb;
119
- off_t offset = sector_num * BDRV_SECTOR_SIZE;
120
- int ret;
121
-
122
- laiocb = qemu_aio_get(&laio_aiocb_info, bs, cb, opaque);
123
- laiocb->nbytes = nb_sectors * BDRV_SECTOR_SIZE;
124
- laiocb->ctx = s;
125
- laiocb->ret = -EINPROGRESS;
126
- laiocb->is_read = (type == QEMU_AIO_READ);
127
- laiocb->qiov = qiov;
128
-
129
- ret = laio_do_submit(fd, laiocb, offset, type);
130
- if (ret < 0) {
131
- qemu_aio_unref(laiocb);
132
- return NULL;
133
- }
134
-
135
- return &laiocb->common;
136
-}
137
-
138
void laio_detach_aio_context(LinuxAioState *s, AioContext *old_context)
139
{
140
aio_set_event_notifier(old_context, &s->e, false, NULL, NULL);
141
--
142
2.20.1
143
144
diff view generated by jsdifflib
New patch
1
1
From: Kenneth Heitke <kenneth.heitke@intel.com>
2
3
Signed-off-by: Kenneth Heitke <kenneth.heitke@intel.com>
4
Reviewed-by: Klaus Birkelund Jensen <klaus.jensen@cnexlabs.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
7
hw/block/nvme.h | 2 +
8
include/block/nvme.h | 2 +
9
hw/block/nvme.c | 106 +++++++++++++++++++++++++++++++++++++++++-
10
hw/block/trace-events | 2 +
11
4 files changed, 110 insertions(+), 2 deletions(-)
12
13
diff --git a/hw/block/nvme.h b/hw/block/nvme.h
14
index XXXXXXX..XXXXXXX 100644
15
--- a/hw/block/nvme.h
16
+++ b/hw/block/nvme.h
17
@@ -XXX,XX +XXX,XX @@ typedef struct NvmeCtrl {
18
uint32_t cmbloc;
19
uint8_t *cmbuf;
20
uint64_t irq_status;
21
+ uint64_t host_timestamp; /* Timestamp sent by the host */
22
+ uint64_t timestamp_set_qemu_clock_ms; /* QEMU clock time */
23
24
char *serial;
25
NvmeNamespace *namespaces;
26
diff --git a/include/block/nvme.h b/include/block/nvme.h
27
index XXXXXXX..XXXXXXX 100644
28
--- a/include/block/nvme.h
29
+++ b/include/block/nvme.h
30
@@ -XXX,XX +XXX,XX @@ enum NvmeIdCtrlOncs {
31
NVME_ONCS_WRITE_ZEROS = 1 << 3,
32
NVME_ONCS_FEATURES = 1 << 4,
33
NVME_ONCS_RESRVATIONS = 1 << 5,
34
+ NVME_ONCS_TIMESTAMP = 1 << 6,
35
};
36
37
#define NVME_CTRL_SQES_MIN(sqes) ((sqes) & 0xf)
38
@@ -XXX,XX +XXX,XX @@ enum NvmeFeatureIds {
39
NVME_INTERRUPT_VECTOR_CONF = 0x9,
40
NVME_WRITE_ATOMICITY = 0xa,
41
NVME_ASYNCHRONOUS_EVENT_CONF = 0xb,
42
+ NVME_TIMESTAMP = 0xe,
43
NVME_SOFTWARE_PROGRESS_MARKER = 0x80
44
};
45
46
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
47
index XXXXXXX..XXXXXXX 100644
48
--- a/hw/block/nvme.c
49
+++ b/hw/block/nvme.c
50
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1,
51
return NVME_INVALID_FIELD | NVME_DNR;
52
}
53
54
+static uint16_t nvme_dma_write_prp(NvmeCtrl *n, uint8_t *ptr, uint32_t len,
55
+ uint64_t prp1, uint64_t prp2)
56
+{
57
+ QEMUSGList qsg;
58
+ QEMUIOVector iov;
59
+ uint16_t status = NVME_SUCCESS;
60
+
61
+ if (nvme_map_prp(&qsg, &iov, prp1, prp2, len, n)) {
62
+ return NVME_INVALID_FIELD | NVME_DNR;
63
+ }
64
+ if (qsg.nsg > 0) {
65
+ if (dma_buf_write(ptr, len, &qsg)) {
66
+ status = NVME_INVALID_FIELD | NVME_DNR;
67
+ }
68
+ qemu_sglist_destroy(&qsg);
69
+ } else {
70
+ if (qemu_iovec_to_buf(&iov, 0, ptr, len) != len) {
71
+ status = NVME_INVALID_FIELD | NVME_DNR;
72
+ }
73
+ qemu_iovec_destroy(&iov);
74
+ }
75
+ return status;
76
+}
77
+
78
static uint16_t nvme_dma_read_prp(NvmeCtrl *n, uint8_t *ptr, uint32_t len,
79
uint64_t prp1, uint64_t prp2)
80
{
81
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeIdentify *c)
82
return ret;
83
}
84
85
-
86
static uint16_t nvme_identify(NvmeCtrl *n, NvmeCmd *cmd)
87
{
88
NvmeIdentify *c = (NvmeIdentify *)cmd;
89
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_identify(NvmeCtrl *n, NvmeCmd *cmd)
90
}
91
}
92
93
+static inline void nvme_set_timestamp(NvmeCtrl *n, uint64_t ts)
94
+{
95
+ trace_nvme_setfeat_timestamp(ts);
96
+
97
+ n->host_timestamp = le64_to_cpu(ts);
98
+ n->timestamp_set_qemu_clock_ms = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
99
+}
100
+
101
+static inline uint64_t nvme_get_timestamp(const NvmeCtrl *n)
102
+{
103
+ uint64_t current_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
104
+ uint64_t elapsed_time = current_time - n->timestamp_set_qemu_clock_ms;
105
+
106
+ union nvme_timestamp {
107
+ struct {
108
+ uint64_t timestamp:48;
109
+ uint64_t sync:1;
110
+ uint64_t origin:3;
111
+ uint64_t rsvd1:12;
112
+ };
113
+ uint64_t all;
114
+ };
115
+
116
+ union nvme_timestamp ts;
117
+ ts.all = 0;
118
+
119
+ /*
120
+ * If the sum of the Timestamp value set by the host and the elapsed
121
+ * time exceeds 2^48, the value returned should be reduced modulo 2^48.
122
+ */
123
+ ts.timestamp = (n->host_timestamp + elapsed_time) & 0xffffffffffff;
124
+
125
+ /* If the host timestamp is non-zero, set the timestamp origin */
126
+ ts.origin = n->host_timestamp ? 0x01 : 0x00;
127
+
128
+ trace_nvme_getfeat_timestamp(ts.all);
129
+
130
+ return cpu_to_le64(ts.all);
131
+}
132
+
133
+static uint16_t nvme_get_feature_timestamp(NvmeCtrl *n, NvmeCmd *cmd)
134
+{
135
+ uint64_t prp1 = le64_to_cpu(cmd->prp1);
136
+ uint64_t prp2 = le64_to_cpu(cmd->prp2);
137
+
138
+ uint64_t timestamp = nvme_get_timestamp(n);
139
+
140
+ return nvme_dma_read_prp(n, (uint8_t *)&timestamp,
141
+ sizeof(timestamp), prp1, prp2);
142
+}
143
+
144
static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
145
{
146
uint32_t dw10 = le32_to_cpu(cmd->cdw10);
147
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
148
result = cpu_to_le32((n->num_queues - 2) | ((n->num_queues - 2) << 16));
149
trace_nvme_getfeat_numq(result);
150
break;
151
+ case NVME_TIMESTAMP:
152
+ return nvme_get_feature_timestamp(n, cmd);
153
+ break;
154
default:
155
trace_nvme_err_invalid_getfeat(dw10);
156
return NVME_INVALID_FIELD | NVME_DNR;
157
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
158
return NVME_SUCCESS;
159
}
160
161
+static uint16_t nvme_set_feature_timestamp(NvmeCtrl *n, NvmeCmd *cmd)
162
+{
163
+ uint16_t ret;
164
+ uint64_t timestamp;
165
+ uint64_t prp1 = le64_to_cpu(cmd->prp1);
166
+ uint64_t prp2 = le64_to_cpu(cmd->prp2);
167
+
168
+ ret = nvme_dma_write_prp(n, (uint8_t *)&timestamp,
169
+ sizeof(timestamp), prp1, prp2);
170
+ if (ret != NVME_SUCCESS) {
171
+ return ret;
172
+ }
173
+
174
+ nvme_set_timestamp(n, timestamp);
175
+
176
+ return NVME_SUCCESS;
177
+}
178
+
179
static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
180
{
181
uint32_t dw10 = le32_to_cpu(cmd->cdw10);
182
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
183
req->cqe.result =
184
cpu_to_le32((n->num_queues - 2) | ((n->num_queues - 2) << 16));
185
break;
186
+
187
+ case NVME_TIMESTAMP:
188
+ return nvme_set_feature_timestamp(n, cmd);
189
+ break;
190
+
191
default:
192
trace_nvme_err_invalid_setfeat(dw10);
193
return NVME_INVALID_FIELD | NVME_DNR;
194
@@ -XXX,XX +XXX,XX @@ static int nvme_start_ctrl(NvmeCtrl *n)
195
nvme_init_sq(&n->admin_sq, n, n->bar.asq, 0, 0,
196
NVME_AQA_ASQS(n->bar.aqa) + 1);
197
198
+ nvme_set_timestamp(n, 0ULL);
199
+
200
return 0;
201
}
202
203
@@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
204
id->sqes = (0x6 << 4) | 0x6;
205
id->cqes = (0x4 << 4) | 0x4;
206
id->nn = cpu_to_le32(n->num_namespaces);
207
- id->oncs = cpu_to_le16(NVME_ONCS_WRITE_ZEROS);
208
+ id->oncs = cpu_to_le16(NVME_ONCS_WRITE_ZEROS | NVME_ONCS_TIMESTAMP);
209
id->psd[0].mp = cpu_to_le16(0x9c4);
210
id->psd[0].enlat = cpu_to_le32(0x10);
211
id->psd[0].exlat = cpu_to_le32(0x4);
212
diff --git a/hw/block/trace-events b/hw/block/trace-events
213
index XXXXXXX..XXXXXXX 100644
214
--- a/hw/block/trace-events
215
+++ b/hw/block/trace-events
216
@@ -XXX,XX +XXX,XX @@ nvme_identify_nslist(uint16_t ns) "identify namespace list, nsid=%"PRIu16""
217
nvme_getfeat_vwcache(const char* result) "get feature volatile write cache, result=%s"
218
nvme_getfeat_numq(int result) "get feature number of queues, result=%d"
219
nvme_setfeat_numq(int reqcq, int reqsq, int gotcq, int gotsq) "requested cq_count=%d sq_count=%d, responding with cq_count=%d sq_count=%d"
220
+nvme_setfeat_timestamp(uint64_t ts) "set feature timestamp = 0x%"PRIx64""
221
+nvme_getfeat_timestamp(uint64_t ts) "get feature timestamp = 0x%"PRIx64""
222
nvme_mmio_intm_set(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask set, data=0x%"PRIx64", new_mask=0x%"PRIx64""
223
nvme_mmio_intm_clr(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask clr, data=0x%"PRIx64", new_mask=0x%"PRIx64""
224
nvme_mmio_cfg(uint64_t data) "wrote MMIO, config controller config=0x%"PRIx64""
225
--
226
2.20.1
227
228
diff view generated by jsdifflib
New patch
1
Just make the test cover the AioContext of the filter node as well.
1
2
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Reviewed-by: Eric Blake <eblake@redhat.com>
5
---
6
tests/test-block-iothread.c | 7 ++++++-
7
1 file changed, 6 insertions(+), 1 deletion(-)
8
9
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
10
index XXXXXXX..XXXXXXX 100644
11
--- a/tests/test-block-iothread.c
12
+++ b/tests/test-block-iothread.c
13
@@ -XXX,XX +XXX,XX @@ static void test_propagate_mirror(void)
14
IOThread *iothread = iothread_new();
15
AioContext *ctx = iothread_get_aio_context(iothread);
16
AioContext *main_ctx = qemu_get_aio_context();
17
- BlockDriverState *src, *target;
18
+ BlockDriverState *src, *target, *filter;
19
BlockBackend *blk;
20
Job *job;
21
Error *local_err = NULL;
22
@@ -XXX,XX +XXX,XX @@ static void test_propagate_mirror(void)
23
false, "filter_node", MIRROR_COPY_MODE_BACKGROUND,
24
&error_abort);
25
job = job_get("job0");
26
+ filter = bdrv_find_node("filter_node");
27
28
/* Change the AioContext of src */
29
bdrv_try_set_aio_context(src, ctx, &error_abort);
30
g_assert(bdrv_get_aio_context(src) == ctx);
31
g_assert(bdrv_get_aio_context(target) == ctx);
32
+ g_assert(bdrv_get_aio_context(filter) == ctx);
33
g_assert(job->aio_context == ctx);
34
35
/* Change the AioContext of target */
36
@@ -XXX,XX +XXX,XX @@ static void test_propagate_mirror(void)
37
aio_context_release(ctx);
38
g_assert(bdrv_get_aio_context(src) == main_ctx);
39
g_assert(bdrv_get_aio_context(target) == main_ctx);
40
+ g_assert(bdrv_get_aio_context(filter) == main_ctx);
41
42
/* With a BlockBackend on src, changing target must fail */
43
blk = blk_new(0, BLK_PERM_ALL);
44
@@ -XXX,XX +XXX,XX @@ static void test_propagate_mirror(void)
45
g_assert(blk_get_aio_context(blk) == main_ctx);
46
g_assert(bdrv_get_aio_context(src) == main_ctx);
47
g_assert(bdrv_get_aio_context(target) == main_ctx);
48
+ g_assert(bdrv_get_aio_context(filter) == main_ctx);
49
50
/* ...unless we explicitly allow it */
51
aio_context_acquire(ctx);
52
@@ -XXX,XX +XXX,XX @@ static void test_propagate_mirror(void)
53
g_assert(blk_get_aio_context(blk) == ctx);
54
g_assert(bdrv_get_aio_context(src) == ctx);
55
g_assert(bdrv_get_aio_context(target) == ctx);
56
+ g_assert(bdrv_get_aio_context(filter) == ctx);
57
58
job_cancel_sync_all();
59
60
--
61
2.20.1
62
63
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
The NBD server uses an AioContext notifier, so it can tolerate that its
2
BlockBackend is switched to a different AioContext. Before we start
3
actually calling bdrv_try_set_aio_context(), which checks for
4
consistency, outside of test cases, we need to make sure that the NBD
5
server actually allows this.
2
6
3
Signed-off-by: Max Reitz <mreitz@redhat.com>
4
Reviewed-by: Alberto Garcia <berto@igalia.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
6
---
9
---
7
tests/qemu-iotests/182 | 71 ++++++++++++++++++++++++++++++++++++++
10
nbd/server.c | 1 +
8
tests/qemu-iotests/182.out | 9 +++++
11
tests/qemu-iotests/240 | 21 +++++++++++++++++++++
9
2 files changed, 80 insertions(+)
12
tests/qemu-iotests/240.out | 13 +++++++++++++
13
3 files changed, 35 insertions(+)
10
14
11
diff --git a/tests/qemu-iotests/182 b/tests/qemu-iotests/182
15
diff --git a/nbd/server.c b/nbd/server.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/nbd/server.c
18
+++ b/nbd/server.c
19
@@ -XXX,XX +XXX,XX @@ NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset,
20
goto fail;
21
}
22
blk_set_enable_write_cache(blk, !writethrough);
23
+ blk_set_allow_aio_context_change(blk, true);
24
25
exp->refcount = 1;
26
QTAILQ_INIT(&exp->clients);
27
diff --git a/tests/qemu-iotests/240 b/tests/qemu-iotests/240
12
index XXXXXXX..XXXXXXX 100755
28
index XXXXXXX..XXXXXXX 100755
13
--- a/tests/qemu-iotests/182
29
--- a/tests/qemu-iotests/240
14
+++ b/tests/qemu-iotests/182
30
+++ b/tests/qemu-iotests/240
15
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
31
@@ -XXX,XX +XXX,XX @@ echo "QA output created by $seq"
16
_cleanup()
32
17
{
33
status=1    # failure is the default!
18
_cleanup_test_img
34
19
+ rm -f "$TEST_IMG.overlay"
35
+_cleanup()
20
}
36
+{
21
trap "_cleanup; exit \$status" 0 1 2 3 15
37
+ rm -f "$TEST_DIR/nbd"
22
38
+}
23
@@ -XXX,XX +XXX,XX @@ echo 'quit' | $QEMU -nographic -monitor stdio \
39
+trap "_cleanup; exit \$status" 0 1 2 3 15
24
40
+
25
_cleanup_qemu
41
# get standard environment, filters and checks
42
. ./common.rc
43
. ./common.filter
44
@@ -XXX,XX +XXX,XX @@ run_qemu <<EOF
45
{ "execute": "quit"}
46
EOF
26
47
27
+echo
48
+echo
28
+echo '=== Testing reopen ==='
49
+echo === Attach a SCSI disks using the same block device as a NBD server ===
29
+echo
50
+echo
30
+
51
+
31
+# This tests that reopening does not unshare any permissions it should
52
+run_qemu <<EOF
32
+# not unshare
53
+{ "execute": "qmp_capabilities" }
33
+# (There was a bug where reopening shared exactly the opposite of the
54
+{ "execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "hd0", "read-only": true}}
34
+# permissions it was supposed to share)
55
+{ "execute": "nbd-server-start", "arguments": {"addr":{"type":"unix","data":{"path":"$TEST_DIR/nbd"}}}}
35
+
56
+{ "execute": "nbd-server-add", "arguments": {"device":"hd0"}}
36
+_launch_qemu
57
+{ "execute": "object-add", "arguments": {"qom-type": "iothread", "id": "iothread0"}}
37
+
58
+{ "execute": "device_add", "arguments": {"id": "scsi0", "driver": "${virtio_scsi}", "iothread": "iothread0"}}
38
+_send_qemu_cmd $QEMU_HANDLE \
59
+{ "execute": "device_add", "arguments": {"id": "scsi-hd0", "driver": "scsi-hd", "drive": "hd0", "bus": "scsi0.0"}}
39
+ "{'execute': 'qmp_capabilities'}" \
60
+{ "execute": "quit"}
40
+ 'return'
61
+EOF
41
+
42
+# Open the image without any format layer (we are not going to access
43
+# it, so that is fine)
44
+# This should keep all permissions shared.
45
+success_or_failure=y _send_qemu_cmd $QEMU_HANDLE \
46
+ "{'execute': 'blockdev-add',
47
+ 'arguments': {
48
+ 'node-name': 'node0',
49
+ 'driver': 'file',
50
+ 'filename': '$TEST_IMG',
51
+ 'locking': 'on'
52
+ } }" \
53
+ 'return' \
54
+ 'error'
55
+
56
+# This snapshot will perform a reopen to drop R/W to RO.
57
+# It should still keep all permissions shared.
58
+success_or_failure=y _send_qemu_cmd $QEMU_HANDLE \
59
+ "{'execute': 'blockdev-snapshot-sync',
60
+ 'arguments': {
61
+ 'node-name': 'node0',
62
+ 'snapshot-file': '$TEST_IMG.overlay',
63
+ 'snapshot-node-name': 'node1'
64
+ } }" \
65
+ 'return' \
66
+ 'error'
67
+
68
+# Now open the same file again
69
+# This does not require any permissions (and does not unshare any), so
70
+# this will not conflict with node0.
71
+success_or_failure=y _send_qemu_cmd $QEMU_HANDLE \
72
+ "{'execute': 'blockdev-add',
73
+ 'arguments': {
74
+ 'node-name': 'node1',
75
+ 'driver': 'file',
76
+ 'filename': '$TEST_IMG',
77
+ 'locking': 'on'
78
+ } }" \
79
+ 'return' \
80
+ 'error'
81
+
82
+# Now we attach the image to a virtio-blk device. This device does
83
+# require some permissions (at least WRITE and READ_CONSISTENT), so if
84
+# reopening node0 unshared any (which it should not have), this will
85
+# fail (but it should not).
86
+success_or_failure=y _send_qemu_cmd $QEMU_HANDLE \
87
+ "{'execute': 'device_add',
88
+ 'arguments': {
89
+ 'driver': 'virtio-blk',
90
+ 'drive': 'node1'
91
+ } }" \
92
+ 'return' \
93
+ 'error'
94
+
95
+_cleanup_qemu
96
+
62
+
97
# success, all done
63
# success, all done
98
echo "*** done"
64
echo "*** done"
99
rm -f $seq.full
65
rm -f $seq.full
100
diff --git a/tests/qemu-iotests/182.out b/tests/qemu-iotests/182.out
66
diff --git a/tests/qemu-iotests/240.out b/tests/qemu-iotests/240.out
101
index XXXXXXX..XXXXXXX 100644
67
index XXXXXXX..XXXXXXX 100644
102
--- a/tests/qemu-iotests/182.out
68
--- a/tests/qemu-iotests/240.out
103
+++ b/tests/qemu-iotests/182.out
69
+++ b/tests/qemu-iotests/240.out
104
@@ -XXX,XX +XXX,XX @@ Starting QEMU
70
@@ -XXX,XX +XXX,XX @@ QMP_VERSION
105
Starting a second QEMU using the same image should fail
71
{"return": {}}
106
QEMU_PROG: -drive file=TEST_DIR/t.qcow2,if=none,id=drive0,file.locking=on: Failed to get "write" lock
72
{"return": {}}
107
Is another process using the image [TEST_DIR/t.qcow2]?
73
{"return": {}}
108
+
74
+
109
+=== Testing reopen ===
75
+=== Attach a SCSI disks using the same block device as a NBD server ===
110
+
76
+
77
+Testing:
78
+QMP_VERSION
111
+{"return": {}}
79
+{"return": {}}
112
+{"return": {}}
80
+{"return": {}}
113
+Formatting 'TEST_DIR/t.qcow2.overlay', fmt=qcow2 size=197120 backing_file=TEST_DIR/t.qcow2 backing_fmt=file cluster_size=65536 lazy_refcounts=off refcount_bits=16
81
+{"return": {}}
82
+{"return": {}}
83
+{"return": {}}
114
+{"return": {}}
84
+{"return": {}}
115
+{"return": {}}
85
+{"return": {}}
116
+{"return": {}}
86
+{"return": {}}
117
*** done
87
*** done
118
--
88
--
119
2.19.1
89
2.20.1
120
90
121
91
diff view generated by jsdifflib
New patch
1
Add an Error parameter to blk_set_aio_context() and use
2
bdrv_child_try_set_aio_context() internally to check whether all
3
involved nodes can actually support the AioContext switch.
1
4
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
7
include/sysemu/block-backend.h | 3 ++-
8
block/block-backend.c | 26 ++++++++++++++++----------
9
hw/block/dataplane/virtio-blk.c | 12 +++++++++---
10
hw/block/dataplane/xen-block.c | 6 ++++--
11
hw/scsi/virtio-scsi.c | 10 +++++++---
12
tests/test-bdrv-drain.c | 8 ++++----
13
tests/test-block-iothread.c | 22 +++++++++++-----------
14
7 files changed, 53 insertions(+), 34 deletions(-)
15
16
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
17
index XXXXXXX..XXXXXXX 100644
18
--- a/include/sysemu/block-backend.h
19
+++ b/include/sysemu/block-backend.h
20
@@ -XXX,XX +XXX,XX @@ void blk_op_unblock(BlockBackend *blk, BlockOpType op, Error *reason);
21
void blk_op_block_all(BlockBackend *blk, Error *reason);
22
void blk_op_unblock_all(BlockBackend *blk, Error *reason);
23
AioContext *blk_get_aio_context(BlockBackend *blk);
24
-void blk_set_aio_context(BlockBackend *blk, AioContext *new_context);
25
+int blk_set_aio_context(BlockBackend *blk, AioContext *new_context,
26
+ Error **errp);
27
void blk_add_aio_context_notifier(BlockBackend *blk,
28
void (*attached_aio_context)(AioContext *new_context, void *opaque),
29
void (*detach_aio_context)(void *opaque), void *opaque);
30
diff --git a/block/block-backend.c b/block/block-backend.c
31
index XXXXXXX..XXXXXXX 100644
32
--- a/block/block-backend.c
33
+++ b/block/block-backend.c
34
@@ -XXX,XX +XXX,XX @@ static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb)
35
return blk_get_aio_context(blk_acb->blk);
36
}
37
38
-static void blk_do_set_aio_context(BlockBackend *blk, AioContext *new_context,
39
- bool update_root_node)
40
+static int blk_do_set_aio_context(BlockBackend *blk, AioContext *new_context,
41
+ bool update_root_node, Error **errp)
42
{
43
BlockDriverState *bs = blk_bs(blk);
44
ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
45
+ int ret;
46
47
if (bs) {
48
+ if (update_root_node) {
49
+ ret = bdrv_child_try_set_aio_context(bs, new_context, blk->root,
50
+ errp);
51
+ if (ret < 0) {
52
+ return ret;
53
+ }
54
+ }
55
if (tgm->throttle_state) {
56
bdrv_drained_begin(bs);
57
throttle_group_detach_aio_context(tgm);
58
throttle_group_attach_aio_context(tgm, new_context);
59
bdrv_drained_end(bs);
60
}
61
- if (update_root_node) {
62
- GSList *ignore = g_slist_prepend(NULL, blk->root);
63
- bdrv_set_aio_context_ignore(bs, new_context, &ignore);
64
- g_slist_free(ignore);
65
- }
66
}
67
+
68
+ return 0;
69
}
70
71
-void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
72
+int blk_set_aio_context(BlockBackend *blk, AioContext *new_context,
73
+ Error **errp)
74
{
75
- blk_do_set_aio_context(blk, new_context, true);
76
+ return blk_do_set_aio_context(blk, new_context, true, errp);
77
}
78
79
static bool blk_root_can_set_aio_ctx(BdrvChild *child, AioContext *ctx,
80
@@ -XXX,XX +XXX,XX @@ static void blk_root_set_aio_ctx(BdrvChild *child, AioContext *ctx,
81
GSList **ignore)
82
{
83
BlockBackend *blk = child->opaque;
84
- blk_do_set_aio_context(blk, ctx, false);
85
+ blk_do_set_aio_context(blk, ctx, false, &error_abort);
86
}
87
88
void blk_add_aio_context_notifier(BlockBackend *blk,
89
diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c
90
index XXXXXXX..XXXXXXX 100644
91
--- a/hw/block/dataplane/virtio-blk.c
92
+++ b/hw/block/dataplane/virtio-blk.c
93
@@ -XXX,XX +XXX,XX @@ int virtio_blk_data_plane_start(VirtIODevice *vdev)
94
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
95
unsigned i;
96
unsigned nvqs = s->conf->num_queues;
97
+ Error *local_err = NULL;
98
int r;
99
100
if (vblk->dataplane_started || s->starting) {
101
@@ -XXX,XX +XXX,XX @@ int virtio_blk_data_plane_start(VirtIODevice *vdev)
102
vblk->dataplane_started = true;
103
trace_virtio_blk_data_plane_start(s);
104
105
- blk_set_aio_context(s->conf->conf.blk, s->ctx);
106
+ r = blk_set_aio_context(s->conf->conf.blk, s->ctx, &local_err);
107
+ if (r < 0) {
108
+ error_report_err(local_err);
109
+ goto fail_guest_notifiers;
110
+ }
111
112
/* Kick right away to begin processing requests already in vring */
113
for (i = 0; i < nvqs; i++) {
114
@@ -XXX,XX +XXX,XX @@ void virtio_blk_data_plane_stop(VirtIODevice *vdev)
115
aio_context_acquire(s->ctx);
116
aio_wait_bh_oneshot(s->ctx, virtio_blk_data_plane_stop_bh, s);
117
118
- /* Drain and switch bs back to the QEMU main loop */
119
- blk_set_aio_context(s->conf->conf.blk, qemu_get_aio_context());
120
+ /* Drain and try to switch bs back to the QEMU main loop. If other users
121
+ * keep the BlockBackend in the iothread, that's ok */
122
+ blk_set_aio_context(s->conf->conf.blk, qemu_get_aio_context(), NULL);
123
124
aio_context_release(s->ctx);
125
126
diff --git a/hw/block/dataplane/xen-block.c b/hw/block/dataplane/xen-block.c
127
index XXXXXXX..XXXXXXX 100644
128
--- a/hw/block/dataplane/xen-block.c
129
+++ b/hw/block/dataplane/xen-block.c
130
@@ -XXX,XX +XXX,XX @@ void xen_block_dataplane_stop(XenBlockDataPlane *dataplane)
131
}
132
133
aio_context_acquire(dataplane->ctx);
134
- blk_set_aio_context(dataplane->blk, qemu_get_aio_context());
135
+ /* Xen doesn't have multiple users for nodes, so this can't fail */
136
+ blk_set_aio_context(dataplane->blk, qemu_get_aio_context(), &error_abort);
137
aio_context_release(dataplane->ctx);
138
139
xendev = dataplane->xendev;
140
@@ -XXX,XX +XXX,XX @@ void xen_block_dataplane_start(XenBlockDataPlane *dataplane,
141
}
142
143
aio_context_acquire(dataplane->ctx);
144
- blk_set_aio_context(dataplane->blk, dataplane->ctx);
145
+ /* If other users keep the BlockBackend in the iothread, that's ok */
146
+ blk_set_aio_context(dataplane->blk, dataplane->ctx, NULL);
147
aio_context_release(dataplane->ctx);
148
return;
149
150
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
151
index XXXXXXX..XXXXXXX 100644
152
--- a/hw/scsi/virtio-scsi.c
153
+++ b/hw/scsi/virtio-scsi.c
154
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev,
155
VirtIODevice *vdev = VIRTIO_DEVICE(hotplug_dev);
156
VirtIOSCSI *s = VIRTIO_SCSI(vdev);
157
SCSIDevice *sd = SCSI_DEVICE(dev);
158
+ int ret;
159
160
if (s->ctx && !s->dataplane_fenced) {
161
AioContext *ctx;
162
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev,
163
return;
164
}
165
virtio_scsi_acquire(s);
166
- blk_set_aio_context(sd->conf.blk, s->ctx);
167
+ ret = blk_set_aio_context(sd->conf.blk, s->ctx, errp);
168
virtio_scsi_release(s);
169
-
170
+ if (ret < 0) {
171
+ return;
172
+ }
173
}
174
175
if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) {
176
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_hotunplug(HotplugHandler *hotplug_dev, DeviceState *dev,
177
178
if (s->ctx) {
179
virtio_scsi_acquire(s);
180
- blk_set_aio_context(sd->conf.blk, qemu_get_aio_context());
181
+ /* If other users keep the BlockBackend in the iothread, that's ok */
182
+ blk_set_aio_context(sd->conf.blk, qemu_get_aio_context(), NULL);
183
virtio_scsi_release(s);
184
}
185
186
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
187
index XXXXXXX..XXXXXXX 100644
188
--- a/tests/test-bdrv-drain.c
189
+++ b/tests/test-bdrv-drain.c
190
@@ -XXX,XX +XXX,XX @@ static void test_iothread_common(enum drain_type drain_type, int drain_thread)
191
s = bs->opaque;
192
blk_insert_bs(blk, bs, &error_abort);
193
194
- blk_set_aio_context(blk, ctx_a);
195
+ blk_set_aio_context(blk, ctx_a, &error_abort);
196
aio_context_acquire(ctx_a);
197
198
s->bh_indirection_ctx = ctx_b;
199
@@ -XXX,XX +XXX,XX @@ static void test_iothread_common(enum drain_type drain_type, int drain_thread)
200
}
201
202
aio_context_acquire(ctx_a);
203
- blk_set_aio_context(blk, qemu_get_aio_context());
204
+ blk_set_aio_context(blk, qemu_get_aio_context(), &error_abort);
205
aio_context_release(ctx_a);
206
207
bdrv_unref(bs);
208
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
209
if (use_iothread) {
210
iothread = iothread_new();
211
ctx = iothread_get_aio_context(iothread);
212
- blk_set_aio_context(blk_src, ctx);
213
+ blk_set_aio_context(blk_src, ctx, &error_abort);
214
} else {
215
ctx = qemu_get_aio_context();
216
}
217
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
218
g_assert_cmpint(ret, ==, (result == TEST_JOB_SUCCESS ? 0 : -EIO));
219
220
if (use_iothread) {
221
- blk_set_aio_context(blk_src, qemu_get_aio_context());
222
+ blk_set_aio_context(blk_src, qemu_get_aio_context(), &error_abort);
223
}
224
aio_context_release(ctx);
225
226
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
227
index XXXXXXX..XXXXXXX 100644
228
--- a/tests/test-block-iothread.c
229
+++ b/tests/test-block-iothread.c
230
@@ -XXX,XX +XXX,XX @@ static void test_sync_op(const void *opaque)
231
blk_insert_bs(blk, bs, &error_abort);
232
c = QLIST_FIRST(&bs->parents);
233
234
- blk_set_aio_context(blk, ctx);
235
+ blk_set_aio_context(blk, ctx, &error_abort);
236
aio_context_acquire(ctx);
237
t->fn(c);
238
if (t->blkfn) {
239
t->blkfn(blk);
240
}
241
aio_context_release(ctx);
242
- blk_set_aio_context(blk, qemu_get_aio_context());
243
+ blk_set_aio_context(blk, qemu_get_aio_context(), &error_abort);
244
245
bdrv_unref(bs);
246
blk_unref(blk);
247
@@ -XXX,XX +XXX,XX @@ static void test_attach_blockjob(void)
248
aio_poll(qemu_get_aio_context(), false);
249
}
250
251
- blk_set_aio_context(blk, ctx);
252
+ blk_set_aio_context(blk, ctx, &error_abort);
253
254
tjob->n = 0;
255
while (tjob->n == 0) {
256
@@ -XXX,XX +XXX,XX @@ static void test_attach_blockjob(void)
257
}
258
259
aio_context_acquire(ctx);
260
- blk_set_aio_context(blk, qemu_get_aio_context());
261
+ blk_set_aio_context(blk, qemu_get_aio_context(), &error_abort);
262
aio_context_release(ctx);
263
264
tjob->n = 0;
265
@@ -XXX,XX +XXX,XX @@ static void test_attach_blockjob(void)
266
aio_poll(qemu_get_aio_context(), false);
267
}
268
269
- blk_set_aio_context(blk, ctx);
270
+ blk_set_aio_context(blk, ctx, &error_abort);
271
272
tjob->n = 0;
273
while (tjob->n == 0) {
274
@@ -XXX,XX +XXX,XX @@ static void test_attach_blockjob(void)
275
276
aio_context_acquire(ctx);
277
job_complete_sync(&tjob->common.job, &error_abort);
278
- blk_set_aio_context(blk, qemu_get_aio_context());
279
+ blk_set_aio_context(blk, qemu_get_aio_context(), &error_abort);
280
aio_context_release(ctx);
281
282
bdrv_unref(bs);
283
@@ -XXX,XX +XXX,XX @@ static void test_propagate_basic(void)
284
bs_verify = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
285
286
/* Switch the AioContext */
287
- blk_set_aio_context(blk, ctx);
288
+ blk_set_aio_context(blk, ctx, &error_abort);
289
g_assert(blk_get_aio_context(blk) == ctx);
290
g_assert(bdrv_get_aio_context(bs_a) == ctx);
291
g_assert(bdrv_get_aio_context(bs_verify) == ctx);
292
@@ -XXX,XX +XXX,XX @@ static void test_propagate_basic(void)
293
294
/* Switch the AioContext back */
295
ctx = qemu_get_aio_context();
296
- blk_set_aio_context(blk, ctx);
297
+ blk_set_aio_context(blk, ctx, &error_abort);
298
g_assert(blk_get_aio_context(blk) == ctx);
299
g_assert(bdrv_get_aio_context(bs_a) == ctx);
300
g_assert(bdrv_get_aio_context(bs_verify) == ctx);
301
@@ -XXX,XX +XXX,XX @@ static void test_propagate_diamond(void)
302
blk_insert_bs(blk, bs_verify, &error_abort);
303
304
/* Switch the AioContext */
305
- blk_set_aio_context(blk, ctx);
306
+ blk_set_aio_context(blk, ctx, &error_abort);
307
g_assert(blk_get_aio_context(blk) == ctx);
308
g_assert(bdrv_get_aio_context(bs_verify) == ctx);
309
g_assert(bdrv_get_aio_context(bs_a) == ctx);
310
@@ -XXX,XX +XXX,XX @@ static void test_propagate_diamond(void)
311
312
/* Switch the AioContext back */
313
ctx = qemu_get_aio_context();
314
- blk_set_aio_context(blk, ctx);
315
+ blk_set_aio_context(blk, ctx, &error_abort);
316
g_assert(blk_get_aio_context(blk) == ctx);
317
g_assert(bdrv_get_aio_context(bs_verify) == ctx);
318
g_assert(bdrv_get_aio_context(bs_a) == ctx);
319
@@ -XXX,XX +XXX,XX @@ static void test_propagate_mirror(void)
320
job_cancel_sync_all();
321
322
aio_context_acquire(ctx);
323
- blk_set_aio_context(blk, main_ctx);
324
+ blk_set_aio_context(blk, main_ctx, &error_abort);
325
bdrv_try_set_aio_context(target, main_ctx, &error_abort);
326
aio_context_release(ctx);
327
328
--
329
2.20.1
330
331
diff view generated by jsdifflib
1
From: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
1
This adds a new parameter to blk_new() which requires its callers to
2
declare from which AioContext this BlockBackend is going to be used (or
3
the locks of which AioContext need to be taken anyway).
2
4
3
Commit c8a35f1cf0f "fdc: use IsaDma interface instead of global DMA_*
5
The given context is only stored and kept up to date when changing
4
functions" accidentally introduced a segfault in fdctrl_stop_transfer() for
6
AioContexts. Actually applying the stored AioContext to the root node
5
non-DMA transfers.
7
is saved for another commit.
6
8
7
If fdctrl->dma_chann has not been configured then the fdctrl->dma interface
8
reference isn't initialised during isabus_fdc_realize(). Unfortunately
9
fdctrl_stop_transfer() unconditionally references the DMA interface when
10
finishing the transfer causing a NULL pointer dereference.
11
12
Fix the issue by adding a check in fdctrl_stop_transfer() so that the DMA
13
interface reference and release method is only invoked if fdctrl->dma_chann
14
has been set.
15
16
(This issue was discovered by Martin testing a recent change in the NetBSD
17
installer under qemu-system-sparc)
18
19
Cc: qemu-stable@nongnu.org
20
Reported-by: Martin Husemann <martin@duskware.de>
21
Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
22
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
23
Reviewed-by: Hervé Poussineau <hpoussin@reactos.org>
24
Reviewed-by: John Snow <jsnow@redhat.com>
25
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
26
---
10
---
27
hw/block/fdc.c | 2 +-
11
include/sysemu/block-backend.h | 2 +-
28
1 file changed, 1 insertion(+), 1 deletion(-)
12
block.c | 2 +-
13
block/backup.c | 3 ++-
14
block/block-backend.c | 18 +++++++++++++++---
15
block/commit.c | 11 +++++++----
16
block/crypto.c | 3 ++-
17
block/mirror.c | 3 ++-
18
block/parallels.c | 3 ++-
19
block/qcow.c | 3 ++-
20
block/qcow2.c | 6 ++++--
21
block/qed.c | 3 ++-
22
block/sheepdog.c | 3 ++-
23
block/vdi.c | 3 ++-
24
block/vhdx.c | 3 ++-
25
block/vmdk.c | 3 ++-
26
block/vpc.c | 3 ++-
27
blockdev.c | 4 ++--
28
blockjob.c | 2 +-
29
hmp.c | 3 ++-
30
hw/block/fdc.c | 2 +-
31
hw/block/xen-block.c | 2 +-
32
hw/core/qdev-properties-system.c | 4 +++-
33
hw/ide/qdev.c | 2 +-
34
hw/scsi/scsi-disk.c | 2 +-
35
migration/block.c | 3 ++-
36
nbd/server.c | 5 +++--
37
qemu-img.c | 6 ++++--
38
tests/test-bdrv-drain.c | 30 +++++++++++++++---------------
39
tests/test-bdrv-graph-mod.c | 5 +++--
40
tests/test-block-backend.c | 6 ++++--
41
tests/test-block-iothread.c | 10 +++++-----
42
tests/test-blockjob.c | 2 +-
43
tests/test-throttle.c | 6 +++---
44
33 files changed, 102 insertions(+), 64 deletions(-)
29
45
46
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
47
index XXXXXXX..XXXXXXX 100644
48
--- a/include/sysemu/block-backend.h
49
+++ b/include/sysemu/block-backend.h
50
@@ -XXX,XX +XXX,XX @@ typedef struct BlockBackendPublic {
51
ThrottleGroupMember throttle_group_member;
52
} BlockBackendPublic;
53
54
-BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm);
55
+BlockBackend *blk_new(AioContext *ctx, uint64_t perm, uint64_t shared_perm);
56
BlockBackend *blk_new_open(const char *filename, const char *reference,
57
QDict *options, int flags, Error **errp);
58
int blk_get_refcnt(BlockBackend *blk);
59
diff --git a/block.c b/block.c
60
index XXXXXXX..XXXXXXX 100644
61
--- a/block.c
62
+++ b/block.c
63
@@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
64
/* Not requesting BLK_PERM_CONSISTENT_READ because we're only
65
* looking at the header to guess the image format. This works even
66
* in cases where a guest would not see a consistent state. */
67
- file = blk_new(0, BLK_PERM_ALL);
68
+ file = blk_new(bdrv_get_aio_context(file_bs), 0, BLK_PERM_ALL);
69
blk_insert_bs(file, file_bs, &local_err);
70
bdrv_unref(file_bs);
71
if (local_err) {
72
diff --git a/block/backup.c b/block/backup.c
73
index XXXXXXX..XXXXXXX 100644
74
--- a/block/backup.c
75
+++ b/block/backup.c
76
@@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
77
}
78
79
/* The target must match the source in size, so no resize here either */
80
- job->target = blk_new(BLK_PERM_WRITE,
81
+ job->target = blk_new(job->common.job.aio_context,
82
+ BLK_PERM_WRITE,
83
BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE |
84
BLK_PERM_WRITE_UNCHANGED | BLK_PERM_GRAPH_MOD);
85
ret = blk_insert_bs(job->target, target, errp);
86
diff --git a/block/block-backend.c b/block/block-backend.c
87
index XXXXXXX..XXXXXXX 100644
88
--- a/block/block-backend.c
89
+++ b/block/block-backend.c
90
@@ -XXX,XX +XXX,XX @@ struct BlockBackend {
91
char *name;
92
int refcnt;
93
BdrvChild *root;
94
+ AioContext *ctx;
95
DriveInfo *legacy_dinfo; /* null unless created by drive_new() */
96
QTAILQ_ENTRY(BlockBackend) link; /* for block_backends */
97
QTAILQ_ENTRY(BlockBackend) monitor_link; /* for monitor_block_backends */
98
@@ -XXX,XX +XXX,XX @@ static const BdrvChildRole child_root = {
99
*
100
* Return the new BlockBackend on success, null on failure.
101
*/
102
-BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm)
103
+BlockBackend *blk_new(AioContext *ctx, uint64_t perm, uint64_t shared_perm)
104
{
105
BlockBackend *blk;
106
107
blk = g_new0(BlockBackend, 1);
108
blk->refcnt = 1;
109
+ blk->ctx = ctx;
110
blk->perm = perm;
111
blk->shared_perm = shared_perm;
112
blk_set_enable_write_cache(blk, true);
113
@@ -XXX,XX +XXX,XX @@ BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm)
114
115
/*
116
* Creates a new BlockBackend, opens a new BlockDriverState, and connects both.
117
+ * The new BlockBackend is in the main AioContext.
118
*
119
* Just as with bdrv_open(), after having called this function the reference to
120
* @options belongs to the block layer (even on failure).
121
@@ -XXX,XX +XXX,XX @@ BlockBackend *blk_new_open(const char *filename, const char *reference,
122
perm |= BLK_PERM_RESIZE;
123
}
124
125
- blk = blk_new(perm, BLK_PERM_ALL);
126
+ blk = blk_new(qemu_get_aio_context(), perm, BLK_PERM_ALL);
127
bs = bdrv_open(filename, reference, options, flags, errp);
128
if (!bs) {
129
blk_unref(blk);
130
@@ -XXX,XX +XXX,XX @@ void blk_op_unblock_all(BlockBackend *blk, Error *reason)
131
132
AioContext *blk_get_aio_context(BlockBackend *blk)
133
{
134
- return bdrv_get_aio_context(blk_bs(blk));
135
+ BlockDriverState *bs = blk_bs(blk);
136
+
137
+ /* FIXME The AioContext of bs and blk can be inconsistent. For the moment,
138
+ * we prefer the one of bs for compatibility. */
139
+ if (bs) {
140
+ return bdrv_get_aio_context(blk_bs(blk));
141
+ }
142
+
143
+ return blk->ctx;
144
}
145
146
static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb)
147
@@ -XXX,XX +XXX,XX @@ static int blk_do_set_aio_context(BlockBackend *blk, AioContext *new_context,
148
}
149
}
150
151
+ blk->ctx = new_context;
152
return 0;
153
}
154
155
diff --git a/block/commit.c b/block/commit.c
156
index XXXXXXX..XXXXXXX 100644
157
--- a/block/commit.c
158
+++ b/block/commit.c
159
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
160
goto fail;
161
}
162
163
- s->base = blk_new(BLK_PERM_CONSISTENT_READ
164
+ s->base = blk_new(s->common.job.aio_context,
165
+ BLK_PERM_CONSISTENT_READ
166
| BLK_PERM_WRITE
167
| BLK_PERM_RESIZE,
168
BLK_PERM_CONSISTENT_READ
169
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
170
s->base_bs = base;
171
172
/* Required permissions are already taken with block_job_add_bdrv() */
173
- s->top = blk_new(0, BLK_PERM_ALL);
174
+ s->top = blk_new(s->common.job.aio_context, 0, BLK_PERM_ALL);
175
ret = blk_insert_bs(s->top, top, errp);
176
if (ret < 0) {
177
goto fail;
178
@@ -XXX,XX +XXX,XX @@ int bdrv_commit(BlockDriverState *bs)
179
BlockDriverState *backing_file_bs = NULL;
180
BlockDriverState *commit_top_bs = NULL;
181
BlockDriver *drv = bs->drv;
182
+ AioContext *ctx;
183
int64_t offset, length, backing_length;
184
int ro;
185
int64_t n;
186
@@ -XXX,XX +XXX,XX @@ int bdrv_commit(BlockDriverState *bs)
187
}
188
}
189
190
- src = blk_new(BLK_PERM_CONSISTENT_READ, BLK_PERM_ALL);
191
- backing = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
192
+ ctx = bdrv_get_aio_context(bs);
193
+ src = blk_new(ctx, BLK_PERM_CONSISTENT_READ, BLK_PERM_ALL);
194
+ backing = blk_new(ctx, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
195
196
ret = blk_insert_bs(src, bs, &local_err);
197
if (ret < 0) {
198
diff --git a/block/crypto.c b/block/crypto.c
199
index XXXXXXX..XXXXXXX 100644
200
--- a/block/crypto.c
201
+++ b/block/crypto.c
202
@@ -XXX,XX +XXX,XX @@ static int block_crypto_co_create_generic(BlockDriverState *bs,
203
QCryptoBlock *crypto = NULL;
204
struct BlockCryptoCreateData data;
205
206
- blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
207
+ blk = blk_new(bdrv_get_aio_context(bs),
208
+ BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
209
210
ret = blk_insert_bs(blk, bs, errp);
211
if (ret < 0) {
212
diff --git a/block/mirror.c b/block/mirror.c
213
index XXXXXXX..XXXXXXX 100644
214
--- a/block/mirror.c
215
+++ b/block/mirror.c
216
@@ -XXX,XX +XXX,XX @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
217
* We can allow anything except resize there.*/
218
target_is_backing = bdrv_chain_contains(bs, target);
219
target_graph_mod = (backing_mode != MIRROR_LEAVE_BACKING_CHAIN);
220
- s->target = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE |
221
+ s->target = blk_new(s->common.job.aio_context,
222
+ BLK_PERM_WRITE | BLK_PERM_RESIZE |
223
(target_graph_mod ? BLK_PERM_GRAPH_MOD : 0),
224
BLK_PERM_WRITE_UNCHANGED |
225
(target_is_backing ? BLK_PERM_CONSISTENT_READ |
226
diff --git a/block/parallels.c b/block/parallels.c
227
index XXXXXXX..XXXXXXX 100644
228
--- a/block/parallels.c
229
+++ b/block/parallels.c
230
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn parallels_co_create(BlockdevCreateOptions* opts,
231
return -EIO;
232
}
233
234
- blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
235
+ blk = blk_new(bdrv_get_aio_context(bs),
236
+ BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
237
ret = blk_insert_bs(blk, bs, errp);
238
if (ret < 0) {
239
goto out;
240
diff --git a/block/qcow.c b/block/qcow.c
241
index XXXXXXX..XXXXXXX 100644
242
--- a/block/qcow.c
243
+++ b/block/qcow.c
244
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow_co_create(BlockdevCreateOptions *opts,
245
return -EIO;
246
}
247
248
- qcow_blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
249
+ qcow_blk = blk_new(bdrv_get_aio_context(bs),
250
+ BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
251
ret = blk_insert_bs(qcow_blk, bs, errp);
252
if (ret < 0) {
253
goto exit;
254
diff --git a/block/qcow2.c b/block/qcow2.c
255
index XXXXXXX..XXXXXXX 100644
256
--- a/block/qcow2.c
257
+++ b/block/qcow2.c
258
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
259
}
260
261
/* Create BlockBackend to write to the image */
262
- blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
263
+ blk = blk_new(bdrv_get_aio_context(bs),
264
+ BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
265
ret = blk_insert_bs(blk, bs, errp);
266
if (ret < 0) {
267
goto out;
268
@@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
269
}
270
271
if (new_size) {
272
- BlockBackend *blk = blk_new(BLK_PERM_RESIZE, BLK_PERM_ALL);
273
+ BlockBackend *blk = blk_new(bdrv_get_aio_context(bs),
274
+ BLK_PERM_RESIZE, BLK_PERM_ALL);
275
ret = blk_insert_bs(blk, bs, errp);
276
if (ret < 0) {
277
blk_unref(blk);
278
diff --git a/block/qed.c b/block/qed.c
279
index XXXXXXX..XXXXXXX 100644
280
--- a/block/qed.c
281
+++ b/block/qed.c
282
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_create(BlockdevCreateOptions *opts,
283
return -EIO;
284
}
285
286
- blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
287
+ blk = blk_new(bdrv_get_aio_context(bs),
288
+ BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
289
ret = blk_insert_bs(blk, bs, errp);
290
if (ret < 0) {
291
goto out;
292
diff --git a/block/sheepdog.c b/block/sheepdog.c
293
index XXXXXXX..XXXXXXX 100644
294
--- a/block/sheepdog.c
295
+++ b/block/sheepdog.c
296
@@ -XXX,XX +XXX,XX @@ static int sd_prealloc(BlockDriverState *bs, int64_t old_size, int64_t new_size,
297
void *buf = NULL;
298
int ret;
299
300
- blk = blk_new(BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | BLK_PERM_RESIZE,
301
+ blk = blk_new(bdrv_get_aio_context(bs),
302
+ BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | BLK_PERM_RESIZE,
303
BLK_PERM_ALL);
304
305
ret = blk_insert_bs(blk, bs, errp);
306
diff --git a/block/vdi.c b/block/vdi.c
307
index XXXXXXX..XXXXXXX 100644
308
--- a/block/vdi.c
309
+++ b/block/vdi.c
310
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
311
goto exit;
312
}
313
314
- blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
315
+ blk = blk_new(bdrv_get_aio_context(bs_file),
316
+ BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
317
ret = blk_insert_bs(blk, bs_file, errp);
318
if (ret < 0) {
319
goto exit;
320
diff --git a/block/vhdx.c b/block/vhdx.c
321
index XXXXXXX..XXXXXXX 100644
322
--- a/block/vhdx.c
323
+++ b/block/vhdx.c
324
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vhdx_co_create(BlockdevCreateOptions *opts,
325
return -EIO;
326
}
327
328
- blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
329
+ blk = blk_new(bdrv_get_aio_context(bs),
330
+ BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
331
ret = blk_insert_bs(blk, bs, errp);
332
if (ret < 0) {
333
goto delete_and_exit;
334
diff --git a/block/vmdk.c b/block/vmdk.c
335
index XXXXXXX..XXXXXXX 100644
336
--- a/block/vmdk.c
337
+++ b/block/vmdk.c
338
@@ -XXX,XX +XXX,XX @@ static BlockBackend *vmdk_co_create_cb(int64_t size, int idx,
339
if (!bs) {
340
return NULL;
341
}
342
- blk = blk_new(BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | BLK_PERM_RESIZE,
343
+ blk = blk_new(bdrv_get_aio_context(bs),
344
+ BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | BLK_PERM_RESIZE,
345
BLK_PERM_ALL);
346
if (blk_insert_bs(blk, bs, errp)) {
347
bdrv_unref(bs);
348
diff --git a/block/vpc.c b/block/vpc.c
349
index XXXXXXX..XXXXXXX 100644
350
--- a/block/vpc.c
351
+++ b/block/vpc.c
352
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_create(BlockdevCreateOptions *opts,
353
return -EIO;
354
}
355
356
- blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
357
+ blk = blk_new(bdrv_get_aio_context(bs),
358
+ BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
359
ret = blk_insert_bs(blk, bs, errp);
360
if (ret < 0) {
361
goto out;
362
diff --git a/blockdev.c b/blockdev.c
363
index XXXXXXX..XXXXXXX 100644
364
--- a/blockdev.c
365
+++ b/blockdev.c
366
@@ -XXX,XX +XXX,XX @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
367
if ((!file || !*file) && !qdict_size(bs_opts)) {
368
BlockBackendRootState *blk_rs;
369
370
- blk = blk_new(0, BLK_PERM_ALL);
371
+ blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
372
blk_rs = blk_get_root_state(blk);
373
blk_rs->open_flags = bdrv_flags;
374
blk_rs->read_only = read_only;
375
@@ -XXX,XX +XXX,XX @@ void qmp_block_resize(bool has_device, const char *device,
376
goto out;
377
}
378
379
- blk = blk_new(BLK_PERM_RESIZE, BLK_PERM_ALL);
380
+ blk = blk_new(qemu_get_aio_context(), BLK_PERM_RESIZE, BLK_PERM_ALL);
381
ret = blk_insert_bs(blk, bs, errp);
382
if (ret < 0) {
383
goto out;
384
diff --git a/blockjob.c b/blockjob.c
385
index XXXXXXX..XXXXXXX 100644
386
--- a/blockjob.c
387
+++ b/blockjob.c
388
@@ -XXX,XX +XXX,XX @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
389
job_id = bdrv_get_device_name(bs);
390
}
391
392
- blk = blk_new(perm, shared_perm);
393
+ blk = blk_new(bdrv_get_aio_context(bs), perm, shared_perm);
394
ret = blk_insert_bs(blk, bs, errp);
395
if (ret < 0) {
396
blk_unref(blk);
397
diff --git a/hmp.c b/hmp.c
398
index XXXXXXX..XXXXXXX 100644
399
--- a/hmp.c
400
+++ b/hmp.c
401
@@ -XXX,XX +XXX,XX @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict)
402
if (!blk) {
403
BlockDriverState *bs = bdrv_lookup_bs(NULL, device, &err);
404
if (bs) {
405
- blk = local_blk = blk_new(0, BLK_PERM_ALL);
406
+ blk = local_blk = blk_new(bdrv_get_aio_context(bs),
407
+ 0, BLK_PERM_ALL);
408
ret = blk_insert_bs(blk, bs, &err);
409
if (ret < 0) {
410
goto fail;
30
diff --git a/hw/block/fdc.c b/hw/block/fdc.c
411
diff --git a/hw/block/fdc.c b/hw/block/fdc.c
31
index XXXXXXX..XXXXXXX 100644
412
index XXXXXXX..XXXXXXX 100644
32
--- a/hw/block/fdc.c
413
--- a/hw/block/fdc.c
33
+++ b/hw/block/fdc.c
414
+++ b/hw/block/fdc.c
34
@@ -XXX,XX +XXX,XX @@ static void fdctrl_stop_transfer(FDCtrl *fdctrl, uint8_t status0,
415
@@ -XXX,XX +XXX,XX @@ static void floppy_drive_realize(DeviceState *qdev, Error **errp)
35
fdctrl->fifo[5] = cur_drv->sect;
416
36
fdctrl->fifo[6] = FD_SECTOR_SC;
417
if (!dev->conf.blk) {
37
fdctrl->data_dir = FD_DIR_READ;
418
/* Anonymous BlockBackend for an empty drive */
38
- if (!(fdctrl->msr & FD_MSR_NONDMA)) {
419
- dev->conf.blk = blk_new(0, BLK_PERM_ALL);
39
+ if (fdctrl->dma_chann != -1 && !(fdctrl->msr & FD_MSR_NONDMA)) {
420
+ dev->conf.blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
40
IsaDmaClass *k = ISADMA_GET_CLASS(fdctrl->dma);
421
ret = blk_attach_dev(dev->conf.blk, qdev);
41
k->release_DREQ(fdctrl->dma, fdctrl->dma_chann);
422
assert(ret == 0);
42
}
423
}
424
diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c
425
index XXXXXXX..XXXXXXX 100644
426
--- a/hw/block/xen-block.c
427
+++ b/hw/block/xen-block.c
428
@@ -XXX,XX +XXX,XX @@ static void xen_cdrom_realize(XenBlockDevice *blockdev, Error **errp)
429
int rc;
430
431
/* Set up an empty drive */
432
- conf->blk = blk_new(0, BLK_PERM_ALL);
433
+ conf->blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
434
435
rc = blk_attach_dev(conf->blk, DEVICE(blockdev));
436
if (!rc) {
437
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
438
index XXXXXXX..XXXXXXX 100644
439
--- a/hw/core/qdev-properties-system.c
440
+++ b/hw/core/qdev-properties-system.c
441
@@ -XXX,XX +XXX,XX @@ static void parse_drive(DeviceState *dev, const char *str, void **ptr,
442
if (!blk) {
443
BlockDriverState *bs = bdrv_lookup_bs(NULL, str, NULL);
444
if (bs) {
445
- blk = blk_new(0, BLK_PERM_ALL);
446
+ /* BlockBackends of devices start in the main context and are only
447
+ * later moved into another context if the device supports that. */
448
+ blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
449
blk_created = true;
450
451
ret = blk_insert_bs(blk, bs, errp);
452
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
453
index XXXXXXX..XXXXXXX 100644
454
--- a/hw/ide/qdev.c
455
+++ b/hw/ide/qdev.c
456
@@ -XXX,XX +XXX,XX @@ static void ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind, Error **errp)
457
return;
458
} else {
459
/* Anonymous BlockBackend for an empty drive */
460
- dev->conf.blk = blk_new(0, BLK_PERM_ALL);
461
+ dev->conf.blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
462
ret = blk_attach_dev(dev->conf.blk, &dev->qdev);
463
assert(ret == 0);
464
}
465
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
466
index XXXXXXX..XXXXXXX 100644
467
--- a/hw/scsi/scsi-disk.c
468
+++ b/hw/scsi/scsi-disk.c
469
@@ -XXX,XX +XXX,XX @@ static void scsi_cd_realize(SCSIDevice *dev, Error **errp)
470
if (!dev->conf.blk) {
471
/* Anonymous BlockBackend for an empty drive. As we put it into
472
* dev->conf, qdev takes care of detaching on unplug. */
473
- dev->conf.blk = blk_new(0, BLK_PERM_ALL);
474
+ dev->conf.blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
475
ret = blk_attach_dev(dev->conf.blk, &dev->qdev);
476
assert(ret == 0);
477
}
478
diff --git a/migration/block.c b/migration/block.c
479
index XXXXXXX..XXXXXXX 100644
480
--- a/migration/block.c
481
+++ b/migration/block.c
482
@@ -XXX,XX +XXX,XX @@ static int init_blk_migration(QEMUFile *f)
483
}
484
485
bmds = g_new0(BlkMigDevState, 1);
486
- bmds->blk = blk_new(BLK_PERM_CONSISTENT_READ, BLK_PERM_ALL);
487
+ bmds->blk = blk_new(qemu_get_aio_context(),
488
+ BLK_PERM_CONSISTENT_READ, BLK_PERM_ALL);
489
bmds->blk_name = g_strdup(bdrv_get_device_name(bs));
490
bmds->bulk_completed = 0;
491
bmds->total_sectors = sectors;
492
diff --git a/nbd/server.c b/nbd/server.c
493
index XXXXXXX..XXXXXXX 100644
494
--- a/nbd/server.c
495
+++ b/nbd/server.c
496
@@ -XXX,XX +XXX,XX @@ NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset,
497
if ((nbdflags & NBD_FLAG_READ_ONLY) == 0) {
498
perm |= BLK_PERM_WRITE;
499
}
500
- blk = blk_new(perm, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED |
501
- BLK_PERM_WRITE | BLK_PERM_GRAPH_MOD);
502
+ blk = blk_new(bdrv_get_aio_context(bs), perm,
503
+ BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED |
504
+ BLK_PERM_WRITE | BLK_PERM_GRAPH_MOD);
505
ret = blk_insert_bs(blk, bs, errp);
506
if (ret < 0) {
507
goto fail;
508
diff --git a/qemu-img.c b/qemu-img.c
509
index XXXXXXX..XXXXXXX 100644
510
--- a/qemu-img.c
511
+++ b/qemu-img.c
512
@@ -XXX,XX +XXX,XX @@ static int img_rebase(int argc, char **argv)
513
BlockDriverState *base_bs = backing_bs(bs);
514
515
if (base_bs) {
516
- blk_old_backing = blk_new(BLK_PERM_CONSISTENT_READ,
517
+ blk_old_backing = blk_new(qemu_get_aio_context(),
518
+ BLK_PERM_CONSISTENT_READ,
519
BLK_PERM_ALL);
520
ret = blk_insert_bs(blk_old_backing, base_bs,
521
&local_err);
522
@@ -XXX,XX +XXX,XX @@ static int img_rebase(int argc, char **argv)
523
prefix_chain_bs = bdrv_find_backing_image(bs, out_real_path);
524
if (prefix_chain_bs) {
525
g_free(out_real_path);
526
- blk_new_backing = blk_new(BLK_PERM_CONSISTENT_READ,
527
+ blk_new_backing = blk_new(qemu_get_aio_context(),
528
+ BLK_PERM_CONSISTENT_READ,
529
BLK_PERM_ALL);
530
ret = blk_insert_bs(blk_new_backing, prefix_chain_bs,
531
&local_err);
532
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
533
index XXXXXXX..XXXXXXX 100644
534
--- a/tests/test-bdrv-drain.c
535
+++ b/tests/test-bdrv-drain.c
536
@@ -XXX,XX +XXX,XX @@ static void test_drv_cb_common(enum drain_type drain_type, bool recursive)
537
538
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, NULL, 0);
539
540
- blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
541
+ blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
542
bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR,
543
&error_abort);
544
s = bs->opaque;
545
@@ -XXX,XX +XXX,XX @@ static void test_quiesce_common(enum drain_type drain_type, bool recursive)
546
BlockBackend *blk;
547
BlockDriverState *bs, *backing;
548
549
- blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
550
+ blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
551
bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR,
552
&error_abort);
553
blk_insert_bs(blk, bs, &error_abort);
554
@@ -XXX,XX +XXX,XX @@ static void test_nested(void)
555
BDRVTestState *s, *backing_s;
556
enum drain_type outer, inner;
557
558
- blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
559
+ blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
560
bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR,
561
&error_abort);
562
s = bs->opaque;
563
@@ -XXX,XX +XXX,XX @@ static void test_multiparent(void)
564
BlockDriverState *bs_a, *bs_b, *backing;
565
BDRVTestState *a_s, *b_s, *backing_s;
566
567
- blk_a = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
568
+ blk_a = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
569
bs_a = bdrv_new_open_driver(&bdrv_test, "test-node-a", BDRV_O_RDWR,
570
&error_abort);
571
a_s = bs_a->opaque;
572
blk_insert_bs(blk_a, bs_a, &error_abort);
573
574
- blk_b = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
575
+ blk_b = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
576
bs_b = bdrv_new_open_driver(&bdrv_test, "test-node-b", BDRV_O_RDWR,
577
&error_abort);
578
b_s = bs_b->opaque;
579
@@ -XXX,XX +XXX,XX @@ static void test_graph_change_drain_subtree(void)
580
BlockDriverState *bs_a, *bs_b, *backing;
581
BDRVTestState *a_s, *b_s, *backing_s;
582
583
- blk_a = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
584
+ blk_a = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
585
bs_a = bdrv_new_open_driver(&bdrv_test, "test-node-a", BDRV_O_RDWR,
586
&error_abort);
587
a_s = bs_a->opaque;
588
blk_insert_bs(blk_a, bs_a, &error_abort);
589
590
- blk_b = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
591
+ blk_b = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
592
bs_b = bdrv_new_open_driver(&bdrv_test, "test-node-b", BDRV_O_RDWR,
593
&error_abort);
594
b_s = bs_b->opaque;
595
@@ -XXX,XX +XXX,XX @@ static void test_graph_change_drain_all(void)
596
BDRVTestState *a_s, *b_s;
597
598
/* Create node A with a BlockBackend */
599
- blk_a = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
600
+ blk_a = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
601
bs_a = bdrv_new_open_driver(&bdrv_test, "test-node-a", BDRV_O_RDWR,
602
&error_abort);
603
a_s = bs_a->opaque;
604
@@ -XXX,XX +XXX,XX @@ static void test_graph_change_drain_all(void)
605
g_assert_cmpint(a_s->drain_count, ==, 1);
606
607
/* Create node B with a BlockBackend */
608
- blk_b = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
609
+ blk_b = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
610
bs_b = bdrv_new_open_driver(&bdrv_test, "test-node-b", BDRV_O_RDWR,
611
&error_abort);
612
b_s = bs_b->opaque;
613
@@ -XXX,XX +XXX,XX @@ static void test_iothread_common(enum drain_type drain_type, int drain_thread)
614
goto out;
615
}
616
617
- blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
618
+ blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
619
bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR,
620
&error_abort);
621
s = bs->opaque;
622
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
623
bdrv_set_backing_hd(src, src_backing, &error_abort);
624
bdrv_unref(src_backing);
625
626
- blk_src = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
627
+ blk_src = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
628
blk_insert_bs(blk_src, src_overlay, &error_abort);
629
630
switch (drain_node) {
631
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
632
633
target = bdrv_new_open_driver(&bdrv_test, "target", BDRV_O_RDWR,
634
&error_abort);
635
- blk_target = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
636
+ blk_target = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
637
blk_insert_bs(blk_target, target, &error_abort);
638
639
aio_context_acquire(ctx);
640
@@ -XXX,XX +XXX,XX @@ static void do_test_delete_by_drain(bool detach_instead_of_delete,
641
&error_abort);
642
bdrv_attach_child(bs, null_bs, "null-child", &child_file, &error_abort);
643
644
- blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
645
+ blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
646
blk_insert_bs(blk, bs, &error_abort);
647
648
/* Referenced by blk now */
649
@@ -XXX,XX +XXX,XX @@ static void test_detach_indirect(bool by_parent_cb)
650
c = bdrv_new_open_driver(&bdrv_test, "c", BDRV_O_RDWR, &error_abort);
651
652
/* blk is a BB for parent-a */
653
- blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
654
+ blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
655
blk_insert_bs(blk, parent_a, &error_abort);
656
bdrv_unref(parent_a);
657
658
@@ -XXX,XX +XXX,XX @@ static void test_append_to_drained(void)
659
BlockDriverState *base, *overlay;
660
BDRVTestState *base_s, *overlay_s;
661
662
- blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
663
+ blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
664
base = bdrv_new_open_driver(&bdrv_test, "base", BDRV_O_RDWR, &error_abort);
665
base_s = base->opaque;
666
blk_insert_bs(blk, base, &error_abort);
667
diff --git a/tests/test-bdrv-graph-mod.c b/tests/test-bdrv-graph-mod.c
668
index XXXXXXX..XXXXXXX 100644
669
--- a/tests/test-bdrv-graph-mod.c
670
+++ b/tests/test-bdrv-graph-mod.c
671
@@ -XXX,XX +XXX,XX @@ static void test_update_perm_tree(void)
672
{
673
Error *local_err = NULL;
674
675
- BlockBackend *root = blk_new(BLK_PERM_WRITE | BLK_PERM_CONSISTENT_READ,
676
+ BlockBackend *root = blk_new(qemu_get_aio_context(),
677
+ BLK_PERM_WRITE | BLK_PERM_CONSISTENT_READ,
678
BLK_PERM_ALL & ~BLK_PERM_WRITE);
679
BlockDriverState *bs = no_perm_node("node");
680
BlockDriverState *filter = pass_through_node("filter");
681
@@ -XXX,XX +XXX,XX @@ static void test_update_perm_tree(void)
682
*/
683
static void test_should_update_child(void)
684
{
685
- BlockBackend *root = blk_new(0, BLK_PERM_ALL);
686
+ BlockBackend *root = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
687
BlockDriverState *bs = no_perm_node("node");
688
BlockDriverState *filter = no_perm_node("filter");
689
BlockDriverState *target = no_perm_node("target");
690
diff --git a/tests/test-block-backend.c b/tests/test-block-backend.c
691
index XXXXXXX..XXXXXXX 100644
692
--- a/tests/test-block-backend.c
693
+++ b/tests/test-block-backend.c
694
@@ -XXX,XX +XXX,XX @@ static void test_drain_aio_error_flush_cb(void *opaque, int ret)
695
696
static void test_drain_aio_error(void)
697
{
698
- BlockBackend *blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
699
+ BlockBackend *blk = blk_new(qemu_get_aio_context(),
700
+ BLK_PERM_ALL, BLK_PERM_ALL);
701
BlockAIOCB *acb;
702
bool completed = false;
703
704
@@ -XXX,XX +XXX,XX @@ static void test_drain_aio_error(void)
705
706
static void test_drain_all_aio_error(void)
707
{
708
- BlockBackend *blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
709
+ BlockBackend *blk = blk_new(qemu_get_aio_context(),
710
+ BLK_PERM_ALL, BLK_PERM_ALL);
711
BlockAIOCB *acb;
712
bool completed = false;
713
714
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
715
index XXXXXXX..XXXXXXX 100644
716
--- a/tests/test-block-iothread.c
717
+++ b/tests/test-block-iothread.c
718
@@ -XXX,XX +XXX,XX @@ static void test_sync_op(const void *opaque)
719
BlockDriverState *bs;
720
BdrvChild *c;
721
722
- blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
723
+ blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
724
bs = bdrv_new_open_driver(&bdrv_test, "base", BDRV_O_RDWR, &error_abort);
725
bs->total_sectors = 65536 / BDRV_SECTOR_SIZE;
726
blk_insert_bs(blk, bs, &error_abort);
727
@@ -XXX,XX +XXX,XX @@ static void test_attach_blockjob(void)
728
BlockDriverState *bs;
729
TestBlockJob *tjob;
730
731
- blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
732
+ blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
733
bs = bdrv_new_open_driver(&bdrv_test, "base", BDRV_O_RDWR, &error_abort);
734
blk_insert_bs(blk, bs, &error_abort);
735
736
@@ -XXX,XX +XXX,XX @@ static void test_propagate_basic(void)
737
QDict *options;
738
739
/* Create bs_a and its BlockBackend */
740
- blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
741
+ blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
742
bs_a = bdrv_new_open_driver(&bdrv_test, "bs_a", BDRV_O_RDWR, &error_abort);
743
blk_insert_bs(blk, bs_a, &error_abort);
744
745
@@ -XXX,XX +XXX,XX @@ static void test_propagate_diamond(void)
746
qdict_put_str(options, "raw", "bs_c");
747
748
bs_verify = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
749
- blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
750
+ blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
751
blk_insert_bs(blk, bs_verify, &error_abort);
752
753
/* Switch the AioContext */
754
@@ -XXX,XX +XXX,XX @@ static void test_propagate_mirror(void)
755
g_assert(bdrv_get_aio_context(filter) == main_ctx);
756
757
/* With a BlockBackend on src, changing target must fail */
758
- blk = blk_new(0, BLK_PERM_ALL);
759
+ blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
760
blk_insert_bs(blk, src, &error_abort);
761
762
bdrv_try_set_aio_context(target, ctx, &local_err);
763
diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c
764
index XXXXXXX..XXXXXXX 100644
765
--- a/tests/test-blockjob.c
766
+++ b/tests/test-blockjob.c
767
@@ -XXX,XX +XXX,XX @@ static BlockJob *do_test_id(BlockBackend *blk, const char *id,
768
static BlockBackend *create_blk(const char *name)
769
{
770
/* No I/O is performed on this device */
771
- BlockBackend *blk = blk_new(0, BLK_PERM_ALL);
772
+ BlockBackend *blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
773
BlockDriverState *bs;
774
775
bs = bdrv_open("null-co://", NULL, NULL, 0, &error_abort);
776
diff --git a/tests/test-throttle.c b/tests/test-throttle.c
777
index XXXXXXX..XXXXXXX 100644
778
--- a/tests/test-throttle.c
779
+++ b/tests/test-throttle.c
780
@@ -XXX,XX +XXX,XX @@ static void test_groups(void)
781
ThrottleGroupMember *tgm1, *tgm2, *tgm3;
782
783
/* No actual I/O is performed on these devices */
784
- blk1 = blk_new(0, BLK_PERM_ALL);
785
- blk2 = blk_new(0, BLK_PERM_ALL);
786
- blk3 = blk_new(0, BLK_PERM_ALL);
787
+ blk1 = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
788
+ blk2 = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
789
+ blk3 = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
790
791
blkp1 = blk_get_public(blk1);
792
blkp2 = blk_get_public(blk2);
43
--
793
--
44
2.19.1
794
2.20.1
45
795
46
796
diff view generated by jsdifflib
New patch
1
Some qdev block devices have support for iothreads and take care of the
2
AioContext they are running in, but most devices don't know about any of
3
this. For the latter category, the qdev drive property must make sure
4
that their BlockBackend is in the main AioContext.
1
5
6
Unfortunately, while the current code just does the same thing for
7
devices that do support iothreads, this is not correct and it would show
8
as soon as we actually try to keep a consistent AioContext assignment
9
across all nodes and users of a block graph subtree: If a node is
10
already in a non-default AioContext because of one of its users,
11
attaching a new device should still be possible if that device can work
12
in the same AioContext. Switching the node back to the main context
13
first and only then into the device AioContext causes failure (because
14
the existing user wouldn't allow the switch to the main context).
15
16
So devices that support iothreads need a different kind of drive
17
property that leaves the node in its current AioContext, but by using
18
this type, the device promises to check later that it can work with this
19
context.
20
21
This patch adds the qdev infrastructure that allows devices to signal
22
that they handle iothreads and qdev should leave the AioContext alone.
23
24
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
25
---
26
include/hw/block/block.h | 7 ++++--
27
include/hw/qdev-properties.h | 3 +++
28
hw/core/qdev-properties-system.c | 43 ++++++++++++++++++++++++++++----
29
3 files changed, 46 insertions(+), 7 deletions(-)
30
31
diff --git a/include/hw/block/block.h b/include/hw/block/block.h
32
index XXXXXXX..XXXXXXX 100644
33
--- a/include/hw/block/block.h
34
+++ b/include/hw/block/block.h
35
@@ -XXX,XX +XXX,XX @@ static inline unsigned int get_physical_block_exp(BlockConf *conf)
36
return exp;
37
}
38
39
-#define DEFINE_BLOCK_PROPERTIES(_state, _conf) \
40
- DEFINE_PROP_DRIVE("drive", _state, _conf.blk), \
41
+#define DEFINE_BLOCK_PROPERTIES_BASE(_state, _conf) \
42
DEFINE_PROP_BLOCKSIZE("logical_block_size", _state, \
43
_conf.logical_block_size), \
44
DEFINE_PROP_BLOCKSIZE("physical_block_size", _state, \
45
@@ -XXX,XX +XXX,XX @@ static inline unsigned int get_physical_block_exp(BlockConf *conf)
46
ON_OFF_AUTO_AUTO), \
47
DEFINE_PROP_BOOL("share-rw", _state, _conf.share_rw, false)
48
49
+#define DEFINE_BLOCK_PROPERTIES(_state, _conf) \
50
+ DEFINE_PROP_DRIVE("drive", _state, _conf.blk), \
51
+ DEFINE_BLOCK_PROPERTIES_BASE(_state, _conf)
52
+
53
#define DEFINE_BLOCK_CHS_PROPERTIES(_state, _conf) \
54
DEFINE_PROP_UINT32("cyls", _state, _conf.cyls, 0), \
55
DEFINE_PROP_UINT32("heads", _state, _conf.heads, 0), \
56
diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h
57
index XXXXXXX..XXXXXXX 100644
58
--- a/include/hw/qdev-properties.h
59
+++ b/include/hw/qdev-properties.h
60
@@ -XXX,XX +XXX,XX @@ extern const PropertyInfo qdev_prop_blockdev_on_error;
61
extern const PropertyInfo qdev_prop_bios_chs_trans;
62
extern const PropertyInfo qdev_prop_fdc_drive_type;
63
extern const PropertyInfo qdev_prop_drive;
64
+extern const PropertyInfo qdev_prop_drive_iothread;
65
extern const PropertyInfo qdev_prop_netdev;
66
extern const PropertyInfo qdev_prop_pci_devfn;
67
extern const PropertyInfo qdev_prop_blocksize;
68
@@ -XXX,XX +XXX,XX @@ extern const PropertyInfo qdev_prop_pcie_link_width;
69
DEFINE_PROP(_n, _s, _f, qdev_prop_netdev, NICPeers)
70
#define DEFINE_PROP_DRIVE(_n, _s, _f) \
71
DEFINE_PROP(_n, _s, _f, qdev_prop_drive, BlockBackend *)
72
+#define DEFINE_PROP_DRIVE_IOTHREAD(_n, _s, _f) \
73
+ DEFINE_PROP(_n, _s, _f, qdev_prop_drive_iothread, BlockBackend *)
74
#define DEFINE_PROP_MACADDR(_n, _s, _f) \
75
DEFINE_PROP(_n, _s, _f, qdev_prop_macaddr, MACAddr)
76
#define DEFINE_PROP_ON_OFF_AUTO(_n, _s, _f, _d) \
77
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
78
index XXXXXXX..XXXXXXX 100644
79
--- a/hw/core/qdev-properties-system.c
80
+++ b/hw/core/qdev-properties-system.c
81
@@ -XXX,XX +XXX,XX @@ static void set_pointer(Object *obj, Visitor *v, Property *prop,
82
83
/* --- drive --- */
84
85
-static void parse_drive(DeviceState *dev, const char *str, void **ptr,
86
- const char *propname, Error **errp)
87
+static void do_parse_drive(DeviceState *dev, const char *str, void **ptr,
88
+ const char *propname, bool iothread, Error **errp)
89
{
90
BlockBackend *blk;
91
bool blk_created = false;
92
@@ -XXX,XX +XXX,XX @@ static void parse_drive(DeviceState *dev, const char *str, void **ptr,
93
if (!blk) {
94
BlockDriverState *bs = bdrv_lookup_bs(NULL, str, NULL);
95
if (bs) {
96
- /* BlockBackends of devices start in the main context and are only
97
- * later moved into another context if the device supports that. */
98
- blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
99
+ /*
100
+ * If the device supports iothreads, it will make sure to move the
101
+ * block node to the right AioContext if necessary (or fail if this
102
+ * isn't possible because of other users). Devices that are not
103
+ * aware of iothreads require their BlockBackends to be in the main
104
+ * AioContext.
105
+ */
106
+ AioContext *ctx = iothread ? bdrv_get_aio_context(bs) :
107
+ qemu_get_aio_context();
108
+ blk = blk_new(ctx, 0, BLK_PERM_ALL);
109
blk_created = true;
110
111
ret = blk_insert_bs(blk, bs, errp);
112
@@ -XXX,XX +XXX,XX @@ fail:
113
}
114
}
115
116
+static void parse_drive(DeviceState *dev, const char *str, void **ptr,
117
+ const char *propname, Error **errp)
118
+{
119
+ do_parse_drive(dev, str, ptr, propname, false, errp);
120
+}
121
+
122
+static void parse_drive_iothread(DeviceState *dev, const char *str, void **ptr,
123
+ const char *propname, Error **errp)
124
+{
125
+ do_parse_drive(dev, str, ptr, propname, true, errp);
126
+}
127
+
128
static void release_drive(Object *obj, const char *name, void *opaque)
129
{
130
DeviceState *dev = DEVICE(obj);
131
@@ -XXX,XX +XXX,XX @@ static void set_drive(Object *obj, Visitor *v, const char *name, void *opaque,
132
set_pointer(obj, v, opaque, parse_drive, name, errp);
133
}
134
135
+static void set_drive_iothread(Object *obj, Visitor *v, const char *name,
136
+ void *opaque, Error **errp)
137
+{
138
+ set_pointer(obj, v, opaque, parse_drive_iothread, name, errp);
139
+}
140
+
141
const PropertyInfo qdev_prop_drive = {
142
.name = "str",
143
.description = "Node name or ID of a block device to use as a backend",
144
@@ -XXX,XX +XXX,XX @@ const PropertyInfo qdev_prop_drive = {
145
.release = release_drive,
146
};
147
148
+const PropertyInfo qdev_prop_drive_iothread = {
149
+ .name = "str",
150
+ .description = "Node name or ID of a block device to use as a backend",
151
+ .get = get_drive,
152
+ .set = set_drive_iothread,
153
+ .release = release_drive,
154
+};
155
+
156
/* --- character device --- */
157
158
static void get_chr(Object *obj, Visitor *v, const char *name, void *opaque,
159
--
160
2.20.1
161
162
diff view generated by jsdifflib
New patch
1
This makes use of qdev_prop_drive_iothread for scsi-disk so that the
2
disk can be attached to a node that is already in the target AioContext.
3
We need to check that the HBA actually supports iothreads, otherwise
4
scsi-disk must make sure that the node is already in the main
5
AioContext.
1
6
7
This changes the error message for conflicting iothread settings.
8
Previously, virtio-scsi produced the error message, now it comes from
9
blk_set_aio_context(). Update a test case accordingly.
10
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
13
include/hw/scsi/scsi.h | 1 +
14
hw/scsi/scsi-disk.c | 22 +++++++++++++++-------
15
hw/scsi/virtio-scsi.c | 15 ++++++++-------
16
tests/qemu-iotests/240.out | 2 +-
17
4 files changed, 25 insertions(+), 15 deletions(-)
18
19
diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h
20
index XXXXXXX..XXXXXXX 100644
21
--- a/include/hw/scsi/scsi.h
22
+++ b/include/hw/scsi/scsi.h
23
@@ -XXX,XX +XXX,XX @@ struct SCSIDevice
24
int scsi_version;
25
int default_scsi_version;
26
bool needs_vpd_bl_emulation;
27
+ bool hba_supports_iothread;
28
};
29
30
extern const VMStateDescription vmstate_scsi_device;
31
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
32
index XXXXXXX..XXXXXXX 100644
33
--- a/hw/scsi/scsi-disk.c
34
+++ b/hw/scsi/scsi-disk.c
35
@@ -XXX,XX +XXX,XX @@ static void scsi_realize(SCSIDevice *dev, Error **errp)
36
return;
37
}
38
39
+ if (blk_get_aio_context(s->qdev.conf.blk) != qemu_get_aio_context() &&
40
+ !s->qdev.hba_supports_iothread)
41
+ {
42
+ error_setg(errp, "HBA does not support iothreads");
43
+ return;
44
+ }
45
+
46
if (dev->type == TYPE_DISK) {
47
if (!blkconf_geometry(&dev->conf, NULL, 65535, 255, 255, errp)) {
48
return;
49
@@ -XXX,XX +XXX,XX @@ static const TypeInfo scsi_disk_base_info = {
50
.abstract = true,
51
};
52
53
-#define DEFINE_SCSI_DISK_PROPERTIES() \
54
- DEFINE_BLOCK_PROPERTIES(SCSIDiskState, qdev.conf), \
55
- DEFINE_BLOCK_ERROR_PROPERTIES(SCSIDiskState, qdev.conf), \
56
- DEFINE_PROP_STRING("ver", SCSIDiskState, version), \
57
- DEFINE_PROP_STRING("serial", SCSIDiskState, serial), \
58
- DEFINE_PROP_STRING("vendor", SCSIDiskState, vendor), \
59
- DEFINE_PROP_STRING("product", SCSIDiskState, product), \
60
+#define DEFINE_SCSI_DISK_PROPERTIES() \
61
+ DEFINE_PROP_DRIVE_IOTHREAD("drive", SCSIDiskState, qdev.conf.blk), \
62
+ DEFINE_BLOCK_PROPERTIES_BASE(SCSIDiskState, qdev.conf), \
63
+ DEFINE_BLOCK_ERROR_PROPERTIES(SCSIDiskState, qdev.conf), \
64
+ DEFINE_PROP_STRING("ver", SCSIDiskState, version), \
65
+ DEFINE_PROP_STRING("serial", SCSIDiskState, serial), \
66
+ DEFINE_PROP_STRING("vendor", SCSIDiskState, vendor), \
67
+ DEFINE_PROP_STRING("product", SCSIDiskState, product), \
68
DEFINE_PROP_STRING("device_id", SCSIDiskState, device_id)
69
70
71
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
72
index XXXXXXX..XXXXXXX 100644
73
--- a/hw/scsi/virtio-scsi.c
74
+++ b/hw/scsi/virtio-scsi.c
75
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_change(SCSIBus *bus, SCSIDevice *dev, SCSISense sense)
76
}
77
}
78
79
+static void virtio_scsi_pre_hotplug(HotplugHandler *hotplug_dev,
80
+ DeviceState *dev, Error **errp)
81
+{
82
+ SCSIDevice *sd = SCSI_DEVICE(dev);
83
+ sd->hba_supports_iothread = true;
84
+}
85
+
86
static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev,
87
Error **errp)
88
{
89
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev,
90
int ret;
91
92
if (s->ctx && !s->dataplane_fenced) {
93
- AioContext *ctx;
94
if (blk_op_is_blocked(sd->conf.blk, BLOCK_OP_TYPE_DATAPLANE, errp)) {
95
return;
96
}
97
- ctx = blk_get_aio_context(sd->conf.blk);
98
- if (ctx != s->ctx && ctx != qemu_get_aio_context()) {
99
- error_setg(errp, "Cannot attach a blockdev that is using "
100
- "a different iothread");
101
- return;
102
- }
103
virtio_scsi_acquire(s);
104
ret = blk_set_aio_context(sd->conf.blk, s->ctx, errp);
105
virtio_scsi_release(s);
106
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_class_init(ObjectClass *klass, void *data)
107
vdc->reset = virtio_scsi_reset;
108
vdc->start_ioeventfd = virtio_scsi_dataplane_start;
109
vdc->stop_ioeventfd = virtio_scsi_dataplane_stop;
110
+ hc->pre_plug = virtio_scsi_pre_hotplug;
111
hc->plug = virtio_scsi_hotplug;
112
hc->unplug = virtio_scsi_hotunplug;
113
}
114
diff --git a/tests/qemu-iotests/240.out b/tests/qemu-iotests/240.out
115
index XXXXXXX..XXXXXXX 100644
116
--- a/tests/qemu-iotests/240.out
117
+++ b/tests/qemu-iotests/240.out
118
@@ -XXX,XX +XXX,XX @@ QMP_VERSION
119
{"return": {}}
120
{"return": {}}
121
{"return": {}}
122
-{"error": {"class": "GenericError", "desc": "Cannot attach a blockdev that is using a different iothread"}}
123
+{"error": {"class": "GenericError", "desc": "Cannot change iothread of active block backend"}}
124
{"return": {}}
125
{"return": {}}
126
{"return": {}}
127
--
128
2.20.1
129
130
diff view generated by jsdifflib
New patch
1
1
So far, we only made sure that updating the AioContext of a node
2
affected the whole subtree. However, if a node is newly attached to a
3
new parent, we also need to make sure that both the subtree of the node
4
and the parent are in the same AioContext. This tries to move the new
5
child node to the parent AioContext and returns an error if this isn't
6
possible.
7
8
BlockBackends now actually apply their AioContext to their root node.
9
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
12
include/block/block_int.h | 1 +
13
block.c | 35 ++++++++++++++++++++++++++++++++++-
14
block/block-backend.c | 9 ++++-----
15
blockjob.c | 10 ++++++++--
16
tests/test-bdrv-drain.c | 6 ++++--
17
5 files changed, 51 insertions(+), 10 deletions(-)
18
19
diff --git a/include/block/block_int.h b/include/block/block_int.h
20
index XXXXXXX..XXXXXXX 100644
21
--- a/include/block/block_int.h
22
+++ b/include/block/block_int.h
23
@@ -XXX,XX +XXX,XX @@ void hmp_drive_add_node(Monitor *mon, const char *optstr);
24
BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
25
const char *child_name,
26
const BdrvChildRole *child_role,
27
+ AioContext *ctx,
28
uint64_t perm, uint64_t shared_perm,
29
void *opaque, Error **errp);
30
void bdrv_root_unref_child(BdrvChild *child);
31
diff --git a/block.c b/block.c
32
index XXXXXXX..XXXXXXX 100644
33
--- a/block.c
34
+++ b/block.c
35
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs)
36
*
37
* On failure NULL is returned, errp is set and the reference to
38
* child_bs is also dropped.
39
+ *
40
+ * The caller must hold the AioContext lock @child_bs, but not that of @ctx
41
+ * (unless @child_bs is already in @ctx).
42
*/
43
BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
44
const char *child_name,
45
const BdrvChildRole *child_role,
46
+ AioContext *ctx,
47
uint64_t perm, uint64_t shared_perm,
48
void *opaque, Error **errp)
49
{
50
BdrvChild *child;
51
+ Error *local_err = NULL;
52
int ret;
53
54
ret = bdrv_check_update_perm(child_bs, NULL, perm, shared_perm, NULL, errp);
55
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
56
.opaque = opaque,
57
};
58
59
+ /* If the AioContexts don't match, first try to move the subtree of
60
+ * child_bs into the AioContext of the new parent. If this doesn't work,
61
+ * try moving the parent into the AioContext of child_bs instead. */
62
+ if (bdrv_get_aio_context(child_bs) != ctx) {
63
+ ret = bdrv_try_set_aio_context(child_bs, ctx, &local_err);
64
+ if (ret < 0 && child_role->can_set_aio_ctx) {
65
+ GSList *ignore = g_slist_prepend(NULL, child);;
66
+ ctx = bdrv_get_aio_context(child_bs);
67
+ if (child_role->can_set_aio_ctx(child, ctx, &ignore, NULL)) {
68
+ error_free(local_err);
69
+ ret = 0;
70
+ g_slist_free(ignore);
71
+ ignore = g_slist_prepend(NULL, child);;
72
+ child_role->set_aio_ctx(child, ctx, &ignore);
73
+ }
74
+ g_slist_free(ignore);
75
+ }
76
+ if (ret < 0) {
77
+ error_propagate(errp, local_err);
78
+ g_free(child);
79
+ bdrv_abort_perm_update(child_bs);
80
+ return NULL;
81
+ }
82
+ }
83
+
84
/* This performs the matching bdrv_set_perm() for the above check. */
85
bdrv_replace_child(child, child_bs);
86
87
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
88
*
89
* On failure NULL is returned, errp is set and the reference to
90
* child_bs is also dropped.
91
+ *
92
+ * If @parent_bs and @child_bs are in different AioContexts, the caller must
93
+ * hold the AioContext lock for @child_bs, but not for @parent_bs.
94
*/
95
BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
96
BlockDriverState *child_bs,
97
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
98
bdrv_get_cumulative_perm(parent_bs, &perm, &shared_perm);
99
100
assert(parent_bs->drv);
101
- assert(bdrv_get_aio_context(parent_bs) == bdrv_get_aio_context(child_bs));
102
bdrv_child_perm(parent_bs, child_bs, NULL, child_role, NULL,
103
perm, shared_perm, &perm, &shared_perm);
104
105
child = bdrv_root_attach_child(child_bs, child_name, child_role,
106
+ bdrv_get_aio_context(parent_bs),
107
perm, shared_perm, parent_bs, errp);
108
if (child == NULL) {
109
return NULL;
110
diff --git a/block/block-backend.c b/block/block-backend.c
111
index XXXXXXX..XXXXXXX 100644
112
--- a/block/block-backend.c
113
+++ b/block/block-backend.c
114
@@ -XXX,XX +XXX,XX @@ BlockBackend *blk_new_open(const char *filename, const char *reference,
115
return NULL;
116
}
117
118
- blk->root = bdrv_root_attach_child(bs, "root", &child_root,
119
+ blk->root = bdrv_root_attach_child(bs, "root", &child_root, blk->ctx,
120
perm, BLK_PERM_ALL, blk, errp);
121
if (!blk->root) {
122
blk_unref(blk);
123
@@ -XXX,XX +XXX,XX @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp)
124
{
125
ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
126
bdrv_ref(bs);
127
- blk->root = bdrv_root_attach_child(bs, "root", &child_root,
128
+ blk->root = bdrv_root_attach_child(bs, "root", &child_root, blk->ctx,
129
blk->perm, blk->shared_perm, blk, errp);
130
if (blk->root == NULL) {
131
return -EPERM;
132
@@ -XXX,XX +XXX,XX @@ AioContext *blk_get_aio_context(BlockBackend *blk)
133
{
134
BlockDriverState *bs = blk_bs(blk);
135
136
- /* FIXME The AioContext of bs and blk can be inconsistent. For the moment,
137
- * we prefer the one of bs for compatibility. */
138
if (bs) {
139
- return bdrv_get_aio_context(blk_bs(blk));
140
+ AioContext *ctx = bdrv_get_aio_context(blk_bs(blk));
141
+ assert(ctx == blk->ctx);
142
}
143
144
return blk->ctx;
145
diff --git a/blockjob.c b/blockjob.c
146
index XXXXXXX..XXXXXXX 100644
147
--- a/blockjob.c
148
+++ b/blockjob.c
149
@@ -XXX,XX +XXX,XX @@ int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs,
150
BdrvChild *c;
151
152
bdrv_ref(bs);
153
- c = bdrv_root_attach_child(bs, name, &child_job, perm, shared_perm,
154
- job, errp);
155
+ if (job->job.aio_context != qemu_get_aio_context()) {
156
+ aio_context_release(job->job.aio_context);
157
+ }
158
+ c = bdrv_root_attach_child(bs, name, &child_job, job->job.aio_context,
159
+ perm, shared_perm, job, errp);
160
+ if (job->job.aio_context != qemu_get_aio_context()) {
161
+ aio_context_acquire(job->job.aio_context);
162
+ }
163
if (c == NULL) {
164
return -EPERM;
165
}
166
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
167
index XXXXXXX..XXXXXXX 100644
168
--- a/tests/test-bdrv-drain.c
169
+++ b/tests/test-bdrv-drain.c
170
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
171
&error_abort);
172
blk_target = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
173
blk_insert_bs(blk_target, target, &error_abort);
174
+ blk_set_allow_aio_context_change(blk_target, true);
175
176
aio_context_acquire(ctx);
177
tjob = block_job_create("job0", &test_job_driver, NULL, src,
178
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
179
g_assert_false(job->job.paused);
180
g_assert_true(job->job.busy); /* We're in qemu_co_sleep_ns() */
181
182
- do_drain_begin(drain_type, target);
183
+ do_drain_begin_unlocked(drain_type, target);
184
185
if (drain_type == BDRV_DRAIN_ALL) {
186
/* bdrv_drain_all() drains both src and target */
187
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
188
g_assert_true(job->job.paused);
189
g_assert_false(job->job.busy); /* The job is paused */
190
191
- do_drain_end(drain_type, target);
192
+ do_drain_end_unlocked(drain_type, target);
193
194
if (use_iothread) {
195
/* paused is reset in the I/O thread, wait for it */
196
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
197
198
if (use_iothread) {
199
blk_set_aio_context(blk_src, qemu_get_aio_context(), &error_abort);
200
+ blk_set_aio_context(blk_target, qemu_get_aio_context(), &error_abort);
201
}
202
aio_context_release(ctx);
203
204
--
205
2.20.1
206
207
diff view generated by jsdifflib
New patch
1
Opening a new parent node for a node that has already been moved into a
2
different AioContext must cause the new parent to move into the same
3
context.
1
4
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
7
tests/test-block-iothread.c | 33 +++++++++++++++++++++++++++++++++
8
1 file changed, 33 insertions(+)
9
10
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/tests/test-block-iothread.c
13
+++ b/tests/test-block-iothread.c
14
@@ -XXX,XX +XXX,XX @@ static void test_propagate_mirror(void)
15
bdrv_unref(target);
16
}
17
18
+static void test_attach_second_node(void)
19
+{
20
+ IOThread *iothread = iothread_new();
21
+ AioContext *ctx = iothread_get_aio_context(iothread);
22
+ AioContext *main_ctx = qemu_get_aio_context();
23
+ BlockBackend *blk;
24
+ BlockDriverState *bs, *filter;
25
+ QDict *options;
26
+
27
+ blk = blk_new(ctx, BLK_PERM_ALL, BLK_PERM_ALL);
28
+ bs = bdrv_new_open_driver(&bdrv_test, "base", BDRV_O_RDWR, &error_abort);
29
+ blk_insert_bs(blk, bs, &error_abort);
30
+
31
+ options = qdict_new();
32
+ qdict_put_str(options, "driver", "raw");
33
+ qdict_put_str(options, "file", "base");
34
+
35
+ filter = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
36
+ g_assert(blk_get_aio_context(blk) == ctx);
37
+ g_assert(bdrv_get_aio_context(bs) == ctx);
38
+ g_assert(bdrv_get_aio_context(filter) == ctx);
39
+
40
+ blk_set_aio_context(blk, main_ctx, &error_abort);
41
+ g_assert(blk_get_aio_context(blk) == main_ctx);
42
+ g_assert(bdrv_get_aio_context(bs) == main_ctx);
43
+ g_assert(bdrv_get_aio_context(filter) == main_ctx);
44
+
45
+ bdrv_unref(filter);
46
+ bdrv_unref(bs);
47
+ blk_unref(blk);
48
+}
49
+
50
int main(int argc, char **argv)
51
{
52
int i;
53
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
54
}
55
56
g_test_add_func("/attach/blockjob", test_attach_blockjob);
57
+ g_test_add_func("/attach/second_node", test_attach_second_node);
58
g_test_add_func("/propagate/basic", test_propagate_basic);
59
g_test_add_func("/propagate/diamond", test_propagate_diamond);
60
g_test_add_func("/propagate/mirror", test_propagate_mirror);
61
--
62
2.20.1
63
64
diff view generated by jsdifflib
New patch
1
Test that BlockBackends preserve their assigned AioContext even when the
2
root node goes away. Inserting a new root node will move it to the right
3
AioContext.
1
4
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
7
tests/test-block-iothread.c | 33 +++++++++++++++++++++++++++++++++
8
1 file changed, 33 insertions(+)
9
10
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/tests/test-block-iothread.c
13
+++ b/tests/test-block-iothread.c
14
@@ -XXX,XX +XXX,XX @@ static void test_attach_second_node(void)
15
blk_unref(blk);
16
}
17
18
+static void test_attach_preserve_blk_ctx(void)
19
+{
20
+ IOThread *iothread = iothread_new();
21
+ AioContext *ctx = iothread_get_aio_context(iothread);
22
+ BlockBackend *blk;
23
+ BlockDriverState *bs;
24
+
25
+ blk = blk_new(ctx, BLK_PERM_ALL, BLK_PERM_ALL);
26
+ bs = bdrv_new_open_driver(&bdrv_test, "base", BDRV_O_RDWR, &error_abort);
27
+ bs->total_sectors = 65536 / BDRV_SECTOR_SIZE;
28
+
29
+ /* Add node to BlockBackend that has an iothread context assigned */
30
+ blk_insert_bs(blk, bs, &error_abort);
31
+ g_assert(blk_get_aio_context(blk) == ctx);
32
+ g_assert(bdrv_get_aio_context(bs) == ctx);
33
+
34
+ /* Remove the node again */
35
+ blk_remove_bs(blk);
36
+ /* TODO bs should move back to main context here */
37
+ g_assert(blk_get_aio_context(blk) == ctx);
38
+ g_assert(bdrv_get_aio_context(bs) == ctx);
39
+
40
+ /* Re-attach the node */
41
+ blk_insert_bs(blk, bs, &error_abort);
42
+ g_assert(blk_get_aio_context(blk) == ctx);
43
+ g_assert(bdrv_get_aio_context(bs) == ctx);
44
+
45
+ blk_set_aio_context(blk, qemu_get_aio_context(), &error_abort);
46
+ bdrv_unref(bs);
47
+ blk_unref(blk);
48
+}
49
+
50
int main(int argc, char **argv)
51
{
52
int i;
53
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
54
55
g_test_add_func("/attach/blockjob", test_attach_blockjob);
56
g_test_add_func("/attach/second_node", test_attach_second_node);
57
+ g_test_add_func("/attach/preserve_blk_ctx", test_attach_preserve_blk_ctx);
58
g_test_add_func("/propagate/basic", test_propagate_basic);
59
g_test_add_func("/propagate/diamond", test_propagate_diamond);
60
g_test_add_func("/propagate/mirror", test_propagate_mirror);
61
--
62
2.20.1
63
64
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
A node should only be in a non-default AioContext if a user is attached
2
to it that requires this. When the last parent of a node is gone, it can
3
move back to the main AioContext.
2
4
3
bdrv_reopen_multiple() does not invoke bdrv_reopen_abort() for the
4
element of the reopen queue for which bdrv_reopen_prepare() failed,
5
because it assumes that the prepare function will have rolled back all
6
changes already.
7
8
However, bdrv_reopen_prepare() does not do this in every case: It may
9
notice an error after BlockDriver.bdrv_reopen_prepare() succeeded, and
10
it will not invoke BlockDriver.bdrv_reopen_abort() then; and neither
11
will bdrv_reopen_multiple(), as explained above.
12
13
This is wrong because we must always call .bdrv_reopen_commit() or
14
.bdrv_reopen_abort() after .bdrv_reopen_prepare() has succeeded.
15
Otherwise, the block driver has no chance to undo what it has done in
16
its implementation of .bdrv_reopen_prepare().
17
18
To fix this, bdrv_reopen_prepare() has to call .bdrv_reopen_abort() if
19
it wants to return an error after .bdrv_reopen_prepare() has succeeded.
20
21
Signed-off-by: Max Reitz <mreitz@redhat.com>
22
Reviewed-by: Alberto Garcia <berto@igalia.com>
23
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
24
---
6
---
25
block.c | 12 ++++++++++++
7
block.c | 4 ++++
26
1 file changed, 12 insertions(+)
8
tests/test-bdrv-drain.c | 2 +-
9
tests/test-block-iothread.c | 3 +--
10
3 files changed, 6 insertions(+), 3 deletions(-)
27
11
28
diff --git a/block.c b/block.c
12
diff --git a/block.c b/block.c
29
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
30
--- a/block.c
14
--- a/block.c
31
+++ b/block.c
15
+++ b/block.c
32
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
16
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs)
33
QDict *orig_reopen_opts;
17
bdrv_get_cumulative_perm(old_bs, &perm, &shared_perm);
34
char *discard = NULL;
18
bdrv_check_perm(old_bs, NULL, perm, shared_perm, NULL, &error_abort);
35
bool read_only;
19
bdrv_set_perm(old_bs, perm, shared_perm);
36
+ bool drv_prepared = false;
20
+
37
21
+ /* When the parent requiring a non-default AioContext is removed, the
38
assert(reopen_state != NULL);
22
+ * node moves back to the main AioContext */
39
assert(reopen_state->bs->drv != NULL);
23
+ bdrv_try_set_aio_context(old_bs, qemu_get_aio_context(), NULL);
40
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
41
goto error;
42
}
24
}
43
25
44
+ drv_prepared = true;
26
if (new_bs) {
45
+
27
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
46
/* Options that are not handled are only okay if they are unchanged
28
index XXXXXXX..XXXXXXX 100644
47
* compared to the old state. It is expected that some options are only
29
--- a/tests/test-bdrv-drain.c
48
* used for the initial open, but not reopen (e.g. filename) */
30
+++ b/tests/test-bdrv-drain.c
49
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
31
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
50
reopen_state->options = qobject_ref(orig_reopen_opts);
32
51
33
if (use_iothread) {
52
error:
34
blk_set_aio_context(blk_src, qemu_get_aio_context(), &error_abort);
53
+ if (ret < 0 && drv_prepared) {
35
- blk_set_aio_context(blk_target, qemu_get_aio_context(), &error_abort);
54
+ /* drv->bdrv_reopen_prepare() has succeeded, so we need to
36
+ assert(blk_get_aio_context(blk_target) == qemu_get_aio_context());
55
+ * call drv->bdrv_reopen_abort() before signaling an error
37
}
56
+ * (bdrv_reopen_multiple() will not call bdrv_reopen_abort()
38
aio_context_release(ctx);
57
+ * when the respective bdrv_reopen_prepare() has failed) */
39
58
+ if (drv->bdrv_reopen_abort) {
40
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
59
+ drv->bdrv_reopen_abort(reopen_state);
41
index XXXXXXX..XXXXXXX 100644
60
+ }
42
--- a/tests/test-block-iothread.c
61
+ }
43
+++ b/tests/test-block-iothread.c
62
qemu_opts_del(opts);
44
@@ -XXX,XX +XXX,XX @@ static void test_attach_preserve_blk_ctx(void)
63
qobject_unref(orig_reopen_opts);
45
64
g_free(discard);
46
/* Remove the node again */
47
blk_remove_bs(blk);
48
- /* TODO bs should move back to main context here */
49
g_assert(blk_get_aio_context(blk) == ctx);
50
- g_assert(bdrv_get_aio_context(bs) == ctx);
51
+ g_assert(bdrv_get_aio_context(bs) == qemu_get_aio_context());
52
53
/* Re-attach the node */
54
blk_insert_bs(blk, bs, &error_abort);
65
--
55
--
66
2.19.1
56
2.20.1
67
57
68
58
diff view generated by jsdifflib
1
From: Li Qiang <liq3ea@gmail.com>
1
Monitor commands can handle errors, so they can easily be converted to
2
using the safer bdrv_try_set_aio_context() function.
2
3
3
Currently, the nvme_cmb_ops mr doesn't check the addr and size.
4
This can lead an oob access issue. This is triggerable in the guest.
5
Add check to avoid this issue.
6
7
Fixes CVE-2018-16847.
8
9
Reported-by: Li Qiang <liq3ea@gmail.com>
10
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
11
Signed-off-by: Li Qiang <liq3ea@gmail.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
5
---
14
hw/block/nvme.c | 7 +++++++
6
blockdev.c | 44 ++++++++++++++++++++++++++++----------------
15
1 file changed, 7 insertions(+)
7
1 file changed, 28 insertions(+), 16 deletions(-)
16
8
17
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
9
diff --git a/blockdev.c b/blockdev.c
18
index XXXXXXX..XXXXXXX 100644
10
index XXXXXXX..XXXXXXX 100644
19
--- a/hw/block/nvme.c
11
--- a/blockdev.c
20
+++ b/hw/block/nvme.c
12
+++ b/blockdev.c
21
@@ -XXX,XX +XXX,XX @@ static void nvme_cmb_write(void *opaque, hwaddr addr, uint64_t data,
13
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_prepare(BlkActionState *common,
22
unsigned size)
14
DO_UPCAST(ExternalSnapshotState, common, common);
23
{
15
TransactionAction *action = common->action;
24
NvmeCtrl *n = (NvmeCtrl *)opaque;
16
AioContext *aio_context;
25
+
17
+ int ret;
26
+ if (addr + size > NVME_CMBSZ_GETSIZE(n->bar.cmbsz)) {
18
27
+ return;
19
/* 'blockdev-snapshot' and 'blockdev-snapshot-sync' have similar
20
* purpose but a different set of parameters */
21
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_prepare(BlkActionState *common,
22
goto out;
23
}
24
25
- bdrv_set_aio_context(state->new_bs, aio_context);
26
+ ret = bdrv_try_set_aio_context(state->new_bs, aio_context, errp);
27
+ if (ret < 0) {
28
+ goto out;
28
+ }
29
+ }
29
memcpy(&n->cmbuf[addr], &data, size);
30
31
/* This removes our old bs and adds the new bs. This is an operation that
32
* can fail, so we need to do it in .prepare; undoing it for abort is
33
@@ -XXX,XX +XXX,XX @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn,
34
int flags, job_flags = JOB_DEFAULT;
35
int64_t size;
36
bool set_backing_hd = false;
37
+ int ret;
38
39
if (!backup->has_speed) {
40
backup->speed = 0;
41
@@ -XXX,XX +XXX,XX @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn,
42
goto out;
43
}
44
45
- bdrv_set_aio_context(target_bs, aio_context);
46
+ ret = bdrv_try_set_aio_context(target_bs, aio_context, errp);
47
+ if (ret < 0) {
48
+ bdrv_unref(target_bs);
49
+ goto out;
50
+ }
51
52
if (set_backing_hd) {
53
bdrv_set_backing_hd(target_bs, source, &local_err);
54
@@ -XXX,XX +XXX,XX @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn,
55
AioContext *aio_context;
56
BlockJob *job = NULL;
57
int job_flags = JOB_DEFAULT;
58
+ int ret;
59
60
if (!backup->has_speed) {
61
backup->speed = 0;
62
@@ -XXX,XX +XXX,XX @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn,
63
goto out;
64
}
65
66
- if (bdrv_get_aio_context(target_bs) != aio_context) {
67
- if (!bdrv_has_blk(target_bs)) {
68
- /* The target BDS is not attached, we can safely move it to another
69
- * AioContext. */
70
- bdrv_set_aio_context(target_bs, aio_context);
71
- } else {
72
- error_setg(errp, "Target is attached to a different thread from "
73
- "source.");
74
- goto out;
75
- }
76
+ ret = bdrv_try_set_aio_context(target_bs, aio_context, errp);
77
+ if (ret < 0) {
78
+ goto out;
79
}
80
81
if (backup->has_bitmap) {
82
@@ -XXX,XX +XXX,XX @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
83
int flags;
84
int64_t size;
85
const char *format = arg->format;
86
+ int ret;
87
88
bs = qmp_get_root_bs(arg->device, errp);
89
if (!bs) {
90
@@ -XXX,XX +XXX,XX @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
91
goto out;
92
}
93
94
- bdrv_set_aio_context(target_bs, aio_context);
95
+ ret = bdrv_try_set_aio_context(target_bs, aio_context, errp);
96
+ if (ret < 0) {
97
+ bdrv_unref(target_bs);
98
+ goto out;
99
+ }
100
101
blockdev_mirror_common(arg->has_job_id ? arg->job_id : NULL, bs, target_bs,
102
arg->has_replaces, arg->replaces, arg->sync,
103
@@ -XXX,XX +XXX,XX @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id,
104
AioContext *aio_context;
105
BlockMirrorBackingMode backing_mode = MIRROR_LEAVE_BACKING_CHAIN;
106
Error *local_err = NULL;
107
+ int ret;
108
109
bs = qmp_get_root_bs(device, errp);
110
if (!bs) {
111
@@ -XXX,XX +XXX,XX @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id,
112
aio_context = bdrv_get_aio_context(bs);
113
aio_context_acquire(aio_context);
114
115
- bdrv_set_aio_context(target_bs, aio_context);
116
+ ret = bdrv_try_set_aio_context(target_bs, aio_context, errp);
117
+ if (ret < 0) {
118
+ goto out;
119
+ }
120
121
blockdev_mirror_common(has_job_id ? job_id : NULL, bs, target_bs,
122
has_replaces, replaces, sync, backing_mode,
123
@@ -XXX,XX +XXX,XX @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id,
124
has_auto_dismiss, auto_dismiss,
125
&local_err);
126
error_propagate(errp, local_err);
127
-
128
+out:
129
aio_context_release(aio_context);
30
}
130
}
31
131
32
@@ -XXX,XX +XXX,XX @@ static uint64_t nvme_cmb_read(void *opaque, hwaddr addr, unsigned size)
132
@@ -XXX,XX +XXX,XX @@ void qmp_x_blockdev_set_iothread(const char *node_name, StrOrNull *iothread,
33
uint64_t val;
133
old_context = bdrv_get_aio_context(bs);
34
NvmeCtrl *n = (NvmeCtrl *)opaque;
134
aio_context_acquire(old_context);
35
135
36
+ if (addr + size > NVME_CMBSZ_GETSIZE(n->bar.cmbsz)) {
136
- bdrv_set_aio_context(bs, new_context);
37
+ return 0;
137
+ bdrv_try_set_aio_context(bs, new_context, errp);
38
+ }
138
39
memcpy(&val, &n->cmbuf[addr], size);
139
aio_context_release(old_context);
40
return val;
41
}
140
}
42
--
141
--
43
2.19.1
142
2.20.1
44
143
45
144
diff view generated by jsdifflib
New patch
1
The mirror and commit block jobs use bdrv_set_aio_context() to move
2
their filter node into the right AioContext before hooking it up in the
3
graph. Similarly, bdrv_open_backing_file() explicitly moves the backing
4
file node into the right AioContext first.
1
5
6
This isn't necessary any more, they get automatically moved into the
7
right context now when attaching them.
8
9
However, in the case of bdrv_open_backing_file() with a node reference,
10
it's actually not only unnecessary, but even wrong: The unchecked
11
bdrv_set_aio_context() changes the AioContext of the child node even if
12
other parents require it to retain the old context. So this is not only
13
a simplification, but a bug fix, too.
14
15
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1684342
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
---
18
block.c | 1 -
19
block/commit.c | 2 --
20
block/mirror.c | 1 -
21
3 files changed, 4 deletions(-)
22
23
diff --git a/block.c b/block.c
24
index XXXXXXX..XXXXXXX 100644
25
--- a/block.c
26
+++ b/block.c
27
@@ -XXX,XX +XXX,XX @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
28
ret = -EINVAL;
29
goto free_exit;
30
}
31
- bdrv_set_aio_context(backing_hd, bdrv_get_aio_context(bs));
32
33
if (implicit_backing) {
34
bdrv_refresh_filename(backing_hd);
35
diff --git a/block/commit.c b/block/commit.c
36
index XXXXXXX..XXXXXXX 100644
37
--- a/block/commit.c
38
+++ b/block/commit.c
39
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
40
commit_top_bs->implicit = true;
41
}
42
commit_top_bs->total_sectors = top->total_sectors;
43
- bdrv_set_aio_context(commit_top_bs, bdrv_get_aio_context(top));
44
45
bdrv_append(commit_top_bs, top, &local_err);
46
if (local_err) {
47
@@ -XXX,XX +XXX,XX @@ int bdrv_commit(BlockDriverState *bs)
48
error_report_err(local_err);
49
goto ro_cleanup;
50
}
51
- bdrv_set_aio_context(commit_top_bs, bdrv_get_aio_context(backing_file_bs));
52
53
bdrv_set_backing_hd(commit_top_bs, backing_file_bs, &error_abort);
54
bdrv_set_backing_hd(bs, commit_top_bs, &error_abort);
55
diff --git a/block/mirror.c b/block/mirror.c
56
index XXXXXXX..XXXXXXX 100644
57
--- a/block/mirror.c
58
+++ b/block/mirror.c
59
@@ -XXX,XX +XXX,XX @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
60
BDRV_REQ_NO_FALLBACK;
61
bs_opaque = g_new0(MirrorBDSOpaque, 1);
62
mirror_top_bs->opaque = bs_opaque;
63
- bdrv_set_aio_context(mirror_top_bs, bdrv_get_aio_context(bs));
64
65
/* bdrv_append takes ownership of the mirror_top_bs reference, need to keep
66
* it alive until block_job_create() succeeds even if bs has no parent. */
67
--
68
2.20.1
69
70
diff view generated by jsdifflib
New patch
1
This tests that blockdev-add can correctly add a qcow2 overlay to an
2
image used by a virtio-scsi disk in an iothread. The interesting point
3
here is whether the newly added node gets correctly moved into the
4
iothread AioContext.
1
5
6
If it isn't, we get an assertion failure in virtio-scsi while processing
7
the next request:
8
9
virtio_scsi_ctx_check: Assertion `blk_get_aio_context(d->conf.blk) == s->ctx' failed.
10
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
13
tests/libqtest.h | 11 +++++++
14
tests/libqtest.c | 19 ++++++++++++
15
tests/virtio-scsi-test.c | 62 ++++++++++++++++++++++++++++++++++++++++
16
3 files changed, 92 insertions(+)
17
18
diff --git a/tests/libqtest.h b/tests/libqtest.h
19
index XXXXXXX..XXXXXXX 100644
20
--- a/tests/libqtest.h
21
+++ b/tests/libqtest.h
22
@@ -XXX,XX +XXX,XX @@ static inline void qtest_end(void)
23
QDict *qmp(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
24
25
/**
26
+ * qmp_assert_success:
27
+ * @fmt...: QMP message to send to qemu, formatted like
28
+ * qobject_from_jsonf_nofail(). See parse_escape() for what's
29
+ * supported after '%'.
30
+ *
31
+ * Sends a QMP message to QEMU and asserts that a 'return' key is present in
32
+ * the response.
33
+ */
34
+void qmp_assert_success(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
35
+
36
+/*
37
* qmp_eventwait:
38
* @s: #event event to wait for.
39
*
40
diff --git a/tests/libqtest.c b/tests/libqtest.c
41
index XXXXXXX..XXXXXXX 100644
42
--- a/tests/libqtest.c
43
+++ b/tests/libqtest.c
44
@@ -XXX,XX +XXX,XX @@ QDict *qmp(const char *fmt, ...)
45
return response;
46
}
47
48
+void qmp_assert_success(const char *fmt, ...)
49
+{
50
+ va_list ap;
51
+ QDict *response;
52
+
53
+ va_start(ap, fmt);
54
+ response = qtest_vqmp(global_qtest, fmt, ap);
55
+ va_end(ap);
56
+
57
+ g_assert(response);
58
+ if (!qdict_haskey(response, "return")) {
59
+ QString *s = qobject_to_json_pretty(QOBJECT(response));
60
+ g_test_message("%s", qstring_get_str(s));
61
+ qobject_unref(s);
62
+ }
63
+ g_assert(qdict_haskey(response, "return"));
64
+ qobject_unref(response);
65
+}
66
+
67
char *hmp(const char *fmt, ...)
68
{
69
va_list ap;
70
diff --git a/tests/virtio-scsi-test.c b/tests/virtio-scsi-test.c
71
index XXXXXXX..XXXXXXX 100644
72
--- a/tests/virtio-scsi-test.c
73
+++ b/tests/virtio-scsi-test.c
74
@@ -XXX,XX +XXX,XX @@ static void test_unaligned_write_same(void *obj, void *data,
75
qvirtio_scsi_pci_free(vs);
76
}
77
78
+static void test_iothread_attach_node(void *obj, void *data,
79
+ QGuestAllocator *t_alloc)
80
+{
81
+ QVirtioSCSI *scsi = obj;
82
+ QVirtioSCSIQueues *vs;
83
+ char tmp_path[] = "/tmp/qtest.XXXXXX";
84
+ int fd;
85
+ int ret;
86
+
87
+ uint8_t buf[512] = { 0 };
88
+ const uint8_t write_cdb[VIRTIO_SCSI_CDB_SIZE] = {
89
+ /* WRITE(10) to LBA 0, transfer length 1 */
90
+ 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00
91
+ };
92
+
93
+ alloc = t_alloc;
94
+ vs = qvirtio_scsi_init(scsi->vdev);
95
+
96
+ /* Create a temporary qcow2 overlay*/
97
+ fd = mkstemp(tmp_path);
98
+ g_assert(fd >= 0);
99
+ close(fd);
100
+
101
+ if (!have_qemu_img()) {
102
+ g_test_message("QTEST_QEMU_IMG not set or qemu-img missing; "
103
+ "skipping snapshot test");
104
+ goto fail;
105
+ }
106
+
107
+ mkqcow2(tmp_path, 64);
108
+
109
+ /* Attach the overlay to the null0 node */
110
+ qmp_assert_success("{'execute': 'blockdev-add', 'arguments': {"
111
+ " 'driver': 'qcow2', 'node-name': 'overlay',"
112
+ " 'backing': 'null0', 'file': {"
113
+ " 'driver': 'file', 'filename': %s}}}", tmp_path);
114
+
115
+ /* Send a request to see if the AioContext is still right */
116
+ ret = virtio_scsi_do_command(vs, write_cdb, NULL, 0, buf, 512, NULL);
117
+ g_assert_cmphex(ret, ==, 0);
118
+
119
+fail:
120
+ qvirtio_scsi_pci_free(vs);
121
+ unlink(tmp_path);
122
+}
123
+
124
static void *virtio_scsi_hotplug_setup(GString *cmd_line, void *arg)
125
{
126
g_string_append(cmd_line,
127
@@ -XXX,XX +XXX,XX @@ static void *virtio_scsi_setup(GString *cmd_line, void *arg)
128
return arg;
129
}
130
131
+static void *virtio_scsi_setup_iothread(GString *cmd_line, void *arg)
132
+{
133
+ g_string_append(cmd_line,
134
+ " -object iothread,id=thread0"
135
+ " -blockdev driver=null-co,node-name=null0"
136
+ " -device scsi-hd,drive=null0");
137
+ return arg;
138
+}
139
+
140
static void register_virtio_scsi_test(void)
141
{
142
QOSGraphTestOptions opts = { };
143
@@ -XXX,XX +XXX,XX @@ static void register_virtio_scsi_test(void)
144
opts.before = virtio_scsi_setup;
145
qos_add_test("unaligned-write-same", "virtio-scsi",
146
test_unaligned_write_same, &opts);
147
+
148
+ opts.before = virtio_scsi_setup_iothread;
149
+ opts.edge = (QOSGraphEdgeOptions) {
150
+ .extra_device_opts = "iothread=thread0",
151
+ };
152
+ qos_add_test("iothread-attach-node", "virtio-scsi",
153
+ test_iothread_attach_node, &opts);
154
}
155
156
libqos_init(register_virtio_scsi_test);
157
--
158
2.20.1
159
160
diff view generated by jsdifflib
New patch
1
This tests that devices refuse to be attached to a node that has already
2
been moved to a different iothread if they can't be or aren't configured
3
to work in the same iothread.
1
4
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
7
tests/qemu-iotests/051 | 24 ++++++++++++++++++++++++
8
tests/qemu-iotests/051.out | 3 +++
9
tests/qemu-iotests/051.pc.out | 27 +++++++++++++++++++++++++++
10
3 files changed, 54 insertions(+)
11
12
diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051
13
index XXXXXXX..XXXXXXX 100755
14
--- a/tests/qemu-iotests/051
15
+++ b/tests/qemu-iotests/051
16
@@ -XXX,XX +XXX,XX @@ case "$QEMU_DEFAULT_MACHINE" in
17
;;
18
esac
19
20
+echo
21
+echo === Attach to node in non-default iothread ===
22
+echo
23
+
24
+case "$QEMU_DEFAULT_MACHINE" in
25
+ pc)
26
+ iothread="-drive file=$TEST_IMG,if=none,node-name=disk -object iothread,id=thread0 -device virtio-scsi,iothread=thread0,id=virtio-scsi0 -device scsi-hd,bus=virtio-scsi0.0,drive=disk,share-rw=on"
27
+
28
+ # Can't add a device in the main thread while virtio-scsi0 uses the node
29
+ run_qemu $iothread -device ide-hd,drive=disk,share-rw=on
30
+ run_qemu $iothread -device virtio-blk-pci,drive=disk,share-rw=on
31
+ run_qemu $iothread -device lsi53c895a,id=lsi0 -device scsi-hd,bus=lsi0.0,drive=disk,share-rw=on
32
+ run_qemu $iothread -device virtio-scsi,id=virtio-scsi1 -device scsi-hd,bus=virtio-scsi1.0,drive=disk,share-rw=on
33
+
34
+ # virtio-blk enables the iothread only when the driver initialises the
35
+ # device, so a second virtio-blk device can't be added even with the
36
+ # same iothread. virtio-scsi allows this.
37
+ run_qemu $iothread -device virtio-blk-pci,drive=disk,iohtread=iothread0,share-rw=on
38
+ run_qemu $iothread -device virtio-scsi,id=virtio-scsi1,iothread=thread0 -device scsi-hd,bus=virtio-scsi1.0,drive=disk,share-rw=on
39
+ ;;
40
+ *)
41
+ ;;
42
+esac
43
+
44
echo
45
echo === Read-only ===
46
echo
47
diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out
48
index XXXXXXX..XXXXXXX 100644
49
--- a/tests/qemu-iotests/051.out
50
+++ b/tests/qemu-iotests/051.out
51
@@ -XXX,XX +XXX,XX @@ QEMU X.Y.Z monitor - type 'help' for more information
52
(qemu) QEMU_PROG: -drive if=virtio: Device needs media, but drive is empty
53
54
55
+=== Attach to node in non-default iothread ===
56
+
57
+
58
=== Read-only ===
59
60
Testing: -drive file=TEST_DIR/t.qcow2,if=virtio,readonly=on
61
diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out
62
index XXXXXXX..XXXXXXX 100644
63
--- a/tests/qemu-iotests/051.pc.out
64
+++ b/tests/qemu-iotests/051.pc.out
65
@@ -XXX,XX +XXX,XX @@ QEMU X.Y.Z monitor - type 'help' for more information
66
(qemu) QEMU_PROG: -device scsi-hd,drive=disk: Device needs media, but drive is empty
67
68
69
+=== Attach to node in non-default iothread ===
70
+
71
+Testing: -drive file=TEST_DIR/t.qcow2,if=none,node-name=disk -object iothread,id=thread0 -device virtio-scsi,iothread=thread0,id=virtio-scsi0 -device scsi-hd,bus=virtio-scsi0.0,drive=disk,share-rw=on -device ide-hd,drive=disk,share-rw=on
72
+QEMU X.Y.Z monitor - type 'help' for more information
73
+(qemu) QEMU_PROG: -device ide-hd,drive=disk,share-rw=on: Cannot change iothread of active block backend
74
+
75
+Testing: -drive file=TEST_DIR/t.qcow2,if=none,node-name=disk -object iothread,id=thread0 -device virtio-scsi,iothread=thread0,id=virtio-scsi0 -device scsi-hd,bus=virtio-scsi0.0,drive=disk,share-rw=on -device virtio-blk-pci,drive=disk,share-rw=on
76
+QEMU X.Y.Z monitor - type 'help' for more information
77
+(qemu) QEMU_PROG: -device virtio-blk-pci,drive=disk,share-rw=on: Cannot change iothread of active block backend
78
+
79
+Testing: -drive file=TEST_DIR/t.qcow2,if=none,node-name=disk -object iothread,id=thread0 -device virtio-scsi,iothread=thread0,id=virtio-scsi0 -device scsi-hd,bus=virtio-scsi0.0,drive=disk,share-rw=on -device lsi53c895a,id=lsi0 -device scsi-hd,bus=lsi0.0,drive=disk,share-rw=on
80
+QEMU X.Y.Z monitor - type 'help' for more information
81
+(qemu) QEMU_PROG: -device scsi-hd,bus=lsi0.0,drive=disk,share-rw=on: HBA does not support iothreads
82
+
83
+Testing: -drive file=TEST_DIR/t.qcow2,if=none,node-name=disk -object iothread,id=thread0 -device virtio-scsi,iothread=thread0,id=virtio-scsi0 -device scsi-hd,bus=virtio-scsi0.0,drive=disk,share-rw=on -device virtio-scsi,id=virtio-scsi1 -device scsi-hd,bus=virtio-scsi1.0,drive=disk,share-rw=on
84
+QEMU X.Y.Z monitor - type 'help' for more information
85
+(qemu) QEMU_PROG: -device scsi-hd,bus=virtio-scsi1.0,drive=disk,share-rw=on: Cannot change iothread of active block backend
86
+
87
+Testing: -drive file=TEST_DIR/t.qcow2,if=none,node-name=disk -object iothread,id=thread0 -device virtio-scsi,iothread=thread0,id=virtio-scsi0 -device scsi-hd,bus=virtio-scsi0.0,drive=disk,share-rw=on -device virtio-blk-pci,drive=disk,iohtread=iothread0,share-rw=on
88
+QEMU X.Y.Z monitor - type 'help' for more information
89
+(qemu) QEMU_PROG: -device virtio-blk-pci,drive=disk,iohtread=iothread0,share-rw=on: Cannot change iothread of active block backend
90
+
91
+Testing: -drive file=TEST_DIR/t.qcow2,if=none,node-name=disk -object iothread,id=thread0 -device virtio-scsi,iothread=thread0,id=virtio-scsi0 -device scsi-hd,bus=virtio-scsi0.0,drive=disk,share-rw=on -device virtio-scsi,id=virtio-scsi1,iothread=thread0 -device scsi-hd,bus=virtio-scsi1.0,drive=disk,share-rw=on
92
+QEMU X.Y.Z monitor - type 'help' for more information
93
+(qemu) quit
94
+
95
+
96
=== Read-only ===
97
98
Testing: -drive file=TEST_DIR/t.qcow2,if=floppy,readonly=on
99
--
100
2.20.1
101
102
diff view generated by jsdifflib
New patch
1
No reason to use the unchecked version in tests, even more so when these
2
are the last callers of bdrv_set_aio_context() outside of block.c.
1
3
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
---
6
tests/test-bdrv-drain.c | 6 +++---
7
1 file changed, 3 insertions(+), 3 deletions(-)
8
9
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
10
index XXXXXXX..XXXXXXX 100644
11
--- a/tests/test-bdrv-drain.c
12
+++ b/tests/test-bdrv-drain.c
13
@@ -XXX,XX +XXX,XX @@ static void test_set_aio_context(void)
14
&error_abort);
15
16
bdrv_drained_begin(bs);
17
- bdrv_set_aio_context(bs, ctx_a);
18
+ bdrv_try_set_aio_context(bs, ctx_a, &error_abort);
19
20
aio_context_acquire(ctx_a);
21
bdrv_drained_end(bs);
22
23
bdrv_drained_begin(bs);
24
- bdrv_set_aio_context(bs, ctx_b);
25
+ bdrv_try_set_aio_context(bs, ctx_b, &error_abort);
26
aio_context_release(ctx_a);
27
aio_context_acquire(ctx_b);
28
- bdrv_set_aio_context(bs, qemu_get_aio_context());
29
+ bdrv_try_set_aio_context(bs, qemu_get_aio_context(), &error_abort);
30
aio_context_release(ctx_b);
31
bdrv_drained_end(bs);
32
33
--
34
2.20.1
35
36
diff view generated by jsdifflib
New patch
1
All callers of bdrv_set_aio_context() are eliminated now, they have
2
moved to bdrv_try_set_aio_context() and related safe functions. Remove
3
bdrv_set_aio_context().
1
4
5
With this, we can now know that the .set_aio_ctx callback must be
6
present in bdrv_set_aio_context_ignore() because
7
bdrv_can_set_aio_context() would have returned false previously, so
8
instead of checking the condition, we can assert it.
9
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
12
docs/devel/multiple-iothreads.txt | 4 ++--
13
include/block/block.h | 9 ---------
14
block.c | 30 ++++++++++++++----------------
15
3 files changed, 16 insertions(+), 27 deletions(-)
16
17
diff --git a/docs/devel/multiple-iothreads.txt b/docs/devel/multiple-iothreads.txt
18
index XXXXXXX..XXXXXXX 100644
19
--- a/docs/devel/multiple-iothreads.txt
20
+++ b/docs/devel/multiple-iothreads.txt
21
@@ -XXX,XX +XXX,XX @@ The AioContext originates from the QEMU block layer, even though nowadays
22
AioContext is a generic event loop that can be used by any QEMU subsystem.
23
24
The block layer has support for AioContext integrated. Each BlockDriverState
25
-is associated with an AioContext using bdrv_set_aio_context() and
26
+is associated with an AioContext using bdrv_try_set_aio_context() and
27
bdrv_get_aio_context(). This allows block layer code to process I/O inside the
28
right AioContext. Other subsystems may wish to follow a similar approach.
29
30
@@ -XXX,XX +XXX,XX @@ Long-running jobs (usually in the form of coroutines) are best scheduled in
31
the BlockDriverState's AioContext to avoid the need to acquire/release around
32
each bdrv_*() call. The functions bdrv_add/remove_aio_context_notifier,
33
or alternatively blk_add/remove_aio_context_notifier if you use BlockBackends,
34
-can be used to get a notification whenever bdrv_set_aio_context() moves a
35
+can be used to get a notification whenever bdrv_try_set_aio_context() moves a
36
BlockDriverState to a different AioContext.
37
diff --git a/include/block/block.h b/include/block/block.h
38
index XXXXXXX..XXXXXXX 100644
39
--- a/include/block/block.h
40
+++ b/include/block/block.h
41
@@ -XXX,XX +XXX,XX @@ AioContext *bdrv_get_aio_context(BlockDriverState *bs);
42
*/
43
void bdrv_coroutine_enter(BlockDriverState *bs, Coroutine *co);
44
45
-/**
46
- * bdrv_set_aio_context:
47
- *
48
- * Changes the #AioContext used for fd handlers, timers, and BHs by this
49
- * BlockDriverState and all its children.
50
- *
51
- * This function must be called with iothread lock held.
52
- */
53
-void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context);
54
void bdrv_set_aio_context_ignore(BlockDriverState *bs,
55
AioContext *new_context, GSList **ignore);
56
int bdrv_try_set_aio_context(BlockDriverState *bs, AioContext *ctx,
57
diff --git a/block.c b/block.c
58
index XXXXXXX..XXXXXXX 100644
59
--- a/block.c
60
+++ b/block.c
61
@@ -XXX,XX +XXX,XX @@ static void bdrv_attach_aio_context(BlockDriverState *bs,
62
bs->walking_aio_notifiers = false;
63
}
64
65
-/* @ignore will accumulate all visited BdrvChild object. The caller is
66
- * responsible for freeing the list afterwards. */
67
+/*
68
+ * Changes the AioContext used for fd handlers, timers, and BHs by this
69
+ * BlockDriverState and all its children and parents.
70
+ *
71
+ * The caller must own the AioContext lock for the old AioContext of bs, but it
72
+ * must not own the AioContext lock for new_context (unless new_context is the
73
+ * same as the current context of bs).
74
+ *
75
+ * @ignore will accumulate all visited BdrvChild object. The caller is
76
+ * responsible for freeing the list afterwards.
77
+ */
78
void bdrv_set_aio_context_ignore(BlockDriverState *bs,
79
AioContext *new_context, GSList **ignore)
80
{
81
@@ -XXX,XX +XXX,XX @@ void bdrv_set_aio_context_ignore(BlockDriverState *bs,
82
if (g_slist_find(*ignore, child)) {
83
continue;
84
}
85
- if (child->role->set_aio_ctx) {
86
- *ignore = g_slist_prepend(*ignore, child);
87
- child->role->set_aio_ctx(child, new_context, ignore);
88
- }
89
+ assert(child->role->set_aio_ctx);
90
+ *ignore = g_slist_prepend(*ignore, child);
91
+ child->role->set_aio_ctx(child, new_context, ignore);
92
}
93
94
bdrv_detach_aio_context(bs);
95
@@ -XXX,XX +XXX,XX @@ void bdrv_set_aio_context_ignore(BlockDriverState *bs,
96
aio_context_release(new_context);
97
}
98
99
-/* The caller must own the AioContext lock for the old AioContext of bs, but it
100
- * must not own the AioContext lock for new_context (unless new_context is
101
- * the same as the current context of bs). */
102
-void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
103
-{
104
- GSList *ignore_list = NULL;
105
- bdrv_set_aio_context_ignore(bs, new_context, &ignore_list);
106
- g_slist_free(ignore_list);
107
-}
108
-
109
static bool bdrv_parent_can_set_aio_context(BdrvChild *c, AioContext *ctx,
110
GSList **ignore, Error **errp)
111
{
112
--
113
2.20.1
114
115
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
Our code was already checking that we did not attempt to
3
Let's at least trace ignored failure.
4
allocate more clusters than what would fit in an INT64 (the
5
physical maximimum if we can access a full off_t's worth of
6
data). But this does not catch smaller limits enforced by
7
various spots in the qcow2 image description: L1 and normal
8
clusters of L2 are documented as having bits 63-56 reserved
9
for other purposes, capping our maximum offset at 64PB (bit
10
55 is the maximum bit set). And for compressed images with
11
2M clusters, the cap drops the maximum offset to bit 48, or
12
a maximum offset of 512TB. If we overflow that offset, we
13
would write compressed data into one place, but try to
14
decompress from another, which won't work.
15
4
16
It's actually possible to prove that overflow can cause image
5
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
17
corruption without this patch; I'll add the iotests separately
6
Reviewed-by: Eric Blake <eblake@redhat.com>
18
in the next commit.
19
20
Signed-off-by: Eric Blake <eblake@redhat.com>
21
Reviewed-by: Alberto Garcia <berto@igalia.com>
22
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
23
---
8
---
24
block/qcow2.h | 6 ++++++
9
block/qcow2-refcount.c | 7 ++++++-
25
block/qcow2-refcount.c | 20 +++++++++++++-------
10
block/trace-events | 3 +++
26
2 files changed, 19 insertions(+), 7 deletions(-)
11
2 files changed, 9 insertions(+), 1 deletion(-)
27
12
28
diff --git a/block/qcow2.h b/block/qcow2.h
29
index XXXXXXX..XXXXXXX 100644
30
--- a/block/qcow2.h
31
+++ b/block/qcow2.h
32
@@ -XXX,XX +XXX,XX @@
33
#define QCOW_MAX_CRYPT_CLUSTERS 32
34
#define QCOW_MAX_SNAPSHOTS 65536
35
36
+/* Field widths in qcow2 mean normal cluster offsets cannot reach
37
+ * 64PB; depending on cluster size, compressed clusters can have a
38
+ * smaller limit (64PB for up to 16k clusters, then ramps down to
39
+ * 512TB for 2M clusters). */
40
+#define QCOW_MAX_CLUSTER_OFFSET ((1ULL << 56) - 1)
41
+
42
/* 8 MB refcount table is enough for 2 PB images at 64k cluster size
43
* (128 GB for 512 byte clusters, 2 EB for 2 MB clusters) */
44
#define QCOW_MAX_REFTABLE_SIZE S_8MiB
45
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
13
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
46
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
47
--- a/block/qcow2-refcount.c
15
--- a/block/qcow2-refcount.c
48
+++ b/block/qcow2-refcount.c
16
+++ b/block/qcow2-refcount.c
49
@@ -XXX,XX +XXX,XX @@
17
@@ -XXX,XX +XXX,XX @@
18
#include "qemu/range.h"
50
#include "qemu/bswap.h"
19
#include "qemu/bswap.h"
51
#include "qemu/cutils.h"
20
#include "qemu/cutils.h"
52
21
+#include "trace.h"
53
-static int64_t alloc_clusters_noref(BlockDriverState *bs, uint64_t size);
22
54
+static int64_t alloc_clusters_noref(BlockDriverState *bs, uint64_t size,
23
static int64_t alloc_clusters_noref(BlockDriverState *bs, uint64_t size,
55
+ uint64_t max);
24
uint64_t max);
56
static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
25
@@ -XXX,XX +XXX,XX @@ void qcow2_process_discards(BlockDriverState *bs, int ret)
57
int64_t offset, int64_t length, uint64_t addend,
26
58
bool decrease, enum qcow2_discard_type type);
27
/* Discard is optional, ignore the return value */
59
@@ -XXX,XX +XXX,XX @@ static int alloc_refcount_block(BlockDriverState *bs,
28
if (ret >= 0) {
60
}
29
- bdrv_pdiscard(bs->file, d->offset, d->bytes);
61
30
+ int r2 = bdrv_pdiscard(bs->file, d->offset, d->bytes);
62
/* Allocate the refcount block itself and mark it as used */
31
+ if (r2 < 0) {
63
- int64_t new_block = alloc_clusters_noref(bs, s->cluster_size);
32
+ trace_qcow2_process_discards_failed_region(d->offset, d->bytes,
64
+ int64_t new_block = alloc_clusters_noref(bs, s->cluster_size, INT64_MAX);
33
+ r2);
65
if (new_block < 0) {
34
+ }
66
return new_block;
67
}
68
@@ -XXX,XX +XXX,XX @@ int qcow2_update_cluster_refcount(BlockDriverState *bs,
69
70
71
/* return < 0 if error */
72
-static int64_t alloc_clusters_noref(BlockDriverState *bs, uint64_t size)
73
+static int64_t alloc_clusters_noref(BlockDriverState *bs, uint64_t size,
74
+ uint64_t max)
75
{
76
BDRVQcow2State *s = bs->opaque;
77
uint64_t i, nb_clusters, refcount;
78
@@ -XXX,XX +XXX,XX @@ retry:
79
}
80
81
/* Make sure that all offsets in the "allocated" range are representable
82
- * in an int64_t */
83
+ * in the requested max */
84
if (s->free_cluster_index > 0 &&
85
- s->free_cluster_index - 1 > (INT64_MAX >> s->cluster_bits))
86
+ s->free_cluster_index - 1 > (max >> s->cluster_bits))
87
{
88
return -EFBIG;
89
}
90
@@ -XXX,XX +XXX,XX @@ int64_t qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size)
91
92
BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC);
93
do {
94
- offset = alloc_clusters_noref(bs, size);
95
+ offset = alloc_clusters_noref(bs, size, QCOW_MAX_CLUSTER_OFFSET);
96
if (offset < 0) {
97
return offset;
98
}
35
}
99
@@ -XXX,XX +XXX,XX @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
36
100
free_in_cluster = s->cluster_size - offset_into_cluster(s, offset);
37
g_free(d);
101
do {
38
diff --git a/block/trace-events b/block/trace-events
102
if (!offset || free_in_cluster < size) {
39
index XXXXXXX..XXXXXXX 100644
103
- int64_t new_cluster = alloc_clusters_noref(bs, s->cluster_size);
40
--- a/block/trace-events
104
+ int64_t new_cluster;
41
+++ b/block/trace-events
42
@@ -XXX,XX +XXX,XX @@ qcow2_cache_get_done(void *co, int c, int i) "co %p is_l2_cache %d index %d"
43
qcow2_cache_flush(void *co, int c) "co %p is_l2_cache %d"
44
qcow2_cache_entry_flush(void *co, int c, int i) "co %p is_l2_cache %d index %d"
45
46
+# qcow2-refcount.c
47
+qcow2_process_discards_failed_region(uint64_t offset, uint64_t bytes, int ret) "offset 0x%" PRIx64 " bytes 0x%" PRIx64 " ret %d"
105
+
48
+
106
+ new_cluster = alloc_clusters_noref(bs, s->cluster_size,
49
# qed-l2-cache.c
107
+ MIN(s->cluster_offset_mask,
50
qed_alloc_l2_cache_entry(void *l2_cache, void *entry) "l2_cache %p entry %p"
108
+ QCOW_MAX_CLUSTER_OFFSET));
51
qed_unref_l2_cache_entry(void *entry, int ref) "entry %p ref %d"
109
if (new_cluster < 0) {
110
return new_cluster;
111
}
112
--
52
--
113
2.19.1
53
2.20.1
114
54
115
55
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
This fixes at least one overflow in qcow2_process_discards, which
4
passes 64bit region length to bdrv_pdiscard where bytes (or sectors in
5
the past) parameter is int since its introduction in 0b919fae.
6
7
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
10
include/block/block.h | 4 ++--
11
block/io.c | 16 ++++++++--------
12
2 files changed, 10 insertions(+), 10 deletions(-)
13
14
diff --git a/include/block/block.h b/include/block/block.h
15
index XXXXXXX..XXXXXXX 100644
16
--- a/include/block/block.h
17
+++ b/include/block/block.h
18
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all(void);
19
AIO_WAIT_WHILE(bdrv_get_aio_context(bs_), \
20
cond); })
21
22
-int bdrv_pdiscard(BdrvChild *child, int64_t offset, int bytes);
23
-int bdrv_co_pdiscard(BdrvChild *child, int64_t offset, int bytes);
24
+int bdrv_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes);
25
+int bdrv_co_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes);
26
int bdrv_has_zero_init_1(BlockDriverState *bs);
27
int bdrv_has_zero_init(BlockDriverState *bs);
28
bool bdrv_unallocated_blocks_are_zero(BlockDriverState *bs);
29
diff --git a/block/io.c b/block/io.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/block/io.c
32
+++ b/block/io.c
33
@@ -XXX,XX +XXX,XX @@ int bdrv_flush(BlockDriverState *bs)
34
typedef struct DiscardCo {
35
BdrvChild *child;
36
int64_t offset;
37
- int bytes;
38
+ int64_t bytes;
39
int ret;
40
} DiscardCo;
41
static void coroutine_fn bdrv_pdiscard_co_entry(void *opaque)
42
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_pdiscard_co_entry(void *opaque)
43
aio_wait_kick();
44
}
45
46
-int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset, int bytes)
47
+int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset,
48
+ int64_t bytes)
49
{
50
BdrvTrackedRequest req;
51
int max_pdiscard, ret;
52
int head, tail, align;
53
BlockDriverState *bs = child->bs;
54
55
- if (!bs || !bs->drv) {
56
+ if (!bs || !bs->drv || !bdrv_is_inserted(bs)) {
57
return -ENOMEDIUM;
58
}
59
60
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset, int bytes)
61
return -EPERM;
62
}
63
64
- ret = bdrv_check_byte_request(bs, offset, bytes);
65
- if (ret < 0) {
66
- return ret;
67
+ if (offset < 0 || bytes < 0 || bytes > INT64_MAX - offset) {
68
+ return -EIO;
69
}
70
71
/* Do nothing if disabled. */
72
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset, int bytes)
73
assert(max_pdiscard >= bs->bl.request_alignment);
74
75
while (bytes > 0) {
76
- int num = bytes;
77
+ int64_t num = bytes;
78
79
if (head) {
80
/* Make small requests to get to alignment boundaries. */
81
@@ -XXX,XX +XXX,XX @@ out:
82
return ret;
83
}
84
85
-int bdrv_pdiscard(BdrvChild *child, int64_t offset, int bytes)
86
+int bdrv_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes)
87
{
88
Coroutine *co;
89
DiscardCo rwco = {
90
--
91
2.20.1
92
93
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
Commit 70ff5b07 wanted to move the diff between actual and reference
2
output to the end after printing the test result line. It really only
3
copied it, though, so the diff is now displayed twice. Remove the old
4
one.
2
5
3
Although off_t permits up to 63 bits (8EB) of file offsets, in
6
Fixes: 70ff5b07fcdd378180ad2d5cc0b0d5e67e7ef325
4
practice, we're going to hit other limits first. Document some
5
of those limits in the qcow2 spec (some are inherent, others are
6
implementation choices of qemu), and how choice of cluster size
7
can influence some of the limits.
8
9
While we cannot map any uncompressed virtual cluster to any
10
address higher than 64 PB (56 bits) (due to the current L1/L2
11
field encoding stopping at bit 55), qemu's cap of 8M for the
12
refcount table can still access larger host addresses for some
13
combinations of large clusters and small refcount_order. For
14
comparison, ext4 with 4k blocks caps files at 16PB.
15
16
Another interesting limit: for compressed clusters, the L2 layout
17
requires an ever-smaller maximum host offset as cluster size gets
18
larger, down to a 512 TB maximum with 2M clusters. In particular,
19
note that with a cluster size of 8k or smaller, the L2 entry for
20
a compressed cluster could technically point beyond the 64PB mark,
21
but when you consider that with 8k clusters and refcount_order = 0,
22
you cannot access beyond 512T without exceeding qemu's limit of an
23
8M cap on the refcount table, it is unlikely that any image in the
24
wild has attempted to do so. To be safe, let's document that bits
25
beyond 55 in a compressed cluster must be 0.
26
27
Signed-off-by: Eric Blake <eblake@redhat.com>
28
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
29
---
8
---
30
docs/interop/qcow2.txt | 38 ++++++++++++++++++++++++++++++++++++--
9
tests/qemu-iotests/check | 1 -
31
1 file changed, 36 insertions(+), 2 deletions(-)
10
1 file changed, 1 deletion(-)
32
11
33
diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt
12
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
34
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100755
35
--- a/docs/interop/qcow2.txt
14
--- a/tests/qemu-iotests/check
36
+++ b/docs/interop/qcow2.txt
15
+++ b/tests/qemu-iotests/check
37
@@ -XXX,XX +XXX,XX @@ The first cluster of a qcow2 image contains the file header:
16
@@ -XXX,XX +XXX,XX @@ do
38
with larger cluster sizes.
17
fi
39
18
else
40
24 - 31: size
19
mv $tmp.out $seq.out.bad
41
- Virtual disk size in bytes
20
- $diff -w "$reference" "$PWD"/$seq.out.bad
42
+ Virtual disk size in bytes.
21
status="fail"
43
+
22
results="output mismatch (see $seq.out.bad)"
44
+ Note: qemu has an implementation limit of 32 MB as
23
printdiff=true
45
+ the maximum L1 table size. With a 2 MB cluster
46
+ size, it is unable to populate a virtual cluster
47
+ beyond 2 EB (61 bits); with a 512 byte cluster
48
+ size, it is unable to populate a virtual size
49
+ larger than 128 GB (37 bits). Meanwhile, L1/L2
50
+ table layouts limit an image to no more than 64 PB
51
+ (56 bits) of populated clusters, and an image may
52
+ hit other limits first (such as a file system's
53
+ maximum size).
54
55
32 - 35: crypt_method
56
0 for no encryption
57
@@ -XXX,XX +XXX,XX @@ in the image file.
58
It contains pointers to the second level structures which are called refcount
59
blocks and are exactly one cluster in size.
60
61
+Although a large enough refcount table can reserve clusters past 64 PB
62
+(56 bits) (assuming the underlying protocol can even be sized that
63
+large), note that some qcow2 metadata such as L1/L2 tables must point
64
+to clusters prior to that point.
65
+
66
+Note: qemu has an implementation limit of 8 MB as the maximum refcount
67
+table size. With a 2 MB cluster size and a default refcount_order of
68
+4, it is unable to reference host resources beyond 2 EB (61 bits); in
69
+the worst case, with a 512 cluster size and refcount_order of 6, it is
70
+unable to access beyond 32 GB (35 bits).
71
+
72
Given an offset into the image file, the refcount of its cluster can be
73
obtained as follows:
74
75
@@ -XXX,XX +XXX,XX @@ The L1 table has a variable size (stored in the header) and may use multiple
76
clusters, however it must be contiguous in the image file. L2 tables are
77
exactly one cluster in size.
78
79
+The L1 and L2 tables have implications on the maximum virtual file
80
+size; for a given L1 table size, a larger cluster size is required for
81
+the guest to have access to more space. Furthermore, a virtual
82
+cluster must currently map to a host offset below 64 PB (56 bits)
83
+(although this limit could be relaxed by putting reserved bits into
84
+use). Additionally, as cluster size increases, the maximum host
85
+offset for a compressed cluster is reduced (a 2M cluster size requires
86
+compressed clusters to reside below 512 TB (49 bits), and this limit
87
+cannot be relaxed without an incompatible layout change).
88
+
89
Given an offset into the virtual disk, the offset into the image file can be
90
obtained as follows:
91
92
@@ -XXX,XX +XXX,XX @@ Standard Cluster Descriptor:
93
Compressed Clusters Descriptor (x = 62 - (cluster_bits - 8)):
94
95
Bit 0 - x-1: Host cluster offset. This is usually _not_ aligned to a
96
- cluster or sector boundary!
97
+ cluster or sector boundary! If cluster_bits is
98
+ small enough that this field includes bits beyond
99
+ 55, those upper bits must be set to 0.
100
101
x - 61: Number of additional 512-byte sectors used for the
102
compressed data, beyond the sector containing the offset
103
--
24
--
104
2.19.1
25
2.20.1
105
26
106
27
diff view generated by jsdifflib