1
The following changes since commit b2f7a038bb4c4fc5ce6b8486e8513dfd97665e2a:
1
The following changes since commit aa9bbd865502ed517624ab6fe7d4b5d89ca95e43:
2
2
3
Merge remote-tracking branch 'remotes/rth/tags/pull-softfloat-20181104' into staging (2018-11-05 10:32:49 +0000)
3
Merge tag 'pull-ppc-20230528' of https://gitlab.com/danielhb/qemu into staging (2023-05-29 14:31:52 -0700)
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
https://repo.or.cz/qemu/kevin.git tags/for-upstream
8
8
9
for you to fetch changes up to 1240ac558d348f6c7a5752b1a57c1da58e4efe3e:
9
for you to fetch changes up to 60f782b6b78211c125970768be726c9f380dbd61:
10
10
11
include: Add a comment to explain the origin of sizes' lookup table (2018-11-05 15:29:59 +0100)
11
aio: remove aio_disable_external() API (2023-05-30 17:37:26 +0200)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block layer patches:
14
Block layer patches
15
15
16
- auto-read-only option to fix commit job when used with -blockdev
16
- Fix blockdev-create with iothreads
17
- Fix help text related qemu-iotests failure (by improving the help text
17
- Remove aio_disable_external() API
18
and updating the reference output)
19
- quorum: Add missing checks when adding/removing child nodes
20
- Don't take address of fields in packed structs
21
- vvfat: Fix crash when reporting error about too many files in directory
22
18
23
----------------------------------------------------------------
19
----------------------------------------------------------------
24
Alberto Garcia (7):
20
Kevin Wolf (12):
25
block: replace "discard" literal with BDRV_OPT_DISCARD macro
21
block-coroutine-wrapper: Take AioContext lock in no_co_wrappers
26
qcow2: Get the request alignment for encrypted images from QCryptoBlock
22
block: Clarify locking rules for bdrv_open(_inherit)()
27
quorum: Remove quorum_err()
23
block: Take main AioContext lock when calling bdrv_open()
28
quorum: Return an error if the blkverify mode has invalid settings
24
block-backend: Fix blk_new_open() for iothreads
29
iotest: Test the blkverify mode of the Quorum driver
25
mirror: Hold main AioContext lock for calling bdrv_open_backing_file()
30
quorum: Forbid adding children in blkverify mode
26
qcow2: Fix open with 'file' in iothread
31
iotest: Test x-blockdev-change on a Quorum
27
raw-format: Fix open with 'file' in iothread
28
copy-before-write: Fix open with child in iothread
29
block: Take AioContext lock in bdrv_open_driver()
30
block: Fix AioContext locking in bdrv_insert_node()
31
iotests: Make verify_virtio_scsi_pci_or_ccw() public
32
iotests: Test blockdev-create in iothread
32
33
33
Cleber Rosa (1):
34
Stefan Hajnoczi (20):
34
iotests: make 083 specific to raw
35
block-backend: split blk_do_set_aio_context()
36
hw/qdev: introduce qdev_is_realized() helper
37
virtio-scsi: avoid race between unplug and transport event
38
virtio-scsi: stop using aio_disable_external() during unplug
39
util/vhost-user-server: rename refcount to in_flight counter
40
block/export: wait for vhost-user-blk requests when draining
41
block/export: stop using is_external in vhost-user-blk server
42
hw/xen: do not use aio_set_fd_handler(is_external=true) in xen_xenstore
43
block: add blk_in_drain() API
44
block: drain from main loop thread in bdrv_co_yield_to_drain()
45
xen-block: implement BlockDevOps->drained_begin()
46
hw/xen: do not set is_external=true on evtchn fds
47
block/export: rewrite vduse-blk drain code
48
block/export: don't require AioContext lock around blk_exp_ref/unref()
49
block/fuse: do not set is_external=true on FUSE fd
50
virtio: make it possible to detach host notifier from any thread
51
virtio-blk: implement BlockDevOps->drained_begin()
52
virtio-scsi: implement BlockDevOps->drained_begin()
53
virtio: do not set is_external=true on host notifiers
54
aio: remove aio_disable_external() API
35
55
36
Daniel P. Berrangé (1):
56
hw/block/dataplane/xen-block.h | 2 +
37
crypto: initialize sector size even when opening with no IO flag
57
include/block/aio.h | 57 ------------
38
58
include/block/block-common.h | 3 +
39
Kevin Wolf (12):
59
include/block/block_int-common.h | 72 +++++++--------
40
vpc: Don't leak opts in vpc_open()
60
include/block/export.h | 2 +
41
block: Update flags in bdrv_set_read_only()
61
include/hw/qdev-core.h | 17 +++-
42
block: Add auto-read-only option
62
include/hw/scsi/scsi.h | 14 +++
43
rbd: Close image in qemu_rbd_open() error path
63
include/qemu/vhost-user-server.h | 8 +-
44
block: Require auto-read-only for existing fallbacks
64
include/sysemu/block-backend-common.h | 25 ++---
45
nbd: Support auto-read-only option
65
include/sysemu/block-backend-global-state.h | 1 +
46
file-posix: Support auto-read-only option
66
util/aio-posix.h | 1 -
47
curl: Support auto-read-only option
67
block.c | 46 ++++++---
48
gluster: Support auto-read-only option
68
block/blkio.c | 15 +--
49
iscsi: Support auto-read-only option
69
block/block-backend.c | 104 ++++++++++++---------
50
block: Make auto-read-only=on default for -drive
70
block/copy-before-write.c | 21 ++++-
51
qemu-iotests: Test auto-read-only with -drive and -blockdev
71
block/curl.c | 10 +-
52
72
block/export/export.c | 13 ++-
53
Leonid Bloch (2):
73
block/export/fuse.c | 56 ++++++++++-
54
vdi: Use a literal number of bytes for DEFAULT_CLUSTER_SIZE
74
block/export/vduse-blk.c | 128 ++++++++++++++++++--------
55
include: Add a comment to explain the origin of sizes' lookup table
75
block/export/vhost-user-blk-server.c | 52 +++++++++--
56
76
block/io.c | 16 ++--
57
Li Qiang (1):
77
block/io_uring.c | 4 +-
58
block: change some function return type to bool
78
block/iscsi.c | 3 +-
59
79
block/linux-aio.c | 4 +-
60
Max Reitz (5):
80
block/mirror.c | 6 ++
61
option: Make option help nicer to read
81
block/nfs.c | 5 +-
62
chardev: Indent list of chardevs
82
block/nvme.c | 8 +-
63
qdev-monitor: Make device options help nicer
83
block/qapi-sysemu.c | 3 +
64
object: Make option help nicer to read
84
block/qcow2.c | 8 +-
65
fw_cfg: Drop newline in @file description
85
block/raw-format.c | 5 +
66
86
block/ssh.c | 4 +-
67
Peter Maydell (5):
87
block/win32-aio.c | 6 +-
68
block/qcow2: Don't take address of fields in packed structs
88
blockdev.c | 29 ++++--
69
block/qcow: Don't take address of fields in packed structs
89
hw/block/dataplane/virtio-blk.c | 23 +++--
70
block/qcow2-bitmap: Don't take address of fields in packed structs
90
hw/block/dataplane/xen-block.c | 42 ++++++---
71
block/vhdx: Don't take address of fields in packed structs
91
hw/block/virtio-blk.c | 38 +++++++-
72
block/vdi: Don't take address of fields in packed structs
92
hw/block/xen-block.c | 24 ++++-
73
93
hw/i386/kvm/xen_xenstore.c | 2 +-
74
Stefan Weil (1):
94
hw/scsi/scsi-bus.c | 46 ++++++++-
75
qemu-io-cmds: Fix two format strings
95
hw/scsi/scsi-disk.c | 27 +++++-
76
96
hw/scsi/virtio-scsi-dataplane.c | 32 +++++--
77
Thomas Huth (1):
97
hw/scsi/virtio-scsi.c | 127 +++++++++++++++++++------
78
block/vvfat: Fix crash when reporting error about too many files in directory
98
hw/virtio/virtio.c | 9 +-
79
99
hw/xen/xen-bus.c | 11 ++-
80
qapi/block-core.json | 7 +
100
io/channel-command.c | 6 +-
81
block/vhdx.h | 12 +-
101
io/channel-file.c | 3 +-
82
include/block/block.h | 5 +-
102
io/channel-socket.c | 3 +-
83
include/qemu/option.h | 2 +-
103
migration/rdma.c | 16 ++--
84
include/qemu/units.h | 18 +
104
qemu-nbd.c | 4 +
85
include/sysemu/block-backend.h | 6 +-
105
tests/unit/test-aio.c | 27 +-----
86
block.c | 60 ++-
106
tests/unit/test-bdrv-drain.c | 15 +--
87
block/block-backend.c | 8 +-
107
tests/unit/test-block-iothread.c | 4 +-
88
block/bochs.c | 17 +-
108
tests/unit/test-fdmon-epoll.c | 73 ---------------
89
block/cloop.c | 16 +-
109
tests/unit/test-nested-aio-poll.c | 9 +-
90
block/curl.c | 8 +-
110
util/aio-posix.c | 20 +---
91
block/dmg.c | 16 +-
111
util/aio-win32.c | 8 +-
92
block/file-posix.c | 19 +-
112
util/async.c | 3 +-
93
block/gluster.c | 12 +-
113
util/fdmon-epoll.c | 10 --
94
block/iscsi.c | 8 +-
114
util/fdmon-io_uring.c | 8 +-
95
block/nbd-client.c | 10 +-
115
util/fdmon-poll.c | 3 +-
96
block/qcow.c | 18 +-
116
util/main-loop.c | 7 +-
97
block/qcow2-bitmap.c | 24 +-
117
util/qemu-coroutine-io.c | 7 +-
98
block/qcow2.c | 66 +--
118
util/vhost-user-server.c | 33 ++++---
99
block/quorum.c | 45 +-
119
scripts/block-coroutine-wrapper.py | 25 +++--
100
block/rbd.c | 14 +-
120
tests/qemu-iotests/iotests.py | 2 +-
101
block/vdi.c | 68 +--
121
hw/scsi/trace-events | 2 +
102
block/vhdx-endian.c | 118 ++---
122
tests/qemu-iotests/256 | 2 +-
103
block/vhdx-log.c | 4 +-
123
tests/qemu-iotests/tests/iothreads-create | 67 ++++++++++++++
104
block/vhdx.c | 18 +-
124
tests/qemu-iotests/tests/iothreads-create.out | 4 +
105
block/vpc.c | 2 +
125
tests/unit/meson.build | 3 -
106
block/vvfat.c | 15 +-
126
70 files changed, 931 insertions(+), 562 deletions(-)
107
blockdev.c | 3 +-
127
delete mode 100644 tests/unit/test-fdmon-epoll.c
108
chardev/char.c | 2 +-
128
create mode 100755 tests/qemu-iotests/tests/iothreads-create
109
crypto/block-qcow.c | 2 +
129
create mode 100644 tests/qemu-iotests/tests/iothreads-create.out
110
qdev-monitor.c | 13 +-
111
qemu-img.c | 4 +-
112
qemu-io-cmds.c | 4 +-
113
util/qemu-option.c | 32 +-
114
vl.c | 15 +-
115
tests/qemu-iotests/081 | 116 +++++
116
tests/qemu-iotests/081.out | 70 +++
117
tests/qemu-iotests/082.out | 956 ++++++++++++++++++++---------------------
118
tests/qemu-iotests/083 | 2 +-
119
tests/qemu-iotests/232 | 147 +++++++
120
tests/qemu-iotests/232.out | 59 +++
121
tests/qemu-iotests/group | 1 +
122
42 files changed, 1266 insertions(+), 776 deletions(-)
123
create mode 100755 tests/qemu-iotests/232
124
create mode 100644 tests/qemu-iotests/232.out
125
diff view generated by jsdifflib
Deleted patch
1
From: Thomas Huth <thuth@redhat.com>
2
1
3
When using the vvfat driver with a directory that contains too many files,
4
QEMU currently crashes. This can be triggered like this for example:
5
6
mkdir /tmp/vvfattest
7
cd /tmp/vvfattest
8
for ((x=0;x<=513;x++)); do mkdir $x; done
9
qemu-system-x86_64 -drive \
10
file.driver=vvfat,file.dir=.,read-only=on,media=cdrom
11
12
Seems like read_directory() is changing the mapping->path variable. Make
13
sure we use the right pointer instead.
14
15
Signed-off-by: Thomas Huth <thuth@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
---
18
block/vvfat.c | 4 ++--
19
1 file changed, 2 insertions(+), 2 deletions(-)
20
21
diff --git a/block/vvfat.c b/block/vvfat.c
22
index XXXXXXX..XXXXXXX 100644
23
--- a/block/vvfat.c
24
+++ b/block/vvfat.c
25
@@ -XXX,XX +XXX,XX @@ static int init_directories(BDRVVVFATState* s,
26
mapping = array_get(&(s->mapping), i);
27
28
if (mapping->mode & MODE_DIRECTORY) {
29
+ char *path = mapping->path;
30
mapping->begin = cluster;
31
if(read_directory(s, i)) {
32
- error_setg(errp, "Could not read directory %s",
33
- mapping->path);
34
+ error_setg(errp, "Could not read directory %s", path);
35
return -1;
36
}
37
mapping = array_get(&(s->mapping), i);
38
--
39
2.19.1
40
41
diff view generated by jsdifflib
1
If read-only=off, but auto-read-only=on is given, open the file
1
All of the functions that currently take a BlockDriverState, BdrvChild
2
read-write if we have the permissions, but instead of erroring out for
2
or BlockBackend as their first parameter expect the associated
3
read-only files, just degrade to read-only.
3
AioContext to be locked when they are called. In the case of
4
no_co_wrappers, they are called from bottom halves directly in the main
5
loop, so no other caller can be expected to take the lock for them. This
6
can result in assertion failures because a lock that isn't taken is
7
released in nested event loops.
8
9
Looking at the first parameter is already done by co_wrappers to decide
10
where the coroutine should run, so doing the same in no_co_wrappers is
11
only consistent. Take the lock in the generated bottom halves to fix the
12
problem.
4
13
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
15
Message-Id: <20230525124713.401149-2-kwolf@redhat.com>
16
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
18
---
8
block/file-posix.c | 19 ++++++++++++++++---
19
include/block/block-common.h | 3 +++
9
1 file changed, 16 insertions(+), 3 deletions(-)
20
block/block-backend.c | 7 ++++++-
21
scripts/block-coroutine-wrapper.py | 25 +++++++++++++++----------
22
3 files changed, 24 insertions(+), 11 deletions(-)
10
23
11
diff --git a/block/file-posix.c b/block/file-posix.c
24
diff --git a/include/block/block-common.h b/include/block/block-common.h
12
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
13
--- a/block/file-posix.c
26
--- a/include/block/block-common.h
14
+++ b/block/file-posix.c
27
+++ b/include/block/block-common.h
15
@@ -XXX,XX +XXX,XX @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
28
@@ -XXX,XX +XXX,XX @@
16
29
* scheduling a BH in the bottom half that runs the respective non-coroutine
17
s->fd = -1;
30
* function. The coroutine yields after scheduling the BH and is reentered when
18
fd = qemu_open(filename, s->open_flags, 0644);
31
* the wrapped function returns.
19
- if (fd < 0) {
32
+ *
20
- ret = -errno;
33
+ * If the first parameter of the function is a BlockDriverState, BdrvChild or
21
- error_setg_errno(errp, errno, "Could not open '%s'", filename);
34
+ * BlockBackend pointer, the AioContext lock for it is taken in the wrapper.
22
+ ret = fd < 0 ? -errno : 0;
35
*/
23
+
36
#define no_co_wrapper
24
+ if (ret == -EACCES || ret == -EROFS) {
37
25
+ /* Try to degrade to read-only, but if it doesn't work, still use the
38
diff --git a/block/block-backend.c b/block/block-backend.c
26
+ * normal error message. */
39
index XXXXXXX..XXXXXXX 100644
27
+ if (bdrv_apply_auto_read_only(bs, NULL, NULL) == 0) {
40
--- a/block/block-backend.c
28
+ bdrv_flags &= ~BDRV_O_RDWR;
41
+++ b/block/block-backend.c
29
+ raw_parse_flags(bdrv_flags, &s->open_flags);
42
@@ -XXX,XX +XXX,XX @@ void blk_op_unblock_all(BlockBackend *blk, Error *reason)
30
+ assert(!(s->open_flags & O_CREAT));
43
31
+ fd = qemu_open(filename, s->open_flags);
44
AioContext *blk_get_aio_context(BlockBackend *blk)
32
+ ret = fd < 0 ? -errno : 0;
45
{
33
+ }
46
- BlockDriverState *bs = blk_bs(blk);
47
+ BlockDriverState *bs;
48
IO_CODE();
49
50
+ if (!blk) {
51
+ return qemu_get_aio_context();
34
+ }
52
+ }
35
+
53
+
36
+ if (ret < 0) {
54
+ bs = blk_bs(blk);
37
+ error_setg_errno(errp, -ret, "Could not open '%s'", filename);
55
if (bs) {
38
if (ret == -EROFS) {
56
AioContext *ctx = bdrv_get_aio_context(blk_bs(blk));
39
ret = -EACCES;
57
assert(ctx == blk->ctx);
40
}
58
diff --git a/scripts/block-coroutine-wrapper.py b/scripts/block-coroutine-wrapper.py
59
index XXXXXXX..XXXXXXX 100644
60
--- a/scripts/block-coroutine-wrapper.py
61
+++ b/scripts/block-coroutine-wrapper.py
62
@@ -XXX,XX +XXX,XX @@ def __init__(self, wrapper_type: str, return_type: str, name: str,
63
raise ValueError(f"no_co function can't be rdlock: {self.name}")
64
self.target_name = f'{subsystem}_{subname}'
65
66
- t = self.args[0].type
67
- if t == 'BlockDriverState *':
68
- ctx = 'bdrv_get_aio_context(bs)'
69
- elif t == 'BdrvChild *':
70
- ctx = 'bdrv_get_aio_context(child->bs)'
71
- elif t == 'BlockBackend *':
72
- ctx = 'blk_get_aio_context(blk)'
73
- else:
74
- ctx = 'qemu_get_aio_context()'
75
- self.ctx = ctx
76
+ self.ctx = self.gen_ctx()
77
78
self.get_result = 's->ret = '
79
self.ret = 'return s.ret;'
80
@@ -XXX,XX +XXX,XX @@ def __init__(self, wrapper_type: str, return_type: str, name: str,
81
self.co_ret = ''
82
self.return_field = ''
83
84
+ def gen_ctx(self, prefix: str = '') -> str:
85
+ t = self.args[0].type
86
+ if t == 'BlockDriverState *':
87
+ return f'bdrv_get_aio_context({prefix}bs)'
88
+ elif t == 'BdrvChild *':
89
+ return f'bdrv_get_aio_context({prefix}child->bs)'
90
+ elif t == 'BlockBackend *':
91
+ return f'blk_get_aio_context({prefix}blk)'
92
+ else:
93
+ return 'qemu_get_aio_context()'
94
+
95
def gen_list(self, format: str) -> str:
96
return ', '.join(format.format_map(arg.__dict__) for arg in self.args)
97
98
@@ -XXX,XX +XXX,XX @@ def gen_no_co_wrapper(func: FuncDecl) -> str:
99
static void {name}_bh(void *opaque)
100
{{
101
{struct_name} *s = opaque;
102
+ AioContext *ctx = {func.gen_ctx('s->')};
103
104
+ aio_context_acquire(ctx);
105
{func.get_result}{name}({ func.gen_list('s->{name}') });
106
+ aio_context_release(ctx);
107
108
aio_co_wake(s->co);
109
}}
41
--
110
--
42
2.19.1
111
2.40.1
43
44
diff view generated by jsdifflib
1
From: Leonid Bloch <lbloch@janustech.com>
1
These functions specify that the caller must hold the "@filename
2
AioContext lock". This doesn't make sense, file names don't have an
3
AioContext. New BlockDriverStates always start in the main AioContext,
4
so this is what we really need here.
2
5
3
If an expression is used to define DEFAULT_CLUSTER_SIZE, when compiled,
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
it will be embedded as a literal expression in the binary (as the
7
Message-Id: <20230525124713.401149-3-kwolf@redhat.com>
5
default value) because it is stringified to mark the size of the default
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
6
value. Now this is fixed by using a defined number to define this value.
7
8
Signed-off-by: Leonid Bloch <lbloch@janustech.com>
9
Reviewed-by: Stefan Weil <sw@weilnetz.de>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
10
---
12
block/vdi.c | 4 ++--
11
block.c | 10 ++--------
13
1 file changed, 2 insertions(+), 2 deletions(-)
12
1 file changed, 2 insertions(+), 8 deletions(-)
14
13
15
diff --git a/block/vdi.c b/block/vdi.c
14
diff --git a/block.c b/block.c
16
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
17
--- a/block/vdi.c
16
--- a/block.c
18
+++ b/block/vdi.c
17
+++ b/block.c
19
@@ -XXX,XX +XXX,XX @@
18
@@ -XXX,XX +XXX,XX @@ out:
20
#define BLOCK_OPT_STATIC "static"
19
* should be opened. If specified, neither options nor a filename may be given,
21
20
* nor can an existing BDS be reused (that is, *pbs has to be NULL).
22
#define SECTOR_SIZE 512
21
*
23
-#define DEFAULT_CLUSTER_SIZE (1 * MiB)
22
- * The caller must always hold @filename AioContext lock, because this
24
+#define DEFAULT_CLUSTER_SIZE S_1MiB
23
- * function eventually calls bdrv_refresh_total_sectors() which polls
25
24
- * when called from non-coroutine context.
26
#if defined(CONFIG_VDI_DEBUG)
25
+ * The caller must always hold the main AioContext lock.
27
#define VDI_DEBUG 1
26
*/
28
@@ -XXX,XX +XXX,XX @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
27
static BlockDriverState * no_coroutine_fn
29
goto fail;
28
bdrv_open_inherit(const char *filename, const char *reference, QDict *options,
30
} else if (header.block_size != DEFAULT_CLUSTER_SIZE) {
29
@@ -XXX,XX +XXX,XX @@ close_and_fail:
31
error_setg(errp, "unsupported VDI image (block size %" PRIu32
30
return NULL;
32
- " is not %" PRIu64 ")",
31
}
33
+ " is not %" PRIu32 ")",
32
34
header.block_size, DEFAULT_CLUSTER_SIZE);
33
-/*
35
ret = -ENOTSUP;
34
- * The caller must always hold @filename AioContext lock, because this
36
goto fail;
35
- * function eventually calls bdrv_refresh_total_sectors() which polls
36
- * when called from non-coroutine context.
37
- */
38
+/* The caller must always hold the main AioContext lock. */
39
BlockDriverState *bdrv_open(const char *filename, const char *reference,
40
QDict *options, int flags, Error **errp)
41
{
37
--
42
--
38
2.19.1
43
2.40.1
39
40
diff view generated by jsdifflib
1
If a management application builds the block graph node by node, the
1
The function documentation already says that all callers must hold the
2
protocol layer doesn't inherit its read-only option from the format
2
main AioContext lock, but not all of them do. This can cause assertion
3
layer any more, so it must be set explicitly.
3
failures when functions called by bdrv_open() try to drop the lock. Fix
4
4
a few more callers to take the lock before calling bdrv_open().
5
Backing files should work on read-only storage, but at the same time, a
6
block job like commit should be able to reopen them read-write if they
7
are on read-write storage. However, without option inheritance, reopen
8
only changes the read-only option for the root node (typically the
9
format layer), but not the protocol layer, so reopening fails (the
10
format layer wants to get write permissions, but the protocol layer is
11
still read-only).
12
13
A simple workaround for the problem in the management tool would be to
14
open the protocol layer always read-write and to make only the format
15
layer read-only for backing files. However, sometimes the file is
16
actually stored on read-only storage and we don't know whether the image
17
can be opened read-write (for example, for NBD it depends on the server
18
we're trying to connect to). This adds an option that makes QEMU try to
19
open the image read-write, but allows it to degrade to a read-only mode
20
without returning an error.
21
22
The documentation for this option is consciously phrased in a way that
23
allows QEMU to switch to a better model eventually: Instead of trying
24
when the image is first opened, making the read-only flag dynamic and
25
changing it automatically whenever the first BLK_PERM_WRITE user is
26
attached or the last one is detached would be much more useful
27
behaviour.
28
29
Unfortunately, this more useful behaviour is also a lot harder to
30
implement, and libvirt needs a solution now before it can switch to
31
-blockdev, so let's start with this easier approach for now.
32
33
Instead of adding a new auto-read-only option, turning the existing
34
read-only into an enum (with a bool alternate for compatibility) was
35
considered, but it complicated the implementation to the point that it
36
didn't seem to be worth it.
37
5
38
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
39
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Message-Id: <20230525124713.401149-4-kwolf@redhat.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
40
---
10
---
41
qapi/block-core.json | 7 +++++++
11
block.c | 3 +++
42
include/block/block.h | 2 ++
12
block/block-backend.c | 2 ++
43
block.c | 17 +++++++++++++++++
13
block/qapi-sysemu.c | 3 +++
44
block/vvfat.c | 1 +
14
blockdev.c | 29 +++++++++++++++++++++++------
45
blockdev.c | 2 +-
15
qemu-nbd.c | 4 ++++
46
5 files changed, 28 insertions(+), 1 deletion(-)
16
tests/unit/test-block-iothread.c | 3 +++
17
6 files changed, 38 insertions(+), 6 deletions(-)
47
18
48
diff --git a/qapi/block-core.json b/qapi/block-core.json
49
index XXXXXXX..XXXXXXX 100644
50
--- a/qapi/block-core.json
51
+++ b/qapi/block-core.json
52
@@ -XXX,XX +XXX,XX @@
53
# either generally or in certain configurations. In this case,
54
# the default value does not work and the option must be
55
# specified explicitly.
56
+# @auto-read-only: if true and @read-only is false, QEMU may automatically
57
+# decide not to open the image read-write as requested, but
58
+# fall back to read-only instead (and switch between the modes
59
+# later), e.g. depending on whether the image file is writable
60
+# or whether a writing user is attached to the node
61
+# (default: false, since 3.1)
62
# @detect-zeroes: detect and optimize zero writes (Since 2.1)
63
# (default: off)
64
# @force-share: force share all permission on added nodes.
65
@@ -XXX,XX +XXX,XX @@
66
'*discard': 'BlockdevDiscardOptions',
67
'*cache': 'BlockdevCacheOptions',
68
'*read-only': 'bool',
69
+ '*auto-read-only': 'bool',
70
'*force-share': 'bool',
71
'*detect-zeroes': 'BlockdevDetectZeroesOptions' },
72
'discriminator': 'driver',
73
diff --git a/include/block/block.h b/include/block/block.h
74
index XXXXXXX..XXXXXXX 100644
75
--- a/include/block/block.h
76
+++ b/include/block/block.h
77
@@ -XXX,XX +XXX,XX @@ typedef struct HDGeometry {
78
select an appropriate protocol driver,
79
ignoring the format layer */
80
#define BDRV_O_NO_IO 0x10000 /* don't initialize for I/O */
81
+#define BDRV_O_AUTO_RDONLY 0x20000 /* degrade to read-only if opening read-write fails */
82
83
#define BDRV_O_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_NO_FLUSH)
84
85
@@ -XXX,XX +XXX,XX @@ typedef struct HDGeometry {
86
#define BDRV_OPT_CACHE_DIRECT "cache.direct"
87
#define BDRV_OPT_CACHE_NO_FLUSH "cache.no-flush"
88
#define BDRV_OPT_READ_ONLY "read-only"
89
+#define BDRV_OPT_AUTO_READ_ONLY "auto-read-only"
90
#define BDRV_OPT_DISCARD "discard"
91
#define BDRV_OPT_FORCE_SHARE "force-share"
92
93
diff --git a/block.c b/block.c
19
diff --git a/block.c b/block.c
94
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
95
--- a/block.c
21
--- a/block.c
96
+++ b/block.c
22
+++ b/block.c
97
@@ -XXX,XX +XXX,XX @@ static void bdrv_inherited_options(int *child_flags, QDict *child_options,
23
@@ -XXX,XX +XXX,XX @@ void bdrv_img_create(const char *filename, const char *fmt,
98
24
return;
99
/* Inherit the read-only option from the parent if it's not set */
100
qdict_copy_default(child_options, parent_options, BDRV_OPT_READ_ONLY);
101
+ qdict_copy_default(child_options, parent_options, BDRV_OPT_AUTO_READ_ONLY);
102
103
/* Our block drivers take care to send flushes and respect unmap policy,
104
* so we can default to enable both on lower layers regardless of the
105
@@ -XXX,XX +XXX,XX @@ static void bdrv_backing_options(int *child_flags, QDict *child_options,
106
107
/* backing files always opened read-only */
108
qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "on");
109
+ qdict_set_default_str(child_options, BDRV_OPT_AUTO_READ_ONLY, "off");
110
flags &= ~BDRV_O_COPY_ON_READ;
111
112
/* snapshot=on is handled on the top layer */
113
@@ -XXX,XX +XXX,XX @@ static void update_flags_from_options(int *flags, QemuOpts *opts)
114
*flags |= BDRV_O_RDWR;
115
}
25
}
116
26
117
+ assert(qemu_opt_find(opts, BDRV_OPT_AUTO_READ_ONLY));
27
+ aio_context_acquire(qemu_get_aio_context());
118
+ if (qemu_opt_get_bool_del(opts, BDRV_OPT_AUTO_READ_ONLY, false)) {
28
+
119
+ *flags |= BDRV_O_AUTO_RDONLY;
29
/* Create parameter list */
120
+ }
30
create_opts = qemu_opts_append(create_opts, drv->create_opts);
31
create_opts = qemu_opts_append(create_opts, proto_drv->create_opts);
32
@@ -XXX,XX +XXX,XX @@ out:
33
qemu_opts_del(opts);
34
qemu_opts_free(create_opts);
35
error_propagate(errp, local_err);
36
+ aio_context_release(qemu_get_aio_context());
121
}
37
}
122
38
123
static void update_options_from_flags(QDict *options, int flags)
39
AioContext *bdrv_get_aio_context(BlockDriverState *bs)
124
@@ -XXX,XX +XXX,XX @@ static void update_options_from_flags(QDict *options, int flags)
40
diff --git a/block/block-backend.c b/block/block-backend.c
125
if (!qdict_haskey(options, BDRV_OPT_READ_ONLY)) {
41
index XXXXXXX..XXXXXXX 100644
126
qdict_put_bool(options, BDRV_OPT_READ_ONLY, !(flags & BDRV_O_RDWR));
42
--- a/block/block-backend.c
43
+++ b/block/block-backend.c
44
@@ -XXX,XX +XXX,XX @@ BlockBackend *blk_new_open(const char *filename, const char *reference,
127
}
45
}
128
+ if (!qdict_haskey(options, BDRV_OPT_AUTO_READ_ONLY)) {
46
129
+ qdict_put_bool(options, BDRV_OPT_AUTO_READ_ONLY,
47
blk = blk_new(qemu_get_aio_context(), perm, shared);
130
+ flags & BDRV_O_AUTO_RDONLY);
48
+ aio_context_acquire(qemu_get_aio_context());
131
+ }
49
bs = bdrv_open(filename, reference, options, flags, errp);
132
}
50
+ aio_context_release(qemu_get_aio_context());
133
51
if (!bs) {
134
static void bdrv_assign_node_name(BlockDriverState *bs,
52
blk_unref(blk);
135
@@ -XXX,XX +XXX,XX @@ QemuOptsList bdrv_runtime_opts = {
53
return NULL;
136
.type = QEMU_OPT_BOOL,
54
diff --git a/block/qapi-sysemu.c b/block/qapi-sysemu.c
137
.help = "Node is opened in read-only mode",
55
index XXXXXXX..XXXXXXX 100644
138
},
56
--- a/block/qapi-sysemu.c
139
+ {
57
+++ b/block/qapi-sysemu.c
140
+ .name = BDRV_OPT_AUTO_READ_ONLY,
58
@@ -XXX,XX +XXX,XX @@ void qmp_blockdev_change_medium(const char *device,
141
+ .type = QEMU_OPT_BOOL,
59
qdict_put_str(options, "driver", format);
142
+ .help = "Node can become read-only if opening read-write fails",
60
}
143
+ },
61
144
{
62
+ aio_context_acquire(qemu_get_aio_context());
145
.name = "detect-zeroes",
63
medium_bs = bdrv_open(filename, NULL, options, bdrv_flags, errp);
146
.type = QEMU_OPT_STRING,
64
+ aio_context_release(qemu_get_aio_context());
147
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp)
148
qdict_set_default_str(qdict, BDRV_OPT_CACHE_DIRECT, "off");
149
qdict_set_default_str(qdict, BDRV_OPT_CACHE_NO_FLUSH, "off");
150
qdict_set_default_str(qdict, BDRV_OPT_READ_ONLY, "off");
151
+ qdict_set_default_str(qdict, BDRV_OPT_AUTO_READ_ONLY, "off");
152
+
65
+
66
if (!medium_bs) {
67
goto fail;
153
}
68
}
154
155
bs = bdrv_open_inherit(NULL, reference, qdict, 0, NULL, NULL, errp);
156
diff --git a/block/vvfat.c b/block/vvfat.c
157
index XXXXXXX..XXXXXXX 100644
158
--- a/block/vvfat.c
159
+++ b/block/vvfat.c
160
@@ -XXX,XX +XXX,XX @@ static void vvfat_qcow_options(int *child_flags, QDict *child_options,
161
int parent_flags, QDict *parent_options)
162
{
163
qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "off");
164
+ qdict_set_default_str(child_options, BDRV_OPT_AUTO_READ_ONLY, "off");
165
qdict_set_default_str(child_options, BDRV_OPT_CACHE_NO_FLUSH, "on");
166
}
167
168
diff --git a/blockdev.c b/blockdev.c
69
diff --git a/blockdev.c b/blockdev.c
169
index XXXXXXX..XXXXXXX 100644
70
index XXXXXXX..XXXXXXX 100644
170
--- a/blockdev.c
71
--- a/blockdev.c
171
+++ b/blockdev.c
72
+++ b/blockdev.c
172
@@ -XXX,XX +XXX,XX @@ void qmp_blockdev_change_medium(bool has_device, const char *device,
73
@@ -XXX,XX +XXX,XX @@ err_no_opts:
173
74
/* Takes the ownership of bs_opts */
174
bdrv_flags = blk_get_open_flags_from_root_state(blk);
75
BlockDriverState *bds_tree_init(QDict *bs_opts, Error **errp)
175
bdrv_flags &= ~(BDRV_O_TEMPORARY | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING |
76
{
176
- BDRV_O_PROTOCOL);
77
+ BlockDriverState *bs;
177
+ BDRV_O_PROTOCOL | BDRV_O_AUTO_RDONLY);
78
int bdrv_flags = 0;
178
79
179
if (!has_read_only) {
80
GLOBAL_STATE_CODE();
180
read_only = BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN;
81
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bds_tree_init(QDict *bs_opts, Error **errp)
82
bdrv_flags |= BDRV_O_INACTIVE;
83
}
84
85
- return bdrv_open(NULL, NULL, bs_opts, bdrv_flags, errp);
86
+ aio_context_acquire(qemu_get_aio_context());
87
+ bs = bdrv_open(NULL, NULL, bs_opts, bdrv_flags, errp);
88
+ aio_context_release(qemu_get_aio_context());
89
+
90
+ return bs;
91
}
92
93
void blockdev_close_all_bdrv_states(void)
94
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_action(TransactionAction *action,
95
}
96
qdict_put_str(options, "driver", format);
97
}
98
+ aio_context_release(aio_context);
99
100
+ aio_context_acquire(qemu_get_aio_context());
101
state->new_bs = bdrv_open(new_image_file, snapshot_ref, options, flags,
102
errp);
103
+ aio_context_release(qemu_get_aio_context());
104
+
105
/* We will manually add the backing_hd field to the bs later */
106
if (!state->new_bs) {
107
- goto out;
108
+ return;
109
}
110
111
+ aio_context_acquire(aio_context);
112
+
113
/*
114
* Allow attaching a backing file to an overlay that's already in use only
115
* if the parents don't assume that they are already seeing a valid image.
116
@@ -XXX,XX +XXX,XX @@ static void drive_backup_action(DriveBackup *backup,
117
if (format) {
118
qdict_put_str(options, "driver", format);
119
}
120
+ aio_context_release(aio_context);
121
122
+ aio_context_acquire(qemu_get_aio_context());
123
target_bs = bdrv_open(backup->target, NULL, options, flags, errp);
124
+ aio_context_release(qemu_get_aio_context());
125
+
126
if (!target_bs) {
127
- goto out;
128
+ return;
129
}
130
131
/* Honor bdrv_try_change_aio_context() context acquisition requirements. */
132
old_context = bdrv_get_aio_context(target_bs);
133
- aio_context_release(aio_context);
134
aio_context_acquire(old_context);
135
136
ret = bdrv_try_change_aio_context(target_bs, aio_context, NULL, errp);
137
@@ -XXX,XX +XXX,XX @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
138
if (format) {
139
qdict_put_str(options, "driver", format);
140
}
141
+ aio_context_release(aio_context);
142
143
/* Mirroring takes care of copy-on-write using the source's backing
144
* file.
145
*/
146
+ aio_context_acquire(qemu_get_aio_context());
147
target_bs = bdrv_open(arg->target, NULL, options, flags, errp);
148
+ aio_context_release(qemu_get_aio_context());
149
+
150
if (!target_bs) {
151
- goto out;
152
+ return;
153
}
154
155
zero_target = (arg->sync == MIRROR_SYNC_MODE_FULL &&
156
@@ -XXX,XX +XXX,XX @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
157
158
/* Honor bdrv_try_change_aio_context() context acquisition requirements. */
159
old_context = bdrv_get_aio_context(target_bs);
160
- aio_context_release(aio_context);
161
aio_context_acquire(old_context);
162
163
ret = bdrv_try_change_aio_context(target_bs, aio_context, NULL, errp);
164
diff --git a/qemu-nbd.c b/qemu-nbd.c
165
index XXXXXXX..XXXXXXX 100644
166
--- a/qemu-nbd.c
167
+++ b/qemu-nbd.c
168
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
169
qdict_put_str(raw_opts, "driver", "raw");
170
qdict_put_str(raw_opts, "file", bs->node_name);
171
qdict_put_int(raw_opts, "offset", dev_offset);
172
+
173
+ aio_context_acquire(qemu_get_aio_context());
174
bs = bdrv_open(NULL, NULL, raw_opts, flags, &error_fatal);
175
+ aio_context_release(qemu_get_aio_context());
176
+
177
blk_remove_bs(blk);
178
blk_insert_bs(blk, bs, &error_fatal);
179
bdrv_unref(bs);
180
diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c
181
index XXXXXXX..XXXXXXX 100644
182
--- a/tests/unit/test-block-iothread.c
183
+++ b/tests/unit/test-block-iothread.c
184
@@ -XXX,XX +XXX,XX @@ static void test_attach_second_node(void)
185
qdict_put_str(options, "driver", "raw");
186
qdict_put_str(options, "file", "base");
187
188
+ /* FIXME raw_open() should take ctx's lock internally */
189
aio_context_acquire(ctx);
190
+ aio_context_acquire(main_ctx);
191
filter = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
192
+ aio_context_release(main_ctx);
193
aio_context_release(ctx);
194
195
g_assert(blk_get_aio_context(blk) == ctx);
181
--
196
--
182
2.19.1
197
2.40.1
183
184
diff view generated by jsdifflib
1
If read-only=off, but auto-read-only=on is given, open the volume
1
This fixes blk_new_open() to not assume that bs is in the main context.
2
read-write if we have the permissions, but instead of erroring out for
2
3
read-only volumes, just degrade to read-only.
3
In particular, the BlockBackend must be created with the right
4
AioContext because it will refuse to move to a different context
5
afterwards. (blk->allow_aio_context_change is false.)
6
7
Use this opportunity to use blk_insert_bs() instead of duplicating the
8
bdrv_root_attach_child() call. This is consistent with what
9
blk_new_with_bs() does. Add comments to document the locking rules.
4
10
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Message-Id: <20230525124713.401149-5-kwolf@redhat.com>
13
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
15
---
8
block/iscsi.c | 8 +++++---
16
block/block-backend.c | 27 +++++++++++++++++++++------
9
1 file changed, 5 insertions(+), 3 deletions(-)
17
1 file changed, 21 insertions(+), 6 deletions(-)
10
18
11
diff --git a/block/iscsi.c b/block/iscsi.c
19
diff --git a/block/block-backend.c b/block/block-backend.c
12
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
13
--- a/block/iscsi.c
21
--- a/block/block-backend.c
14
+++ b/block/iscsi.c
22
+++ b/block/block-backend.c
15
@@ -XXX,XX +XXX,XX @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
23
@@ -XXX,XX +XXX,XX @@ BlockBackend *blk_new(AioContext *ctx, uint64_t perm, uint64_t shared_perm)
16
/* Check the write protect flag of the LUN if we want to write */
24
* Both sets of permissions can be changed later using blk_set_perm().
17
if (iscsilun->type == TYPE_DISK && (flags & BDRV_O_RDWR) &&
25
*
18
iscsilun->write_protected) {
26
* Return the new BlockBackend on success, null on failure.
19
- error_setg(errp, "Cannot open a write protected LUN as read-write");
27
+ *
20
- ret = -EACCES;
28
+ * Callers must hold the AioContext lock of @bs.
21
- goto out;
29
*/
22
+ ret = bdrv_apply_auto_read_only(bs, "LUN is write protected", errp);
30
BlockBackend *blk_new_with_bs(BlockDriverState *bs, uint64_t perm,
23
+ if (ret < 0) {
31
uint64_t shared_perm, Error **errp)
24
+ goto out;
32
@@ -XXX,XX +XXX,XX @@ BlockBackend *blk_new_with_bs(BlockDriverState *bs, uint64_t perm,
25
+ }
33
26
+ flags &= ~BDRV_O_RDWR;
34
/*
35
* Creates a new BlockBackend, opens a new BlockDriverState, and connects both.
36
- * The new BlockBackend is in the main AioContext.
37
+ * By default, the new BlockBackend is in the main AioContext, but if the
38
+ * parameters connect it with any existing node in a different AioContext, it
39
+ * may end up there instead.
40
*
41
* Just as with bdrv_open(), after having called this function the reference to
42
* @options belongs to the block layer (even on failure).
43
*
44
+ * Called without holding an AioContext lock.
45
+ *
46
* TODO: Remove @filename and @flags; it should be possible to specify a whole
47
* BDS tree just by specifying the @options QDict (or @reference,
48
* alternatively). At the time of adding this function, this is not possible,
49
@@ -XXX,XX +XXX,XX @@ BlockBackend *blk_new_open(const char *filename, const char *reference,
50
{
51
BlockBackend *blk;
52
BlockDriverState *bs;
53
+ AioContext *ctx;
54
uint64_t perm = 0;
55
uint64_t shared = BLK_PERM_ALL;
56
57
@@ -XXX,XX +XXX,XX @@ BlockBackend *blk_new_open(const char *filename, const char *reference,
58
shared = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED;
27
}
59
}
28
60
29
iscsi_readcapacity_sync(iscsilun, &local_err);
61
- blk = blk_new(qemu_get_aio_context(), perm, shared);
62
aio_context_acquire(qemu_get_aio_context());
63
bs = bdrv_open(filename, reference, options, flags, errp);
64
aio_context_release(qemu_get_aio_context());
65
if (!bs) {
66
- blk_unref(blk);
67
return NULL;
68
}
69
70
- blk->root = bdrv_root_attach_child(bs, "root", &child_root,
71
- BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
72
- perm, shared, blk, errp);
73
+ /* bdrv_open() could have moved bs to a different AioContext */
74
+ ctx = bdrv_get_aio_context(bs);
75
+ blk = blk_new(bdrv_get_aio_context(bs), perm, shared);
76
+ blk->perm = perm;
77
+ blk->shared_perm = shared;
78
+
79
+ aio_context_acquire(ctx);
80
+ blk_insert_bs(blk, bs, errp);
81
+ bdrv_unref(bs);
82
+ aio_context_release(ctx);
83
+
84
if (!blk->root) {
85
blk_unref(blk);
86
return NULL;
87
@@ -XXX,XX +XXX,XX @@ void blk_remove_bs(BlockBackend *blk)
88
89
/*
90
* Associates a new BlockDriverState with @blk.
91
+ *
92
+ * Callers must hold the AioContext lock of @bs.
93
*/
94
int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp)
95
{
30
--
96
--
31
2.19.1
97
2.40.1
32
33
diff view generated by jsdifflib
1
Some block drivers have traditionally changed their node to read-only
1
bdrv_open_backing_file() calls bdrv_open_inherit(), so all callers must
2
mode without asking the user. This behaviour has been marked deprecated
2
hold the main AioContext lock.
3
since 2.11, expecting users to provide an explicit read-only=on option.
4
5
Now that we have auto-read-only=on, enable these drivers to make use of
6
the option.
7
8
This is the only use of bdrv_set_read_only(), so we can make it a bit
9
more specific and turn it into a bdrv_apply_auto_read_only() that is
10
more convenient for drivers to use.
11
3
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Reviewed-by: Eric Blake <eblake@redhat.com>
5
Message-Id: <20230525124713.401149-6-kwolf@redhat.com>
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
8
---
15
include/block/block.h | 3 ++-
9
block.c | 2 ++
16
block.c | 42 +++++++++++++++++++++++++++---------------
10
block/mirror.c | 6 ++++++
17
block/bochs.c | 17 ++++++-----------
11
2 files changed, 8 insertions(+)
18
block/cloop.c | 16 +++++-----------
19
block/dmg.c | 16 +++++-----------
20
block/rbd.c | 15 ++++-----------
21
block/vvfat.c | 10 ++--------
22
7 files changed, 51 insertions(+), 68 deletions(-)
23
12
24
diff --git a/include/block/block.h b/include/block/block.h
25
index XXXXXXX..XXXXXXX 100644
26
--- a/include/block/block.h
27
+++ b/include/block/block.h
28
@@ -XXX,XX +XXX,XX @@ int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
29
bool bdrv_is_read_only(BlockDriverState *bs);
30
int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only,
31
bool ignore_allow_rdw, Error **errp);
32
-int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp);
33
+int bdrv_apply_auto_read_only(BlockDriverState *bs, const char *errmsg,
34
+ Error **errp);
35
bool bdrv_is_writable(BlockDriverState *bs);
36
bool bdrv_is_sg(BlockDriverState *bs);
37
bool bdrv_is_inserted(BlockDriverState *bs);
38
diff --git a/block.c b/block.c
13
diff --git a/block.c b/block.c
39
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
40
--- a/block.c
15
--- a/block.c
41
+++ b/block.c
16
+++ b/block.c
42
@@ -XXX,XX +XXX,XX @@ int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only,
17
@@ -XXX,XX +XXX,XX @@ int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
43
return 0;
18
* itself, all options starting with "${bdref_key}." are considered part of the
19
* BlockdevRef.
20
*
21
+ * The caller must hold the main AioContext lock.
22
+ *
23
* TODO Can this be unified with bdrv_open_image()?
24
*/
25
int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
26
diff --git a/block/mirror.c b/block/mirror.c
27
index XXXXXXX..XXXXXXX 100644
28
--- a/block/mirror.c
29
+++ b/block/mirror.c
30
@@ -XXX,XX +XXX,XX @@ static int mirror_exit_common(Job *job)
31
bool abort = job->ret < 0;
32
int ret = 0;
33
34
+ GLOBAL_STATE_CODE();
35
+
36
if (s->prepared) {
37
return 0;
38
}
39
s->prepared = true;
40
41
+ aio_context_acquire(qemu_get_aio_context());
42
+
43
mirror_top_bs = s->mirror_top_bs;
44
bs_opaque = mirror_top_bs->opaque;
45
src = mirror_top_bs->backing->bs;
46
@@ -XXX,XX +XXX,XX @@ static int mirror_exit_common(Job *job)
47
bdrv_unref(mirror_top_bs);
48
bdrv_unref(src);
49
50
+ aio_context_release(qemu_get_aio_context());
51
+
52
return ret;
44
}
53
}
45
54
46
-/* TODO Remove (deprecated since 2.11)
47
- * Block drivers are not supposed to automatically change bs->read_only.
48
- * Instead, they should just check whether they can provide what the user
49
- * explicitly requested and error out if read-write is requested, but they can
50
- * only provide read-only access. */
51
-int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
52
+/*
53
+ * Called by a driver that can only provide a read-only image.
54
+ *
55
+ * Returns 0 if the node is already read-only or it could switch the node to
56
+ * read-only because BDRV_O_AUTO_RDONLY is set.
57
+ *
58
+ * Returns -EACCES if the node is read-write and BDRV_O_AUTO_RDONLY is not set
59
+ * or bdrv_can_set_read_only() forbids making the node read-only. If @errmsg
60
+ * is not NULL, it is used as the error message for the Error object.
61
+ */
62
+int bdrv_apply_auto_read_only(BlockDriverState *bs, const char *errmsg,
63
+ Error **errp)
64
{
65
int ret = 0;
66
67
- ret = bdrv_can_set_read_only(bs, read_only, false, errp);
68
- if (ret < 0) {
69
- return ret;
70
+ if (!(bs->open_flags & BDRV_O_RDWR)) {
71
+ return 0;
72
+ }
73
+ if (!(bs->open_flags & BDRV_O_AUTO_RDONLY)) {
74
+ goto fail;
75
}
76
77
- bs->read_only = read_only;
78
-
79
- if (read_only) {
80
- bs->open_flags &= ~BDRV_O_RDWR;
81
- } else {
82
- bs->open_flags |= BDRV_O_RDWR;
83
+ ret = bdrv_can_set_read_only(bs, true, false, NULL);
84
+ if (ret < 0) {
85
+ goto fail;
86
}
87
88
+ bs->read_only = true;
89
+ bs->open_flags &= ~BDRV_O_RDWR;
90
+
91
return 0;
92
+
93
+fail:
94
+ error_setg(errp, "%s", errmsg ?: "Image is read-only");
95
+ return -EACCES;
96
}
97
98
void bdrv_get_full_backing_filename_from_filename(const char *backed,
99
diff --git a/block/bochs.c b/block/bochs.c
100
index XXXXXXX..XXXXXXX 100644
101
--- a/block/bochs.c
102
+++ b/block/bochs.c
103
@@ -XXX,XX +XXX,XX @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
104
struct bochs_header bochs;
105
int ret;
106
107
+ /* No write support yet */
108
+ ret = bdrv_apply_auto_read_only(bs, NULL, errp);
109
+ if (ret < 0) {
110
+ return ret;
111
+ }
112
+
113
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
114
false, errp);
115
if (!bs->file) {
116
return -EINVAL;
117
}
118
119
- if (!bdrv_is_read_only(bs)) {
120
- error_report("Opening bochs images without an explicit read-only=on "
121
- "option is deprecated. Future versions will refuse to "
122
- "open the image instead of automatically marking the "
123
- "image read-only.");
124
- ret = bdrv_set_read_only(bs, true, errp); /* no write support yet */
125
- if (ret < 0) {
126
- return ret;
127
- }
128
- }
129
-
130
ret = bdrv_pread(bs->file, 0, &bochs, sizeof(bochs));
131
if (ret < 0) {
132
return ret;
133
diff --git a/block/cloop.c b/block/cloop.c
134
index XXXXXXX..XXXXXXX 100644
135
--- a/block/cloop.c
136
+++ b/block/cloop.c
137
@@ -XXX,XX +XXX,XX @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
138
uint32_t offsets_size, max_compressed_block_size = 1, i;
139
int ret;
140
141
+ ret = bdrv_apply_auto_read_only(bs, NULL, errp);
142
+ if (ret < 0) {
143
+ return ret;
144
+ }
145
+
146
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
147
false, errp);
148
if (!bs->file) {
149
return -EINVAL;
150
}
151
152
- if (!bdrv_is_read_only(bs)) {
153
- error_report("Opening cloop images without an explicit read-only=on "
154
- "option is deprecated. Future versions will refuse to "
155
- "open the image instead of automatically marking the "
156
- "image read-only.");
157
- ret = bdrv_set_read_only(bs, true, errp);
158
- if (ret < 0) {
159
- return ret;
160
- }
161
- }
162
-
163
/* read header */
164
ret = bdrv_pread(bs->file, 128, &s->block_size, 4);
165
if (ret < 0) {
166
diff --git a/block/dmg.c b/block/dmg.c
167
index XXXXXXX..XXXXXXX 100644
168
--- a/block/dmg.c
169
+++ b/block/dmg.c
170
@@ -XXX,XX +XXX,XX @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
171
int64_t offset;
172
int ret;
173
174
+ ret = bdrv_apply_auto_read_only(bs, NULL, errp);
175
+ if (ret < 0) {
176
+ return ret;
177
+ }
178
+
179
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
180
false, errp);
181
if (!bs->file) {
182
return -EINVAL;
183
}
184
185
- if (!bdrv_is_read_only(bs)) {
186
- error_report("Opening dmg images without an explicit read-only=on "
187
- "option is deprecated. Future versions will refuse to "
188
- "open the image instead of automatically marking the "
189
- "image read-only.");
190
- ret = bdrv_set_read_only(bs, true, errp);
191
- if (ret < 0) {
192
- return ret;
193
- }
194
- }
195
-
196
block_module_load_one("dmg-bz2");
197
198
s->n_chunks = 0;
199
diff --git a/block/rbd.c b/block/rbd.c
200
index XXXXXXX..XXXXXXX 100644
201
--- a/block/rbd.c
202
+++ b/block/rbd.c
203
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
204
/* If we are using an rbd snapshot, we must be r/o, otherwise
205
* leave as-is */
206
if (s->snap != NULL) {
207
- if (!bdrv_is_read_only(bs)) {
208
- error_report("Opening rbd snapshots without an explicit "
209
- "read-only=on option is deprecated. Future versions "
210
- "will refuse to open the image instead of "
211
- "automatically marking the image read-only.");
212
- r = bdrv_set_read_only(bs, true, &local_err);
213
- if (r < 0) {
214
- rbd_close(s->image);
215
- error_propagate(errp, local_err);
216
- goto failed_open;
217
- }
218
+ r = bdrv_apply_auto_read_only(bs, "rbd snapshots are read-only", errp);
219
+ if (r < 0) {
220
+ rbd_close(s->image);
221
+ goto failed_open;
222
}
223
}
224
225
diff --git a/block/vvfat.c b/block/vvfat.c
226
index XXXXXXX..XXXXXXX 100644
227
--- a/block/vvfat.c
228
+++ b/block/vvfat.c
229
@@ -XXX,XX +XXX,XX @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
230
"Unable to set VVFAT to 'rw' when drive is read-only");
231
goto fail;
232
}
233
- } else if (!bdrv_is_read_only(bs)) {
234
- error_report("Opening non-rw vvfat images without an explicit "
235
- "read-only=on option is deprecated. Future versions "
236
- "will refuse to open the image instead of "
237
- "automatically marking the image read-only.");
238
- /* read only is the default for safety */
239
- ret = bdrv_set_read_only(bs, true, &local_err);
240
+ } else {
241
+ ret = bdrv_apply_auto_read_only(bs, NULL, errp);
242
if (ret < 0) {
243
- error_propagate(errp, local_err);
244
goto fail;
245
}
246
}
247
--
55
--
248
2.19.1
56
2.40.1
249
250
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
qcow2_open() doesn't work correctly when opening the 'file' child moves
2
bs to an iothread, for several reasons:
2
3
3
This doesn't have any practical effect at the moment because the
4
- It uses BDRV_POLL_WHILE() to wait for the qcow2_open_entry()
4
values of BDRV_SECTOR_SIZE, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE and
5
coroutine, which involves dropping the AioContext lock for bs when it
5
QCRYPTO_BLOCK_QCOW_SECTOR_SIZE are all the same (512 bytes), but
6
is not in the main context - but we don't hold it, so this crashes.
6
future encryption methods could have different requirements.
7
7
8
Signed-off-by: Alberto Garcia <berto@igalia.com>
8
- It runs the qcow2_open_entry() coroutine in the current thread instead
9
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
9
of the new AioContext of bs.
10
11
- qcow2_open_entry() doesn't notify the main loop when it's done.
12
13
This patches fixes these issues around delegating work to a coroutine.
14
Temporarily dropping the main AioContext lock is not necessary because
15
we know we run in the main thread.
16
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
Message-Id: <20230525124713.401149-7-kwolf@redhat.com>
19
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
20
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
21
---
12
block/qcow2.c | 2 +-
22
block.c | 6 ++++++
13
1 file changed, 1 insertion(+), 1 deletion(-)
23
block/qcow2.c | 8 ++++++--
24
2 files changed, 12 insertions(+), 2 deletions(-)
14
25
26
diff --git a/block.c b/block.c
27
index XXXXXXX..XXXXXXX 100644
28
--- a/block.c
29
+++ b/block.c
30
@@ -XXX,XX +XXX,XX @@ done:
31
* BlockdevRef.
32
*
33
* The BlockdevRef will be removed from the options QDict.
34
+ *
35
+ * @parent can move to a different AioContext in this function. Callers must
36
+ * make sure that their AioContext locking is still correct after this.
37
*/
38
BdrvChild *bdrv_open_child(const char *filename,
39
QDict *options, const char *bdref_key,
40
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_open_child(const char *filename,
41
42
/*
43
* Wrapper on bdrv_open_child() for most popular case: open primary child of bs.
44
+ *
45
+ * @parent can move to a different AioContext in this function. Callers must
46
+ * make sure that their AioContext locking is still correct after this.
47
*/
48
int bdrv_open_file_child(const char *filename,
49
QDict *options, const char *bdref_key,
15
diff --git a/block/qcow2.c b/block/qcow2.c
50
diff --git a/block/qcow2.c b/block/qcow2.c
16
index XXXXXXX..XXXXXXX 100644
51
index XXXXXXX..XXXXXXX 100644
17
--- a/block/qcow2.c
52
--- a/block/qcow2.c
18
+++ b/block/qcow2.c
53
+++ b/block/qcow2.c
19
@@ -XXX,XX +XXX,XX @@ static void qcow2_refresh_limits(BlockDriverState *bs, Error **errp)
54
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn qcow2_open_entry(void *opaque)
20
55
qoc->ret = qcow2_do_open(qoc->bs, qoc->options, qoc->flags, true,
21
if (bs->encrypted) {
56
qoc->errp);
22
/* Encryption works on a sector granularity */
57
qemu_co_mutex_unlock(&s->lock);
23
- bs->bl.request_alignment = BDRV_SECTOR_SIZE;
58
+
24
+ bs->bl.request_alignment = qcrypto_block_get_sector_size(s->crypto);
59
+ aio_wait_kick();
25
}
60
}
26
bs->bl.pwrite_zeroes_alignment = s->cluster_size;
61
27
bs->bl.pdiscard_alignment = s->cluster_size;
62
static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
63
@@ -XXX,XX +XXX,XX @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
64
65
assert(!qemu_in_coroutine());
66
assert(qemu_get_current_aio_context() == qemu_get_aio_context());
67
- qemu_coroutine_enter(qemu_coroutine_create(qcow2_open_entry, &qoc));
68
- BDRV_POLL_WHILE(bs, qoc.ret == -EINPROGRESS);
69
+
70
+ aio_co_enter(bdrv_get_aio_context(bs),
71
+ qemu_coroutine_create(qcow2_open_entry, &qoc));
72
+ AIO_WAIT_WHILE_UNLOCKED(NULL, qoc.ret == -EINPROGRESS);
73
74
return qoc.ret;
75
}
28
--
76
--
29
2.19.1
77
2.40.1
30
31
diff view generated by jsdifflib
1
If read-only=off, but auto-read-only=on is given, open a read-write NBD
1
When opening the 'file' child moves bs to an iothread, we need to hold
2
connection if the server provides a read-write export, but instead of
2
the AioContext lock of it before we can call raw_apply_options() (and
3
erroring out for read-only exports, just degrade to read-only.
3
more specifically, bdrv_getlength() inside of it).
4
4
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
6
Message-Id: <20230525124713.401149-8-kwolf@redhat.com>
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
9
---
8
block/nbd-client.c | 10 +++++-----
10
block/raw-format.c | 5 +++++
9
1 file changed, 5 insertions(+), 5 deletions(-)
11
tests/unit/test-block-iothread.c | 3 ---
12
2 files changed, 5 insertions(+), 3 deletions(-)
10
13
11
diff --git a/block/nbd-client.c b/block/nbd-client.c
14
diff --git a/block/raw-format.c b/block/raw-format.c
12
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
13
--- a/block/nbd-client.c
16
--- a/block/raw-format.c
14
+++ b/block/nbd-client.c
17
+++ b/block/raw-format.c
15
@@ -XXX,XX +XXX,XX @@ int nbd_client_init(BlockDriverState *bs,
18
@@ -XXX,XX +XXX,XX @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
16
logout("Failed to negotiate with the NBD server\n");
19
Error **errp)
20
{
21
BDRVRawState *s = bs->opaque;
22
+ AioContext *ctx;
23
bool has_size;
24
uint64_t offset, size;
25
BdrvChildRole file_role;
26
@@ -XXX,XX +XXX,XX @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
27
bs->file->bs->filename);
28
}
29
30
+ ctx = bdrv_get_aio_context(bs);
31
+ aio_context_acquire(ctx);
32
ret = raw_apply_options(bs, s, offset, has_size, size, errp);
33
+ aio_context_release(ctx);
34
+
35
if (ret < 0) {
17
return ret;
36
return ret;
18
}
37
}
19
- if (client->info.flags & NBD_FLAG_READ_ONLY &&
38
diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c
20
- !bdrv_is_read_only(bs)) {
39
index XXXXXXX..XXXXXXX 100644
21
- error_setg(errp,
40
--- a/tests/unit/test-block-iothread.c
22
- "request for write access conflicts with read-only export");
41
+++ b/tests/unit/test-block-iothread.c
23
- return -EACCES;
42
@@ -XXX,XX +XXX,XX @@ static void test_attach_second_node(void)
24
+ if (client->info.flags & NBD_FLAG_READ_ONLY) {
43
qdict_put_str(options, "driver", "raw");
25
+ ret = bdrv_apply_auto_read_only(bs, "NBD export is read-only", errp);
44
qdict_put_str(options, "file", "base");
26
+ if (ret < 0) {
45
27
+ return ret;
46
- /* FIXME raw_open() should take ctx's lock internally */
28
+ }
47
- aio_context_acquire(ctx);
29
}
48
aio_context_acquire(main_ctx);
30
if (client->info.flags & NBD_FLAG_SEND_FUA) {
49
filter = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
31
bs->supported_write_flags = BDRV_REQ_FUA;
50
aio_context_release(main_ctx);
51
- aio_context_release(ctx);
52
53
g_assert(blk_get_aio_context(blk) == ctx);
54
g_assert(bdrv_get_aio_context(bs) == ctx);
32
--
55
--
33
2.19.1
56
2.40.1
34
35
diff view generated by jsdifflib
1
If read-only=off, but auto-read-only=on is given, just degrade to
1
The AioContext lock must not be held for bdrv_open_child(), but it is
2
read-only.
2
necessary for the following operations, in particular those using nested
3
event loops in coroutine wrappers.
4
5
Temporarily dropping the main AioContext lock is not necessary because
6
we know we run in the main thread.
3
7
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Message-Id: <20230525124713.401149-9-kwolf@redhat.com>
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
12
---
7
block/curl.c | 8 ++++----
13
block/copy-before-write.c | 21 ++++++++++++++++-----
8
1 file changed, 4 insertions(+), 4 deletions(-)
14
1 file changed, 16 insertions(+), 5 deletions(-)
9
15
10
diff --git a/block/curl.c b/block/curl.c
16
diff --git a/block/copy-before-write.c b/block/copy-before-write.c
11
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
12
--- a/block/curl.c
18
--- a/block/copy-before-write.c
13
+++ b/block/curl.c
19
+++ b/block/copy-before-write.c
14
@@ -XXX,XX +XXX,XX @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
20
@@ -XXX,XX +XXX,XX @@ static int cbw_open(BlockDriverState *bs, QDict *options, int flags,
15
const char *protocol_delimiter;
21
int64_t cluster_size;
22
g_autoptr(BlockdevOptions) full_opts = NULL;
23
BlockdevOptionsCbw *opts;
24
+ AioContext *ctx;
16
int ret;
25
int ret;
17
26
18
-
27
full_opts = cbw_parse_options(options, errp);
19
- if (flags & BDRV_O_RDWR) {
28
@@ -XXX,XX +XXX,XX @@ static int cbw_open(BlockDriverState *bs, QDict *options, int flags,
20
- error_setg(errp, "curl block device does not support writes");
29
return -EINVAL;
21
- return -EROFS;
22
+ ret = bdrv_apply_auto_read_only(bs, "curl driver does not support writes",
23
+ errp);
24
+ if (ret < 0) {
25
+ return ret;
26
}
30
}
27
31
28
if (!libcurl_initialized) {
32
+ ctx = bdrv_get_aio_context(bs);
33
+ aio_context_acquire(ctx);
34
+
35
if (opts->bitmap) {
36
bitmap = block_dirty_bitmap_lookup(opts->bitmap->node,
37
opts->bitmap->name, NULL, errp);
38
if (!bitmap) {
39
- return -EINVAL;
40
+ ret = -EINVAL;
41
+ goto out;
42
}
43
}
44
s->on_cbw_error = opts->has_on_cbw_error ? opts->on_cbw_error :
45
@@ -XXX,XX +XXX,XX @@ static int cbw_open(BlockDriverState *bs, QDict *options, int flags,
46
s->bcs = block_copy_state_new(bs->file, s->target, bitmap, errp);
47
if (!s->bcs) {
48
error_prepend(errp, "Cannot create block-copy-state: ");
49
- return -EINVAL;
50
+ ret = -EINVAL;
51
+ goto out;
52
}
53
54
cluster_size = block_copy_cluster_size(s->bcs);
55
56
s->done_bitmap = bdrv_create_dirty_bitmap(bs, cluster_size, NULL, errp);
57
if (!s->done_bitmap) {
58
- return -EINVAL;
59
+ ret = -EINVAL;
60
+ goto out;
61
}
62
bdrv_disable_dirty_bitmap(s->done_bitmap);
63
64
/* s->access_bitmap starts equal to bcs bitmap */
65
s->access_bitmap = bdrv_create_dirty_bitmap(bs, cluster_size, NULL, errp);
66
if (!s->access_bitmap) {
67
- return -EINVAL;
68
+ ret = -EINVAL;
69
+ goto out;
70
}
71
bdrv_disable_dirty_bitmap(s->access_bitmap);
72
bdrv_dirty_bitmap_merge_internal(s->access_bitmap,
73
@@ -XXX,XX +XXX,XX @@ static int cbw_open(BlockDriverState *bs, QDict *options, int flags,
74
qemu_co_mutex_init(&s->lock);
75
QLIST_INIT(&s->frozen_read_reqs);
76
77
- return 0;
78
+ ret = 0;
79
+out:
80
+ aio_context_release(ctx);
81
+ return ret;
82
}
83
84
static void cbw_close(BlockDriverState *bs)
29
--
85
--
30
2.19.1
86
2.40.1
31
32
diff view generated by jsdifflib
1
To fully change the read-only state of a node, we must not only change
1
bdrv_refresh_total_sectors() and bdrv_refresh_limits() expect to be
2
bs->read_only, but also update bs->open_flags.
2
called under the AioContext lock of the node. Take the lock.
3
3
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Eric Blake <eblake@redhat.com>
5
Message-Id: <20230525124713.401149-10-kwolf@redhat.com>
6
Reviewed-by: Alberto Garcia <berto@igalia.com>
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
8
---
8
block.c | 7 +++++++
9
block.c | 7 +++++++
9
1 file changed, 7 insertions(+)
10
1 file changed, 7 insertions(+)
10
11
11
diff --git a/block.c b/block.c
12
diff --git a/block.c b/block.c
12
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
13
--- a/block.c
14
--- a/block.c
14
+++ b/block.c
15
+++ b/block.c
15
@@ -XXX,XX +XXX,XX @@ int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
16
@@ -XXX,XX +XXX,XX @@ static int no_coroutine_fn GRAPH_UNLOCKED
17
bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv, const char *node_name,
18
QDict *options, int open_flags, Error **errp)
19
{
20
+ AioContext *ctx;
21
Error *local_err = NULL;
22
int i, ret;
23
GLOBAL_STATE_CODE();
24
@@ -XXX,XX +XXX,XX @@ bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv, const char *node_name,
25
bs->supported_read_flags |= BDRV_REQ_REGISTERED_BUF;
26
bs->supported_write_flags |= BDRV_REQ_REGISTERED_BUF;
27
28
+ /* Get the context after .bdrv_open, it can change the context */
29
+ ctx = bdrv_get_aio_context(bs);
30
+ aio_context_acquire(ctx);
31
+
32
ret = bdrv_refresh_total_sectors(bs, bs->total_sectors);
33
if (ret < 0) {
34
error_setg_errno(errp, -ret, "Could not refresh total sector count");
35
+ aio_context_release(ctx);
36
return ret;
16
}
37
}
17
38
18
bs->read_only = read_only;
39
bdrv_graph_rdlock_main_loop();
19
+
40
bdrv_refresh_limits(bs, NULL, &local_err);
20
+ if (read_only) {
41
bdrv_graph_rdunlock_main_loop();
21
+ bs->open_flags &= ~BDRV_O_RDWR;
42
+ aio_context_release(ctx);
22
+ } else {
43
23
+ bs->open_flags |= BDRV_O_RDWR;
44
if (local_err) {
24
+ }
45
error_propagate(errp, local_err);
25
+
26
return 0;
27
}
28
29
--
46
--
30
2.19.1
47
2.40.1
31
32
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
While calling bdrv_new_open_driver_opts(), the main AioContext lock must
2
be held, not the lock of the AioContext of the block subtree it will be
3
added to afterwards.
2
4
3
Signed-off-by: Alberto Garcia <berto@igalia.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Message-Id: <20230525124713.401149-11-kwolf@redhat.com>
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
---
9
---
6
block.c | 6 +++---
10
block.c | 11 +++++++++++
7
1 file changed, 3 insertions(+), 3 deletions(-)
11
1 file changed, 11 insertions(+)
8
12
9
diff --git a/block.c b/block.c
13
diff --git a/block.c b/block.c
10
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
11
--- a/block.c
15
--- a/block.c
12
+++ b/block.c
16
+++ b/block.c
13
@@ -XXX,XX +XXX,XX @@ QemuOptsList bdrv_runtime_opts = {
17
@@ -XXX,XX +XXX,XX @@ static void bdrv_delete(BlockDriverState *bs)
14
.help = "try to optimize zero writes (off, on, unmap)",
18
* empty set of options. The reference to the QDict belongs to the block layer
15
},
19
* after the call (even on failure), so if the caller intends to reuse the
16
{
20
* dictionary, it needs to use qobject_ref() before calling bdrv_open.
17
- .name = "discard",
21
+ *
18
+ .name = BDRV_OPT_DISCARD,
22
+ * The caller holds the AioContext lock for @bs. It must make sure that @bs
19
.type = QEMU_OPT_STRING,
23
+ * stays in the same AioContext, i.e. @options must not refer to nodes in a
20
.help = "discard operation (ignore/off, unmap/on)",
24
+ * different AioContext.
21
},
25
*/
22
@@ -XXX,XX +XXX,XX @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file,
26
BlockDriverState *bdrv_insert_node(BlockDriverState *bs, QDict *options,
23
}
27
int flags, Error **errp)
24
}
28
{
25
29
ERRP_GUARD();
26
- discard = qemu_opt_get(opts, "discard");
30
int ret;
27
+ discard = qemu_opt_get(opts, BDRV_OPT_DISCARD);
31
+ AioContext *ctx = bdrv_get_aio_context(bs);
28
if (discard != NULL) {
32
BlockDriverState *new_node_bs = NULL;
29
if (bdrv_parse_discard_flags(discard, &bs->open_flags) != 0) {
33
const char *drvname, *node_name;
30
error_setg(errp, "Invalid discard option");
34
BlockDriver *drv;
31
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
35
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_insert_node(BlockDriverState *bs, QDict *options,
32
36
33
update_flags_from_options(&reopen_state->flags, opts);
37
GLOBAL_STATE_CODE();
34
38
35
- discard = qemu_opt_get_del(opts, "discard");
39
+ aio_context_release(ctx);
36
+ discard = qemu_opt_get_del(opts, BDRV_OPT_DISCARD);
40
+ aio_context_acquire(qemu_get_aio_context());
37
if (discard != NULL) {
41
new_node_bs = bdrv_new_open_driver_opts(drv, node_name, options, flags,
38
if (bdrv_parse_discard_flags(discard, &reopen_state->flags) != 0) {
42
errp);
39
error_setg(errp, "Invalid discard option");
43
+ aio_context_release(qemu_get_aio_context());
44
+ aio_context_acquire(ctx);
45
+ assert(bdrv_get_aio_context(bs) == ctx);
46
+
47
options = NULL; /* bdrv_new_open_driver() eats options */
48
if (!new_node_bs) {
49
error_prepend(errp, "Could not create node: ");
40
--
50
--
41
2.19.1
51
2.40.1
42
43
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
It has no internal callers, so its only use is being called from
2
individual test cases. If the name starts with an underscore, it is
3
considered private and linters warn against calling it. 256 only gets
4
away with it currently because it's on the exception list for linters.
2
5
3
Just like in qemu_opts_print_help(), print the object name as a caption
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
instead of on every single line, indent all options, add angle brackets
7
Message-Id: <20230525124713.401149-12-kwolf@redhat.com>
5
around types, and align the descriptions after 24 characters.
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
6
7
Also, indent every object name in the list of available objects.
8
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
10
---
13
vl.c | 13 ++++++++++---
11
tests/qemu-iotests/iotests.py | 2 +-
14
1 file changed, 10 insertions(+), 3 deletions(-)
12
tests/qemu-iotests/256 | 2 +-
13
2 files changed, 2 insertions(+), 2 deletions(-)
15
14
16
diff --git a/vl.c b/vl.c
15
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
17
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
18
--- a/vl.c
17
--- a/tests/qemu-iotests/iotests.py
19
+++ b/vl.c
18
+++ b/tests/qemu-iotests/iotests.py
20
@@ -XXX,XX +XXX,XX @@ static bool object_create_initial(const char *type, QemuOpts *opts)
19
@@ -XXX,XX +XXX,XX @@ def _verify_virtio_blk() -> None:
21
list = object_class_get_list_sorted(TYPE_USER_CREATABLE, false);
20
if 'virtio-blk' not in out:
22
for (l = list; l != NULL; l = l->next) {
21
notrun('Missing virtio-blk in QEMU binary')
23
ObjectClass *oc = OBJECT_CLASS(l->data);
22
24
- printf("%s\n", object_class_get_name(oc));
23
-def _verify_virtio_scsi_pci_or_ccw() -> None:
25
+ printf(" %s\n", object_class_get_name(oc));
24
+def verify_virtio_scsi_pci_or_ccw() -> None:
26
}
25
out = qemu_pipe('-M', 'none', '-device', 'help')
27
g_slist_free(list);
26
if 'virtio-scsi-pci' not in out and 'virtio-scsi-ccw' not in out:
28
exit(0);
27
notrun('Missing virtio-scsi-pci or virtio-scsi-ccw in QEMU binary')
29
@@ -XXX,XX +XXX,XX @@ static bool object_create_initial(const char *type, QemuOpts *opts)
28
diff --git a/tests/qemu-iotests/256 b/tests/qemu-iotests/256
30
}
29
index XXXXXXX..XXXXXXX 100755
31
30
--- a/tests/qemu-iotests/256
32
str = g_string_new(NULL);
31
+++ b/tests/qemu-iotests/256
33
- g_string_append_printf(str, "%s.%s=%s", type,
32
@@ -XXX,XX +XXX,XX @@ import os
34
- prop->name, prop->type);
33
import iotests
35
+ g_string_append_printf(str, " %s=<%s>", prop->name, prop->type);
34
from iotests import log
36
if (prop->description) {
35
37
+ if (str->len < 24) {
36
-iotests._verify_virtio_scsi_pci_or_ccw()
38
+ g_string_append_printf(str, "%*s", 24 - (int)str->len, "");
37
+iotests.verify_virtio_scsi_pci_or_ccw()
39
+ }
38
40
g_string_append_printf(str, " - %s", prop->description);
39
iotests.script_initialize(supported_fmts=['qcow2'])
41
}
40
size = 64 * 1024 * 1024
42
g_ptr_array_add(array, g_string_free(str, false));
43
}
44
g_ptr_array_sort(array, (GCompareFunc)qemu_pstrcmp0);
45
+ if (array->len > 0) {
46
+ printf("%s options:\n", type);
47
+ } else {
48
+ printf("There are no options for %s.\n", type);
49
+ }
50
for (i = 0; i < array->len; i++) {
51
printf("%s\n", (char *)array->pdata[i]);
52
}
53
--
41
--
54
2.19.1
42
2.40.1
55
56
diff view generated by jsdifflib
1
If blockdev-create references an existing node in an iothread (e.g. as
2
it's 'file' child), then suddenly all of the image creation code must
3
run in that AioContext, too. Test that this actually works.
4
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Reviewed-by: Eric Blake <eblake@redhat.com>
6
Message-Id: <20230525124713.401149-13-kwolf@redhat.com>
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
3
---
9
---
4
tests/qemu-iotests/232 | 147 +++++++++++++++++++++++++++++++++++++
10
tests/qemu-iotests/tests/iothreads-create | 67 +++++++++++++++++++
5
tests/qemu-iotests/232.out | 59 +++++++++++++++
11
tests/qemu-iotests/tests/iothreads-create.out | 4 ++
6
tests/qemu-iotests/group | 1 +
12
2 files changed, 71 insertions(+)
7
3 files changed, 207 insertions(+)
13
create mode 100755 tests/qemu-iotests/tests/iothreads-create
8
create mode 100755 tests/qemu-iotests/232
14
create mode 100644 tests/qemu-iotests/tests/iothreads-create.out
9
create mode 100644 tests/qemu-iotests/232.out
10
15
11
diff --git a/tests/qemu-iotests/232 b/tests/qemu-iotests/232
16
diff --git a/tests/qemu-iotests/tests/iothreads-create b/tests/qemu-iotests/tests/iothreads-create
12
new file mode 100755
17
new file mode 100755
13
index XXXXXXX..XXXXXXX
18
index XXXXXXX..XXXXXXX
14
--- /dev/null
19
--- /dev/null
15
+++ b/tests/qemu-iotests/232
20
+++ b/tests/qemu-iotests/tests/iothreads-create
16
@@ -XXX,XX +XXX,XX @@
21
@@ -XXX,XX +XXX,XX @@
17
+#!/bin/bash
22
+#!/usr/bin/env python3
23
+# group: rw quick
18
+#
24
+#
19
+# Test for auto-read-only
25
+# Copyright (C) 2023 Red Hat, Inc.
20
+#
21
+# Copyright (C) 2018 Red Hat, Inc.
22
+#
26
+#
23
+# This program is free software; you can redistribute it and/or modify
27
+# This program is free software; you can redistribute it and/or modify
24
+# it under the terms of the GNU General Public License as published by
28
+# it under the terms of the GNU General Public License as published by
25
+# the Free Software Foundation; either version 2 of the License, or
29
+# the Free Software Foundation; either version 2 of the License, or
26
+# (at your option) any later version.
30
+# (at your option) any later version.
...
...
31
+# GNU General Public License for more details.
35
+# GNU General Public License for more details.
32
+#
36
+#
33
+# You should have received a copy of the GNU General Public License
37
+# You should have received a copy of the GNU General Public License
34
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
38
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
35
+#
39
+#
40
+# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
36
+
41
+
37
+# creator
42
+import asyncio
38
+owner=kwolf@redhat.com
43
+import iotests
39
+
44
+
40
+seq=`basename $0`
45
+iotests.script_initialize(supported_fmts=['qcow2', 'qcow', 'qed', 'vdi',
41
+echo "QA output created by $seq"
46
+ 'vmdk', 'parallels'])
47
+iotests.verify_virtio_scsi_pci_or_ccw()
42
+
48
+
43
+here=`pwd`
49
+with iotests.FilePath('disk.img') as img_path, \
44
+status=1    # failure is the default!
50
+ iotests.VM() as vm:
45
+
51
+
46
+_cleanup()
52
+ iotests.qemu_img_create('-f', 'raw', img_path, '0')
47
+{
48
+ _cleanup_test_img
49
+ rm -f $TEST_IMG.snap
50
+}
51
+trap "_cleanup; exit \$status" 0 1 2 3 15
52
+
53
+
53
+# get standard environment, filters and checks
54
+ vm.add_object('iothread,id=iothread0')
54
+. ./common.rc
55
+ vm.add_blockdev(f'file,node-name=img-file,read-only=on,'
55
+. ./common.filter
56
+ f'filename={img_path}')
57
+ vm.add_device('virtio-scsi,iothread=iothread0')
58
+ vm.add_device('scsi-hd,drive=img-file,share-rw=on')
56
+
59
+
57
+_supported_fmt generic
60
+ vm.launch()
58
+_supported_proto file
59
+_supported_os Linux
60
+
61
+
61
+function do_run_qemu()
62
+ iotests.log(vm.qmp(
62
+{
63
+ 'blockdev-reopen',
63
+ echo Testing: "$@"
64
+ options=[{
64
+ (
65
+ 'driver': 'file',
65
+ if ! test -t 0; then
66
+ 'filename': img_path,
66
+ while read cmd; do
67
+ 'node-name': 'img-file',
67
+ echo $cmd
68
+ 'read-only': False,
68
+ done
69
+ }],
69
+ fi
70
+ ))
70
+ echo quit
71
+ iotests.log(vm.qmp(
71
+ ) | $QEMU -nographic -monitor stdio -nodefaults "$@"
72
+ 'blockdev-create',
72
+ echo
73
+ job_id='job0',
73
+}
74
+ options={
75
+ 'driver': iotests.imgfmt,
76
+ 'file': 'img-file',
77
+ 'size': 1024 * 1024,
78
+ },
79
+ ))
74
+
80
+
75
+function run_qemu()
81
+ # Should succeed and not time out
76
+{
82
+ try:
77
+ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_hmp |
83
+ vm.run_job('job0', wait=5.0)
78
+ _filter_generated_node_ids | _filter_imgfmt
84
+ vm.shutdown()
79
+}
85
+ except asyncio.TimeoutError:
80
+
86
+ # VM may be stuck, kill it
81
+function run_qemu_info_block()
87
+ vm.kill()
82
+{
88
+ raise
83
+ echo "info block -n" | run_qemu "$@" | grep -e "(file" -e "QEMU_PROG"
89
diff --git a/tests/qemu-iotests/tests/iothreads-create.out b/tests/qemu-iotests/tests/iothreads-create.out
84
+}
85
+
86
+size=128M
87
+
88
+_make_test_img $size
89
+
90
+echo
91
+echo "=== -drive with read-write image: read-only/auto-read-only combinations ==="
92
+echo
93
+
94
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=on,auto-read-only=off
95
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=on,auto-read-only=on
96
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=on
97
+echo
98
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=off,auto-read-only=off
99
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=off,auto-read-only=on
100
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=off
101
+echo
102
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,auto-read-only=off
103
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,auto-read-only=on
104
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none
105
+
106
+echo
107
+echo "=== -drive with read-only image: read-only/auto-read-only combinations ==="
108
+echo
109
+
110
+chmod a-w $TEST_IMG
111
+
112
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=on,auto-read-only=off
113
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=on,auto-read-only=on
114
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=on
115
+echo
116
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=off,auto-read-only=off
117
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=off,auto-read-only=on
118
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=off
119
+echo
120
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,auto-read-only=off
121
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,auto-read-only=on
122
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none
123
+
124
+echo
125
+echo "=== -blockdev with read-write image: read-only/auto-read-only combinations ==="
126
+echo
127
+
128
+chmod a+w $TEST_IMG
129
+
130
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=on,auto-read-only=off
131
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=on,auto-read-only=on
132
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=on
133
+echo
134
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=off,auto-read-only=off
135
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=off,auto-read-only=on
136
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=off
137
+echo
138
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,auto-read-only=off
139
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,auto-read-only=on
140
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0
141
+
142
+echo
143
+echo "=== -blockdev with read-only image: read-only/auto-read-only combinations ==="
144
+echo
145
+
146
+chmod a-w $TEST_IMG
147
+
148
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=on,auto-read-only=off
149
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=on,auto-read-only=on
150
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=on
151
+echo
152
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=off,auto-read-only=off
153
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=off,auto-read-only=on
154
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=off
155
+echo
156
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,auto-read-only=off
157
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,auto-read-only=on
158
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0
159
+
160
+# success, all done
161
+echo "*** done"
162
+rm -f $seq.full
163
+status=0
164
diff --git a/tests/qemu-iotests/232.out b/tests/qemu-iotests/232.out
165
new file mode 100644
90
new file mode 100644
166
index XXXXXXX..XXXXXXX
91
index XXXXXXX..XXXXXXX
167
--- /dev/null
92
--- /dev/null
168
+++ b/tests/qemu-iotests/232.out
93
+++ b/tests/qemu-iotests/tests/iothreads-create.out
169
@@ -XXX,XX +XXX,XX @@
94
@@ -XXX,XX +XXX,XX @@
170
+QA output created by 232
95
+{"return": {}}
171
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
96
+{"return": {}}
172
+
97
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
173
+=== -drive with read-write image: read-only/auto-read-only combinations ===
98
+{"return": {}}
174
+
175
+NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
176
+NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
177
+NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
178
+
179
+NODE_NAME: TEST_DIR/t.IMGFMT (file)
180
+NODE_NAME: TEST_DIR/t.IMGFMT (file)
181
+NODE_NAME: TEST_DIR/t.IMGFMT (file)
182
+
183
+NODE_NAME: TEST_DIR/t.IMGFMT (file)
184
+NODE_NAME: TEST_DIR/t.IMGFMT (file)
185
+NODE_NAME: TEST_DIR/t.IMGFMT (file)
186
+
187
+=== -drive with read-only image: read-only/auto-read-only combinations ===
188
+
189
+NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
190
+NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
191
+NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
192
+
193
+QEMU_PROG: -drive driver=file,file=TEST_DIR/t.IMGFMT,if=none,read-only=off,auto-read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
194
+NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
195
+NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
196
+
197
+QEMU_PROG: -drive driver=file,file=TEST_DIR/t.IMGFMT,if=none,auto-read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
198
+NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
199
+NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
200
+
201
+=== -blockdev with read-write image: read-only/auto-read-only combinations ===
202
+
203
+node0: TEST_DIR/t.IMGFMT (file, read-only)
204
+node0: TEST_DIR/t.IMGFMT (file, read-only)
205
+node0: TEST_DIR/t.IMGFMT (file, read-only)
206
+
207
+node0: TEST_DIR/t.IMGFMT (file)
208
+node0: TEST_DIR/t.IMGFMT (file)
209
+node0: TEST_DIR/t.IMGFMT (file)
210
+
211
+node0: TEST_DIR/t.IMGFMT (file)
212
+node0: TEST_DIR/t.IMGFMT (file)
213
+node0: TEST_DIR/t.IMGFMT (file)
214
+
215
+=== -blockdev with read-only image: read-only/auto-read-only combinations ===
216
+
217
+node0: TEST_DIR/t.IMGFMT (file, read-only)
218
+node0: TEST_DIR/t.IMGFMT (file, read-only)
219
+node0: TEST_DIR/t.IMGFMT (file, read-only)
220
+
221
+QEMU_PROG: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0,read-only=off,auto-read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
222
+node0: TEST_DIR/t.IMGFMT (file, read-only)
223
+QEMU_PROG: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0,read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
224
+
225
+QEMU_PROG: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0,auto-read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
226
+node0: TEST_DIR/t.IMGFMT (file, read-only)
227
+QEMU_PROG: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
228
+*** done
229
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
230
index XXXXXXX..XXXXXXX 100644
231
--- a/tests/qemu-iotests/group
232
+++ b/tests/qemu-iotests/group
233
@@ -XXX,XX +XXX,XX @@
234
227 auto quick
235
229 auto quick
236
231 auto quick
237
+232 auto quick
238
--
99
--
239
2.19.1
100
2.40.1
240
241
diff view generated by jsdifflib
1
From: Li Qiang <liq3ea@163.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
Signed-off-by: Li Qiang <liq3ea@163.com>
3
blk_set_aio_context() is not fully transactional because
4
Reviewed-by: Alberto Garcia <berto@igalia.com>
4
blk_do_set_aio_context() updates blk->ctx outside the transaction. Most
5
of the time this goes unnoticed but a BlockDevOps.drained_end() callback
6
that invokes blk_get_aio_context() fails assert(ctx == blk->ctx). This
7
happens because blk->ctx is only assigned after
8
BlockDevOps.drained_end() is called and we're in an intermediate state
9
where BlockDrvierState nodes already have the new context and the
10
BlockBackend still has the old context.
11
12
Making blk_set_aio_context() fully transactional solves this assertion
13
failure because the BlockBackend's context is updated as part of the
14
transaction (before BlockDevOps.drained_end() is called).
15
16
Split blk_do_set_aio_context() in order to solve this assertion failure.
17
This helper function actually serves two different purposes:
18
1. It drives blk_set_aio_context().
19
2. It responds to BdrvChildClass->change_aio_ctx().
20
21
Get rid of the helper function. Do #1 inside blk_set_aio_context() and
22
do #2 inside blk_root_set_aio_ctx_commit(). This simplifies the code.
23
24
The only drawback of the fully transactional approach is that
25
blk_set_aio_context() must contend with blk_root_set_aio_ctx_commit()
26
being invoked as part of the AioContext change propagation. This can be
27
solved by temporarily setting blk->allow_aio_context_change to true.
28
29
Future patches call blk_get_aio_context() from
30
BlockDevOps->drained_end(), so this patch will become necessary.
31
32
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
33
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
34
Message-Id: <20230516190238.8401-2-stefanha@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
35
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
36
---
7
include/sysemu/block-backend.h | 6 +++---
37
block/block-backend.c | 61 ++++++++++++++++---------------------------
8
block/block-backend.c | 8 ++++----
38
1 file changed, 23 insertions(+), 38 deletions(-)
9
2 files changed, 7 insertions(+), 7 deletions(-)
10
39
11
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
12
index XXXXXXX..XXXXXXX 100644
13
--- a/include/sysemu/block-backend.h
14
+++ b/include/sysemu/block-backend.h
15
@@ -XXX,XX +XXX,XX @@ BlockErrorAction blk_get_error_action(BlockBackend *blk, bool is_read,
16
int error);
17
void blk_error_action(BlockBackend *blk, BlockErrorAction action,
18
bool is_read, int error);
19
-int blk_is_read_only(BlockBackend *blk);
20
-int blk_is_sg(BlockBackend *blk);
21
-int blk_enable_write_cache(BlockBackend *blk);
22
+bool blk_is_read_only(BlockBackend *blk);
23
+bool blk_is_sg(BlockBackend *blk);
24
+bool blk_enable_write_cache(BlockBackend *blk);
25
void blk_set_enable_write_cache(BlockBackend *blk, bool wce);
26
void blk_invalidate_cache(BlockBackend *blk, Error **errp);
27
bool blk_is_inserted(BlockBackend *blk);
28
diff --git a/block/block-backend.c b/block/block-backend.c
40
diff --git a/block/block-backend.c b/block/block-backend.c
29
index XXXXXXX..XXXXXXX 100644
41
index XXXXXXX..XXXXXXX 100644
30
--- a/block/block-backend.c
42
--- a/block/block-backend.c
31
+++ b/block/block-backend.c
43
+++ b/block/block-backend.c
32
@@ -XXX,XX +XXX,XX @@ void blk_error_action(BlockBackend *blk, BlockErrorAction action,
44
@@ -XXX,XX +XXX,XX @@ static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb)
45
return blk_get_aio_context(blk_acb->blk);
46
}
47
48
-static int blk_do_set_aio_context(BlockBackend *blk, AioContext *new_context,
49
- bool update_root_node, Error **errp)
50
+int blk_set_aio_context(BlockBackend *blk, AioContext *new_context,
51
+ Error **errp)
52
{
53
+ bool old_allow_change;
54
BlockDriverState *bs = blk_bs(blk);
55
- ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
56
int ret;
57
58
- if (bs) {
59
- bdrv_ref(bs);
60
-
61
- if (update_root_node) {
62
- /*
63
- * update_root_node MUST be false for blk_root_set_aio_ctx_commit(),
64
- * as we are already in the commit function of a transaction.
65
- */
66
- ret = bdrv_try_change_aio_context(bs, new_context, blk->root, errp);
67
- if (ret < 0) {
68
- bdrv_unref(bs);
69
- return ret;
70
- }
71
- }
72
- /*
73
- * Make blk->ctx consistent with the root node before we invoke any
74
- * other operations like drain that might inquire blk->ctx
75
- */
76
- blk->ctx = new_context;
77
- if (tgm->throttle_state) {
78
- bdrv_drained_begin(bs);
79
- throttle_group_detach_aio_context(tgm);
80
- throttle_group_attach_aio_context(tgm, new_context);
81
- bdrv_drained_end(bs);
82
- }
83
+ GLOBAL_STATE_CODE();
84
85
- bdrv_unref(bs);
86
- } else {
87
+ if (!bs) {
88
blk->ctx = new_context;
89
+ return 0;
33
}
90
}
91
92
- return 0;
93
-}
94
+ bdrv_ref(bs);
95
96
-int blk_set_aio_context(BlockBackend *blk, AioContext *new_context,
97
- Error **errp)
98
-{
99
- GLOBAL_STATE_CODE();
100
- return blk_do_set_aio_context(blk, new_context, true, errp);
101
+ old_allow_change = blk->allow_aio_context_change;
102
+ blk->allow_aio_context_change = true;
103
+
104
+ ret = bdrv_try_change_aio_context(bs, new_context, NULL, errp);
105
+
106
+ blk->allow_aio_context_change = old_allow_change;
107
+
108
+ bdrv_unref(bs);
109
+ return ret;
34
}
110
}
35
111
36
-int blk_is_read_only(BlockBackend *blk)
112
typedef struct BdrvStateBlkRootContext {
37
+bool blk_is_read_only(BlockBackend *blk)
113
@@ -XXX,XX +XXX,XX @@ static void blk_root_set_aio_ctx_commit(void *opaque)
38
{
114
{
39
BlockDriverState *bs = blk_bs(blk);
115
BdrvStateBlkRootContext *s = opaque;
40
116
BlockBackend *blk = s->blk;
41
@@ -XXX,XX +XXX,XX @@ int blk_is_read_only(BlockBackend *blk)
117
+ AioContext *new_context = s->new_ctx;
42
}
118
+ ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
119
120
- blk_do_set_aio_context(blk, s->new_ctx, false, &error_abort);
121
+ blk->ctx = new_context;
122
+ if (tgm->throttle_state) {
123
+ throttle_group_detach_aio_context(tgm);
124
+ throttle_group_attach_aio_context(tgm, new_context);
125
+ }
43
}
126
}
44
127
45
-int blk_is_sg(BlockBackend *blk)
128
static TransactionActionDrv set_blk_root_context = {
46
+bool blk_is_sg(BlockBackend *blk)
47
{
48
BlockDriverState *bs = blk_bs(blk);
49
50
if (!bs) {
51
- return 0;
52
+ return false;
53
}
54
55
return bdrv_is_sg(bs);
56
}
57
58
-int blk_enable_write_cache(BlockBackend *blk)
59
+bool blk_enable_write_cache(BlockBackend *blk)
60
{
61
return blk->enable_write_cache;
62
}
63
--
129
--
64
2.19.1
130
2.40.1
65
66
diff view generated by jsdifflib
1
From: Peter Maydell <peter.maydell@linaro.org>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
Taking the address of a field in a packed struct is a bad idea, because
3
Add a helper function to check whether the device is realized without
4
it might not be actually aligned enough for that pointer type (and
4
requiring the Big QEMU Lock. The next patch adds a second caller. The
5
thus cause a crash on dereference on some host architectures). Newer
5
goal is to avoid spreading DeviceState field accesses throughout the
6
versions of clang warn about this. Avoid the bug by not using the
6
code.
7
"modify in place" byte swapping functions.
8
7
9
There are a few places where the in-place swap function is
8
Suggested-by: Philippe Mathieu-Daudé <philmd@linaro.org>
10
used on something other than a packed struct field; we convert
9
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
11
those anyway, for consistency.
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
11
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
13
Patch produced with scripts/coccinelle/inplace-byteswaps.cocci.
12
Message-Id: <20230516190238.8401-3-stefanha@redhat.com>
14
15
There are other places where we take the address of a packed member
16
in this file for other purposes than passing it to a byteswap
17
function (all the calls to qemu_uuid_*()); we leave those for now.
18
19
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
20
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
21
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
22
---
14
---
23
block/vdi.c | 64 ++++++++++++++++++++++++++---------------------------
15
include/hw/qdev-core.h | 17 ++++++++++++++---
24
1 file changed, 32 insertions(+), 32 deletions(-)
16
hw/scsi/scsi-bus.c | 3 +--
17
2 files changed, 15 insertions(+), 5 deletions(-)
25
18
26
diff --git a/block/vdi.c b/block/vdi.c
19
diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
27
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
28
--- a/block/vdi.c
21
--- a/include/hw/qdev-core.h
29
+++ b/block/vdi.c
22
+++ b/include/hw/qdev-core.h
23
@@ -XXX,XX +XXX,XX @@
24
#ifndef QDEV_CORE_H
25
#define QDEV_CORE_H
26
27
+#include "qemu/atomic.h"
28
#include "qemu/queue.h"
29
#include "qemu/bitmap.h"
30
#include "qemu/rcu.h"
30
@@ -XXX,XX +XXX,XX @@ typedef struct {
31
@@ -XXX,XX +XXX,XX @@ typedef struct {
31
32
32
static void vdi_header_to_cpu(VdiHeader *header)
33
/**
33
{
34
* DeviceState:
34
- le32_to_cpus(&header->signature);
35
- * @realized: Indicates whether the device has been fully constructed.
35
- le32_to_cpus(&header->version);
36
- * When accessed outside big qemu lock, must be accessed with
36
- le32_to_cpus(&header->header_size);
37
- * qatomic_load_acquire()
37
- le32_to_cpus(&header->image_type);
38
* @reset: ResettableState for the device; handled by Resettable interface.
38
- le32_to_cpus(&header->image_flags);
39
*
39
- le32_to_cpus(&header->offset_bmap);
40
* This structure should not be accessed directly. We declare it here
40
- le32_to_cpus(&header->offset_data);
41
@@ -XXX,XX +XXX,XX @@ DeviceState *qdev_new(const char *name);
41
- le32_to_cpus(&header->cylinders);
42
*/
42
- le32_to_cpus(&header->heads);
43
DeviceState *qdev_try_new(const char *name);
43
- le32_to_cpus(&header->sectors);
44
44
- le32_to_cpus(&header->sector_size);
45
+/**
45
- le64_to_cpus(&header->disk_size);
46
+ * qdev_is_realized:
46
- le32_to_cpus(&header->block_size);
47
+ * @dev: The device to check.
47
- le32_to_cpus(&header->block_extra);
48
+ *
48
- le32_to_cpus(&header->blocks_in_image);
49
+ * May be called outside big qemu lock.
49
- le32_to_cpus(&header->blocks_allocated);
50
+ *
50
+ header->signature = le32_to_cpu(header->signature);
51
+ * Returns: %true% if the device has been fully constructed, %false% otherwise.
51
+ header->version = le32_to_cpu(header->version);
52
+ */
52
+ header->header_size = le32_to_cpu(header->header_size);
53
+static inline bool qdev_is_realized(DeviceState *dev)
53
+ header->image_type = le32_to_cpu(header->image_type);
54
+{
54
+ header->image_flags = le32_to_cpu(header->image_flags);
55
+ return qatomic_load_acquire(&dev->realized);
55
+ header->offset_bmap = le32_to_cpu(header->offset_bmap);
56
+}
56
+ header->offset_data = le32_to_cpu(header->offset_data);
57
+
57
+ header->cylinders = le32_to_cpu(header->cylinders);
58
/**
58
+ header->heads = le32_to_cpu(header->heads);
59
* qdev_realize: Realize @dev.
59
+ header->sectors = le32_to_cpu(header->sectors);
60
* @dev: device to realize
60
+ header->sector_size = le32_to_cpu(header->sector_size);
61
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
61
+ header->disk_size = le64_to_cpu(header->disk_size);
62
index XXXXXXX..XXXXXXX 100644
62
+ header->block_size = le32_to_cpu(header->block_size);
63
--- a/hw/scsi/scsi-bus.c
63
+ header->block_extra = le32_to_cpu(header->block_extra);
64
+++ b/hw/scsi/scsi-bus.c
64
+ header->blocks_in_image = le32_to_cpu(header->blocks_in_image);
65
@@ -XXX,XX +XXX,XX @@ static SCSIDevice *do_scsi_device_find(SCSIBus *bus,
65
+ header->blocks_allocated = le32_to_cpu(header->blocks_allocated);
66
* the user access the device.
66
qemu_uuid_bswap(&header->uuid_image);
67
*/
67
qemu_uuid_bswap(&header->uuid_last_snap);
68
68
qemu_uuid_bswap(&header->uuid_link);
69
- if (retval && !include_unrealized &&
69
@@ -XXX,XX +XXX,XX @@ static void vdi_header_to_cpu(VdiHeader *header)
70
- !qatomic_load_acquire(&retval->qdev.realized)) {
70
71
+ if (retval && !include_unrealized && !qdev_is_realized(&retval->qdev)) {
71
static void vdi_header_to_le(VdiHeader *header)
72
retval = NULL;
72
{
73
}
73
- cpu_to_le32s(&header->signature);
74
74
- cpu_to_le32s(&header->version);
75
- cpu_to_le32s(&header->header_size);
76
- cpu_to_le32s(&header->image_type);
77
- cpu_to_le32s(&header->image_flags);
78
- cpu_to_le32s(&header->offset_bmap);
79
- cpu_to_le32s(&header->offset_data);
80
- cpu_to_le32s(&header->cylinders);
81
- cpu_to_le32s(&header->heads);
82
- cpu_to_le32s(&header->sectors);
83
- cpu_to_le32s(&header->sector_size);
84
- cpu_to_le64s(&header->disk_size);
85
- cpu_to_le32s(&header->block_size);
86
- cpu_to_le32s(&header->block_extra);
87
- cpu_to_le32s(&header->blocks_in_image);
88
- cpu_to_le32s(&header->blocks_allocated);
89
+ header->signature = cpu_to_le32(header->signature);
90
+ header->version = cpu_to_le32(header->version);
91
+ header->header_size = cpu_to_le32(header->header_size);
92
+ header->image_type = cpu_to_le32(header->image_type);
93
+ header->image_flags = cpu_to_le32(header->image_flags);
94
+ header->offset_bmap = cpu_to_le32(header->offset_bmap);
95
+ header->offset_data = cpu_to_le32(header->offset_data);
96
+ header->cylinders = cpu_to_le32(header->cylinders);
97
+ header->heads = cpu_to_le32(header->heads);
98
+ header->sectors = cpu_to_le32(header->sectors);
99
+ header->sector_size = cpu_to_le32(header->sector_size);
100
+ header->disk_size = cpu_to_le64(header->disk_size);
101
+ header->block_size = cpu_to_le32(header->block_size);
102
+ header->block_extra = cpu_to_le32(header->block_extra);
103
+ header->blocks_in_image = cpu_to_le32(header->blocks_in_image);
104
+ header->blocks_allocated = cpu_to_le32(header->blocks_allocated);
105
qemu_uuid_bswap(&header->uuid_image);
106
qemu_uuid_bswap(&header->uuid_last_snap);
107
qemu_uuid_bswap(&header->uuid_link);
108
--
75
--
109
2.19.1
76
2.40.1
110
77
111
78
diff view generated by jsdifflib
1
From: Peter Maydell <peter.maydell@linaro.org>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
Taking the address of a field in a packed struct is a bad idea, because
3
Only report a transport reset event to the guest after the SCSIDevice
4
it might not be actually aligned enough for that pointer type (and
4
has been unrealized by qdev_simple_device_unplug_cb().
5
thus cause a crash on dereference on some host architectures). Newer
6
versions of clang warn about this. Avoid the bug by not using the
7
"modify in place" byte swapping functions.
8
5
9
There are a few places where the in-place swap function is
6
qdev_simple_device_unplug_cb() sets the SCSIDevice's qdev.realized field
10
used on something other than a packed struct field; we convert
7
to false so that scsi_device_find/get() no longer see it.
11
those anyway, for consistency.
12
8
13
Patch produced with scripts/coccinelle/inplace-byteswaps.cocci.
9
scsi_target_emulate_report_luns() also needs to be updated to filter out
10
SCSIDevices that are unrealized.
14
11
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Change virtio_scsi_push_event() to take event information as an argument
16
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
13
instead of the SCSIDevice. This allows virtio_scsi_hotunplug() to emit a
14
VIRTIO_SCSI_T_TRANSPORT_RESET event after the SCSIDevice has already
15
been unrealized.
16
17
These changes ensure that the guest driver does not see the SCSIDevice
18
that's being unplugged if it responds very quickly to the transport
19
reset event.
20
21
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
22
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
23
Reviewed-by: Daniil Tatianin <d-tatianin@yandex-team.ru>
24
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
25
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
26
Message-Id: <20230516190238.8401-4-stefanha@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
27
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
---
28
---
19
block/vhdx.h | 12 ++---
29
hw/scsi/scsi-bus.c | 3 +-
20
block/vhdx-endian.c | 118 ++++++++++++++++++++++----------------------
30
hw/scsi/virtio-scsi.c | 86 ++++++++++++++++++++++++++++++-------------
21
block/vhdx-log.c | 4 +-
31
2 files changed, 63 insertions(+), 26 deletions(-)
22
block/vhdx.c | 18 +++----
23
4 files changed, 76 insertions(+), 76 deletions(-)
24
32
25
diff --git a/block/vhdx.h b/block/vhdx.h
33
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
26
index XXXXXXX..XXXXXXX 100644
34
index XXXXXXX..XXXXXXX 100644
27
--- a/block/vhdx.h
35
--- a/hw/scsi/scsi-bus.c
28
+++ b/block/vhdx.h
36
+++ b/hw/scsi/scsi-bus.c
29
@@ -XXX,XX +XXX,XX @@ int vhdx_log_write_and_flush(BlockDriverState *bs, BDRVVHDXState *s,
37
@@ -XXX,XX +XXX,XX @@ static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
30
38
DeviceState *qdev = kid->child;
31
static inline void leguid_to_cpus(MSGUID *guid)
39
SCSIDevice *dev = SCSI_DEVICE(qdev);
40
41
- if (dev->channel == channel && dev->id == id && dev->lun != 0) {
42
+ if (dev->channel == channel && dev->id == id && dev->lun != 0 &&
43
+ qdev_is_realized(&dev->qdev)) {
44
store_lun(tmp, dev->lun);
45
g_byte_array_append(buf, tmp, 8);
46
len += 8;
47
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
48
index XXXXXXX..XXXXXXX 100644
49
--- a/hw/scsi/virtio-scsi.c
50
+++ b/hw/scsi/virtio-scsi.c
51
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_reset(VirtIODevice *vdev)
52
s->events_dropped = false;
53
}
54
55
-static void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
56
- uint32_t event, uint32_t reason)
57
+typedef struct {
58
+ uint32_t event;
59
+ uint32_t reason;
60
+ union {
61
+ /* Used by messages specific to a device */
62
+ struct {
63
+ uint32_t id;
64
+ uint32_t lun;
65
+ } address;
66
+ };
67
+} VirtIOSCSIEventInfo;
68
+
69
+static void virtio_scsi_push_event(VirtIOSCSI *s,
70
+ const VirtIOSCSIEventInfo *info)
32
{
71
{
33
- le32_to_cpus(&guid->data1);
72
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
34
- le16_to_cpus(&guid->data2);
73
VirtIOSCSIReq *req;
35
- le16_to_cpus(&guid->data3);
74
VirtIOSCSIEvent *evt;
36
+ guid->data1 = le32_to_cpu(guid->data1);
75
VirtIODevice *vdev = VIRTIO_DEVICE(s);
37
+ guid->data2 = le16_to_cpu(guid->data2);
76
+ uint32_t event = info->event;
38
+ guid->data3 = le16_to_cpu(guid->data3);
77
+ uint32_t reason = info->reason;
78
79
if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
80
return;
81
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
82
memset(evt, 0, sizeof(VirtIOSCSIEvent));
83
evt->event = virtio_tswap32(vdev, event);
84
evt->reason = virtio_tswap32(vdev, reason);
85
- if (!dev) {
86
- assert(event == VIRTIO_SCSI_T_EVENTS_MISSED);
87
- } else {
88
+ if (event != VIRTIO_SCSI_T_EVENTS_MISSED) {
89
evt->lun[0] = 1;
90
- evt->lun[1] = dev->id;
91
+ evt->lun[1] = info->address.id;
92
93
/* Linux wants us to keep the same encoding we use for REPORT LUNS. */
94
- if (dev->lun >= 256) {
95
- evt->lun[2] = (dev->lun >> 8) | 0x40;
96
+ if (info->address.lun >= 256) {
97
+ evt->lun[2] = (info->address.lun >> 8) | 0x40;
98
}
99
- evt->lun[3] = dev->lun & 0xFF;
100
+ evt->lun[3] = info->address.lun & 0xFF;
101
}
102
trace_virtio_scsi_event(virtio_scsi_get_lun(evt->lun), event, reason);
103
-
104
+
105
virtio_scsi_complete_req(req);
39
}
106
}
40
107
41
static inline void cpu_to_leguids(MSGUID *guid)
108
static void virtio_scsi_handle_event_vq(VirtIOSCSI *s, VirtQueue *vq)
42
{
109
{
43
- cpu_to_le32s(&guid->data1);
110
if (s->events_dropped) {
44
- cpu_to_le16s(&guid->data2);
111
- virtio_scsi_push_event(s, NULL, VIRTIO_SCSI_T_NO_EVENT, 0);
45
- cpu_to_le16s(&guid->data3);
112
+ VirtIOSCSIEventInfo info = {
46
+ guid->data1 = cpu_to_le32(guid->data1);
113
+ .event = VIRTIO_SCSI_T_NO_EVENT,
47
+ guid->data2 = cpu_to_le16(guid->data2);
114
+ };
48
+ guid->data3 = cpu_to_le16(guid->data3);
115
+ virtio_scsi_push_event(s, &info);
116
}
49
}
117
}
50
118
51
void vhdx_header_le_import(VHDXHeader *h);
119
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_change(SCSIBus *bus, SCSIDevice *dev, SCSISense sense)
52
diff --git a/block/vhdx-endian.c b/block/vhdx-endian.c
120
53
index XXXXXXX..XXXXXXX 100644
121
if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_CHANGE) &&
54
--- a/block/vhdx-endian.c
122
dev->type != TYPE_ROM) {
55
+++ b/block/vhdx-endian.c
123
+ VirtIOSCSIEventInfo info = {
56
@@ -XXX,XX +XXX,XX @@ void vhdx_header_le_import(VHDXHeader *h)
124
+ .event = VIRTIO_SCSI_T_PARAM_CHANGE,
57
{
125
+ .reason = sense.asc | (sense.ascq << 8),
58
assert(h != NULL);
126
+ .address = {
59
127
+ .id = dev->id,
60
- le32_to_cpus(&h->signature);
128
+ .lun = dev->lun,
61
- le32_to_cpus(&h->checksum);
129
+ },
62
- le64_to_cpus(&h->sequence_number);
130
+ };
63
+ h->signature = le32_to_cpu(h->signature);
131
+
64
+ h->checksum = le32_to_cpu(h->checksum);
132
virtio_scsi_acquire(s);
65
+ h->sequence_number = le64_to_cpu(h->sequence_number);
133
- virtio_scsi_push_event(s, dev, VIRTIO_SCSI_T_PARAM_CHANGE,
66
134
- sense.asc | (sense.ascq << 8));
67
leguid_to_cpus(&h->file_write_guid);
135
+ virtio_scsi_push_event(s, &info);
68
leguid_to_cpus(&h->data_write_guid);
136
virtio_scsi_release(s);
69
leguid_to_cpus(&h->log_guid);
137
}
70
71
- le16_to_cpus(&h->log_version);
72
- le16_to_cpus(&h->version);
73
- le32_to_cpus(&h->log_length);
74
- le64_to_cpus(&h->log_offset);
75
+ h->log_version = le16_to_cpu(h->log_version);
76
+ h->version = le16_to_cpu(h->version);
77
+ h->log_length = le32_to_cpu(h->log_length);
78
+ h->log_offset = le64_to_cpu(h->log_offset);
79
}
138
}
80
139
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev,
81
void vhdx_header_le_export(VHDXHeader *orig_h, VHDXHeader *new_h)
140
}
82
@@ -XXX,XX +XXX,XX @@ void vhdx_log_desc_le_import(VHDXLogDescriptor *d)
141
83
{
142
if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) {
84
assert(d != NULL);
143
+ VirtIOSCSIEventInfo info = {
85
144
+ .event = VIRTIO_SCSI_T_TRANSPORT_RESET,
86
- le32_to_cpus(&d->signature);
145
+ .reason = VIRTIO_SCSI_EVT_RESET_RESCAN,
87
- le64_to_cpus(&d->file_offset);
146
+ .address = {
88
- le64_to_cpus(&d->sequence_number);
147
+ .id = sd->id,
89
+ d->signature = le32_to_cpu(d->signature);
148
+ .lun = sd->lun,
90
+ d->file_offset = le64_to_cpu(d->file_offset);
149
+ },
91
+ d->sequence_number = le64_to_cpu(d->sequence_number);
150
+ };
151
+
152
virtio_scsi_acquire(s);
153
- virtio_scsi_push_event(s, sd,
154
- VIRTIO_SCSI_T_TRANSPORT_RESET,
155
- VIRTIO_SCSI_EVT_RESET_RESCAN);
156
+ virtio_scsi_push_event(s, &info);
157
scsi_bus_set_ua(&s->bus, SENSE_CODE(REPORTED_LUNS_CHANGED));
158
virtio_scsi_release(s);
159
}
160
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_hotunplug(HotplugHandler *hotplug_dev, DeviceState *dev,
161
VirtIOSCSI *s = VIRTIO_SCSI(vdev);
162
SCSIDevice *sd = SCSI_DEVICE(dev);
163
AioContext *ctx = s->ctx ?: qemu_get_aio_context();
164
-
165
- if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) {
166
- virtio_scsi_acquire(s);
167
- virtio_scsi_push_event(s, sd,
168
- VIRTIO_SCSI_T_TRANSPORT_RESET,
169
- VIRTIO_SCSI_EVT_RESET_REMOVED);
170
- scsi_bus_set_ua(&s->bus, SENSE_CODE(REPORTED_LUNS_CHANGED));
171
- virtio_scsi_release(s);
172
- }
173
+ VirtIOSCSIEventInfo info = {
174
+ .event = VIRTIO_SCSI_T_TRANSPORT_RESET,
175
+ .reason = VIRTIO_SCSI_EVT_RESET_REMOVED,
176
+ .address = {
177
+ .id = sd->id,
178
+ .lun = sd->lun,
179
+ },
180
+ };
181
182
aio_disable_external(ctx);
183
qdev_simple_device_unplug_cb(hotplug_dev, dev, errp);
184
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_hotunplug(HotplugHandler *hotplug_dev, DeviceState *dev,
185
blk_set_aio_context(sd->conf.blk, qemu_get_aio_context(), NULL);
186
virtio_scsi_release(s);
187
}
188
+
189
+ if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) {
190
+ virtio_scsi_acquire(s);
191
+ virtio_scsi_push_event(s, &info);
192
+ scsi_bus_set_ua(&s->bus, SENSE_CODE(REPORTED_LUNS_CHANGED));
193
+ virtio_scsi_release(s);
194
+ }
92
}
195
}
93
196
94
void vhdx_log_desc_le_export(VHDXLogDescriptor *d)
197
static struct SCSIBusInfo virtio_scsi_scsi_info = {
95
{
96
assert(d != NULL);
97
98
- cpu_to_le32s(&d->signature);
99
- cpu_to_le32s(&d->trailing_bytes);
100
- cpu_to_le64s(&d->leading_bytes);
101
- cpu_to_le64s(&d->file_offset);
102
- cpu_to_le64s(&d->sequence_number);
103
+ d->signature = cpu_to_le32(d->signature);
104
+ d->trailing_bytes = cpu_to_le32(d->trailing_bytes);
105
+ d->leading_bytes = cpu_to_le64(d->leading_bytes);
106
+ d->file_offset = cpu_to_le64(d->file_offset);
107
+ d->sequence_number = cpu_to_le64(d->sequence_number);
108
}
109
110
void vhdx_log_data_le_import(VHDXLogDataSector *d)
111
{
112
assert(d != NULL);
113
114
- le32_to_cpus(&d->data_signature);
115
- le32_to_cpus(&d->sequence_high);
116
- le32_to_cpus(&d->sequence_low);
117
+ d->data_signature = le32_to_cpu(d->data_signature);
118
+ d->sequence_high = le32_to_cpu(d->sequence_high);
119
+ d->sequence_low = le32_to_cpu(d->sequence_low);
120
}
121
122
void vhdx_log_data_le_export(VHDXLogDataSector *d)
123
{
124
assert(d != NULL);
125
126
- cpu_to_le32s(&d->data_signature);
127
- cpu_to_le32s(&d->sequence_high);
128
- cpu_to_le32s(&d->sequence_low);
129
+ d->data_signature = cpu_to_le32(d->data_signature);
130
+ d->sequence_high = cpu_to_le32(d->sequence_high);
131
+ d->sequence_low = cpu_to_le32(d->sequence_low);
132
}
133
134
void vhdx_log_entry_hdr_le_import(VHDXLogEntryHeader *hdr)
135
{
136
assert(hdr != NULL);
137
138
- le32_to_cpus(&hdr->signature);
139
- le32_to_cpus(&hdr->checksum);
140
- le32_to_cpus(&hdr->entry_length);
141
- le32_to_cpus(&hdr->tail);
142
- le64_to_cpus(&hdr->sequence_number);
143
- le32_to_cpus(&hdr->descriptor_count);
144
+ hdr->signature = le32_to_cpu(hdr->signature);
145
+ hdr->checksum = le32_to_cpu(hdr->checksum);
146
+ hdr->entry_length = le32_to_cpu(hdr->entry_length);
147
+ hdr->tail = le32_to_cpu(hdr->tail);
148
+ hdr->sequence_number = le64_to_cpu(hdr->sequence_number);
149
+ hdr->descriptor_count = le32_to_cpu(hdr->descriptor_count);
150
leguid_to_cpus(&hdr->log_guid);
151
- le64_to_cpus(&hdr->flushed_file_offset);
152
- le64_to_cpus(&hdr->last_file_offset);
153
+ hdr->flushed_file_offset = le64_to_cpu(hdr->flushed_file_offset);
154
+ hdr->last_file_offset = le64_to_cpu(hdr->last_file_offset);
155
}
156
157
void vhdx_log_entry_hdr_le_export(VHDXLogEntryHeader *hdr)
158
{
159
assert(hdr != NULL);
160
161
- cpu_to_le32s(&hdr->signature);
162
- cpu_to_le32s(&hdr->checksum);
163
- cpu_to_le32s(&hdr->entry_length);
164
- cpu_to_le32s(&hdr->tail);
165
- cpu_to_le64s(&hdr->sequence_number);
166
- cpu_to_le32s(&hdr->descriptor_count);
167
+ hdr->signature = cpu_to_le32(hdr->signature);
168
+ hdr->checksum = cpu_to_le32(hdr->checksum);
169
+ hdr->entry_length = cpu_to_le32(hdr->entry_length);
170
+ hdr->tail = cpu_to_le32(hdr->tail);
171
+ hdr->sequence_number = cpu_to_le64(hdr->sequence_number);
172
+ hdr->descriptor_count = cpu_to_le32(hdr->descriptor_count);
173
cpu_to_leguids(&hdr->log_guid);
174
- cpu_to_le64s(&hdr->flushed_file_offset);
175
- cpu_to_le64s(&hdr->last_file_offset);
176
+ hdr->flushed_file_offset = cpu_to_le64(hdr->flushed_file_offset);
177
+ hdr->last_file_offset = cpu_to_le64(hdr->last_file_offset);
178
}
179
180
181
@@ -XXX,XX +XXX,XX @@ void vhdx_region_header_le_import(VHDXRegionTableHeader *hdr)
182
{
183
assert(hdr != NULL);
184
185
- le32_to_cpus(&hdr->signature);
186
- le32_to_cpus(&hdr->checksum);
187
- le32_to_cpus(&hdr->entry_count);
188
+ hdr->signature = le32_to_cpu(hdr->signature);
189
+ hdr->checksum = le32_to_cpu(hdr->checksum);
190
+ hdr->entry_count = le32_to_cpu(hdr->entry_count);
191
}
192
193
void vhdx_region_header_le_export(VHDXRegionTableHeader *hdr)
194
{
195
assert(hdr != NULL);
196
197
- cpu_to_le32s(&hdr->signature);
198
- cpu_to_le32s(&hdr->checksum);
199
- cpu_to_le32s(&hdr->entry_count);
200
+ hdr->signature = cpu_to_le32(hdr->signature);
201
+ hdr->checksum = cpu_to_le32(hdr->checksum);
202
+ hdr->entry_count = cpu_to_le32(hdr->entry_count);
203
}
204
205
void vhdx_region_entry_le_import(VHDXRegionTableEntry *e)
206
@@ -XXX,XX +XXX,XX @@ void vhdx_region_entry_le_import(VHDXRegionTableEntry *e)
207
assert(e != NULL);
208
209
leguid_to_cpus(&e->guid);
210
- le64_to_cpus(&e->file_offset);
211
- le32_to_cpus(&e->length);
212
- le32_to_cpus(&e->data_bits);
213
+ e->file_offset = le64_to_cpu(e->file_offset);
214
+ e->length = le32_to_cpu(e->length);
215
+ e->data_bits = le32_to_cpu(e->data_bits);
216
}
217
218
void vhdx_region_entry_le_export(VHDXRegionTableEntry *e)
219
@@ -XXX,XX +XXX,XX @@ void vhdx_region_entry_le_export(VHDXRegionTableEntry *e)
220
assert(e != NULL);
221
222
cpu_to_leguids(&e->guid);
223
- cpu_to_le64s(&e->file_offset);
224
- cpu_to_le32s(&e->length);
225
- cpu_to_le32s(&e->data_bits);
226
+ e->file_offset = cpu_to_le64(e->file_offset);
227
+ e->length = cpu_to_le32(e->length);
228
+ e->data_bits = cpu_to_le32(e->data_bits);
229
}
230
231
232
@@ -XXX,XX +XXX,XX @@ void vhdx_metadata_header_le_import(VHDXMetadataTableHeader *hdr)
233
{
234
assert(hdr != NULL);
235
236
- le64_to_cpus(&hdr->signature);
237
- le16_to_cpus(&hdr->entry_count);
238
+ hdr->signature = le64_to_cpu(hdr->signature);
239
+ hdr->entry_count = le16_to_cpu(hdr->entry_count);
240
}
241
242
void vhdx_metadata_header_le_export(VHDXMetadataTableHeader *hdr)
243
{
244
assert(hdr != NULL);
245
246
- cpu_to_le64s(&hdr->signature);
247
- cpu_to_le16s(&hdr->entry_count);
248
+ hdr->signature = cpu_to_le64(hdr->signature);
249
+ hdr->entry_count = cpu_to_le16(hdr->entry_count);
250
}
251
252
void vhdx_metadata_entry_le_import(VHDXMetadataTableEntry *e)
253
@@ -XXX,XX +XXX,XX @@ void vhdx_metadata_entry_le_import(VHDXMetadataTableEntry *e)
254
assert(e != NULL);
255
256
leguid_to_cpus(&e->item_id);
257
- le32_to_cpus(&e->offset);
258
- le32_to_cpus(&e->length);
259
- le32_to_cpus(&e->data_bits);
260
+ e->offset = le32_to_cpu(e->offset);
261
+ e->length = le32_to_cpu(e->length);
262
+ e->data_bits = le32_to_cpu(e->data_bits);
263
}
264
void vhdx_metadata_entry_le_export(VHDXMetadataTableEntry *e)
265
{
266
assert(e != NULL);
267
268
cpu_to_leguids(&e->item_id);
269
- cpu_to_le32s(&e->offset);
270
- cpu_to_le32s(&e->length);
271
- cpu_to_le32s(&e->data_bits);
272
+ e->offset = cpu_to_le32(e->offset);
273
+ e->length = cpu_to_le32(e->length);
274
+ e->data_bits = cpu_to_le32(e->data_bits);
275
}
276
diff --git a/block/vhdx-log.c b/block/vhdx-log.c
277
index XXXXXXX..XXXXXXX 100644
278
--- a/block/vhdx-log.c
279
+++ b/block/vhdx-log.c
280
@@ -XXX,XX +XXX,XX @@ static void vhdx_log_raw_to_le_sector(VHDXLogDescriptor *desc,
281
/* 8 + 4084 + 4 = 4096, 1 log sector */
282
memcpy(&desc->leading_bytes, data, 8);
283
data += 8;
284
- cpu_to_le64s(&desc->leading_bytes);
285
+ desc->leading_bytes = cpu_to_le64(desc->leading_bytes);
286
memcpy(sector->data, data, 4084);
287
data += 4084;
288
memcpy(&desc->trailing_bytes, data, 4);
289
- cpu_to_le32s(&desc->trailing_bytes);
290
+ desc->trailing_bytes = cpu_to_le32(desc->trailing_bytes);
291
data += 4;
292
293
sector->sequence_high = (uint32_t) (seq >> 32);
294
diff --git a/block/vhdx.c b/block/vhdx.c
295
index XXXXXXX..XXXXXXX 100644
296
--- a/block/vhdx.c
297
+++ b/block/vhdx.c
298
@@ -XXX,XX +XXX,XX @@ uint32_t vhdx_update_checksum(uint8_t *buf, size_t size, int crc_offset)
299
300
memset(buf + crc_offset, 0, sizeof(crc));
301
crc = crc32c(0xffffffff, buf, size);
302
- cpu_to_le32s(&crc);
303
+ crc = cpu_to_le32(crc);
304
memcpy(buf + crc_offset, &crc, sizeof(crc));
305
306
return crc;
307
@@ -XXX,XX +XXX,XX @@ static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s)
308
goto exit;
309
}
310
311
- le32_to_cpus(&s->params.block_size);
312
- le32_to_cpus(&s->params.data_bits);
313
+ s->params.block_size = le32_to_cpu(s->params.block_size);
314
+ s->params.data_bits = le32_to_cpu(s->params.data_bits);
315
316
317
/* We now have the file parameters, so we can tell if this is a
318
@@ -XXX,XX +XXX,XX @@ static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s)
319
goto exit;
320
}
321
322
- le64_to_cpus(&s->virtual_disk_size);
323
- le32_to_cpus(&s->logical_sector_size);
324
- le32_to_cpus(&s->physical_sector_size);
325
+ s->virtual_disk_size = le64_to_cpu(s->virtual_disk_size);
326
+ s->logical_sector_size = le32_to_cpu(s->logical_sector_size);
327
+ s->physical_sector_size = le32_to_cpu(s->physical_sector_size);
328
329
if (s->params.block_size < VHDX_BLOCK_SIZE_MIN ||
330
s->params.block_size > VHDX_BLOCK_SIZE_MAX) {
331
@@ -XXX,XX +XXX,XX @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags,
332
/* endian convert, and verify populated BAT field file offsets against
333
* region table and log entries */
334
for (i = 0; i < s->bat_entries; i++) {
335
- le64_to_cpus(&s->bat[i]);
336
+ s->bat[i] = le64_to_cpu(s->bat[i]);
337
if (payblocks--) {
338
/* payload bat entries */
339
if ((s->bat[i] & VHDX_BAT_STATE_BIT_MASK) ==
340
@@ -XXX,XX +XXX,XX @@ static int vhdx_create_new_metadata(BlockBackend *blk,
341
mt_file_params->block_size = cpu_to_le32(block_size);
342
if (type == VHDX_TYPE_FIXED) {
343
mt_file_params->data_bits |= VHDX_PARAMS_LEAVE_BLOCKS_ALLOCED;
344
- cpu_to_le32s(&mt_file_params->data_bits);
345
+ mt_file_params->data_bits = cpu_to_le32(mt_file_params->data_bits);
346
}
347
348
vhdx_guid_generate(&mt_page83->page_83_data);
349
@@ -XXX,XX +XXX,XX @@ static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
350
sinfo.file_offset = ROUND_UP(sinfo.file_offset, MiB);
351
vhdx_update_bat_table_entry(blk_bs(blk), s, &sinfo, &unused, &unused,
352
block_state);
353
- cpu_to_le64s(&s->bat[sinfo.bat_idx]);
354
+ s->bat[sinfo.bat_idx] = cpu_to_le64(s->bat[sinfo.bat_idx]);
355
sector_num += s->sectors_per_block;
356
}
357
ret = blk_pwrite(blk, file_offset, s->bat, length, 0);
358
--
198
--
359
2.19.1
199
2.40.1
360
361
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
Signed-off-by: Alberto Garcia <berto@igalia.com>
3
This patch is part of an effort to remove the aio_disable_external()
4
API because it does not fit in a multi-queue block layer world where
5
many AioContexts may be submitting requests to the same disk.
6
7
The SCSI emulation code is already in good shape to stop using
8
aio_disable_external(). It was only used by commit 9c5aad84da1c
9
("virtio-scsi: fixed virtio_scsi_ctx_check failed when detaching scsi
10
disk") to ensure that virtio_scsi_hotunplug() works while the guest
11
driver is submitting I/O.
12
13
Ensure virtio_scsi_hotunplug() is safe as follows:
14
15
1. qdev_simple_device_unplug_cb() -> qdev_unrealize() ->
16
device_set_realized() calls qatomic_set(&dev->realized, false) so
17
that future scsi_device_get() calls return NULL because they exclude
18
SCSIDevices with realized=false.
19
20
That means virtio-scsi will reject new I/O requests to this
21
SCSIDevice with VIRTIO_SCSI_S_BAD_TARGET even while
22
virtio_scsi_hotunplug() is still executing. We are protected against
23
new requests!
24
25
2. scsi_qdev_unrealize() already contains a call to
26
scsi_device_purge_requests() so that in-flight requests are cancelled
27
synchronously. This ensures that no in-flight requests remain once
28
qdev_simple_device_unplug_cb() returns.
29
30
Thanks to these two conditions we don't need aio_disable_external()
31
anymore.
32
33
Cc: Zhengui Li <lizhengui@huawei.com>
34
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
35
Reviewed-by: Daniil Tatianin <d-tatianin@yandex-team.ru>
36
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
37
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
38
Message-Id: <20230516190238.8401-5-stefanha@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
39
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
---
40
---
6
tests/qemu-iotests/081 | 30 ++++++++++++++++++++++++++++++
41
hw/scsi/virtio-scsi.c | 3 ---
7
tests/qemu-iotests/081.out | 16 ++++++++++++++++
42
1 file changed, 3 deletions(-)
8
2 files changed, 46 insertions(+)
9
43
10
diff --git a/tests/qemu-iotests/081 b/tests/qemu-iotests/081
44
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
11
index XXXXXXX..XXXXXXX 100755
12
--- a/tests/qemu-iotests/081
13
+++ b/tests/qemu-iotests/081
14
@@ -XXX,XX +XXX,XX @@ echo "== checking that quorum is broken =="
15
16
$QEMU_IO -c "open -o $quorum" -c "read -P 0x32 0 $size" | _filter_qemu_io
17
18
+echo
19
+echo "== checking the blkverify mode with broken content =="
20
+
21
+quorum="driver=raw,file.driver=quorum,file.vote-threshold=2,file.blkverify=on"
22
+quorum="$quorum,file.children.0.file.filename=$TEST_DIR/1.raw"
23
+quorum="$quorum,file.children.1.file.filename=$TEST_DIR/2.raw"
24
+quorum="$quorum,file.children.0.driver=raw"
25
+quorum="$quorum,file.children.1.driver=raw"
26
+
27
+$QEMU_IO -c "open -o $quorum" -c "read -P 0x32 0 $size" | _filter_qemu_io
28
+
29
+echo
30
+echo "== writing the same data to both files =="
31
+
32
+$QEMU_IO -c "write -P 0x32 0 $size" "$TEST_DIR/1.raw" | _filter_qemu_io
33
+$QEMU_IO -c "write -P 0x32 0 $size" "$TEST_DIR/2.raw" | _filter_qemu_io
34
+
35
+echo
36
+echo "== checking the blkverify mode with valid content =="
37
+
38
+$QEMU_IO -c "open -o $quorum" -c "read -P 0x32 0 $size" | _filter_qemu_io
39
+
40
+echo
41
+echo "== checking the blkverify mode with invalid settings =="
42
+
43
+quorum="$quorum,file.children.2.file.filename=$TEST_DIR/3.raw"
44
+quorum="$quorum,file.children.2.driver=raw"
45
+
46
+$QEMU_IO -c "open -o $quorum" | _filter_qemu_io
47
+
48
# success, all done
49
echo "*** done"
50
rm -f $seq.full
51
diff --git a/tests/qemu-iotests/081.out b/tests/qemu-iotests/081.out
52
index XXXXXXX..XXXXXXX 100644
45
index XXXXXXX..XXXXXXX 100644
53
--- a/tests/qemu-iotests/081.out
46
--- a/hw/scsi/virtio-scsi.c
54
+++ b/tests/qemu-iotests/081.out
47
+++ b/hw/scsi/virtio-scsi.c
55
@@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 0
48
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_hotunplug(HotplugHandler *hotplug_dev, DeviceState *dev,
56
49
VirtIODevice *vdev = VIRTIO_DEVICE(hotplug_dev);
57
== checking that quorum is broken ==
50
VirtIOSCSI *s = VIRTIO_SCSI(vdev);
58
read failed: Input/output error
51
SCSIDevice *sd = SCSI_DEVICE(dev);
59
+
52
- AioContext *ctx = s->ctx ?: qemu_get_aio_context();
60
+== checking the blkverify mode with broken content ==
53
VirtIOSCSIEventInfo info = {
61
+quorum: offset=0 bytes=10485760 contents mismatch at offset 0
54
.event = VIRTIO_SCSI_T_TRANSPORT_RESET,
62
+
55
.reason = VIRTIO_SCSI_EVT_RESET_REMOVED,
63
+== writing the same data to both files ==
56
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_hotunplug(HotplugHandler *hotplug_dev, DeviceState *dev,
64
+wrote 10485760/10485760 bytes at offset 0
57
},
65
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
58
};
66
+wrote 10485760/10485760 bytes at offset 0
59
67
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
60
- aio_disable_external(ctx);
68
+
61
qdev_simple_device_unplug_cb(hotplug_dev, dev, errp);
69
+== checking the blkverify mode with valid content ==
62
- aio_enable_external(ctx);
70
+read 10485760/10485760 bytes at offset 0
63
71
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
64
if (s->ctx) {
72
+
65
virtio_scsi_acquire(s);
73
+== checking the blkverify mode with invalid settings ==
74
+can't open: blkverify=on can only be set if there are exactly two files and vote-threshold is 2
75
*** done
76
--
66
--
77
2.19.1
67
2.40.1
78
79
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
This adds some whitespace into the option help (including indentation)
3
The VuServer object has a refcount field and ref/unref APIs. The name is
4
and puts angle brackets around the type names. Furthermore, the list
4
confusing because it's actually an in-flight request counter instead of
5
name is no longer printed as part of every line, but only once in
5
a refcount.
6
advance, and only if the caller did not print a caption already.
7
6
8
This patch also restores the description alignment we had before commit
7
Normally a refcount destroys the object upon reaching zero. The VuServer
9
9cbef9d68ee1d8d0, just at 24 instead of 16 characters like we used to.
8
counter is used to wake up the vhost-user coroutine when there are no
10
This increase is because now we have the type and two spaces of
9
more requests.
11
indentation before the description, and with a usual type name length of
12
three chracters, this sums up to eight additional characters -- which
13
means that we now need 24 characters to get the same amount of padding
14
for most options. Also, 24 is a third of 80, which makes it kind of a
15
round number in terminal terms.
16
10
17
Finally, this patch amends the reference output of iotest 082 to match
11
Avoid confusing by renaming refcount and ref/unref to in_flight and
18
the changes (and thus makes it pass again).
12
inc/dec.
19
13
20
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
21
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
15
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
16
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
17
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
18
Message-Id: <20230516190238.8401-6-stefanha@redhat.com>
22
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
23
---
20
---
24
include/qemu/option.h | 2 +-
21
include/qemu/vhost-user-server.h | 6 +++---
25
qemu-img.c | 4 +-
22
block/export/vhost-user-blk-server.c | 11 +++++++----
26
util/qemu-option.c | 32 +-
23
util/vhost-user-server.c | 14 +++++++-------
27
tests/qemu-iotests/082.out | 956 ++++++++++++++++++-------------------
24
3 files changed, 17 insertions(+), 14 deletions(-)
28
4 files changed, 507 insertions(+), 487 deletions(-)
29
25
30
diff --git a/include/qemu/option.h b/include/qemu/option.h
26
diff --git a/include/qemu/vhost-user-server.h b/include/qemu/vhost-user-server.h
31
index XXXXXXX..XXXXXXX 100644
27
index XXXXXXX..XXXXXXX 100644
32
--- a/include/qemu/option.h
28
--- a/include/qemu/vhost-user-server.h
33
+++ b/include/qemu/option.h
29
+++ b/include/qemu/vhost-user-server.h
34
@@ -XXX,XX +XXX,XX @@ typedef int (*qemu_opts_loopfunc)(void *opaque, QemuOpts *opts, Error **errp);
30
@@ -XXX,XX +XXX,XX @@ typedef struct {
35
int qemu_opts_foreach(QemuOptsList *list, qemu_opts_loopfunc func,
31
const VuDevIface *vu_iface;
36
void *opaque, Error **errp);
32
37
void qemu_opts_print(QemuOpts *opts, const char *sep);
33
/* Protected by ctx lock */
38
-void qemu_opts_print_help(QemuOptsList *list);
34
- unsigned int refcount;
39
+void qemu_opts_print_help(QemuOptsList *list, bool print_caption);
35
+ unsigned int in_flight;
40
void qemu_opts_free(QemuOptsList *list);
36
bool wait_idle;
41
QemuOptsList *qemu_opts_append(QemuOptsList *dst, QemuOptsList *list);
37
VuDev vu_dev;
42
38
QIOChannel *ioc; /* The I/O channel with the client */
43
diff --git a/qemu-img.c b/qemu-img.c
39
@@ -XXX,XX +XXX,XX @@ bool vhost_user_server_start(VuServer *server,
40
41
void vhost_user_server_stop(VuServer *server);
42
43
-void vhost_user_server_ref(VuServer *server);
44
-void vhost_user_server_unref(VuServer *server);
45
+void vhost_user_server_inc_in_flight(VuServer *server);
46
+void vhost_user_server_dec_in_flight(VuServer *server);
47
48
void vhost_user_server_attach_aio_context(VuServer *server, AioContext *ctx);
49
void vhost_user_server_detach_aio_context(VuServer *server);
50
diff --git a/block/export/vhost-user-blk-server.c b/block/export/vhost-user-blk-server.c
44
index XXXXXXX..XXXXXXX 100644
51
index XXXXXXX..XXXXXXX 100644
45
--- a/qemu-img.c
52
--- a/block/export/vhost-user-blk-server.c
46
+++ b/qemu-img.c
53
+++ b/block/export/vhost-user-blk-server.c
47
@@ -XXX,XX +XXX,XX @@ static int print_block_option_help(const char *filename, const char *fmt)
54
@@ -XXX,XX +XXX,XX @@ static void vu_blk_req_complete(VuBlkReq *req, size_t in_len)
55
free(req);
56
}
57
58
-/* Called with server refcount increased, must decrease before returning */
59
+/*
60
+ * Called with server in_flight counter increased, must decrease before
61
+ * returning.
62
+ */
63
static void coroutine_fn vu_blk_virtio_process_req(void *opaque)
64
{
65
VuBlkReq *req = opaque;
66
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn vu_blk_virtio_process_req(void *opaque)
67
in_num, out_num);
68
if (in_len < 0) {
69
free(req);
70
- vhost_user_server_unref(server);
71
+ vhost_user_server_dec_in_flight(server);
72
return;
48
}
73
}
49
74
50
printf("Supported options:\n");
75
vu_blk_req_complete(req, in_len);
51
- qemu_opts_print_help(create_opts);
76
- vhost_user_server_unref(server);
52
+ qemu_opts_print_help(create_opts, false);
77
+ vhost_user_server_dec_in_flight(server);
53
qemu_opts_free(create_opts);
54
return 0;
55
}
78
}
56
@@ -XXX,XX +XXX,XX @@ static int print_amend_option_help(const char *format)
79
57
assert(drv->create_opts);
80
static void vu_blk_process_vq(VuDev *vu_dev, int idx)
58
81
@@ -XXX,XX +XXX,XX @@ static void vu_blk_process_vq(VuDev *vu_dev, int idx)
59
printf("Creation options for '%s':\n", format);
82
Coroutine *co =
60
- qemu_opts_print_help(drv->create_opts);
83
qemu_coroutine_create(vu_blk_virtio_process_req, req);
61
+ qemu_opts_print_help(drv->create_opts, false);
84
62
printf("\nNote that not all of these options may be amendable.\n");
85
- vhost_user_server_ref(server);
63
return 0;
86
+ vhost_user_server_inc_in_flight(server);
87
qemu_coroutine_enter(co);
88
}
64
}
89
}
65
diff --git a/util/qemu-option.c b/util/qemu-option.c
90
diff --git a/util/vhost-user-server.c b/util/vhost-user-server.c
66
index XXXXXXX..XXXXXXX 100644
91
index XXXXXXX..XXXXXXX 100644
67
--- a/util/qemu-option.c
92
--- a/util/vhost-user-server.c
68
+++ b/util/qemu-option.c
93
+++ b/util/vhost-user-server.c
69
@@ -XXX,XX +XXX,XX @@ static const char *opt_type_to_string(enum QemuOptType type)
94
@@ -XXX,XX +XXX,XX @@ static void panic_cb(VuDev *vu_dev, const char *buf)
70
g_assert_not_reached();
95
error_report("vu_panic: %s", buf);
71
}
96
}
72
97
73
-void qemu_opts_print_help(QemuOptsList *list)
98
-void vhost_user_server_ref(VuServer *server)
74
+/**
99
+void vhost_user_server_inc_in_flight(VuServer *server)
75
+ * Print the list of options available in the given list. If
76
+ * @print_caption is true, a caption (including the list name, if it
77
+ * exists) is printed. The options itself will be indented, so
78
+ * @print_caption should only be set to false if the caller prints its
79
+ * own custom caption (so that the indentation makes sense).
80
+ */
81
+void qemu_opts_print_help(QemuOptsList *list, bool print_caption)
82
{
100
{
83
QemuOptDesc *desc;
101
assert(!server->wait_idle);
84
int i;
102
- server->refcount++;
85
@@ -XXX,XX +XXX,XX @@ void qemu_opts_print_help(QemuOptsList *list)
103
+ server->in_flight++;
86
desc = list->desc;
104
}
87
while (desc && desc->name) {
105
88
GString *str = g_string_new(NULL);
106
-void vhost_user_server_unref(VuServer *server)
89
- if (list->name) {
107
+void vhost_user_server_dec_in_flight(VuServer *server)
90
- g_string_append_printf(str, "%s.", list->name);
108
{
91
- }
109
- server->refcount--;
92
- g_string_append_printf(str, "%s=%s", desc->name,
110
- if (server->wait_idle && !server->refcount) {
93
+ g_string_append_printf(str, " %s=<%s>", desc->name,
111
+ server->in_flight--;
94
opt_type_to_string(desc->type));
112
+ if (server->wait_idle && !server->in_flight) {
95
if (desc->help) {
113
aio_co_wake(server->co_trip);
96
+ if (str->len < 24) {
97
+ g_string_append_printf(str, "%*s", 24 - (int)str->len, "");
98
+ }
99
g_string_append_printf(str, " - %s", desc->help);
100
}
101
g_ptr_array_add(array, g_string_free(str, false));
102
@@ -XXX,XX +XXX,XX @@ void qemu_opts_print_help(QemuOptsList *list)
103
}
114
}
104
115
}
105
g_ptr_array_sort(array, (GCompareFunc)qemu_pstrcmp0);
116
@@ -XXX,XX +XXX,XX @@ static coroutine_fn void vu_client_trip(void *opaque)
106
+ if (print_caption && array->len > 0) {
117
/* Keep running */
107
+ if (list->name) {
108
+ printf("%s options:\n", list->name);
109
+ } else {
110
+ printf("Options:\n");
111
+ }
112
+ } else if (array->len == 0) {
113
+ if (list->name) {
114
+ printf("There are no options for %s.\n", list->name);
115
+ } else {
116
+ printf("No options available.\n");
117
+ }
118
+ }
119
for (i = 0; i < array->len; i++) {
120
printf("%s\n", (char *)array->pdata[i]);
121
}
118
}
122
@@ -XXX,XX +XXX,XX @@ QemuOpts *qemu_opts_parse_noisily(QemuOptsList *list, const char *params,
119
123
opts = opts_parse(list, params, permit_abbrev, false, &invalidp, &err);
120
- if (server->refcount) {
124
if (err) {
121
+ if (server->in_flight) {
125
if (invalidp && has_help_option(params)) {
122
/* Wait for requests to complete before we can unmap the memory */
126
- qemu_opts_print_help(list);
123
server->wait_idle = true;
127
+ qemu_opts_print_help(list, true);
124
qemu_coroutine_yield();
128
error_free(err);
125
server->wait_idle = false;
129
} else {
126
}
130
error_report_err(err);
127
- assert(server->refcount == 0);
131
diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out
128
+ assert(server->in_flight == 0);
132
index XXXXXXX..XXXXXXX 100644
129
133
--- a/tests/qemu-iotests/082.out
130
vu_deinit(vu_dev);
134
+++ b/tests/qemu-iotests/082.out
131
135
@@ -XXX,XX +XXX,XX @@ cluster_size: 8192
136
137
Testing: create -f qcow2 -o help TEST_DIR/t.qcow2 128M
138
Supported options:
139
-size Virtual disk size
140
-compat Compatibility level (0.10 or 1.1)
141
-backing_file File name of a base image
142
-backing_fmt Image format of the base image
143
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
144
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
145
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
146
-encrypt.cipher-alg Name of encryption cipher algorithm
147
-encrypt.cipher-mode Name of encryption cipher mode
148
-encrypt.ivgen-alg Name of IV generator algorithm
149
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
150
-encrypt.hash-alg Name of encryption hash algorithm
151
-encrypt.iter-time Time to spend in PBKDF in milliseconds
152
-cluster_size qcow2 cluster size
153
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
154
-lazy_refcounts Postpone refcount updates
155
-refcount_bits Width of a reference count entry in bits
156
-nocow Turn off copy-on-write (valid only on btrfs)
157
+ backing_file=<str> - File name of a base image
158
+ backing_fmt=<str> - Image format of the base image
159
+ cluster_size=<size> - qcow2 cluster size
160
+ compat=<str> - Compatibility level (0.10 or 1.1)
161
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
162
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
163
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
164
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
165
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
166
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
167
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
168
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
169
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
170
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
171
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
172
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
173
+ refcount_bits=<num> - Width of a reference count entry in bits
174
+ size=<size> - Virtual disk size
175
176
Testing: create -f qcow2 -o ? TEST_DIR/t.qcow2 128M
177
Supported options:
178
-size Virtual disk size
179
-compat Compatibility level (0.10 or 1.1)
180
-backing_file File name of a base image
181
-backing_fmt Image format of the base image
182
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
183
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
184
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
185
-encrypt.cipher-alg Name of encryption cipher algorithm
186
-encrypt.cipher-mode Name of encryption cipher mode
187
-encrypt.ivgen-alg Name of IV generator algorithm
188
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
189
-encrypt.hash-alg Name of encryption hash algorithm
190
-encrypt.iter-time Time to spend in PBKDF in milliseconds
191
-cluster_size qcow2 cluster size
192
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
193
-lazy_refcounts Postpone refcount updates
194
-refcount_bits Width of a reference count entry in bits
195
-nocow Turn off copy-on-write (valid only on btrfs)
196
+ backing_file=<str> - File name of a base image
197
+ backing_fmt=<str> - Image format of the base image
198
+ cluster_size=<size> - qcow2 cluster size
199
+ compat=<str> - Compatibility level (0.10 or 1.1)
200
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
201
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
202
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
203
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
204
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
205
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
206
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
207
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
208
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
209
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
210
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
211
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
212
+ refcount_bits=<num> - Width of a reference count entry in bits
213
+ size=<size> - Virtual disk size
214
215
Testing: create -f qcow2 -o cluster_size=4k,help TEST_DIR/t.qcow2 128M
216
Supported options:
217
-size Virtual disk size
218
-compat Compatibility level (0.10 or 1.1)
219
-backing_file File name of a base image
220
-backing_fmt Image format of the base image
221
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
222
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
223
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
224
-encrypt.cipher-alg Name of encryption cipher algorithm
225
-encrypt.cipher-mode Name of encryption cipher mode
226
-encrypt.ivgen-alg Name of IV generator algorithm
227
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
228
-encrypt.hash-alg Name of encryption hash algorithm
229
-encrypt.iter-time Time to spend in PBKDF in milliseconds
230
-cluster_size qcow2 cluster size
231
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
232
-lazy_refcounts Postpone refcount updates
233
-refcount_bits Width of a reference count entry in bits
234
-nocow Turn off copy-on-write (valid only on btrfs)
235
+ backing_file=<str> - File name of a base image
236
+ backing_fmt=<str> - Image format of the base image
237
+ cluster_size=<size> - qcow2 cluster size
238
+ compat=<str> - Compatibility level (0.10 or 1.1)
239
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
240
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
241
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
242
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
243
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
244
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
245
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
246
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
247
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
248
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
249
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
250
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
251
+ refcount_bits=<num> - Width of a reference count entry in bits
252
+ size=<size> - Virtual disk size
253
254
Testing: create -f qcow2 -o cluster_size=4k,? TEST_DIR/t.qcow2 128M
255
Supported options:
256
-size Virtual disk size
257
-compat Compatibility level (0.10 or 1.1)
258
-backing_file File name of a base image
259
-backing_fmt Image format of the base image
260
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
261
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
262
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
263
-encrypt.cipher-alg Name of encryption cipher algorithm
264
-encrypt.cipher-mode Name of encryption cipher mode
265
-encrypt.ivgen-alg Name of IV generator algorithm
266
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
267
-encrypt.hash-alg Name of encryption hash algorithm
268
-encrypt.iter-time Time to spend in PBKDF in milliseconds
269
-cluster_size qcow2 cluster size
270
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
271
-lazy_refcounts Postpone refcount updates
272
-refcount_bits Width of a reference count entry in bits
273
-nocow Turn off copy-on-write (valid only on btrfs)
274
+ backing_file=<str> - File name of a base image
275
+ backing_fmt=<str> - Image format of the base image
276
+ cluster_size=<size> - qcow2 cluster size
277
+ compat=<str> - Compatibility level (0.10 or 1.1)
278
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
279
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
280
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
281
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
282
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
283
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
284
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
285
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
286
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
287
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
288
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
289
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
290
+ refcount_bits=<num> - Width of a reference count entry in bits
291
+ size=<size> - Virtual disk size
292
293
Testing: create -f qcow2 -o help,cluster_size=4k TEST_DIR/t.qcow2 128M
294
Supported options:
295
-size Virtual disk size
296
-compat Compatibility level (0.10 or 1.1)
297
-backing_file File name of a base image
298
-backing_fmt Image format of the base image
299
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
300
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
301
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
302
-encrypt.cipher-alg Name of encryption cipher algorithm
303
-encrypt.cipher-mode Name of encryption cipher mode
304
-encrypt.ivgen-alg Name of IV generator algorithm
305
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
306
-encrypt.hash-alg Name of encryption hash algorithm
307
-encrypt.iter-time Time to spend in PBKDF in milliseconds
308
-cluster_size qcow2 cluster size
309
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
310
-lazy_refcounts Postpone refcount updates
311
-refcount_bits Width of a reference count entry in bits
312
-nocow Turn off copy-on-write (valid only on btrfs)
313
+ backing_file=<str> - File name of a base image
314
+ backing_fmt=<str> - Image format of the base image
315
+ cluster_size=<size> - qcow2 cluster size
316
+ compat=<str> - Compatibility level (0.10 or 1.1)
317
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
318
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
319
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
320
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
321
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
322
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
323
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
324
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
325
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
326
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
327
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
328
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
329
+ refcount_bits=<num> - Width of a reference count entry in bits
330
+ size=<size> - Virtual disk size
331
332
Testing: create -f qcow2 -o ?,cluster_size=4k TEST_DIR/t.qcow2 128M
333
Supported options:
334
-size Virtual disk size
335
-compat Compatibility level (0.10 or 1.1)
336
-backing_file File name of a base image
337
-backing_fmt Image format of the base image
338
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
339
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
340
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
341
-encrypt.cipher-alg Name of encryption cipher algorithm
342
-encrypt.cipher-mode Name of encryption cipher mode
343
-encrypt.ivgen-alg Name of IV generator algorithm
344
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
345
-encrypt.hash-alg Name of encryption hash algorithm
346
-encrypt.iter-time Time to spend in PBKDF in milliseconds
347
-cluster_size qcow2 cluster size
348
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
349
-lazy_refcounts Postpone refcount updates
350
-refcount_bits Width of a reference count entry in bits
351
-nocow Turn off copy-on-write (valid only on btrfs)
352
+ backing_file=<str> - File name of a base image
353
+ backing_fmt=<str> - Image format of the base image
354
+ cluster_size=<size> - qcow2 cluster size
355
+ compat=<str> - Compatibility level (0.10 or 1.1)
356
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
357
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
358
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
359
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
360
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
361
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
362
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
363
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
364
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
365
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
366
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
367
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
368
+ refcount_bits=<num> - Width of a reference count entry in bits
369
+ size=<size> - Virtual disk size
370
371
Testing: create -f qcow2 -o cluster_size=4k -o help TEST_DIR/t.qcow2 128M
372
Supported options:
373
-size Virtual disk size
374
-compat Compatibility level (0.10 or 1.1)
375
-backing_file File name of a base image
376
-backing_fmt Image format of the base image
377
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
378
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
379
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
380
-encrypt.cipher-alg Name of encryption cipher algorithm
381
-encrypt.cipher-mode Name of encryption cipher mode
382
-encrypt.ivgen-alg Name of IV generator algorithm
383
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
384
-encrypt.hash-alg Name of encryption hash algorithm
385
-encrypt.iter-time Time to spend in PBKDF in milliseconds
386
-cluster_size qcow2 cluster size
387
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
388
-lazy_refcounts Postpone refcount updates
389
-refcount_bits Width of a reference count entry in bits
390
-nocow Turn off copy-on-write (valid only on btrfs)
391
+ backing_file=<str> - File name of a base image
392
+ backing_fmt=<str> - Image format of the base image
393
+ cluster_size=<size> - qcow2 cluster size
394
+ compat=<str> - Compatibility level (0.10 or 1.1)
395
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
396
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
397
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
398
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
399
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
400
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
401
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
402
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
403
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
404
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
405
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
406
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
407
+ refcount_bits=<num> - Width of a reference count entry in bits
408
+ size=<size> - Virtual disk size
409
410
Testing: create -f qcow2 -o cluster_size=4k -o ? TEST_DIR/t.qcow2 128M
411
Supported options:
412
-size Virtual disk size
413
-compat Compatibility level (0.10 or 1.1)
414
-backing_file File name of a base image
415
-backing_fmt Image format of the base image
416
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
417
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
418
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
419
-encrypt.cipher-alg Name of encryption cipher algorithm
420
-encrypt.cipher-mode Name of encryption cipher mode
421
-encrypt.ivgen-alg Name of IV generator algorithm
422
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
423
-encrypt.hash-alg Name of encryption hash algorithm
424
-encrypt.iter-time Time to spend in PBKDF in milliseconds
425
-cluster_size qcow2 cluster size
426
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
427
-lazy_refcounts Postpone refcount updates
428
-refcount_bits Width of a reference count entry in bits
429
-nocow Turn off copy-on-write (valid only on btrfs)
430
+ backing_file=<str> - File name of a base image
431
+ backing_fmt=<str> - Image format of the base image
432
+ cluster_size=<size> - qcow2 cluster size
433
+ compat=<str> - Compatibility level (0.10 or 1.1)
434
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
435
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
436
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
437
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
438
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
439
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
440
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
441
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
442
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
443
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
444
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
445
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
446
+ refcount_bits=<num> - Width of a reference count entry in bits
447
+ size=<size> - Virtual disk size
448
449
Testing: create -f qcow2 -u -o backing_file=TEST_DIR/t.qcow2,,help TEST_DIR/t.qcow2 128M
450
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2,,help cluster_size=65536 lazy_refcounts=off refcount_bits=16
451
@@ -XXX,XX +XXX,XX @@ qemu-img: Invalid option list: ,,
452
453
Testing: create -f qcow2 -o help
454
Supported options:
455
-size Virtual disk size
456
-compat Compatibility level (0.10 or 1.1)
457
-backing_file File name of a base image
458
-backing_fmt Image format of the base image
459
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
460
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
461
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
462
-encrypt.cipher-alg Name of encryption cipher algorithm
463
-encrypt.cipher-mode Name of encryption cipher mode
464
-encrypt.ivgen-alg Name of IV generator algorithm
465
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
466
-encrypt.hash-alg Name of encryption hash algorithm
467
-encrypt.iter-time Time to spend in PBKDF in milliseconds
468
-cluster_size qcow2 cluster size
469
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
470
-lazy_refcounts Postpone refcount updates
471
-refcount_bits Width of a reference count entry in bits
472
+ backing_file=<str> - File name of a base image
473
+ backing_fmt=<str> - Image format of the base image
474
+ cluster_size=<size> - qcow2 cluster size
475
+ compat=<str> - Compatibility level (0.10 or 1.1)
476
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
477
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
478
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
479
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
480
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
481
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
482
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
483
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
484
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
485
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
486
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
487
+ refcount_bits=<num> - Width of a reference count entry in bits
488
+ size=<size> - Virtual disk size
489
490
Testing: create -o help
491
Supported options:
492
-size Virtual disk size
493
+ size=<size> - Virtual disk size
494
495
Testing: create -f bochs -o help
496
qemu-img: Format driver 'bochs' does not support image creation
497
@@ -XXX,XX +XXX,XX @@ cluster_size: 8192
498
499
Testing: convert -O qcow2 -o help TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
500
Supported options:
501
-size Virtual disk size
502
-compat Compatibility level (0.10 or 1.1)
503
-backing_file File name of a base image
504
-backing_fmt Image format of the base image
505
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
506
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
507
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
508
-encrypt.cipher-alg Name of encryption cipher algorithm
509
-encrypt.cipher-mode Name of encryption cipher mode
510
-encrypt.ivgen-alg Name of IV generator algorithm
511
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
512
-encrypt.hash-alg Name of encryption hash algorithm
513
-encrypt.iter-time Time to spend in PBKDF in milliseconds
514
-cluster_size qcow2 cluster size
515
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
516
-lazy_refcounts Postpone refcount updates
517
-refcount_bits Width of a reference count entry in bits
518
-nocow Turn off copy-on-write (valid only on btrfs)
519
+ backing_file=<str> - File name of a base image
520
+ backing_fmt=<str> - Image format of the base image
521
+ cluster_size=<size> - qcow2 cluster size
522
+ compat=<str> - Compatibility level (0.10 or 1.1)
523
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
524
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
525
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
526
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
527
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
528
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
529
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
530
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
531
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
532
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
533
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
534
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
535
+ refcount_bits=<num> - Width of a reference count entry in bits
536
+ size=<size> - Virtual disk size
537
538
Testing: convert -O qcow2 -o ? TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
539
Supported options:
540
-size Virtual disk size
541
-compat Compatibility level (0.10 or 1.1)
542
-backing_file File name of a base image
543
-backing_fmt Image format of the base image
544
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
545
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
546
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
547
-encrypt.cipher-alg Name of encryption cipher algorithm
548
-encrypt.cipher-mode Name of encryption cipher mode
549
-encrypt.ivgen-alg Name of IV generator algorithm
550
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
551
-encrypt.hash-alg Name of encryption hash algorithm
552
-encrypt.iter-time Time to spend in PBKDF in milliseconds
553
-cluster_size qcow2 cluster size
554
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
555
-lazy_refcounts Postpone refcount updates
556
-refcount_bits Width of a reference count entry in bits
557
-nocow Turn off copy-on-write (valid only on btrfs)
558
+ backing_file=<str> - File name of a base image
559
+ backing_fmt=<str> - Image format of the base image
560
+ cluster_size=<size> - qcow2 cluster size
561
+ compat=<str> - Compatibility level (0.10 or 1.1)
562
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
563
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
564
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
565
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
566
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
567
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
568
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
569
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
570
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
571
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
572
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
573
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
574
+ refcount_bits=<num> - Width of a reference count entry in bits
575
+ size=<size> - Virtual disk size
576
577
Testing: convert -O qcow2 -o cluster_size=4k,help TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
578
Supported options:
579
-size Virtual disk size
580
-compat Compatibility level (0.10 or 1.1)
581
-backing_file File name of a base image
582
-backing_fmt Image format of the base image
583
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
584
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
585
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
586
-encrypt.cipher-alg Name of encryption cipher algorithm
587
-encrypt.cipher-mode Name of encryption cipher mode
588
-encrypt.ivgen-alg Name of IV generator algorithm
589
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
590
-encrypt.hash-alg Name of encryption hash algorithm
591
-encrypt.iter-time Time to spend in PBKDF in milliseconds
592
-cluster_size qcow2 cluster size
593
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
594
-lazy_refcounts Postpone refcount updates
595
-refcount_bits Width of a reference count entry in bits
596
-nocow Turn off copy-on-write (valid only on btrfs)
597
+ backing_file=<str> - File name of a base image
598
+ backing_fmt=<str> - Image format of the base image
599
+ cluster_size=<size> - qcow2 cluster size
600
+ compat=<str> - Compatibility level (0.10 or 1.1)
601
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
602
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
603
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
604
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
605
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
606
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
607
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
608
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
609
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
610
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
611
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
612
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
613
+ refcount_bits=<num> - Width of a reference count entry in bits
614
+ size=<size> - Virtual disk size
615
616
Testing: convert -O qcow2 -o cluster_size=4k,? TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
617
Supported options:
618
-size Virtual disk size
619
-compat Compatibility level (0.10 or 1.1)
620
-backing_file File name of a base image
621
-backing_fmt Image format of the base image
622
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
623
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
624
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
625
-encrypt.cipher-alg Name of encryption cipher algorithm
626
-encrypt.cipher-mode Name of encryption cipher mode
627
-encrypt.ivgen-alg Name of IV generator algorithm
628
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
629
-encrypt.hash-alg Name of encryption hash algorithm
630
-encrypt.iter-time Time to spend in PBKDF in milliseconds
631
-cluster_size qcow2 cluster size
632
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
633
-lazy_refcounts Postpone refcount updates
634
-refcount_bits Width of a reference count entry in bits
635
-nocow Turn off copy-on-write (valid only on btrfs)
636
+ backing_file=<str> - File name of a base image
637
+ backing_fmt=<str> - Image format of the base image
638
+ cluster_size=<size> - qcow2 cluster size
639
+ compat=<str> - Compatibility level (0.10 or 1.1)
640
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
641
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
642
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
643
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
644
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
645
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
646
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
647
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
648
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
649
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
650
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
651
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
652
+ refcount_bits=<num> - Width of a reference count entry in bits
653
+ size=<size> - Virtual disk size
654
655
Testing: convert -O qcow2 -o help,cluster_size=4k TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
656
Supported options:
657
-size Virtual disk size
658
-compat Compatibility level (0.10 or 1.1)
659
-backing_file File name of a base image
660
-backing_fmt Image format of the base image
661
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
662
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
663
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
664
-encrypt.cipher-alg Name of encryption cipher algorithm
665
-encrypt.cipher-mode Name of encryption cipher mode
666
-encrypt.ivgen-alg Name of IV generator algorithm
667
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
668
-encrypt.hash-alg Name of encryption hash algorithm
669
-encrypt.iter-time Time to spend in PBKDF in milliseconds
670
-cluster_size qcow2 cluster size
671
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
672
-lazy_refcounts Postpone refcount updates
673
-refcount_bits Width of a reference count entry in bits
674
-nocow Turn off copy-on-write (valid only on btrfs)
675
+ backing_file=<str> - File name of a base image
676
+ backing_fmt=<str> - Image format of the base image
677
+ cluster_size=<size> - qcow2 cluster size
678
+ compat=<str> - Compatibility level (0.10 or 1.1)
679
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
680
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
681
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
682
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
683
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
684
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
685
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
686
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
687
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
688
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
689
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
690
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
691
+ refcount_bits=<num> - Width of a reference count entry in bits
692
+ size=<size> - Virtual disk size
693
694
Testing: convert -O qcow2 -o ?,cluster_size=4k TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
695
Supported options:
696
-size Virtual disk size
697
-compat Compatibility level (0.10 or 1.1)
698
-backing_file File name of a base image
699
-backing_fmt Image format of the base image
700
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
701
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
702
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
703
-encrypt.cipher-alg Name of encryption cipher algorithm
704
-encrypt.cipher-mode Name of encryption cipher mode
705
-encrypt.ivgen-alg Name of IV generator algorithm
706
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
707
-encrypt.hash-alg Name of encryption hash algorithm
708
-encrypt.iter-time Time to spend in PBKDF in milliseconds
709
-cluster_size qcow2 cluster size
710
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
711
-lazy_refcounts Postpone refcount updates
712
-refcount_bits Width of a reference count entry in bits
713
-nocow Turn off copy-on-write (valid only on btrfs)
714
+ backing_file=<str> - File name of a base image
715
+ backing_fmt=<str> - Image format of the base image
716
+ cluster_size=<size> - qcow2 cluster size
717
+ compat=<str> - Compatibility level (0.10 or 1.1)
718
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
719
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
720
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
721
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
722
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
723
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
724
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
725
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
726
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
727
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
728
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
729
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
730
+ refcount_bits=<num> - Width of a reference count entry in bits
731
+ size=<size> - Virtual disk size
732
733
Testing: convert -O qcow2 -o cluster_size=4k -o help TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
734
Supported options:
735
-size Virtual disk size
736
-compat Compatibility level (0.10 or 1.1)
737
-backing_file File name of a base image
738
-backing_fmt Image format of the base image
739
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
740
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
741
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
742
-encrypt.cipher-alg Name of encryption cipher algorithm
743
-encrypt.cipher-mode Name of encryption cipher mode
744
-encrypt.ivgen-alg Name of IV generator algorithm
745
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
746
-encrypt.hash-alg Name of encryption hash algorithm
747
-encrypt.iter-time Time to spend in PBKDF in milliseconds
748
-cluster_size qcow2 cluster size
749
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
750
-lazy_refcounts Postpone refcount updates
751
-refcount_bits Width of a reference count entry in bits
752
-nocow Turn off copy-on-write (valid only on btrfs)
753
+ backing_file=<str> - File name of a base image
754
+ backing_fmt=<str> - Image format of the base image
755
+ cluster_size=<size> - qcow2 cluster size
756
+ compat=<str> - Compatibility level (0.10 or 1.1)
757
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
758
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
759
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
760
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
761
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
762
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
763
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
764
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
765
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
766
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
767
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
768
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
769
+ refcount_bits=<num> - Width of a reference count entry in bits
770
+ size=<size> - Virtual disk size
771
772
Testing: convert -O qcow2 -o cluster_size=4k -o ? TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
773
Supported options:
774
-size Virtual disk size
775
-compat Compatibility level (0.10 or 1.1)
776
-backing_file File name of a base image
777
-backing_fmt Image format of the base image
778
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
779
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
780
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
781
-encrypt.cipher-alg Name of encryption cipher algorithm
782
-encrypt.cipher-mode Name of encryption cipher mode
783
-encrypt.ivgen-alg Name of IV generator algorithm
784
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
785
-encrypt.hash-alg Name of encryption hash algorithm
786
-encrypt.iter-time Time to spend in PBKDF in milliseconds
787
-cluster_size qcow2 cluster size
788
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
789
-lazy_refcounts Postpone refcount updates
790
-refcount_bits Width of a reference count entry in bits
791
-nocow Turn off copy-on-write (valid only on btrfs)
792
+ backing_file=<str> - File name of a base image
793
+ backing_fmt=<str> - Image format of the base image
794
+ cluster_size=<size> - qcow2 cluster size
795
+ compat=<str> - Compatibility level (0.10 or 1.1)
796
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
797
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
798
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
799
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
800
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
801
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
802
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
803
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
804
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
805
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
806
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
807
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
808
+ refcount_bits=<num> - Width of a reference count entry in bits
809
+ size=<size> - Virtual disk size
810
811
Testing: convert -O qcow2 -o backing_file=TEST_DIR/t.qcow2,,help TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
812
qemu-img: Could not open 'TEST_DIR/t.qcow2.base': Could not open backing file: Could not open 'TEST_DIR/t.qcow2,help': No such file or directory
813
@@ -XXX,XX +XXX,XX @@ qemu-img: Invalid option list: ,,
814
815
Testing: convert -O qcow2 -o help
816
Supported options:
817
-size Virtual disk size
818
-compat Compatibility level (0.10 or 1.1)
819
-backing_file File name of a base image
820
-backing_fmt Image format of the base image
821
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
822
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
823
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
824
-encrypt.cipher-alg Name of encryption cipher algorithm
825
-encrypt.cipher-mode Name of encryption cipher mode
826
-encrypt.ivgen-alg Name of IV generator algorithm
827
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
828
-encrypt.hash-alg Name of encryption hash algorithm
829
-encrypt.iter-time Time to spend in PBKDF in milliseconds
830
-cluster_size qcow2 cluster size
831
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
832
-lazy_refcounts Postpone refcount updates
833
-refcount_bits Width of a reference count entry in bits
834
+ backing_file=<str> - File name of a base image
835
+ backing_fmt=<str> - Image format of the base image
836
+ cluster_size=<size> - qcow2 cluster size
837
+ compat=<str> - Compatibility level (0.10 or 1.1)
838
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
839
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
840
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
841
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
842
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
843
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
844
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
845
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
846
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
847
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
848
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
849
+ refcount_bits=<num> - Width of a reference count entry in bits
850
+ size=<size> - Virtual disk size
851
852
Testing: convert -o help
853
Supported options:
854
-size Virtual disk size
855
+ size=<size> - Virtual disk size
856
857
Testing: convert -O bochs -o help
858
qemu-img: Format driver 'bochs' does not support image creation
859
@@ -XXX,XX +XXX,XX @@ cluster_size: 65536
860
861
Testing: amend -f qcow2 -o help TEST_DIR/t.qcow2
862
Creation options for 'qcow2':
863
-size Virtual disk size
864
-compat Compatibility level (0.10 or 1.1)
865
-backing_file File name of a base image
866
-backing_fmt Image format of the base image
867
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
868
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
869
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
870
-encrypt.cipher-alg Name of encryption cipher algorithm
871
-encrypt.cipher-mode Name of encryption cipher mode
872
-encrypt.ivgen-alg Name of IV generator algorithm
873
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
874
-encrypt.hash-alg Name of encryption hash algorithm
875
-encrypt.iter-time Time to spend in PBKDF in milliseconds
876
-cluster_size qcow2 cluster size
877
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
878
-lazy_refcounts Postpone refcount updates
879
-refcount_bits Width of a reference count entry in bits
880
+ backing_file=<str> - File name of a base image
881
+ backing_fmt=<str> - Image format of the base image
882
+ cluster_size=<size> - qcow2 cluster size
883
+ compat=<str> - Compatibility level (0.10 or 1.1)
884
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
885
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
886
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
887
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
888
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
889
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
890
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
891
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
892
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
893
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
894
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
895
+ refcount_bits=<num> - Width of a reference count entry in bits
896
+ size=<size> - Virtual disk size
897
898
Note that not all of these options may be amendable.
899
900
Testing: amend -f qcow2 -o ? TEST_DIR/t.qcow2
901
Creation options for 'qcow2':
902
-size Virtual disk size
903
-compat Compatibility level (0.10 or 1.1)
904
-backing_file File name of a base image
905
-backing_fmt Image format of the base image
906
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
907
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
908
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
909
-encrypt.cipher-alg Name of encryption cipher algorithm
910
-encrypt.cipher-mode Name of encryption cipher mode
911
-encrypt.ivgen-alg Name of IV generator algorithm
912
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
913
-encrypt.hash-alg Name of encryption hash algorithm
914
-encrypt.iter-time Time to spend in PBKDF in milliseconds
915
-cluster_size qcow2 cluster size
916
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
917
-lazy_refcounts Postpone refcount updates
918
-refcount_bits Width of a reference count entry in bits
919
+ backing_file=<str> - File name of a base image
920
+ backing_fmt=<str> - Image format of the base image
921
+ cluster_size=<size> - qcow2 cluster size
922
+ compat=<str> - Compatibility level (0.10 or 1.1)
923
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
924
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
925
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
926
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
927
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
928
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
929
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
930
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
931
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
932
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
933
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
934
+ refcount_bits=<num> - Width of a reference count entry in bits
935
+ size=<size> - Virtual disk size
936
937
Note that not all of these options may be amendable.
938
939
Testing: amend -f qcow2 -o cluster_size=4k,help TEST_DIR/t.qcow2
940
Creation options for 'qcow2':
941
-size Virtual disk size
942
-compat Compatibility level (0.10 or 1.1)
943
-backing_file File name of a base image
944
-backing_fmt Image format of the base image
945
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
946
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
947
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
948
-encrypt.cipher-alg Name of encryption cipher algorithm
949
-encrypt.cipher-mode Name of encryption cipher mode
950
-encrypt.ivgen-alg Name of IV generator algorithm
951
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
952
-encrypt.hash-alg Name of encryption hash algorithm
953
-encrypt.iter-time Time to spend in PBKDF in milliseconds
954
-cluster_size qcow2 cluster size
955
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
956
-lazy_refcounts Postpone refcount updates
957
-refcount_bits Width of a reference count entry in bits
958
+ backing_file=<str> - File name of a base image
959
+ backing_fmt=<str> - Image format of the base image
960
+ cluster_size=<size> - qcow2 cluster size
961
+ compat=<str> - Compatibility level (0.10 or 1.1)
962
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
963
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
964
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
965
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
966
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
967
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
968
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
969
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
970
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
971
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
972
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
973
+ refcount_bits=<num> - Width of a reference count entry in bits
974
+ size=<size> - Virtual disk size
975
976
Note that not all of these options may be amendable.
977
978
Testing: amend -f qcow2 -o cluster_size=4k,? TEST_DIR/t.qcow2
979
Creation options for 'qcow2':
980
-size Virtual disk size
981
-compat Compatibility level (0.10 or 1.1)
982
-backing_file File name of a base image
983
-backing_fmt Image format of the base image
984
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
985
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
986
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
987
-encrypt.cipher-alg Name of encryption cipher algorithm
988
-encrypt.cipher-mode Name of encryption cipher mode
989
-encrypt.ivgen-alg Name of IV generator algorithm
990
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
991
-encrypt.hash-alg Name of encryption hash algorithm
992
-encrypt.iter-time Time to spend in PBKDF in milliseconds
993
-cluster_size qcow2 cluster size
994
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
995
-lazy_refcounts Postpone refcount updates
996
-refcount_bits Width of a reference count entry in bits
997
+ backing_file=<str> - File name of a base image
998
+ backing_fmt=<str> - Image format of the base image
999
+ cluster_size=<size> - qcow2 cluster size
1000
+ compat=<str> - Compatibility level (0.10 or 1.1)
1001
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
1002
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
1003
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
1004
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
1005
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
1006
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
1007
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
1008
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
1009
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
1010
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
1011
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
1012
+ refcount_bits=<num> - Width of a reference count entry in bits
1013
+ size=<size> - Virtual disk size
1014
1015
Note that not all of these options may be amendable.
1016
1017
Testing: amend -f qcow2 -o help,cluster_size=4k TEST_DIR/t.qcow2
1018
Creation options for 'qcow2':
1019
-size Virtual disk size
1020
-compat Compatibility level (0.10 or 1.1)
1021
-backing_file File name of a base image
1022
-backing_fmt Image format of the base image
1023
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
1024
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
1025
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
1026
-encrypt.cipher-alg Name of encryption cipher algorithm
1027
-encrypt.cipher-mode Name of encryption cipher mode
1028
-encrypt.ivgen-alg Name of IV generator algorithm
1029
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
1030
-encrypt.hash-alg Name of encryption hash algorithm
1031
-encrypt.iter-time Time to spend in PBKDF in milliseconds
1032
-cluster_size qcow2 cluster size
1033
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
1034
-lazy_refcounts Postpone refcount updates
1035
-refcount_bits Width of a reference count entry in bits
1036
+ backing_file=<str> - File name of a base image
1037
+ backing_fmt=<str> - Image format of the base image
1038
+ cluster_size=<size> - qcow2 cluster size
1039
+ compat=<str> - Compatibility level (0.10 or 1.1)
1040
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
1041
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
1042
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
1043
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
1044
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
1045
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
1046
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
1047
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
1048
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
1049
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
1050
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
1051
+ refcount_bits=<num> - Width of a reference count entry in bits
1052
+ size=<size> - Virtual disk size
1053
1054
Note that not all of these options may be amendable.
1055
1056
Testing: amend -f qcow2 -o ?,cluster_size=4k TEST_DIR/t.qcow2
1057
Creation options for 'qcow2':
1058
-size Virtual disk size
1059
-compat Compatibility level (0.10 or 1.1)
1060
-backing_file File name of a base image
1061
-backing_fmt Image format of the base image
1062
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
1063
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
1064
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
1065
-encrypt.cipher-alg Name of encryption cipher algorithm
1066
-encrypt.cipher-mode Name of encryption cipher mode
1067
-encrypt.ivgen-alg Name of IV generator algorithm
1068
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
1069
-encrypt.hash-alg Name of encryption hash algorithm
1070
-encrypt.iter-time Time to spend in PBKDF in milliseconds
1071
-cluster_size qcow2 cluster size
1072
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
1073
-lazy_refcounts Postpone refcount updates
1074
-refcount_bits Width of a reference count entry in bits
1075
+ backing_file=<str> - File name of a base image
1076
+ backing_fmt=<str> - Image format of the base image
1077
+ cluster_size=<size> - qcow2 cluster size
1078
+ compat=<str> - Compatibility level (0.10 or 1.1)
1079
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
1080
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
1081
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
1082
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
1083
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
1084
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
1085
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
1086
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
1087
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
1088
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
1089
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
1090
+ refcount_bits=<num> - Width of a reference count entry in bits
1091
+ size=<size> - Virtual disk size
1092
1093
Note that not all of these options may be amendable.
1094
1095
Testing: amend -f qcow2 -o cluster_size=4k -o help TEST_DIR/t.qcow2
1096
Creation options for 'qcow2':
1097
-size Virtual disk size
1098
-compat Compatibility level (0.10 or 1.1)
1099
-backing_file File name of a base image
1100
-backing_fmt Image format of the base image
1101
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
1102
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
1103
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
1104
-encrypt.cipher-alg Name of encryption cipher algorithm
1105
-encrypt.cipher-mode Name of encryption cipher mode
1106
-encrypt.ivgen-alg Name of IV generator algorithm
1107
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
1108
-encrypt.hash-alg Name of encryption hash algorithm
1109
-encrypt.iter-time Time to spend in PBKDF in milliseconds
1110
-cluster_size qcow2 cluster size
1111
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
1112
-lazy_refcounts Postpone refcount updates
1113
-refcount_bits Width of a reference count entry in bits
1114
+ backing_file=<str> - File name of a base image
1115
+ backing_fmt=<str> - Image format of the base image
1116
+ cluster_size=<size> - qcow2 cluster size
1117
+ compat=<str> - Compatibility level (0.10 or 1.1)
1118
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
1119
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
1120
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
1121
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
1122
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
1123
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
1124
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
1125
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
1126
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
1127
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
1128
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
1129
+ refcount_bits=<num> - Width of a reference count entry in bits
1130
+ size=<size> - Virtual disk size
1131
1132
Note that not all of these options may be amendable.
1133
1134
Testing: amend -f qcow2 -o cluster_size=4k -o ? TEST_DIR/t.qcow2
1135
Creation options for 'qcow2':
1136
-size Virtual disk size
1137
-compat Compatibility level (0.10 or 1.1)
1138
-backing_file File name of a base image
1139
-backing_fmt Image format of the base image
1140
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
1141
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
1142
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
1143
-encrypt.cipher-alg Name of encryption cipher algorithm
1144
-encrypt.cipher-mode Name of encryption cipher mode
1145
-encrypt.ivgen-alg Name of IV generator algorithm
1146
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
1147
-encrypt.hash-alg Name of encryption hash algorithm
1148
-encrypt.iter-time Time to spend in PBKDF in milliseconds
1149
-cluster_size qcow2 cluster size
1150
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
1151
-lazy_refcounts Postpone refcount updates
1152
-refcount_bits Width of a reference count entry in bits
1153
+ backing_file=<str> - File name of a base image
1154
+ backing_fmt=<str> - Image format of the base image
1155
+ cluster_size=<size> - qcow2 cluster size
1156
+ compat=<str> - Compatibility level (0.10 or 1.1)
1157
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
1158
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
1159
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
1160
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
1161
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
1162
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
1163
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
1164
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
1165
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
1166
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
1167
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
1168
+ refcount_bits=<num> - Width of a reference count entry in bits
1169
+ size=<size> - Virtual disk size
1170
1171
Note that not all of these options may be amendable.
1172
1173
@@ -XXX,XX +XXX,XX @@ qemu-img: Invalid option list: ,,
1174
1175
Testing: amend -f qcow2 -o help
1176
Creation options for 'qcow2':
1177
-size Virtual disk size
1178
-compat Compatibility level (0.10 or 1.1)
1179
-backing_file File name of a base image
1180
-backing_fmt Image format of the base image
1181
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
1182
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
1183
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
1184
-encrypt.cipher-alg Name of encryption cipher algorithm
1185
-encrypt.cipher-mode Name of encryption cipher mode
1186
-encrypt.ivgen-alg Name of IV generator algorithm
1187
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
1188
-encrypt.hash-alg Name of encryption hash algorithm
1189
-encrypt.iter-time Time to spend in PBKDF in milliseconds
1190
-cluster_size qcow2 cluster size
1191
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
1192
-lazy_refcounts Postpone refcount updates
1193
-refcount_bits Width of a reference count entry in bits
1194
+ backing_file=<str> - File name of a base image
1195
+ backing_fmt=<str> - Image format of the base image
1196
+ cluster_size=<size> - qcow2 cluster size
1197
+ compat=<str> - Compatibility level (0.10 or 1.1)
1198
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
1199
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
1200
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
1201
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
1202
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
1203
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
1204
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
1205
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
1206
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
1207
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
1208
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
1209
+ refcount_bits=<num> - Width of a reference count entry in bits
1210
+ size=<size> - Virtual disk size
1211
1212
Note that not all of these options may be amendable.
1213
1214
Testing: convert -o help
1215
Supported options:
1216
-size Virtual disk size
1217
+ size=<size> - Virtual disk size
1218
1219
Testing: amend -f bochs -o help
1220
qemu-img: Format driver 'bochs' does not support option amendment
1221
--
132
--
1222
2.19.1
133
2.40.1
1223
134
1224
135
diff view generated by jsdifflib
1
From: Leonid Bloch <lbloch@janustech.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
The lookup table for power-of-two sizes was added in commit 540b8492618eb
3
Each vhost-user-blk request runs in a coroutine. When the BlockBackend
4
for the purpose of having convenient shortcuts for these sizes in cases
4
enters a drained section we need to enter a quiescent state. Currently
5
when the literal number has to be present at compile time, and
5
any in-flight requests race with bdrv_drained_begin() because it is
6
expressions as '(1 * KiB)' can not be used. One such case is the
6
unaware of vhost-user-blk requests.
7
stringification of sizes. Beyond that, it is convenient to use these
8
shortcuts for all power-of-two sizes, even if they don't have to be
9
literal numbers.
10
7
11
Despite its convenience, this table introduced 55 lines of "dumb" code,
8
When blk_co_preadv/pwritev()/etc returns it wakes the
12
the purpose and origin of which are obscure without reading the message
9
bdrv_drained_begin() thread but vhost-user-blk request processing has
13
of the commit which introduced it. This patch fixes that by adding a
10
not yet finished. The request coroutine continues executing while the
14
comment to the code itself with a brief explanation for the reasoning
11
main loop thread thinks it is in a drained section.
15
behind this table. This comment includes the short AWK script that
16
generated the table, so that anyone who's interested could make sure
17
that the values in it are correct (otherwise these values look as if
18
they were typed manually).
19
12
20
Signed-off-by: Leonid Bloch <lbloch@janustech.com>
13
One example where this is unsafe is for blk_set_aio_context() where
14
bdrv_drained_begin() is called before .aio_context_detached() and
15
.aio_context_attach(). If request coroutines are still running after
16
bdrv_drained_begin(), then the AioContext could change underneath them
17
and they race with new requests processed in the new AioContext. This
18
could lead to virtqueue corruption, for example.
19
20
(This example is theoretical, I came across this while reading the
21
code and have not tried to reproduce it.)
22
23
It's easy to make bdrv_drained_begin() wait for in-flight requests: add
24
a .drained_poll() callback that checks the VuServer's in-flight counter.
25
VuServer just needs an API that returns true when there are requests in
26
flight. The in-flight counter needs to be atomic.
27
28
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
29
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
30
Message-Id: <20230516190238.8401-7-stefanha@redhat.com>
21
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
31
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
22
---
32
---
23
include/qemu/units.h | 18 ++++++++++++++++++
33
include/qemu/vhost-user-server.h | 4 +++-
24
1 file changed, 18 insertions(+)
34
block/export/vhost-user-blk-server.c | 13 +++++++++++++
35
util/vhost-user-server.c | 18 ++++++++++++------
36
3 files changed, 28 insertions(+), 7 deletions(-)
25
37
26
diff --git a/include/qemu/units.h b/include/qemu/units.h
38
diff --git a/include/qemu/vhost-user-server.h b/include/qemu/vhost-user-server.h
27
index XXXXXXX..XXXXXXX 100644
39
index XXXXXXX..XXXXXXX 100644
28
--- a/include/qemu/units.h
40
--- a/include/qemu/vhost-user-server.h
29
+++ b/include/qemu/units.h
41
+++ b/include/qemu/vhost-user-server.h
30
@@ -XXX,XX +XXX,XX @@
42
@@ -XXX,XX +XXX,XX @@ typedef struct {
31
#define PiB (INT64_C(1) << 50)
43
int max_queues;
32
#define EiB (INT64_C(1) << 60)
44
const VuDevIface *vu_iface;
45
46
+ unsigned int in_flight; /* atomic */
47
+
48
/* Protected by ctx lock */
49
- unsigned int in_flight;
50
bool wait_idle;
51
VuDev vu_dev;
52
QIOChannel *ioc; /* The I/O channel with the client */
53
@@ -XXX,XX +XXX,XX @@ void vhost_user_server_stop(VuServer *server);
54
55
void vhost_user_server_inc_in_flight(VuServer *server);
56
void vhost_user_server_dec_in_flight(VuServer *server);
57
+bool vhost_user_server_has_in_flight(VuServer *server);
58
59
void vhost_user_server_attach_aio_context(VuServer *server, AioContext *ctx);
60
void vhost_user_server_detach_aio_context(VuServer *server);
61
diff --git a/block/export/vhost-user-blk-server.c b/block/export/vhost-user-blk-server.c
62
index XXXXXXX..XXXXXXX 100644
63
--- a/block/export/vhost-user-blk-server.c
64
+++ b/block/export/vhost-user-blk-server.c
65
@@ -XXX,XX +XXX,XX @@ static void vu_blk_exp_resize(void *opaque)
66
vu_config_change_msg(&vexp->vu_server.vu_dev);
67
}
33
68
34
+/*
69
+/*
35
+ * The following lookup table is intended to be used when a literal string of
70
+ * Ensures that bdrv_drained_begin() waits until in-flight requests complete.
36
+ * the number of bytes is required (for example if it needs to be stringified).
37
+ * It can also be used for generic shortcuts of power-of-two sizes.
38
+ * This table is generated using the AWK script below:
39
+ *
71
+ *
40
+ * BEGIN {
72
+ * Called with vexp->export.ctx acquired.
41
+ * suffix="KMGTPE";
42
+ * for(i=10; i<64; i++) {
43
+ * val=2**i;
44
+ * s=substr(suffix, int(i/10), 1);
45
+ * n=2**(i%10);
46
+ * pad=21-int(log(n)/log(10));
47
+ * printf("#define S_%d%siB %*d\n", n, s, pad, val);
48
+ * }
49
+ * }
50
+ */
73
+ */
74
+static bool vu_blk_drained_poll(void *opaque)
75
+{
76
+ VuBlkExport *vexp = opaque;
51
+
77
+
52
#define S_1KiB 1024
78
+ return vhost_user_server_has_in_flight(&vexp->vu_server);
53
#define S_2KiB 2048
79
+}
54
#define S_4KiB 4096
80
+
81
static const BlockDevOps vu_blk_dev_ops = {
82
+ .drained_poll = vu_blk_drained_poll,
83
.resize_cb = vu_blk_exp_resize,
84
};
85
86
diff --git a/util/vhost-user-server.c b/util/vhost-user-server.c
87
index XXXXXXX..XXXXXXX 100644
88
--- a/util/vhost-user-server.c
89
+++ b/util/vhost-user-server.c
90
@@ -XXX,XX +XXX,XX @@ static void panic_cb(VuDev *vu_dev, const char *buf)
91
void vhost_user_server_inc_in_flight(VuServer *server)
92
{
93
assert(!server->wait_idle);
94
- server->in_flight++;
95
+ qatomic_inc(&server->in_flight);
96
}
97
98
void vhost_user_server_dec_in_flight(VuServer *server)
99
{
100
- server->in_flight--;
101
- if (server->wait_idle && !server->in_flight) {
102
- aio_co_wake(server->co_trip);
103
+ if (qatomic_fetch_dec(&server->in_flight) == 1) {
104
+ if (server->wait_idle) {
105
+ aio_co_wake(server->co_trip);
106
+ }
107
}
108
}
109
110
+bool vhost_user_server_has_in_flight(VuServer *server)
111
+{
112
+ return qatomic_load_acquire(&server->in_flight) > 0;
113
+}
114
+
115
static bool coroutine_fn
116
vu_message_read(VuDev *vu_dev, int conn_fd, VhostUserMsg *vmsg)
117
{
118
@@ -XXX,XX +XXX,XX @@ static coroutine_fn void vu_client_trip(void *opaque)
119
/* Keep running */
120
}
121
122
- if (server->in_flight) {
123
+ if (vhost_user_server_has_in_flight(server)) {
124
/* Wait for requests to complete before we can unmap the memory */
125
server->wait_idle = true;
126
qemu_coroutine_yield();
127
server->wait_idle = false;
128
}
129
- assert(server->in_flight == 0);
130
+ assert(!vhost_user_server_has_in_flight(server));
131
132
vu_deinit(vu_dev);
133
55
--
134
--
56
2.19.1
135
2.40.1
57
58
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
The blkverify mode of Quorum can only be enabled if the number of
3
vhost-user activity must be suspended during bdrv_drained_begin/end().
4
children is exactly two and the value of vote-threshold is also two.
4
This prevents new requests from interfering with whatever is happening
5
in the drained section.
5
6
6
If the user tries to enable it but the other settings are incorrect
7
Previously this was done using aio_set_fd_handler()'s is_external
7
then QEMU simply prints an error message to stderr and carries on
8
argument. In a multi-queue block layer world the aio_disable_external()
8
disabling the blkverify setting.
9
API cannot be used since multiple AioContext may be processing I/O, not
10
just one.
9
11
10
This patch makes quorum_open() fail and return an error in this case.
12
Switch to BlockDevOps->drained_begin/end() callbacks.
11
13
12
Signed-off-by: Alberto Garcia <berto@igalia.com>
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
13
Reported-by: Markus Armbruster <armbru@redhat.com>
15
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
16
Message-Id: <20230516190238.8401-8-stefanha@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
18
---
16
block/quorum.c | 13 ++++++-------
19
block/export/vhost-user-blk-server.c | 28 ++++++++++++++++++++++++++--
17
1 file changed, 6 insertions(+), 7 deletions(-)
20
util/vhost-user-server.c | 10 +++++-----
21
2 files changed, 31 insertions(+), 7 deletions(-)
18
22
19
diff --git a/block/quorum.c b/block/quorum.c
23
diff --git a/block/export/vhost-user-blk-server.c b/block/export/vhost-user-blk-server.c
20
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
21
--- a/block/quorum.c
25
--- a/block/export/vhost-user-blk-server.c
22
+++ b/block/quorum.c
26
+++ b/block/export/vhost-user-blk-server.c
23
@@ -XXX,XX +XXX,XX @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags,
27
@@ -XXX,XX +XXX,XX @@ static void blk_aio_attached(AioContext *ctx, void *opaque)
24
s->read_pattern = ret;
28
{
25
29
VuBlkExport *vexp = opaque;
26
if (s->read_pattern == QUORUM_READ_PATTERN_QUORUM) {
30
27
- /* is the driver in blkverify mode */
31
+ /*
28
- if (qemu_opt_get_bool(opts, QUORUM_OPT_BLKVERIFY, false) &&
32
+ * The actual attach will happen in vu_blk_drained_end() and we just
29
- s->num_children == 2 && s->threshold == 2) {
33
+ * restore ctx here.
30
- s->is_blkverify = true;
34
+ */
31
- } else if (qemu_opt_get_bool(opts, QUORUM_OPT_BLKVERIFY, false)) {
35
vexp->export.ctx = ctx;
32
- fprintf(stderr, "blkverify mode is set by setting blkverify=on "
36
- vhost_user_server_attach_aio_context(&vexp->vu_server, ctx);
33
- "and using two files with vote_threshold=2\n");
37
}
34
+ s->is_blkverify = qemu_opt_get_bool(opts, QUORUM_OPT_BLKVERIFY, false);
38
35
+ if (s->is_blkverify && (s->num_children != 2 || s->threshold != 2)) {
39
static void blk_aio_detach(void *opaque)
36
+ error_setg(&local_err, "blkverify=on can only be set if there are "
40
{
37
+ "exactly two files and vote-threshold is 2");
41
VuBlkExport *vexp = opaque;
38
+ ret = -EINVAL;
42
39
+ goto exit;
43
- vhost_user_server_detach_aio_context(&vexp->vu_server);
44
+ /*
45
+ * The actual detach already happened in vu_blk_drained_begin() but from
46
+ * this point on we must not access ctx anymore.
47
+ */
48
vexp->export.ctx = NULL;
49
}
50
51
@@ -XXX,XX +XXX,XX @@ static void vu_blk_exp_resize(void *opaque)
52
vu_config_change_msg(&vexp->vu_server.vu_dev);
53
}
54
55
+/* Called with vexp->export.ctx acquired */
56
+static void vu_blk_drained_begin(void *opaque)
57
+{
58
+ VuBlkExport *vexp = opaque;
59
+
60
+ vhost_user_server_detach_aio_context(&vexp->vu_server);
61
+}
62
+
63
+/* Called with vexp->export.blk AioContext acquired */
64
+static void vu_blk_drained_end(void *opaque)
65
+{
66
+ VuBlkExport *vexp = opaque;
67
+
68
+ vhost_user_server_attach_aio_context(&vexp->vu_server, vexp->export.ctx);
69
+}
70
+
71
/*
72
* Ensures that bdrv_drained_begin() waits until in-flight requests complete.
73
*
74
@@ -XXX,XX +XXX,XX @@ static bool vu_blk_drained_poll(void *opaque)
75
}
76
77
static const BlockDevOps vu_blk_dev_ops = {
78
+ .drained_begin = vu_blk_drained_begin,
79
+ .drained_end = vu_blk_drained_end,
80
.drained_poll = vu_blk_drained_poll,
81
.resize_cb = vu_blk_exp_resize,
82
};
83
diff --git a/util/vhost-user-server.c b/util/vhost-user-server.c
84
index XXXXXXX..XXXXXXX 100644
85
--- a/util/vhost-user-server.c
86
+++ b/util/vhost-user-server.c
87
@@ -XXX,XX +XXX,XX @@ set_watch(VuDev *vu_dev, int fd, int vu_evt,
88
vu_fd_watch->fd = fd;
89
vu_fd_watch->cb = cb;
90
qemu_socket_set_nonblock(fd);
91
- aio_set_fd_handler(server->ioc->ctx, fd, true, kick_handler,
92
+ aio_set_fd_handler(server->ioc->ctx, fd, false, kick_handler,
93
NULL, NULL, NULL, vu_fd_watch);
94
vu_fd_watch->vu_dev = vu_dev;
95
vu_fd_watch->pvt = pvt;
96
@@ -XXX,XX +XXX,XX @@ static void remove_watch(VuDev *vu_dev, int fd)
97
if (!vu_fd_watch) {
98
return;
99
}
100
- aio_set_fd_handler(server->ioc->ctx, fd, true,
101
+ aio_set_fd_handler(server->ioc->ctx, fd, false,
102
NULL, NULL, NULL, NULL, NULL);
103
104
QTAILQ_REMOVE(&server->vu_fd_watches, vu_fd_watch, next);
105
@@ -XXX,XX +XXX,XX @@ void vhost_user_server_stop(VuServer *server)
106
VuFdWatch *vu_fd_watch;
107
108
QTAILQ_FOREACH(vu_fd_watch, &server->vu_fd_watches, next) {
109
- aio_set_fd_handler(server->ctx, vu_fd_watch->fd, true,
110
+ aio_set_fd_handler(server->ctx, vu_fd_watch->fd, false,
111
NULL, NULL, NULL, NULL, vu_fd_watch);
40
}
112
}
41
113
42
s->rewrite_corrupted = qemu_opt_get_bool(opts, QUORUM_OPT_REWRITE,
114
@@ -XXX,XX +XXX,XX @@ void vhost_user_server_attach_aio_context(VuServer *server, AioContext *ctx)
115
qio_channel_attach_aio_context(server->ioc, ctx);
116
117
QTAILQ_FOREACH(vu_fd_watch, &server->vu_fd_watches, next) {
118
- aio_set_fd_handler(ctx, vu_fd_watch->fd, true, kick_handler, NULL,
119
+ aio_set_fd_handler(ctx, vu_fd_watch->fd, false, kick_handler, NULL,
120
NULL, NULL, vu_fd_watch);
121
}
122
123
@@ -XXX,XX +XXX,XX @@ void vhost_user_server_detach_aio_context(VuServer *server)
124
VuFdWatch *vu_fd_watch;
125
126
QTAILQ_FOREACH(vu_fd_watch, &server->vu_fd_watches, next) {
127
- aio_set_fd_handler(server->ctx, vu_fd_watch->fd, true,
128
+ aio_set_fd_handler(server->ctx, vu_fd_watch->fd, false,
129
NULL, NULL, NULL, NULL, vu_fd_watch);
130
}
131
43
--
132
--
44
2.19.1
133
2.40.1
45
46
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
There is no good reason why there should be a newline in this
3
There is no need to suspend activity between aio_disable_external() and
4
description, so remove it.
4
aio_enable_external(), which is mainly used for the block layer's drain
5
operation.
5
6
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
This is part of ongoing work to remove the aio_disable_external() API.
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
8
8
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
9
Reviewed-by: David Woodhouse <dwmw@amazon.co.uk>
10
Reviewed-by: Paul Durrant <paul@xen.org>
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
13
Message-Id: <20230516190238.8401-9-stefanha@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
15
---
11
vl.c | 2 +-
16
hw/i386/kvm/xen_xenstore.c | 2 +-
12
1 file changed, 1 insertion(+), 1 deletion(-)
17
1 file changed, 1 insertion(+), 1 deletion(-)
13
18
14
diff --git a/vl.c b/vl.c
19
diff --git a/hw/i386/kvm/xen_xenstore.c b/hw/i386/kvm/xen_xenstore.c
15
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
16
--- a/vl.c
21
--- a/hw/i386/kvm/xen_xenstore.c
17
+++ b/vl.c
22
+++ b/hw/i386/kvm/xen_xenstore.c
18
@@ -XXX,XX +XXX,XX @@ static QemuOptsList qemu_fw_cfg_opts = {
23
@@ -XXX,XX +XXX,XX @@ static void xen_xenstore_realize(DeviceState *dev, Error **errp)
19
}, {
24
error_setg(errp, "Xenstore evtchn port init failed");
20
.name = "file",
25
return;
21
.type = QEMU_OPT_STRING,
26
}
22
- .help = "Sets the name of the file from which\n"
27
- aio_set_fd_handler(qemu_get_aio_context(), xen_be_evtchn_fd(s->eh), true,
23
+ .help = "Sets the name of the file from which "
28
+ aio_set_fd_handler(qemu_get_aio_context(), xen_be_evtchn_fd(s->eh), false,
24
"the fw_cfg blob will be loaded",
29
xen_xenstore_event, NULL, NULL, NULL, s);
25
}, {
30
26
.name = "string",
31
s->impl = xs_impl_create(xen_domid);
27
--
32
--
28
2.19.1
33
2.40.1
29
30
diff view generated by jsdifflib
1
From: Stefan Weil <sw@weilnetz.de>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
Use %zu instead of %zd for unsigned numbers.
3
The BlockBackend quiesce_counter is greater than zero during drained
4
sections. Add an API to check whether the BlockBackend is in a drained
5
section.
4
6
5
This fixes two error messages from the LSTM static code analyzer:
7
The next patch will use this API.
6
8
7
This argument should be of type 'ssize_t' but is of type 'unsigned long'
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
8
10
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Stefan Weil <sw@weilnetz.de>
11
Message-Id: <20230516190238.8401-10-stefanha@redhat.com>
10
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
13
---
13
qemu-io-cmds.c | 4 ++--
14
include/sysemu/block-backend-global-state.h | 1 +
14
1 file changed, 2 insertions(+), 2 deletions(-)
15
block/block-backend.c | 7 +++++++
16
2 files changed, 8 insertions(+)
15
17
16
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
18
diff --git a/include/sysemu/block-backend-global-state.h b/include/sysemu/block-backend-global-state.h
17
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
18
--- a/qemu-io-cmds.c
20
--- a/include/sysemu/block-backend-global-state.h
19
+++ b/qemu-io-cmds.c
21
+++ b/include/sysemu/block-backend-global-state.h
20
@@ -XXX,XX +XXX,XX @@ static int readv_f(BlockBackend *blk, int argc, char **argv)
22
@@ -XXX,XX +XXX,XX @@ void blk_activate(BlockBackend *blk, Error **errp);
21
memset(cmp_buf, pattern, qiov.size);
23
int blk_make_zero(BlockBackend *blk, BdrvRequestFlags flags);
22
if (memcmp(buf, cmp_buf, qiov.size)) {
24
void blk_aio_cancel(BlockAIOCB *acb);
23
printf("Pattern verification failed at offset %"
25
int blk_commit_all(void);
24
- PRId64 ", %zd bytes\n", offset, qiov.size);
26
+bool blk_in_drain(BlockBackend *blk);
25
+ PRId64 ", %zu bytes\n", offset, qiov.size);
27
void blk_drain(BlockBackend *blk);
26
ret = -EINVAL;
28
void blk_drain_all(void);
27
}
29
void blk_set_on_error(BlockBackend *blk, BlockdevOnError on_read_error,
28
g_free(cmp_buf);
30
diff --git a/block/block-backend.c b/block/block-backend.c
29
@@ -XXX,XX +XXX,XX @@ static void aio_read_done(void *opaque, int ret)
31
index XXXXXXX..XXXXXXX 100644
30
memset(cmp_buf, ctx->pattern, ctx->qiov.size);
32
--- a/block/block-backend.c
31
if (memcmp(ctx->buf, cmp_buf, ctx->qiov.size)) {
33
+++ b/block/block-backend.c
32
printf("Pattern verification failed at offset %"
34
@@ -XXX,XX +XXX,XX @@ blk_check_byte_request(BlockBackend *blk, int64_t offset, int64_t bytes)
33
- PRId64 ", %zd bytes\n", ctx->offset, ctx->qiov.size);
35
return 0;
34
+ PRId64 ", %zu bytes\n", ctx->offset, ctx->qiov.size);
36
}
35
}
37
36
g_free(cmp_buf);
38
+/* Are we currently in a drained section? */
37
}
39
+bool blk_in_drain(BlockBackend *blk)
40
+{
41
+ GLOBAL_STATE_CODE(); /* change to IO_OR_GS_CODE(), if necessary */
42
+ return qatomic_read(&blk->quiesce_counter);
43
+}
44
+
45
/* To be called between exactly one pair of blk_inc/dec_in_flight() */
46
static void coroutine_fn blk_wait_while_drained(BlockBackend *blk)
47
{
38
--
48
--
39
2.19.1
49
2.40.1
40
41
diff view generated by jsdifflib
1
From: Daniel P. Berrangé <berrange@redhat.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
The qcow2 block driver expects to see a valid sector size even when it
3
For simplicity, always run BlockDevOps .drained_begin/end/poll()
4
has opened the crypto layer with QCRYPTO_BLOCK_OPEN_NO_IO.
4
callbacks in the main loop thread. This makes it easier to implement the
5
5
callbacks and avoids extra locks.
6
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
6
7
Reviewed-by: Alberto Garcia <berto@igalia.com>
7
Move the function pointer declarations from the I/O Code section to the
8
Global State section for BlockDevOps, BdrvChildClass, and BlockDriver.
9
10
Narrow IO_OR_GS_CODE() to GLOBAL_STATE_CODE() where appropriate.
11
12
The test-bdrv-drain test case calls bdrv_drain() from an IOThread. This
13
is now only allowed from coroutine context, so update the test case to
14
run in a coroutine.
15
16
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
17
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
18
Message-Id: <20230516190238.8401-11-stefanha@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
20
---
10
crypto/block-qcow.c | 2 ++
21
include/block/block_int-common.h | 72 +++++++++++++--------------
11
1 file changed, 2 insertions(+)
22
include/sysemu/block-backend-common.h | 25 +++++-----
12
23
block/io.c | 14 ++++--
13
diff --git a/crypto/block-qcow.c b/crypto/block-qcow.c
24
tests/unit/test-bdrv-drain.c | 14 +++---
14
index XXXXXXX..XXXXXXX 100644
25
4 files changed, 67 insertions(+), 58 deletions(-)
15
--- a/crypto/block-qcow.c
26
16
+++ b/crypto/block-qcow.c
27
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
17
@@ -XXX,XX +XXX,XX @@ qcrypto_block_qcow_open(QCryptoBlock *block,
28
index XXXXXXX..XXXXXXX 100644
18
Error **errp)
29
--- a/include/block/block_int-common.h
19
{
30
+++ b/include/block/block_int-common.h
20
if (flags & QCRYPTO_BLOCK_OPEN_NO_IO) {
31
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
21
+ block->sector_size = QCRYPTO_BLOCK_QCOW_SECTOR_SIZE;
32
void (*bdrv_attach_aio_context)(BlockDriverState *bs,
22
+ block->payload_offset = 0;
33
AioContext *new_context);
23
return 0;
34
24
} else {
35
+ /**
25
if (!options->u.qcow.key_secret) {
36
+ * bdrv_drain_begin is called if implemented in the beginning of a
37
+ * drain operation to drain and stop any internal sources of requests in
38
+ * the driver.
39
+ * bdrv_drain_end is called if implemented at the end of the drain.
40
+ *
41
+ * They should be used by the driver to e.g. manage scheduled I/O
42
+ * requests, or toggle an internal state. After the end of the drain new
43
+ * requests will continue normally.
44
+ *
45
+ * Implementations of both functions must not call aio_poll().
46
+ */
47
+ void (*bdrv_drain_begin)(BlockDriverState *bs);
48
+ void (*bdrv_drain_end)(BlockDriverState *bs);
49
+
50
/**
51
* Try to get @bs's logical and physical block size.
52
* On success, store them in @bsz and return zero.
53
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
54
void coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_io_unplug)(
55
BlockDriverState *bs);
56
57
- /**
58
- * bdrv_drain_begin is called if implemented in the beginning of a
59
- * drain operation to drain and stop any internal sources of requests in
60
- * the driver.
61
- * bdrv_drain_end is called if implemented at the end of the drain.
62
- *
63
- * They should be used by the driver to e.g. manage scheduled I/O
64
- * requests, or toggle an internal state. After the end of the drain new
65
- * requests will continue normally.
66
- *
67
- * Implementations of both functions must not call aio_poll().
68
- */
69
- void (*bdrv_drain_begin)(BlockDriverState *bs);
70
- void (*bdrv_drain_end)(BlockDriverState *bs);
71
-
72
bool (*bdrv_supports_persistent_dirty_bitmap)(BlockDriverState *bs);
73
74
bool coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_can_store_new_dirty_bitmap)(
75
@@ -XXX,XX +XXX,XX @@ struct BdrvChildClass {
76
void GRAPH_WRLOCK_PTR (*attach)(BdrvChild *child);
77
void GRAPH_WRLOCK_PTR (*detach)(BdrvChild *child);
78
79
+ /*
80
+ * If this pair of functions is implemented, the parent doesn't issue new
81
+ * requests after returning from .drained_begin() until .drained_end() is
82
+ * called.
83
+ *
84
+ * These functions must not change the graph (and therefore also must not
85
+ * call aio_poll(), which could change the graph indirectly).
86
+ *
87
+ * Note that this can be nested. If drained_begin() was called twice, new
88
+ * I/O is allowed only after drained_end() was called twice, too.
89
+ */
90
+ void (*drained_begin)(BdrvChild *child);
91
+ void (*drained_end)(BdrvChild *child);
92
+
93
+ /*
94
+ * Returns whether the parent has pending requests for the child. This
95
+ * callback is polled after .drained_begin() has been called until all
96
+ * activity on the child has stopped.
97
+ */
98
+ bool (*drained_poll)(BdrvChild *child);
99
+
100
/*
101
* Notifies the parent that the filename of its child has changed (e.g.
102
* because the direct child was removed from the backing chain), so that it
103
@@ -XXX,XX +XXX,XX @@ struct BdrvChildClass {
104
const char *(*get_name)(BdrvChild *child);
105
106
AioContext *(*get_parent_aio_context)(BdrvChild *child);
107
-
108
- /*
109
- * If this pair of functions is implemented, the parent doesn't issue new
110
- * requests after returning from .drained_begin() until .drained_end() is
111
- * called.
112
- *
113
- * These functions must not change the graph (and therefore also must not
114
- * call aio_poll(), which could change the graph indirectly).
115
- *
116
- * Note that this can be nested. If drained_begin() was called twice, new
117
- * I/O is allowed only after drained_end() was called twice, too.
118
- */
119
- void (*drained_begin)(BdrvChild *child);
120
- void (*drained_end)(BdrvChild *child);
121
-
122
- /*
123
- * Returns whether the parent has pending requests for the child. This
124
- * callback is polled after .drained_begin() has been called until all
125
- * activity on the child has stopped.
126
- */
127
- bool (*drained_poll)(BdrvChild *child);
128
};
129
130
extern const BdrvChildClass child_of_bds;
131
diff --git a/include/sysemu/block-backend-common.h b/include/sysemu/block-backend-common.h
132
index XXXXXXX..XXXXXXX 100644
133
--- a/include/sysemu/block-backend-common.h
134
+++ b/include/sysemu/block-backend-common.h
135
@@ -XXX,XX +XXX,XX @@ typedef struct BlockDevOps {
136
*/
137
bool (*is_medium_locked)(void *opaque);
138
139
+ /*
140
+ * Runs when the backend receives a drain request.
141
+ */
142
+ void (*drained_begin)(void *opaque);
143
+ /*
144
+ * Runs when the backend's last drain request ends.
145
+ */
146
+ void (*drained_end)(void *opaque);
147
+ /*
148
+ * Is the device still busy?
149
+ */
150
+ bool (*drained_poll)(void *opaque);
151
+
152
/*
153
* I/O API functions. These functions are thread-safe.
154
*
155
@@ -XXX,XX +XXX,XX @@ typedef struct BlockDevOps {
156
* Runs when the size changed (e.g. monitor command block_resize)
157
*/
158
void (*resize_cb)(void *opaque);
159
- /*
160
- * Runs when the backend receives a drain request.
161
- */
162
- void (*drained_begin)(void *opaque);
163
- /*
164
- * Runs when the backend's last drain request ends.
165
- */
166
- void (*drained_end)(void *opaque);
167
- /*
168
- * Is the device still busy?
169
- */
170
- bool (*drained_poll)(void *opaque);
171
} BlockDevOps;
172
173
/*
174
diff --git a/block/io.c b/block/io.c
175
index XXXXXXX..XXXXXXX 100644
176
--- a/block/io.c
177
+++ b/block/io.c
178
@@ -XXX,XX +XXX,XX @@ static void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore)
179
180
void bdrv_parent_drained_end_single(BdrvChild *c)
181
{
182
- IO_OR_GS_CODE();
183
+ GLOBAL_STATE_CODE();
184
185
assert(c->quiesced_parent);
186
c->quiesced_parent = false;
187
@@ -XXX,XX +XXX,XX @@ static bool bdrv_parent_drained_poll(BlockDriverState *bs, BdrvChild *ignore,
188
189
void bdrv_parent_drained_begin_single(BdrvChild *c)
190
{
191
- IO_OR_GS_CODE();
192
+ GLOBAL_STATE_CODE();
193
194
assert(!c->quiesced_parent);
195
c->quiesced_parent = true;
196
@@ -XXX,XX +XXX,XX @@ typedef struct {
197
bool bdrv_drain_poll(BlockDriverState *bs, BdrvChild *ignore_parent,
198
bool ignore_bds_parents)
199
{
200
- IO_OR_GS_CODE();
201
+ GLOBAL_STATE_CODE();
202
203
if (bdrv_parent_drained_poll(bs, ignore_parent, ignore_bds_parents)) {
204
return true;
205
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
206
if (ctx != co_ctx) {
207
aio_context_release(ctx);
208
}
209
- replay_bh_schedule_oneshot_event(ctx, bdrv_co_drain_bh_cb, &data);
210
+ replay_bh_schedule_oneshot_event(qemu_get_aio_context(),
211
+ bdrv_co_drain_bh_cb, &data);
212
213
qemu_coroutine_yield();
214
/* If we are resumed from some other event (such as an aio completion or a
215
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent,
216
return;
217
}
218
219
+ GLOBAL_STATE_CODE();
220
+
221
/* Stop things in parent-to-child order */
222
if (qatomic_fetch_inc(&bs->quiesce_counter) == 0) {
223
aio_disable_external(bdrv_get_aio_context(bs));
224
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent)
225
{
226
int old_quiesce_counter;
227
228
+ IO_OR_GS_CODE();
229
+
230
if (qemu_in_coroutine()) {
231
bdrv_co_yield_to_drain(bs, false, parent, false);
232
return;
233
}
234
assert(bs->quiesce_counter > 0);
235
+ GLOBAL_STATE_CODE();
236
237
/* Re-enable things in child-to-parent order */
238
old_quiesce_counter = qatomic_fetch_dec(&bs->quiesce_counter);
239
diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c
240
index XXXXXXX..XXXXXXX 100644
241
--- a/tests/unit/test-bdrv-drain.c
242
+++ b/tests/unit/test-bdrv-drain.c
243
@@ -XXX,XX +XXX,XX @@ struct test_iothread_data {
244
BlockDriverState *bs;
245
enum drain_type drain_type;
246
int *aio_ret;
247
+ bool co_done;
248
};
249
250
-static void test_iothread_drain_entry(void *opaque)
251
+static void coroutine_fn test_iothread_drain_co_entry(void *opaque)
252
{
253
struct test_iothread_data *data = opaque;
254
255
- aio_context_acquire(bdrv_get_aio_context(data->bs));
256
do_drain_begin(data->drain_type, data->bs);
257
g_assert_cmpint(*data->aio_ret, ==, 0);
258
do_drain_end(data->drain_type, data->bs);
259
- aio_context_release(bdrv_get_aio_context(data->bs));
260
261
- qemu_event_set(&done_event);
262
+ data->co_done = true;
263
+ aio_wait_kick();
264
}
265
266
static void test_iothread_aio_cb(void *opaque, int ret)
267
@@ -XXX,XX +XXX,XX @@ static void test_iothread_common(enum drain_type drain_type, int drain_thread)
268
BlockDriverState *bs;
269
BDRVTestState *s;
270
BlockAIOCB *acb;
271
+ Coroutine *co;
272
int aio_ret;
273
struct test_iothread_data data;
274
275
@@ -XXX,XX +XXX,XX @@ static void test_iothread_common(enum drain_type drain_type, int drain_thread)
276
}
277
break;
278
case 1:
279
- aio_bh_schedule_oneshot(ctx_a, test_iothread_drain_entry, &data);
280
- qemu_event_wait(&done_event);
281
+ co = qemu_coroutine_create(test_iothread_drain_co_entry, &data);
282
+ aio_co_enter(ctx_a, co);
283
+ AIO_WAIT_WHILE_UNLOCKED(NULL, !data.co_done);
284
break;
285
default:
286
g_assert_not_reached();
26
--
287
--
27
2.19.1
288
2.40.1
28
29
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
The blkverify mode of Quorum only works when the number of children is
3
Detach event channels during drained sections to stop I/O submission
4
exactly two, so any attempt to add a new one must return an error.
4
from the ring. xen-block is no longer reliant on aio_disable_external()
5
after this patch. This will allow us to remove the
6
aio_disable_external() API once all other code that relies on it is
7
converted.
5
8
6
quorum_del_child() on the other hand doesn't need any additional check
9
Extend xen_device_set_event_channel_context() to allow ctx=NULL. The
7
because decreasing the number of children would make it go under the
10
event channel still exists but the event loop does not monitor the file
8
vote threshold.
11
descriptor. Event channel processing can resume by calling
12
xen_device_set_event_channel_context() with a non-NULL ctx.
9
13
10
Signed-off-by: Alberto Garcia <berto@igalia.com>
14
Factor out xen_device_set_event_channel_context() calls in
11
Reported-by: Kevin Wolf <kwolf@redhat.com>
15
hw/block/dataplane/xen-block.c into attach/detach helper functions.
16
Incidentally, these don't require the AioContext lock because
17
aio_set_fd_handler() is thread-safe.
18
19
It's safer to register BlockDevOps after the dataplane instance has been
20
created. The BlockDevOps .drained_begin/end() callbacks depend on the
21
dataplane instance, so move the blk_set_dev_ops() call after
22
xen_block_dataplane_create().
23
24
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
25
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
26
Message-Id: <20230516190238.8401-12-stefanha@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
27
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
28
---
14
block/quorum.c | 8 ++++++++
29
hw/block/dataplane/xen-block.h | 2 ++
15
1 file changed, 8 insertions(+)
30
hw/block/dataplane/xen-block.c | 42 +++++++++++++++++++++++++---------
31
hw/block/xen-block.c | 24 ++++++++++++++++---
32
hw/xen/xen-bus.c | 7 ++++--
33
4 files changed, 59 insertions(+), 16 deletions(-)
16
34
17
diff --git a/block/quorum.c b/block/quorum.c
35
diff --git a/hw/block/dataplane/xen-block.h b/hw/block/dataplane/xen-block.h
18
index XXXXXXX..XXXXXXX 100644
36
index XXXXXXX..XXXXXXX 100644
19
--- a/block/quorum.c
37
--- a/hw/block/dataplane/xen-block.h
20
+++ b/block/quorum.c
38
+++ b/hw/block/dataplane/xen-block.h
21
@@ -XXX,XX +XXX,XX @@ static void quorum_add_child(BlockDriverState *bs, BlockDriverState *child_bs,
39
@@ -XXX,XX +XXX,XX @@ void xen_block_dataplane_start(XenBlockDataPlane *dataplane,
22
char indexstr[32];
40
unsigned int protocol,
23
int ret;
41
Error **errp);
24
42
void xen_block_dataplane_stop(XenBlockDataPlane *dataplane);
25
+ if (s->is_blkverify) {
43
+void xen_block_dataplane_attach(XenBlockDataPlane *dataplane);
26
+ error_setg(errp, "Cannot add a child to a quorum in blkverify mode");
44
+void xen_block_dataplane_detach(XenBlockDataPlane *dataplane);
45
46
#endif /* HW_BLOCK_DATAPLANE_XEN_BLOCK_H */
47
diff --git a/hw/block/dataplane/xen-block.c b/hw/block/dataplane/xen-block.c
48
index XXXXXXX..XXXXXXX 100644
49
--- a/hw/block/dataplane/xen-block.c
50
+++ b/hw/block/dataplane/xen-block.c
51
@@ -XXX,XX +XXX,XX @@ void xen_block_dataplane_destroy(XenBlockDataPlane *dataplane)
52
g_free(dataplane);
53
}
54
55
+void xen_block_dataplane_detach(XenBlockDataPlane *dataplane)
56
+{
57
+ if (!dataplane || !dataplane->event_channel) {
27
+ return;
58
+ return;
28
+ }
59
+ }
29
+
60
+
30
assert(s->num_children <= INT_MAX / sizeof(BdrvChild *));
61
+ /* Only reason for failure is a NULL channel */
31
if (s->num_children == INT_MAX / sizeof(BdrvChild *) ||
62
+ xen_device_set_event_channel_context(dataplane->xendev,
32
s->next_child_index == UINT_MAX) {
63
+ dataplane->event_channel,
33
@@ -XXX,XX +XXX,XX @@ static void quorum_del_child(BlockDriverState *bs, BdrvChild *child,
64
+ NULL, &error_abort);
65
+}
66
+
67
+void xen_block_dataplane_attach(XenBlockDataPlane *dataplane)
68
+{
69
+ if (!dataplane || !dataplane->event_channel) {
70
+ return;
71
+ }
72
+
73
+ /* Only reason for failure is a NULL channel */
74
+ xen_device_set_event_channel_context(dataplane->xendev,
75
+ dataplane->event_channel,
76
+ dataplane->ctx, &error_abort);
77
+}
78
+
79
void xen_block_dataplane_stop(XenBlockDataPlane *dataplane)
80
{
81
XenDevice *xendev;
82
@@ -XXX,XX +XXX,XX @@ void xen_block_dataplane_stop(XenBlockDataPlane *dataplane)
83
84
xendev = dataplane->xendev;
85
86
- aio_context_acquire(dataplane->ctx);
87
- if (dataplane->event_channel) {
88
- /* Only reason for failure is a NULL channel */
89
- xen_device_set_event_channel_context(xendev, dataplane->event_channel,
90
- qemu_get_aio_context(),
91
- &error_abort);
92
+ if (!blk_in_drain(dataplane->blk)) {
93
+ xen_block_dataplane_detach(dataplane);
94
}
95
+
96
+ aio_context_acquire(dataplane->ctx);
97
/* Xen doesn't have multiple users for nodes, so this can't fail */
98
blk_set_aio_context(dataplane->blk, qemu_get_aio_context(), &error_abort);
99
aio_context_release(dataplane->ctx);
100
@@ -XXX,XX +XXX,XX @@ void xen_block_dataplane_start(XenBlockDataPlane *dataplane,
101
blk_set_aio_context(dataplane->blk, dataplane->ctx, NULL);
102
aio_context_release(old_context);
103
104
- /* Only reason for failure is a NULL channel */
105
- aio_context_acquire(dataplane->ctx);
106
- xen_device_set_event_channel_context(xendev, dataplane->event_channel,
107
- dataplane->ctx, &error_abort);
108
- aio_context_release(dataplane->ctx);
109
+ if (!blk_in_drain(dataplane->blk)) {
110
+ xen_block_dataplane_attach(dataplane);
111
+ }
112
113
return;
114
115
diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c
116
index XXXXXXX..XXXXXXX 100644
117
--- a/hw/block/xen-block.c
118
+++ b/hw/block/xen-block.c
119
@@ -XXX,XX +XXX,XX @@ static void xen_block_resize_cb(void *opaque)
120
xen_device_backend_printf(xendev, "state", "%u", state);
121
}
122
123
+/* Suspend request handling */
124
+static void xen_block_drained_begin(void *opaque)
125
+{
126
+ XenBlockDevice *blockdev = opaque;
127
+
128
+ xen_block_dataplane_detach(blockdev->dataplane);
129
+}
130
+
131
+/* Resume request handling */
132
+static void xen_block_drained_end(void *opaque)
133
+{
134
+ XenBlockDevice *blockdev = opaque;
135
+
136
+ xen_block_dataplane_attach(blockdev->dataplane);
137
+}
138
+
139
static const BlockDevOps xen_block_dev_ops = {
140
- .resize_cb = xen_block_resize_cb,
141
+ .resize_cb = xen_block_resize_cb,
142
+ .drained_begin = xen_block_drained_begin,
143
+ .drained_end = xen_block_drained_end,
144
};
145
146
static void xen_block_realize(XenDevice *xendev, Error **errp)
147
@@ -XXX,XX +XXX,XX @@ static void xen_block_realize(XenDevice *xendev, Error **errp)
34
return;
148
return;
35
}
149
}
36
150
37
+ /* We know now that num_children > threshold, so blkverify must be false */
151
- blk_set_dev_ops(blk, &xen_block_dev_ops, blockdev);
38
+ assert(!s->is_blkverify);
152
-
153
if (conf->discard_granularity == -1) {
154
conf->discard_granularity = conf->physical_block_size;
155
}
156
@@ -XXX,XX +XXX,XX @@ static void xen_block_realize(XenDevice *xendev, Error **errp)
157
blockdev->dataplane =
158
xen_block_dataplane_create(xendev, blk, conf->logical_block_size,
159
blockdev->props.iothread);
39
+
160
+
40
bdrv_drained_begin(bs);
161
+ blk_set_dev_ops(blk, &xen_block_dev_ops, blockdev);
41
162
}
42
/* We can safely remove this child now */
163
164
static void xen_block_frontend_changed(XenDevice *xendev,
165
diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c
166
index XXXXXXX..XXXXXXX 100644
167
--- a/hw/xen/xen-bus.c
168
+++ b/hw/xen/xen-bus.c
169
@@ -XXX,XX +XXX,XX @@ void xen_device_set_event_channel_context(XenDevice *xendev,
170
NULL, NULL, NULL, NULL, NULL);
171
172
channel->ctx = ctx;
173
- aio_set_fd_handler(channel->ctx, qemu_xen_evtchn_fd(channel->xeh), true,
174
- xen_device_event, NULL, xen_device_poll, NULL, channel);
175
+ if (ctx) {
176
+ aio_set_fd_handler(channel->ctx, qemu_xen_evtchn_fd(channel->xeh),
177
+ true, xen_device_event, NULL, xen_device_poll, NULL,
178
+ channel);
179
+ }
180
}
181
182
XenEventChannel *xen_device_bind_event_channel(XenDevice *xendev,
43
--
183
--
44
2.19.1
184
2.40.1
45
46
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
Just like in qemu_opts_print_help(), print the device name as a caption
3
is_external=true suspends fd handlers between aio_disable_external() and
4
instead of on every single line, indent all options, add angle brackets
4
aio_enable_external(). The block layer's drain operation uses this
5
around types, and align the descriptions after 24 characters. Also,
5
mechanism to prevent new I/O from sneaking in between
6
separate the descriptions with " - " instead of putting them in
6
bdrv_drained_begin() and bdrv_drained_end().
7
parentheses, because that is what we do everywhere else. This does look
8
a bit funny here because basically all bits have the description
9
"on/off", but funny does not mean it is less readable.
10
7
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
The previous commit converted the xen-block device to use BlockDevOps
12
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
9
.drained_begin/end() callbacks. It no longer relies on is_external=true
10
so it is safe to pass is_external=false.
11
12
This is part of ongoing work to remove the aio_disable_external() API.
13
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
15
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
16
Message-Id: <20230516190238.8401-13-stefanha@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
18
---
15
qdev-monitor.c | 13 +++++++++++--
19
hw/xen/xen-bus.c | 8 ++++----
16
1 file changed, 11 insertions(+), 2 deletions(-)
20
1 file changed, 4 insertions(+), 4 deletions(-)
17
21
18
diff --git a/qdev-monitor.c b/qdev-monitor.c
22
diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c
19
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
20
--- a/qdev-monitor.c
24
--- a/hw/xen/xen-bus.c
21
+++ b/qdev-monitor.c
25
+++ b/hw/xen/xen-bus.c
22
@@ -XXX,XX +XXX,XX @@ int qdev_device_help(QemuOpts *opts)
26
@@ -XXX,XX +XXX,XX @@ void xen_device_set_event_channel_context(XenDevice *xendev,
23
goto error;
24
}
27
}
25
28
26
+ if (prop_list) {
29
if (channel->ctx)
27
+ out_printf("%s options:\n", driver);
30
- aio_set_fd_handler(channel->ctx, qemu_xen_evtchn_fd(channel->xeh), true,
28
+ } else {
31
+ aio_set_fd_handler(channel->ctx, qemu_xen_evtchn_fd(channel->xeh), false,
29
+ out_printf("There are no options for %s.\n", driver);
32
NULL, NULL, NULL, NULL, NULL);
30
+ }
33
31
for (prop = prop_list; prop; prop = prop->next) {
34
channel->ctx = ctx;
32
- out_printf("%s.%s=%s", driver, prop->value->name, prop->value->type);
35
if (ctx) {
33
+ int len;
36
aio_set_fd_handler(channel->ctx, qemu_xen_evtchn_fd(channel->xeh),
34
+ out_printf(" %s=<%s>%n", prop->value->name, prop->value->type, &len);
37
- true, xen_device_event, NULL, xen_device_poll, NULL,
35
if (prop->value->has_description) {
38
- channel);
36
- out_printf(" (%s)\n", prop->value->description);
39
+ false, xen_device_event, NULL, xen_device_poll,
37
+ if (len < 24) {
40
+ NULL, channel);
38
+ out_printf("%*s", 24 - len, "");
41
}
39
+ }
42
}
40
+ out_printf(" - %s\n", prop->value->description);
43
41
} else {
44
@@ -XXX,XX +XXX,XX @@ void xen_device_unbind_event_channel(XenDevice *xendev,
42
out_printf("\n");
45
43
}
46
QLIST_REMOVE(channel, list);
47
48
- aio_set_fd_handler(channel->ctx, qemu_xen_evtchn_fd(channel->xeh), true,
49
+ aio_set_fd_handler(channel->ctx, qemu_xen_evtchn_fd(channel->xeh), false,
50
NULL, NULL, NULL, NULL, NULL);
51
52
if (qemu_xen_evtchn_unbind(channel->xeh, channel->local_port) < 0) {
44
--
53
--
45
2.19.1
54
2.40.1
46
47
diff view generated by jsdifflib
1
From: Peter Maydell <peter.maydell@linaro.org>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
Taking the address of a field in a packed struct is a bad idea, because
3
vduse_blk_detach_ctx() waits for in-flight requests using
4
it might not be actually aligned enough for that pointer type (and
4
AIO_WAIT_WHILE(). This is not allowed according to a comment in
5
thus cause a crash on dereference on some host architectures). Newer
5
bdrv_set_aio_context_commit():
6
versions of clang warn about this. Avoid the bug by not using the
6
7
"modify in place" byte swapping functions.
7
/*
8
8
* Take the old AioContex when detaching it from bs.
9
There are a few places where the in-place swap function is
9
* At this point, new_context lock is already acquired, and we are now
10
used on something other than a packed struct field; we convert
10
* also taking old_context. This is safe as long as bdrv_detach_aio_context
11
those anyway, for consistency.
11
* does not call AIO_POLL_WHILE().
12
12
*/
13
This patch was produced with the following spatch script:
13
14
14
Use this opportunity to rewrite the drain code in vduse-blk:
15
@@
15
16
expression E;
16
- Use the BlockExport refcount so that vduse_blk_exp_delete() is only
17
@@
17
called when there are no more requests in flight.
18
-be16_to_cpus(&E);
18
19
+E = be16_to_cpu(E);
19
- Implement .drained_poll() so in-flight request coroutines are stopped
20
@@
20
by the time .bdrv_detach_aio_context() is called.
21
expression E;
21
22
@@
22
- Remove AIO_WAIT_WHILE() from vduse_blk_detach_ctx() to solve the
23
-be32_to_cpus(&E);
23
.bdrv_detach_aio_context() constraint violation. It's no longer
24
+E = be32_to_cpu(E);
24
needed due to the previous changes.
25
@@
25
26
expression E;
26
- Always handle the VDUSE file descriptor, even in drained sections. The
27
@@
27
VDUSE file descriptor doesn't submit I/O, so it's safe to handle it in
28
-be64_to_cpus(&E);
28
drained sections. This ensures that the VDUSE kernel code gets a fast
29
+E = be64_to_cpu(E);
29
response.
30
@@
30
31
expression E;
31
- Suspend virtqueue fd handlers in .drained_begin() and resume them in
32
@@
32
.drained_end(). This eliminates the need for the
33
-cpu_to_be16s(&E);
33
aio_set_fd_handler(is_external=true) flag, which is being removed from
34
+E = cpu_to_be16(E);
34
QEMU.
35
@@
35
36
expression E;
36
This is a long list but splitting it into individual commits would
37
@@
37
probably lead to git bisect failures - the changes are all related.
38
-cpu_to_be32s(&E);
38
39
+E = cpu_to_be32(E);
39
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
40
@@
40
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
41
expression E;
41
Message-Id: <20230516190238.8401-14-stefanha@redhat.com>
42
@@
43
-cpu_to_be64s(&E);
44
+E = cpu_to_be64(E);
45
46
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
47
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
48
Tested-by: John Snow <jsnow@redhat.com>
49
Reviewed-by: John Snow <jsnow@redhat.com>
50
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
42
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
51
---
43
---
52
block/qcow.c | 18 +++++++++---------
44
block/export/vduse-blk.c | 132 +++++++++++++++++++++++++++------------
53
1 file changed, 9 insertions(+), 9 deletions(-)
45
1 file changed, 93 insertions(+), 39 deletions(-)
54
46
55
diff --git a/block/qcow.c b/block/qcow.c
47
diff --git a/block/export/vduse-blk.c b/block/export/vduse-blk.c
56
index XXXXXXX..XXXXXXX 100644
48
index XXXXXXX..XXXXXXX 100644
57
--- a/block/qcow.c
49
--- a/block/export/vduse-blk.c
58
+++ b/block/qcow.c
50
+++ b/block/export/vduse-blk.c
59
@@ -XXX,XX +XXX,XX @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
51
@@ -XXX,XX +XXX,XX @@ typedef struct VduseBlkExport {
60
if (ret < 0) {
52
VduseDev *dev;
61
goto fail;
53
uint16_t num_queues;
54
char *recon_file;
55
- unsigned int inflight;
56
+ unsigned int inflight; /* atomic */
57
+ bool vqs_started;
58
} VduseBlkExport;
59
60
typedef struct VduseBlkReq {
61
@@ -XXX,XX +XXX,XX @@ typedef struct VduseBlkReq {
62
63
static void vduse_blk_inflight_inc(VduseBlkExport *vblk_exp)
64
{
65
- vblk_exp->inflight++;
66
+ if (qatomic_fetch_inc(&vblk_exp->inflight) == 0) {
67
+ /* Prevent export from being deleted */
68
+ aio_context_acquire(vblk_exp->export.ctx);
69
+ blk_exp_ref(&vblk_exp->export);
70
+ aio_context_release(vblk_exp->export.ctx);
71
+ }
72
}
73
74
static void vduse_blk_inflight_dec(VduseBlkExport *vblk_exp)
75
{
76
- if (--vblk_exp->inflight == 0) {
77
+ if (qatomic_fetch_dec(&vblk_exp->inflight) == 1) {
78
+ /* Wake AIO_WAIT_WHILE() */
79
aio_wait_kick();
80
+
81
+ /* Now the export can be deleted */
82
+ aio_context_acquire(vblk_exp->export.ctx);
83
+ blk_exp_unref(&vblk_exp->export);
84
+ aio_context_release(vblk_exp->export.ctx);
62
}
85
}
63
- be32_to_cpus(&header.magic);
86
}
64
- be32_to_cpus(&header.version);
87
65
- be64_to_cpus(&header.backing_file_offset);
88
@@ -XXX,XX +XXX,XX @@ static void vduse_blk_enable_queue(VduseDev *dev, VduseVirtq *vq)
66
- be32_to_cpus(&header.backing_file_size);
89
{
67
- be32_to_cpus(&header.mtime);
90
VduseBlkExport *vblk_exp = vduse_dev_get_priv(dev);
68
- be64_to_cpus(&header.size);
91
69
- be32_to_cpus(&header.crypt_method);
92
+ if (!vblk_exp->vqs_started) {
70
- be64_to_cpus(&header.l1_table_offset);
93
+ return; /* vduse_blk_drained_end() will start vqs later */
71
+ header.magic = be32_to_cpu(header.magic);
94
+ }
72
+ header.version = be32_to_cpu(header.version);
95
+
73
+ header.backing_file_offset = be64_to_cpu(header.backing_file_offset);
96
aio_set_fd_handler(vblk_exp->export.ctx, vduse_queue_get_fd(vq),
74
+ header.backing_file_size = be32_to_cpu(header.backing_file_size);
97
- true, on_vduse_vq_kick, NULL, NULL, NULL, vq);
75
+ header.mtime = be32_to_cpu(header.mtime);
98
+ false, on_vduse_vq_kick, NULL, NULL, NULL, vq);
76
+ header.size = be64_to_cpu(header.size);
99
/* Make sure we don't miss any kick afer reconnecting */
77
+ header.crypt_method = be32_to_cpu(header.crypt_method);
100
eventfd_write(vduse_queue_get_fd(vq), 1);
78
+ header.l1_table_offset = be64_to_cpu(header.l1_table_offset);
101
}
79
102
@@ -XXX,XX +XXX,XX @@ static void vduse_blk_enable_queue(VduseDev *dev, VduseVirtq *vq)
80
if (header.magic != QCOW_MAGIC) {
103
static void vduse_blk_disable_queue(VduseDev *dev, VduseVirtq *vq)
81
error_setg(errp, "Image not in qcow format");
104
{
82
@@ -XXX,XX +XXX,XX @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
105
VduseBlkExport *vblk_exp = vduse_dev_get_priv(dev);
106
+ int fd = vduse_queue_get_fd(vq);
107
108
- aio_set_fd_handler(vblk_exp->export.ctx, vduse_queue_get_fd(vq),
109
- true, NULL, NULL, NULL, NULL, NULL);
110
+ if (fd < 0) {
111
+ return;
112
+ }
113
+
114
+ aio_set_fd_handler(vblk_exp->export.ctx, fd, false,
115
+ NULL, NULL, NULL, NULL, NULL);
116
}
117
118
static const VduseOps vduse_blk_ops = {
119
@@ -XXX,XX +XXX,XX @@ static void on_vduse_dev_kick(void *opaque)
120
121
static void vduse_blk_attach_ctx(VduseBlkExport *vblk_exp, AioContext *ctx)
122
{
123
- int i;
124
-
125
aio_set_fd_handler(vblk_exp->export.ctx, vduse_dev_get_fd(vblk_exp->dev),
126
- true, on_vduse_dev_kick, NULL, NULL, NULL,
127
+ false, on_vduse_dev_kick, NULL, NULL, NULL,
128
vblk_exp->dev);
129
130
- for (i = 0; i < vblk_exp->num_queues; i++) {
131
- VduseVirtq *vq = vduse_dev_get_queue(vblk_exp->dev, i);
132
- int fd = vduse_queue_get_fd(vq);
133
-
134
- if (fd < 0) {
135
- continue;
136
- }
137
- aio_set_fd_handler(vblk_exp->export.ctx, fd, true,
138
- on_vduse_vq_kick, NULL, NULL, NULL, vq);
139
- }
140
+ /* Virtqueues are handled by vduse_blk_drained_end() */
141
}
142
143
static void vduse_blk_detach_ctx(VduseBlkExport *vblk_exp)
144
{
145
- int i;
146
-
147
- for (i = 0; i < vblk_exp->num_queues; i++) {
148
- VduseVirtq *vq = vduse_dev_get_queue(vblk_exp->dev, i);
149
- int fd = vduse_queue_get_fd(vq);
150
-
151
- if (fd < 0) {
152
- continue;
153
- }
154
- aio_set_fd_handler(vblk_exp->export.ctx, fd,
155
- true, NULL, NULL, NULL, NULL, NULL);
156
- }
157
aio_set_fd_handler(vblk_exp->export.ctx, vduse_dev_get_fd(vblk_exp->dev),
158
- true, NULL, NULL, NULL, NULL, NULL);
159
+ false, NULL, NULL, NULL, NULL, NULL);
160
161
- AIO_WAIT_WHILE(vblk_exp->export.ctx, vblk_exp->inflight > 0);
162
+ /* Virtqueues are handled by vduse_blk_drained_begin() */
163
}
164
165
166
@@ -XXX,XX +XXX,XX @@ static void vduse_blk_resize(void *opaque)
167
(char *)&config.capacity);
168
}
169
170
+static void vduse_blk_stop_virtqueues(VduseBlkExport *vblk_exp)
171
+{
172
+ for (uint16_t i = 0; i < vblk_exp->num_queues; i++) {
173
+ VduseVirtq *vq = vduse_dev_get_queue(vblk_exp->dev, i);
174
+ vduse_blk_disable_queue(vblk_exp->dev, vq);
175
+ }
176
+
177
+ vblk_exp->vqs_started = false;
178
+}
179
+
180
+static void vduse_blk_start_virtqueues(VduseBlkExport *vblk_exp)
181
+{
182
+ vblk_exp->vqs_started = true;
183
+
184
+ for (uint16_t i = 0; i < vblk_exp->num_queues; i++) {
185
+ VduseVirtq *vq = vduse_dev_get_queue(vblk_exp->dev, i);
186
+ vduse_blk_enable_queue(vblk_exp->dev, vq);
187
+ }
188
+}
189
+
190
+static void vduse_blk_drained_begin(void *opaque)
191
+{
192
+ BlockExport *exp = opaque;
193
+ VduseBlkExport *vblk_exp = container_of(exp, VduseBlkExport, export);
194
+
195
+ vduse_blk_stop_virtqueues(vblk_exp);
196
+}
197
+
198
+static void vduse_blk_drained_end(void *opaque)
199
+{
200
+ BlockExport *exp = opaque;
201
+ VduseBlkExport *vblk_exp = container_of(exp, VduseBlkExport, export);
202
+
203
+ vduse_blk_start_virtqueues(vblk_exp);
204
+}
205
+
206
+static bool vduse_blk_drained_poll(void *opaque)
207
+{
208
+ BlockExport *exp = opaque;
209
+ VduseBlkExport *vblk_exp = container_of(exp, VduseBlkExport, export);
210
+
211
+ return qatomic_read(&vblk_exp->inflight) > 0;
212
+}
213
+
214
static const BlockDevOps vduse_block_ops = {
215
- .resize_cb = vduse_blk_resize,
216
+ .resize_cb = vduse_blk_resize,
217
+ .drained_begin = vduse_blk_drained_begin,
218
+ .drained_end = vduse_blk_drained_end,
219
+ .drained_poll = vduse_blk_drained_poll,
220
};
221
222
static int vduse_blk_exp_create(BlockExport *exp, BlockExportOptions *opts,
223
@@ -XXX,XX +XXX,XX @@ static int vduse_blk_exp_create(BlockExport *exp, BlockExportOptions *opts,
224
vblk_exp->handler.serial = g_strdup(vblk_opts->serial ?: "");
225
vblk_exp->handler.logical_block_size = logical_block_size;
226
vblk_exp->handler.writable = opts->writable;
227
+ vblk_exp->vqs_started = true;
228
229
config.capacity =
230
cpu_to_le64(blk_getlength(exp->blk) >> VIRTIO_BLK_SECTOR_BITS);
231
@@ -XXX,XX +XXX,XX @@ static int vduse_blk_exp_create(BlockExport *exp, BlockExportOptions *opts,
232
vduse_dev_setup_queue(vblk_exp->dev, i, queue_size);
83
}
233
}
84
234
85
for(i = 0;i < s->l1_size; i++) {
235
- aio_set_fd_handler(exp->ctx, vduse_dev_get_fd(vblk_exp->dev), true,
86
- be64_to_cpus(&s->l1_table[i]);
236
+ aio_set_fd_handler(exp->ctx, vduse_dev_get_fd(vblk_exp->dev), false,
87
+ s->l1_table[i] = be64_to_cpu(s->l1_table[i]);
237
on_vduse_dev_kick, NULL, NULL, NULL, vblk_exp->dev);
88
}
238
89
239
blk_add_aio_context_notifier(exp->blk, blk_aio_attached, blk_aio_detach,
90
/* alloc L2 cache (max. 64k * 16 * 8 = 8 MB) */
240
vblk_exp);
241
-
242
blk_set_dev_ops(exp->blk, &vduse_block_ops, exp);
243
244
+ /*
245
+ * We handle draining ourselves using an in-flight counter and by disabling
246
+ * virtqueue fd handlers. Do not queue BlockBackend requests, they need to
247
+ * complete so the in-flight counter reaches zero.
248
+ */
249
+ blk_set_disable_request_queuing(exp->blk, true);
250
+
251
return 0;
252
err:
253
vduse_dev_destroy(vblk_exp->dev);
254
@@ -XXX,XX +XXX,XX @@ static void vduse_blk_exp_delete(BlockExport *exp)
255
VduseBlkExport *vblk_exp = container_of(exp, VduseBlkExport, export);
256
int ret;
257
258
+ assert(qatomic_read(&vblk_exp->inflight) == 0);
259
+
260
+ vduse_blk_detach_ctx(vblk_exp);
261
blk_remove_aio_context_notifier(exp->blk, blk_aio_attached, blk_aio_detach,
262
vblk_exp);
263
ret = vduse_dev_destroy(vblk_exp->dev);
264
@@ -XXX,XX +XXX,XX @@ static void vduse_blk_exp_delete(BlockExport *exp)
265
g_free(vblk_exp->handler.serial);
266
}
267
268
+/* Called with exp->ctx acquired */
269
static void vduse_blk_exp_request_shutdown(BlockExport *exp)
270
{
271
VduseBlkExport *vblk_exp = container_of(exp, VduseBlkExport, export);
272
273
- aio_context_acquire(vblk_exp->export.ctx);
274
- vduse_blk_detach_ctx(vblk_exp);
275
- aio_context_acquire(vblk_exp->export.ctx);
276
+ vduse_blk_stop_virtqueues(vblk_exp);
277
}
278
279
const BlockExportDriver blk_exp_vduse_blk = {
91
--
280
--
92
2.19.1
281
2.40.1
93
94
diff view generated by jsdifflib
1
From: Cleber Rosa <crosa@redhat.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
While testing the Python 3 changes which touch the 083 test, I noticed
3
The FUSE export calls blk_exp_ref/unref() without the AioContext lock.
4
that it would fail with qcow2. Expanding the testing, I noticed it
4
Instead of fixing the FUSE export, adjust blk_exp_ref/unref() so they
5
had nothing to do with the Python 3 changes, and in fact, it would not
5
work without the AioContext lock. This way it's less error-prone.
6
pass on anything but raw:
7
6
8
raw: pass
7
Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
9
bochs: not generic
8
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
cloop: not generic
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
11
parallels: fail
10
Message-Id: <20230516190238.8401-15-stefanha@redhat.com>
12
qcow: fail
13
qcow2: fail
14
qed: fail
15
vdi: fail
16
vhdx: fail
17
vmdk: fail
18
vpc: fail
19
luks: fail
20
21
The errors are a mixture I/O and "image not in xxx format", such as:
22
23
=== Check disconnect before data ===
24
25
Unexpected end-of-file before all bytes were read
26
-read failed: Input/output error
27
+can't open device nbd+tcp://127.0.0.1:PORT/foo: Could not open 'nbd://127.0.0.1:PORT/foo': Input/output error
28
29
=== Check disconnect after data ===
30
31
-read 512/512 bytes at offset 0
32
-512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
33
+can't open device nbd+tcp://127.0.0.1:PORT/foo: Image not in qcow format
34
35
I'm not aware if there's a quick fix, so, for the time being, it looks
36
like the honest approach is to make the test known to work on raw
37
only.
38
39
Signed-off-by: Cleber Rosa <crosa@redhat.com>
40
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
41
---
12
---
42
tests/qemu-iotests/083 | 2 +-
13
include/block/export.h | 2 ++
43
1 file changed, 1 insertion(+), 1 deletion(-)
14
block/export/export.c | 13 ++++++-------
15
block/export/vduse-blk.c | 4 ----
16
3 files changed, 8 insertions(+), 11 deletions(-)
44
17
45
diff --git a/tests/qemu-iotests/083 b/tests/qemu-iotests/083
18
diff --git a/include/block/export.h b/include/block/export.h
46
index XXXXXXX..XXXXXXX 100755
19
index XXXXXXX..XXXXXXX 100644
47
--- a/tests/qemu-iotests/083
20
--- a/include/block/export.h
48
+++ b/tests/qemu-iotests/083
21
+++ b/include/block/export.h
49
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
22
@@ -XXX,XX +XXX,XX @@ struct BlockExport {
50
. ./common.rc
23
* Reference count for this block export. This includes strong references
51
. ./common.filter
24
* both from the owner (qemu-nbd or the monitor) and clients connected to
52
25
* the export.
53
-_supported_fmt generic
26
+ *
54
+_supported_fmt raw
27
+ * Use atomics to access this field.
55
_supported_proto nbd
28
*/
56
_supported_os Linux
29
int refcount;
30
31
diff --git a/block/export/export.c b/block/export/export.c
32
index XXXXXXX..XXXXXXX 100644
33
--- a/block/export/export.c
34
+++ b/block/export/export.c
35
@@ -XXX,XX +XXX,XX @@ fail:
36
return NULL;
37
}
38
39
-/* Callers must hold exp->ctx lock */
40
void blk_exp_ref(BlockExport *exp)
41
{
42
- assert(exp->refcount > 0);
43
- exp->refcount++;
44
+ assert(qatomic_read(&exp->refcount) > 0);
45
+ qatomic_inc(&exp->refcount);
46
}
47
48
/* Runs in the main thread */
49
@@ -XXX,XX +XXX,XX @@ static void blk_exp_delete_bh(void *opaque)
50
aio_context_release(aio_context);
51
}
52
53
-/* Callers must hold exp->ctx lock */
54
void blk_exp_unref(BlockExport *exp)
55
{
56
- assert(exp->refcount > 0);
57
- if (--exp->refcount == 0) {
58
+ assert(qatomic_read(&exp->refcount) > 0);
59
+ if (qatomic_fetch_dec(&exp->refcount) == 1) {
60
/* Touch the block_exports list only in the main thread */
61
aio_bh_schedule_oneshot(qemu_get_aio_context(), blk_exp_delete_bh,
62
exp);
63
@@ -XXX,XX +XXX,XX @@ void qmp_block_export_del(const char *id,
64
if (!has_mode) {
65
mode = BLOCK_EXPORT_REMOVE_MODE_SAFE;
66
}
67
- if (mode == BLOCK_EXPORT_REMOVE_MODE_SAFE && exp->refcount > 1) {
68
+ if (mode == BLOCK_EXPORT_REMOVE_MODE_SAFE &&
69
+ qatomic_read(&exp->refcount) > 1) {
70
error_setg(errp, "export '%s' still in use", exp->id);
71
error_append_hint(errp, "Use mode='hard' to force client "
72
"disconnect\n");
73
diff --git a/block/export/vduse-blk.c b/block/export/vduse-blk.c
74
index XXXXXXX..XXXXXXX 100644
75
--- a/block/export/vduse-blk.c
76
+++ b/block/export/vduse-blk.c
77
@@ -XXX,XX +XXX,XX @@ static void vduse_blk_inflight_inc(VduseBlkExport *vblk_exp)
78
{
79
if (qatomic_fetch_inc(&vblk_exp->inflight) == 0) {
80
/* Prevent export from being deleted */
81
- aio_context_acquire(vblk_exp->export.ctx);
82
blk_exp_ref(&vblk_exp->export);
83
- aio_context_release(vblk_exp->export.ctx);
84
}
85
}
86
87
@@ -XXX,XX +XXX,XX @@ static void vduse_blk_inflight_dec(VduseBlkExport *vblk_exp)
88
aio_wait_kick();
89
90
/* Now the export can be deleted */
91
- aio_context_acquire(vblk_exp->export.ctx);
92
blk_exp_unref(&vblk_exp->export);
93
- aio_context_release(vblk_exp->export.ctx);
94
}
95
}
57
96
58
--
97
--
59
2.19.1
98
2.40.1
60
61
diff view generated by jsdifflib
1
From: Peter Maydell <peter.maydell@linaro.org>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
Taking the address of a field in a packed struct is a bad idea, because
3
This is part of ongoing work to remove the aio_disable_external() API.
4
it might not be actually aligned enough for that pointer type (and
5
thus cause a crash on dereference on some host architectures). Newer
6
versions of clang warn about this. Avoid the bug by not using the
7
"modify in place" byte swapping functions.
8
4
9
There are a few places where the in-place swap function is
5
Use BlockDevOps .drained_begin/end/poll() instead of
10
used on something other than a packed struct field; we convert
6
aio_set_fd_handler(is_external=true).
11
those anyway, for consistency.
12
7
13
This patch was produced with the following spatch script
8
As a side-effect the FUSE export now follows AioContext changes like the
14
(and hand-editing to fold a few resulting overlength lines):
9
other export types.
15
10
16
@@
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
17
expression E;
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
18
@@
13
Message-Id: <20230516190238.8401-16-stefanha@redhat.com>
19
-be16_to_cpus(&E);
20
+E = be16_to_cpu(E);
21
@@
22
expression E;
23
@@
24
-be32_to_cpus(&E);
25
+E = be32_to_cpu(E);
26
@@
27
expression E;
28
@@
29
-be64_to_cpus(&E);
30
+E = be64_to_cpu(E);
31
@@
32
expression E;
33
@@
34
-cpu_to_be16s(&E);
35
+E = cpu_to_be16(E);
36
@@
37
expression E;
38
@@
39
-cpu_to_be32s(&E);
40
+E = cpu_to_be32(E);
41
@@
42
expression E;
43
@@
44
-cpu_to_be64s(&E);
45
+E = cpu_to_be64(E);
46
47
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
48
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
49
Tested-by: John Snow <jsnow@redhat.com>
50
Reviewed-by: John Snow <jsnow@redhat.com>
51
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
52
---
15
---
53
block/qcow2.c | 64 +++++++++++++++++++++++++++------------------------
16
block/export/fuse.c | 56 +++++++++++++++++++++++++++++++++++++++++++--
54
1 file changed, 34 insertions(+), 30 deletions(-)
17
1 file changed, 54 insertions(+), 2 deletions(-)
55
18
56
diff --git a/block/qcow2.c b/block/qcow2.c
19
diff --git a/block/export/fuse.c b/block/export/fuse.c
57
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
58
--- a/block/qcow2.c
21
--- a/block/export/fuse.c
59
+++ b/block/qcow2.c
22
+++ b/block/export/fuse.c
60
@@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
23
@@ -XXX,XX +XXX,XX @@ typedef struct FuseExport {
61
"pread fail from offset %" PRIu64, offset);
24
62
return 1;
25
struct fuse_session *fuse_session;
63
}
26
struct fuse_buf fuse_buf;
64
- be32_to_cpus(&ext.magic);
27
+ unsigned int in_flight; /* atomic */
65
- be32_to_cpus(&ext.len);
28
bool mounted, fd_handler_set_up;
66
+ ext.magic = be32_to_cpu(ext.magic);
29
67
+ ext.len = be32_to_cpu(ext.len);
30
char *mountpoint;
68
offset += sizeof(ext);
31
@@ -XXX,XX +XXX,XX @@ static void read_from_fuse_export(void *opaque);
69
#ifdef DEBUG_EXT
32
static bool is_regular_file(const char *path, Error **errp);
70
printf("ext.magic = 0x%x\n", ext.magic);
33
71
@@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
34
72
"Unable to read CRYPTO header extension");
35
+static void fuse_export_drained_begin(void *opaque)
73
return ret;
36
+{
74
}
37
+ FuseExport *exp = opaque;
75
- be64_to_cpus(&s->crypto_header.offset);
38
+
76
- be64_to_cpus(&s->crypto_header.length);
39
+ aio_set_fd_handler(exp->common.ctx,
77
+ s->crypto_header.offset = be64_to_cpu(s->crypto_header.offset);
40
+ fuse_session_fd(exp->fuse_session), false,
78
+ s->crypto_header.length = be64_to_cpu(s->crypto_header.length);
41
+ NULL, NULL, NULL, NULL, NULL);
79
42
+ exp->fd_handler_set_up = false;
80
if ((s->crypto_header.offset % s->cluster_size) != 0) {
43
+}
81
error_setg(errp, "Encryption header offset '%" PRIu64 "' is "
44
+
82
@@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
45
+static void fuse_export_drained_end(void *opaque)
83
return -EINVAL;
46
+{
84
}
47
+ FuseExport *exp = opaque;
85
48
+
86
- be32_to_cpus(&bitmaps_ext.nb_bitmaps);
49
+ /* Refresh AioContext in case it changed */
87
- be64_to_cpus(&bitmaps_ext.bitmap_directory_size);
50
+ exp->common.ctx = blk_get_aio_context(exp->common.blk);
88
- be64_to_cpus(&bitmaps_ext.bitmap_directory_offset);
51
+
89
+ bitmaps_ext.nb_bitmaps = be32_to_cpu(bitmaps_ext.nb_bitmaps);
52
+ aio_set_fd_handler(exp->common.ctx,
90
+ bitmaps_ext.bitmap_directory_size =
53
+ fuse_session_fd(exp->fuse_session), false,
91
+ be64_to_cpu(bitmaps_ext.bitmap_directory_size);
54
+ read_from_fuse_export, NULL, NULL, NULL, exp);
92
+ bitmaps_ext.bitmap_directory_offset =
55
+ exp->fd_handler_set_up = true;
93
+ be64_to_cpu(bitmaps_ext.bitmap_directory_offset);
56
+}
94
57
+
95
if (bitmaps_ext.nb_bitmaps > QCOW2_MAX_BITMAPS) {
58
+static bool fuse_export_drained_poll(void *opaque)
96
error_setg(errp,
59
+{
97
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
60
+ FuseExport *exp = opaque;
98
error_setg_errno(errp, -ret, "Could not read qcow2 header");
61
+
99
goto fail;
62
+ return qatomic_read(&exp->in_flight) > 0;
100
}
63
+}
101
- be32_to_cpus(&header.magic);
64
+
102
- be32_to_cpus(&header.version);
65
+static const BlockDevOps fuse_export_blk_dev_ops = {
103
- be64_to_cpus(&header.backing_file_offset);
66
+ .drained_begin = fuse_export_drained_begin,
104
- be32_to_cpus(&header.backing_file_size);
67
+ .drained_end = fuse_export_drained_end,
105
- be64_to_cpus(&header.size);
68
+ .drained_poll = fuse_export_drained_poll,
106
- be32_to_cpus(&header.cluster_bits);
69
+};
107
- be32_to_cpus(&header.crypt_method);
70
+
108
- be64_to_cpus(&header.l1_table_offset);
71
static int fuse_export_create(BlockExport *blk_exp,
109
- be32_to_cpus(&header.l1_size);
72
BlockExportOptions *blk_exp_args,
110
- be64_to_cpus(&header.refcount_table_offset);
73
Error **errp)
111
- be32_to_cpus(&header.refcount_table_clusters);
74
@@ -XXX,XX +XXX,XX @@ static int fuse_export_create(BlockExport *blk_exp,
112
- be64_to_cpus(&header.snapshots_offset);
113
- be32_to_cpus(&header.nb_snapshots);
114
+ header.magic = be32_to_cpu(header.magic);
115
+ header.version = be32_to_cpu(header.version);
116
+ header.backing_file_offset = be64_to_cpu(header.backing_file_offset);
117
+ header.backing_file_size = be32_to_cpu(header.backing_file_size);
118
+ header.size = be64_to_cpu(header.size);
119
+ header.cluster_bits = be32_to_cpu(header.cluster_bits);
120
+ header.crypt_method = be32_to_cpu(header.crypt_method);
121
+ header.l1_table_offset = be64_to_cpu(header.l1_table_offset);
122
+ header.l1_size = be32_to_cpu(header.l1_size);
123
+ header.refcount_table_offset = be64_to_cpu(header.refcount_table_offset);
124
+ header.refcount_table_clusters =
125
+ be32_to_cpu(header.refcount_table_clusters);
126
+ header.snapshots_offset = be64_to_cpu(header.snapshots_offset);
127
+ header.nb_snapshots = be32_to_cpu(header.nb_snapshots);
128
129
if (header.magic != QCOW_MAGIC) {
130
error_setg(errp, "Image is not in qcow2 format");
131
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
132
header.refcount_order = 4;
133
header.header_length = 72;
134
} else {
135
- be64_to_cpus(&header.incompatible_features);
136
- be64_to_cpus(&header.compatible_features);
137
- be64_to_cpus(&header.autoclear_features);
138
- be32_to_cpus(&header.refcount_order);
139
- be32_to_cpus(&header.header_length);
140
+ header.incompatible_features =
141
+ be64_to_cpu(header.incompatible_features);
142
+ header.compatible_features = be64_to_cpu(header.compatible_features);
143
+ header.autoclear_features = be64_to_cpu(header.autoclear_features);
144
+ header.refcount_order = be32_to_cpu(header.refcount_order);
145
+ header.header_length = be32_to_cpu(header.header_length);
146
147
if (header.header_length < 104) {
148
error_setg(errp, "qcow2 header too short");
149
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
150
goto fail;
151
}
152
for(i = 0;i < s->l1_size; i++) {
153
- be64_to_cpus(&s->l1_table[i]);
154
+ s->l1_table[i] = be64_to_cpu(s->l1_table[i]);
155
}
75
}
156
}
76
}
157
77
158
@@ -XXX,XX +XXX,XX @@ int qcow2_update_header(BlockDriverState *bs)
78
+ blk_set_dev_ops(exp->common.blk, &fuse_export_blk_dev_ops, exp);
159
79
+
160
/* Full disk encryption header pointer extension */
80
+ /*
161
if (s->crypto_header.offset != 0) {
81
+ * We handle draining ourselves using an in-flight counter and by disabling
162
- cpu_to_be64s(&s->crypto_header.offset);
82
+ * the FUSE fd handler. Do not queue BlockBackend requests, they need to
163
- cpu_to_be64s(&s->crypto_header.length);
83
+ * complete so the in-flight counter reaches zero.
164
+ s->crypto_header.offset = cpu_to_be64(s->crypto_header.offset);
84
+ */
165
+ s->crypto_header.length = cpu_to_be64(s->crypto_header.length);
85
+ blk_set_disable_request_queuing(exp->common.blk, true);
166
ret = header_ext_add(buf, QCOW2_EXT_MAGIC_CRYPTO_HEADER,
86
+
167
&s->crypto_header, sizeof(s->crypto_header),
87
init_exports_table();
168
buflen);
88
169
- be64_to_cpus(&s->crypto_header.offset);
89
/*
170
- be64_to_cpus(&s->crypto_header.length);
90
@@ -XXX,XX +XXX,XX @@ static int setup_fuse_export(FuseExport *exp, const char *mountpoint,
171
+ s->crypto_header.offset = be64_to_cpu(s->crypto_header.offset);
91
g_hash_table_insert(exports, g_strdup(mountpoint), NULL);
172
+ s->crypto_header.length = be64_to_cpu(s->crypto_header.length);
92
173
if (ret < 0) {
93
aio_set_fd_handler(exp->common.ctx,
174
goto fail;
94
- fuse_session_fd(exp->fuse_session), true,
95
+ fuse_session_fd(exp->fuse_session), false,
96
read_from_fuse_export, NULL, NULL, NULL, exp);
97
exp->fd_handler_set_up = true;
98
99
@@ -XXX,XX +XXX,XX @@ static void read_from_fuse_export(void *opaque)
100
101
blk_exp_ref(&exp->common);
102
103
+ qatomic_inc(&exp->in_flight);
104
+
105
do {
106
ret = fuse_session_receive_buf(exp->fuse_session, &exp->fuse_buf);
107
} while (ret == -EINTR);
108
@@ -XXX,XX +XXX,XX @@ static void read_from_fuse_export(void *opaque)
109
fuse_session_process_buf(exp->fuse_session, &exp->fuse_buf);
110
111
out:
112
+ if (qatomic_fetch_dec(&exp->in_flight) == 1) {
113
+ aio_wait_kick(); /* wake AIO_WAIT_WHILE() */
114
+ }
115
+
116
blk_exp_unref(&exp->common);
117
}
118
119
@@ -XXX,XX +XXX,XX @@ static void fuse_export_shutdown(BlockExport *blk_exp)
120
121
if (exp->fd_handler_set_up) {
122
aio_set_fd_handler(exp->common.ctx,
123
- fuse_session_fd(exp->fuse_session), true,
124
+ fuse_session_fd(exp->fuse_session), false,
125
NULL, NULL, NULL, NULL, NULL);
126
exp->fd_handler_set_up = false;
175
}
127
}
176
--
128
--
177
2.19.1
129
2.40.1
178
179
diff view generated by jsdifflib
1
From: Peter Maydell <peter.maydell@linaro.org>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
Taking the address of a field in a packed struct is a bad idea, because
3
virtio_queue_aio_detach_host_notifier() does two things:
4
it might not be actually aligned enough for that pointer type (and
4
1. It removes the fd handler from the event loop.
5
thus cause a crash on dereference on some host architectures). Newer
5
2. It processes the virtqueue one last time.
6
versions of clang warn about this. Avoid the bug by not using the
7
"modify in place" byte swapping functions.
8
6
9
There are a few places where the in-place swap function is
7
The first step can be peformed by any thread and without taking the
10
used on something other than a packed struct field; we convert
8
AioContext lock.
11
those anyway, for consistency.
12
9
13
This patch was produced with the following spatch script:
10
The second step may need the AioContext lock (depending on the device
11
implementation) and runs in the thread where request processing takes
12
place. virtio-blk and virtio-scsi therefore call
13
virtio_queue_aio_detach_host_notifier() from a BH that is scheduled in
14
AioContext.
14
15
15
@@
16
The next patch will introduce a .drained_begin() function that needs to
16
expression E;
17
call virtio_queue_aio_detach_host_notifier(). .drained_begin() functions
17
@@
18
cannot call aio_poll() to wait synchronously for the BH. It is possible
18
-be16_to_cpus(&E);
19
for a .drained_poll() callback to asynchronously wait for the BH, but
19
+E = be16_to_cpu(E);
20
that is more complex than necessary here.
20
@@
21
expression E;
22
@@
23
-be32_to_cpus(&E);
24
+E = be32_to_cpu(E);
25
@@
26
expression E;
27
@@
28
-be64_to_cpus(&E);
29
+E = be64_to_cpu(E);
30
@@
31
expression E;
32
@@
33
-cpu_to_be16s(&E);
34
+E = cpu_to_be16(E);
35
@@
36
expression E;
37
@@
38
-cpu_to_be32s(&E);
39
+E = cpu_to_be32(E);
40
@@
41
expression E;
42
@@
43
-cpu_to_be64s(&E);
44
+E = cpu_to_be64(E);
45
21
46
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
22
Move the virtqueue processing out to the callers of
47
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
23
virtio_queue_aio_detach_host_notifier() so that the function can be
48
Tested-by: John Snow <jsnow@redhat.com>
24
called from any thread. This is in preparation for the next patch.
49
Reviewed-by: John Snow <jsnow@redhat.com>
25
26
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
27
Message-Id: <20230516190238.8401-17-stefanha@redhat.com>
50
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
28
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
51
---
29
---
52
block/qcow2-bitmap.c | 24 ++++++++++++------------
30
hw/block/dataplane/virtio-blk.c | 7 +++++++
53
1 file changed, 12 insertions(+), 12 deletions(-)
31
hw/scsi/virtio-scsi-dataplane.c | 14 ++++++++++++++
32
hw/virtio/virtio.c | 3 ---
33
3 files changed, 21 insertions(+), 3 deletions(-)
54
34
55
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
35
diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c
56
index XXXXXXX..XXXXXXX 100644
36
index XXXXXXX..XXXXXXX 100644
57
--- a/block/qcow2-bitmap.c
37
--- a/hw/block/dataplane/virtio-blk.c
58
+++ b/block/qcow2-bitmap.c
38
+++ b/hw/block/dataplane/virtio-blk.c
59
@@ -XXX,XX +XXX,XX @@ static inline void bitmap_table_to_be(uint64_t *bitmap_table, size_t size)
39
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_data_plane_stop_bh(void *opaque)
60
size_t i;
40
61
41
for (i = 0; i < s->conf->num_queues; i++) {
62
for (i = 0; i < size; ++i) {
42
VirtQueue *vq = virtio_get_queue(s->vdev, i);
63
- cpu_to_be64s(&bitmap_table[i]);
43
+ EventNotifier *host_notifier = virtio_queue_get_host_notifier(vq);
64
+ bitmap_table[i] = cpu_to_be64(bitmap_table[i]);
44
45
virtio_queue_aio_detach_host_notifier(vq, s->ctx);
46
+
47
+ /*
48
+ * Test and clear notifier after disabling event, in case poll callback
49
+ * didn't have time to run.
50
+ */
51
+ virtio_queue_host_notifier_read(host_notifier);
65
}
52
}
66
}
53
}
67
54
68
@@ -XXX,XX +XXX,XX @@ static int bitmap_table_load(BlockDriverState *bs, Qcow2BitmapTable *tb,
55
diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c
56
index XXXXXXX..XXXXXXX 100644
57
--- a/hw/scsi/virtio-scsi-dataplane.c
58
+++ b/hw/scsi/virtio-scsi-dataplane.c
59
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_dataplane_stop_bh(void *opaque)
60
{
61
VirtIOSCSI *s = opaque;
62
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
63
+ EventNotifier *host_notifier;
64
int i;
65
66
virtio_queue_aio_detach_host_notifier(vs->ctrl_vq, s->ctx);
67
+ host_notifier = virtio_queue_get_host_notifier(vs->ctrl_vq);
68
+
69
+ /*
70
+ * Test and clear notifier after disabling event, in case poll callback
71
+ * didn't have time to run.
72
+ */
73
+ virtio_queue_host_notifier_read(host_notifier);
74
+
75
virtio_queue_aio_detach_host_notifier(vs->event_vq, s->ctx);
76
+ host_notifier = virtio_queue_get_host_notifier(vs->event_vq);
77
+ virtio_queue_host_notifier_read(host_notifier);
78
+
79
for (i = 0; i < vs->conf.num_queues; i++) {
80
virtio_queue_aio_detach_host_notifier(vs->cmd_vqs[i], s->ctx);
81
+ host_notifier = virtio_queue_get_host_notifier(vs->cmd_vqs[i]);
82
+ virtio_queue_host_notifier_read(host_notifier);
69
}
83
}
70
84
}
71
for (i = 0; i < tb->size; ++i) {
85
72
- be64_to_cpus(&table[i]);
86
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
73
+ table[i] = be64_to_cpu(table[i]);
87
index XXXXXXX..XXXXXXX 100644
74
ret = check_table_entry(table[i], s->cluster_size);
88
--- a/hw/virtio/virtio.c
75
if (ret < 0) {
89
+++ b/hw/virtio/virtio.c
76
goto fail;
90
@@ -XXX,XX +XXX,XX @@ void virtio_queue_aio_attach_host_notifier_no_poll(VirtQueue *vq, AioContext *ct
77
@@ -XXX,XX +XXX,XX @@ fail:
91
void virtio_queue_aio_detach_host_notifier(VirtQueue *vq, AioContext *ctx)
78
79
static inline void bitmap_dir_entry_to_cpu(Qcow2BitmapDirEntry *entry)
80
{
92
{
81
- be64_to_cpus(&entry->bitmap_table_offset);
93
aio_set_event_notifier(ctx, &vq->host_notifier, true, NULL, NULL, NULL);
82
- be32_to_cpus(&entry->bitmap_table_size);
94
- /* Test and clear notifier before after disabling event,
83
- be32_to_cpus(&entry->flags);
95
- * in case poll callback didn't have time to run. */
84
- be16_to_cpus(&entry->name_size);
96
- virtio_queue_host_notifier_read(&vq->host_notifier);
85
- be32_to_cpus(&entry->extra_data_size);
86
+ entry->bitmap_table_offset = be64_to_cpu(entry->bitmap_table_offset);
87
+ entry->bitmap_table_size = be32_to_cpu(entry->bitmap_table_size);
88
+ entry->flags = be32_to_cpu(entry->flags);
89
+ entry->name_size = be16_to_cpu(entry->name_size);
90
+ entry->extra_data_size = be32_to_cpu(entry->extra_data_size);
91
}
97
}
92
98
93
static inline void bitmap_dir_entry_to_be(Qcow2BitmapDirEntry *entry)
99
void virtio_queue_host_notifier_read(EventNotifier *n)
94
{
95
- cpu_to_be64s(&entry->bitmap_table_offset);
96
- cpu_to_be32s(&entry->bitmap_table_size);
97
- cpu_to_be32s(&entry->flags);
98
- cpu_to_be16s(&entry->name_size);
99
- cpu_to_be32s(&entry->extra_data_size);
100
+ entry->bitmap_table_offset = cpu_to_be64(entry->bitmap_table_offset);
101
+ entry->bitmap_table_size = cpu_to_be32(entry->bitmap_table_size);
102
+ entry->flags = cpu_to_be32(entry->flags);
103
+ entry->name_size = cpu_to_be16(entry->name_size);
104
+ entry->extra_data_size = cpu_to_be32(entry->extra_data_size);
105
}
106
107
static inline int calc_dir_entry_size(size_t name_size, size_t extra_data_size)
108
--
100
--
109
2.19.1
101
2.40.1
110
111
diff view generated by jsdifflib
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
3
Detach ioeventfds during drained sections to stop I/O submission from
4
the guest. virtio-blk is no longer reliant on aio_disable_external()
5
after this patch. This will allow us to remove the
6
aio_disable_external() API once all other code that relies on it is
7
converted.
8
9
Take extra care to avoid attaching/detaching ioeventfds if the data
10
plane is started/stopped during a drained section. This should be rare,
11
but maybe the mirror block job can trigger it.
12
13
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
14
Message-Id: <20230516190238.8401-18-stefanha@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Reviewed-by: Alberto Garcia <berto@igalia.com>
3
---
16
---
4
block/vpc.c | 2 ++
17
hw/block/dataplane/virtio-blk.c | 16 ++++++++------
5
1 file changed, 2 insertions(+)
18
hw/block/virtio-blk.c | 38 ++++++++++++++++++++++++++++++++-
19
2 files changed, 47 insertions(+), 7 deletions(-)
6
20
7
diff --git a/block/vpc.c b/block/vpc.c
21
diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c
8
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
9
--- a/block/vpc.c
23
--- a/hw/block/dataplane/virtio-blk.c
10
+++ b/block/vpc.c
24
+++ b/hw/block/dataplane/virtio-blk.c
11
@@ -XXX,XX +XXX,XX @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
25
@@ -XXX,XX +XXX,XX @@ int virtio_blk_data_plane_start(VirtIODevice *vdev)
12
}
26
}
13
27
14
qemu_co_mutex_init(&s->lock);
28
/* Get this show started by hooking up our callbacks */
15
+ qemu_opts_del(opts);
29
- aio_context_acquire(s->ctx);
16
30
- for (i = 0; i < nvqs; i++) {
31
- VirtQueue *vq = virtio_get_queue(s->vdev, i);
32
+ if (!blk_in_drain(s->conf->conf.blk)) {
33
+ aio_context_acquire(s->ctx);
34
+ for (i = 0; i < nvqs; i++) {
35
+ VirtQueue *vq = virtio_get_queue(s->vdev, i);
36
37
- virtio_queue_aio_attach_host_notifier(vq, s->ctx);
38
+ virtio_queue_aio_attach_host_notifier(vq, s->ctx);
39
+ }
40
+ aio_context_release(s->ctx);
41
}
42
- aio_context_release(s->ctx);
17
return 0;
43
return 0;
18
44
19
fail:
45
fail_aio_context:
20
+ qemu_opts_del(opts);
46
@@ -XXX,XX +XXX,XX @@ void virtio_blk_data_plane_stop(VirtIODevice *vdev)
21
qemu_vfree(s->pagetable);
47
s->stopping = true;
22
#ifdef CACHE
48
trace_virtio_blk_data_plane_stop(s);
23
g_free(s->pageentry_u8);
49
50
- aio_wait_bh_oneshot(s->ctx, virtio_blk_data_plane_stop_bh, s);
51
+ if (!blk_in_drain(s->conf->conf.blk)) {
52
+ aio_wait_bh_oneshot(s->ctx, virtio_blk_data_plane_stop_bh, s);
53
+ }
54
55
aio_context_acquire(s->ctx);
56
57
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
58
index XXXXXXX..XXXXXXX 100644
59
--- a/hw/block/virtio-blk.c
60
+++ b/hw/block/virtio-blk.c
61
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_resize(void *opaque)
62
aio_bh_schedule_oneshot(qemu_get_aio_context(), virtio_resize_cb, vdev);
63
}
64
65
+/* Suspend virtqueue ioeventfd processing during drain */
66
+static void virtio_blk_drained_begin(void *opaque)
67
+{
68
+ VirtIOBlock *s = opaque;
69
+ VirtIODevice *vdev = VIRTIO_DEVICE(opaque);
70
+ AioContext *ctx = blk_get_aio_context(s->conf.conf.blk);
71
+
72
+ if (!s->dataplane || !s->dataplane_started) {
73
+ return;
74
+ }
75
+
76
+ for (uint16_t i = 0; i < s->conf.num_queues; i++) {
77
+ VirtQueue *vq = virtio_get_queue(vdev, i);
78
+ virtio_queue_aio_detach_host_notifier(vq, ctx);
79
+ }
80
+}
81
+
82
+/* Resume virtqueue ioeventfd processing after drain */
83
+static void virtio_blk_drained_end(void *opaque)
84
+{
85
+ VirtIOBlock *s = opaque;
86
+ VirtIODevice *vdev = VIRTIO_DEVICE(opaque);
87
+ AioContext *ctx = blk_get_aio_context(s->conf.conf.blk);
88
+
89
+ if (!s->dataplane || !s->dataplane_started) {
90
+ return;
91
+ }
92
+
93
+ for (uint16_t i = 0; i < s->conf.num_queues; i++) {
94
+ VirtQueue *vq = virtio_get_queue(vdev, i);
95
+ virtio_queue_aio_attach_host_notifier(vq, ctx);
96
+ }
97
+}
98
+
99
static const BlockDevOps virtio_block_ops = {
100
- .resize_cb = virtio_blk_resize,
101
+ .resize_cb = virtio_blk_resize,
102
+ .drained_begin = virtio_blk_drained_begin,
103
+ .drained_end = virtio_blk_drained_end,
104
};
105
106
static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
24
--
107
--
25
2.19.1
108
2.40.1
26
27
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
This patch tests that you can add and remove drives from a Quorum
3
The virtio-scsi Host Bus Adapter provides access to devices on a SCSI
4
using the x-blockdev-change command.
4
bus. Those SCSI devices typically have a BlockBackend. When the
5
5
BlockBackend enters a drained section, the SCSI device must temporarily
6
Signed-off-by: Alberto Garcia <berto@igalia.com>
6
stop submitting new I/O requests.
7
8
Implement this behavior by temporarily stopping virtio-scsi virtqueue
9
processing when one of the SCSI devices enters a drained section. The
10
new scsi_device_drained_begin() API allows scsi-disk to message the
11
virtio-scsi HBA.
12
13
scsi_device_drained_begin() uses a drain counter so that multiple SCSI
14
devices can have overlapping drained sections. The HBA only sees one
15
pair of .drained_begin/end() calls.
16
17
After this commit, virtio-scsi no longer depends on hw/virtio's
18
ioeventfd aio_set_event_notifier(is_external=true). This commit is a
19
step towards removing the aio_disable_external() API.
20
21
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
22
Message-Id: <20230516190238.8401-19-stefanha@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
23
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
24
---
9
tests/qemu-iotests/081 | 86 ++++++++++++++++++++++++++++++++++++++
25
include/hw/scsi/scsi.h | 14 ++++++++++++
10
tests/qemu-iotests/081.out | 54 ++++++++++++++++++++++++
26
hw/scsi/scsi-bus.c | 40 +++++++++++++++++++++++++++++++++
11
2 files changed, 140 insertions(+)
27
hw/scsi/scsi-disk.c | 27 +++++++++++++++++-----
12
28
hw/scsi/virtio-scsi-dataplane.c | 18 +++++++++------
13
diff --git a/tests/qemu-iotests/081 b/tests/qemu-iotests/081
29
hw/scsi/virtio-scsi.c | 38 +++++++++++++++++++++++++++++++
14
index XXXXXXX..XXXXXXX 100755
30
hw/scsi/trace-events | 2 ++
15
--- a/tests/qemu-iotests/081
31
6 files changed, 127 insertions(+), 12 deletions(-)
16
+++ b/tests/qemu-iotests/081
32
17
@@ -XXX,XX +XXX,XX @@ quorum="$quorum,file.children.2.driver=raw"
33
diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h
18
34
index XXXXXXX..XXXXXXX 100644
19
$QEMU_IO -c "open -o $quorum" | _filter_qemu_io
35
--- a/include/hw/scsi/scsi.h
20
36
+++ b/include/hw/scsi/scsi.h
21
+echo
37
@@ -XXX,XX +XXX,XX @@ struct SCSIBusInfo {
22
+echo "== dynamically adding a child to a quorum =="
38
void (*save_request)(QEMUFile *f, SCSIRequest *req);
23
+
39
void *(*load_request)(QEMUFile *f, SCSIRequest *req);
24
+for verify in false true; do
40
void (*free_request)(SCSIBus *bus, void *priv);
25
+ run_qemu <<EOF
41
+
26
+ { "execute": "qmp_capabilities" }
42
+ /*
27
+ { "execute": "blockdev-add",
43
+ * Temporarily stop submitting new requests between drained_begin() and
28
+ "arguments": {
44
+ * drained_end(). Called from the main loop thread with the BQL held.
29
+ "driver": "quorum",
45
+ *
30
+ "node-name": "drive0-quorum",
46
+ * Implement these callbacks if request processing is triggered by a file
31
+ "vote-threshold": 2,
47
+ * descriptor like an EventNotifier. Otherwise set them to NULL.
32
+ "blkverify": ${verify},
48
+ */
33
+ "children": [
49
+ void (*drained_begin)(SCSIBus *bus);
34
+ {
50
+ void (*drained_end)(SCSIBus *bus);
35
+ "driver": "$IMGFMT",
51
};
36
+ "file": {
52
37
+ "driver": "file",
53
#define TYPE_SCSI_BUS "SCSI"
38
+ "filename": "$TEST_DIR/1.raw"
54
@@ -XXX,XX +XXX,XX @@ struct SCSIBus {
39
+ }
55
40
+ },
56
SCSISense unit_attention;
41
+ {
57
const SCSIBusInfo *info;
42
+ "driver": "$IMGFMT",
58
+
43
+ "file": {
59
+ int drain_count; /* protected by BQL */
44
+ "driver": "file",
60
};
45
+ "filename": "$TEST_DIR/2.raw"
61
46
+ }
62
/**
47
+ }
63
@@ -XXX,XX +XXX,XX @@ void scsi_req_cancel_complete(SCSIRequest *req);
48
+ ]
64
void scsi_req_cancel(SCSIRequest *req);
65
void scsi_req_cancel_async(SCSIRequest *req, Notifier *notifier);
66
void scsi_req_retry(SCSIRequest *req);
67
+void scsi_device_drained_begin(SCSIDevice *sdev);
68
+void scsi_device_drained_end(SCSIDevice *sdev);
69
void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense);
70
void scsi_device_set_ua(SCSIDevice *sdev, SCSISense sense);
71
void scsi_device_report_change(SCSIDevice *dev, SCSISense sense);
72
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
73
index XXXXXXX..XXXXXXX 100644
74
--- a/hw/scsi/scsi-bus.c
75
+++ b/hw/scsi/scsi-bus.c
76
@@ -XXX,XX +XXX,XX @@ void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense)
77
scsi_device_set_ua(sdev, sense);
78
}
79
80
+void scsi_device_drained_begin(SCSIDevice *sdev)
81
+{
82
+ SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, sdev->qdev.parent_bus);
83
+ if (!bus) {
84
+ return;
85
+ }
86
+
87
+ assert(qemu_get_current_aio_context() == qemu_get_aio_context());
88
+ assert(bus->drain_count < INT_MAX);
89
+
90
+ /*
91
+ * Multiple BlockBackends can be on a SCSIBus and each may begin/end
92
+ * draining at any time. Keep a counter so HBAs only see begin/end once.
93
+ */
94
+ if (bus->drain_count++ == 0) {
95
+ trace_scsi_bus_drained_begin(bus, sdev);
96
+ if (bus->info->drained_begin) {
97
+ bus->info->drained_begin(bus);
49
+ }
98
+ }
50
+ }
99
+ }
51
+ { "execute": "blockdev-add",
100
+}
52
+ "arguments": {
101
+
53
+ "node-name": "drive3",
102
+void scsi_device_drained_end(SCSIDevice *sdev)
54
+ "driver": "$IMGFMT",
103
+{
55
+ "file": {
104
+ SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, sdev->qdev.parent_bus);
56
+ "driver": "file",
105
+ if (!bus) {
57
+ "filename": "$TEST_DIR/2.raw"
106
+ return;
58
+ }
107
+ }
108
+
109
+ assert(qemu_get_current_aio_context() == qemu_get_aio_context());
110
+ assert(bus->drain_count > 0);
111
+
112
+ if (bus->drain_count-- == 1) {
113
+ trace_scsi_bus_drained_end(bus, sdev);
114
+ if (bus->info->drained_end) {
115
+ bus->info->drained_end(bus);
59
+ }
116
+ }
60
+ }
117
+ }
61
+ { "execute": "x-blockdev-change",
118
+}
62
+ "arguments": { "parent": "drive0-quorum",
119
+
63
+ "node": "drive3" } }
120
static char *scsibus_get_dev_path(DeviceState *dev)
64
+ { "execute": "quit" }
121
{
65
+EOF
122
SCSIDevice *d = SCSI_DEVICE(dev);
66
+done
123
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
67
+
124
index XXXXXXX..XXXXXXX 100644
68
+echo
125
--- a/hw/scsi/scsi-disk.c
69
+echo "== dynamically removing a child from a quorum =="
126
+++ b/hw/scsi/scsi-disk.c
70
+
127
@@ -XXX,XX +XXX,XX @@ static void scsi_disk_reset(DeviceState *dev)
71
+for verify in false true; do
128
s->qdev.scsi_version = s->qdev.default_scsi_version;
72
+ for vote_threshold in 1 2; do
129
}
73
+ run_qemu <<EOF
130
74
+ { "execute": "qmp_capabilities" }
131
+static void scsi_disk_drained_begin(void *opaque)
75
+ { "execute": "blockdev-add",
132
+{
76
+ "arguments": {
133
+ SCSIDiskState *s = opaque;
77
+ "driver": "quorum",
134
+
78
+ "node-name": "drive0-quorum",
135
+ scsi_device_drained_begin(&s->qdev);
79
+ "vote-threshold": ${vote_threshold},
136
+}
80
+ "blkverify": ${verify},
137
+
81
+ "children": [
138
+static void scsi_disk_drained_end(void *opaque)
82
+ {
139
+{
83
+ "driver": "$IMGFMT",
140
+ SCSIDiskState *s = opaque;
84
+ "file": {
141
+
85
+ "driver": "file",
142
+ scsi_device_drained_end(&s->qdev);
86
+ "filename": "$TEST_DIR/1.raw"
143
+}
87
+ }
144
+
88
+ },
145
static void scsi_disk_resize_cb(void *opaque)
89
+ {
146
{
90
+ "driver": "$IMGFMT",
147
SCSIDiskState *s = opaque;
91
+ "file": {
148
@@ -XXX,XX +XXX,XX @@ static bool scsi_cd_is_medium_locked(void *opaque)
92
+ "driver": "file",
149
}
93
+ "filename": "$TEST_DIR/2.raw"
150
94
+ }
151
static const BlockDevOps scsi_disk_removable_block_ops = {
95
+ }
152
- .change_media_cb = scsi_cd_change_media_cb,
96
+ ]
153
+ .change_media_cb = scsi_cd_change_media_cb,
97
+ }
154
+ .drained_begin = scsi_disk_drained_begin,
155
+ .drained_end = scsi_disk_drained_end,
156
.eject_request_cb = scsi_cd_eject_request_cb,
157
- .is_tray_open = scsi_cd_is_tray_open,
158
.is_medium_locked = scsi_cd_is_medium_locked,
159
-
160
- .resize_cb = scsi_disk_resize_cb,
161
+ .is_tray_open = scsi_cd_is_tray_open,
162
+ .resize_cb = scsi_disk_resize_cb,
163
};
164
165
static const BlockDevOps scsi_disk_block_ops = {
166
- .resize_cb = scsi_disk_resize_cb,
167
+ .drained_begin = scsi_disk_drained_begin,
168
+ .drained_end = scsi_disk_drained_end,
169
+ .resize_cb = scsi_disk_resize_cb,
170
};
171
172
static void scsi_disk_unit_attention_reported(SCSIDevice *dev)
173
diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c
174
index XXXXXXX..XXXXXXX 100644
175
--- a/hw/scsi/virtio-scsi-dataplane.c
176
+++ b/hw/scsi/virtio-scsi-dataplane.c
177
@@ -XXX,XX +XXX,XX @@ int virtio_scsi_dataplane_start(VirtIODevice *vdev)
178
s->dataplane_starting = false;
179
s->dataplane_started = true;
180
181
- aio_context_acquire(s->ctx);
182
- virtio_queue_aio_attach_host_notifier(vs->ctrl_vq, s->ctx);
183
- virtio_queue_aio_attach_host_notifier_no_poll(vs->event_vq, s->ctx);
184
+ if (s->bus.drain_count == 0) {
185
+ aio_context_acquire(s->ctx);
186
+ virtio_queue_aio_attach_host_notifier(vs->ctrl_vq, s->ctx);
187
+ virtio_queue_aio_attach_host_notifier_no_poll(vs->event_vq, s->ctx);
188
189
- for (i = 0; i < vs->conf.num_queues; i++) {
190
- virtio_queue_aio_attach_host_notifier(vs->cmd_vqs[i], s->ctx);
191
+ for (i = 0; i < vs->conf.num_queues; i++) {
192
+ virtio_queue_aio_attach_host_notifier(vs->cmd_vqs[i], s->ctx);
98
+ }
193
+ }
99
+ { "execute": "x-blockdev-change",
194
+ aio_context_release(s->ctx);
100
+ "arguments": { "parent": "drive0-quorum",
195
}
101
+ "child": "children.1" } }
196
- aio_context_release(s->ctx);
102
+ { "execute": "quit" }
197
return 0;
103
+EOF
198
104
+ done
199
fail_host_notifiers:
105
+done
200
@@ -XXX,XX +XXX,XX @@ void virtio_scsi_dataplane_stop(VirtIODevice *vdev)
106
+
201
}
107
# success, all done
202
s->dataplane_stopping = true;
108
echo "*** done"
203
109
rm -f $seq.full
204
- aio_wait_bh_oneshot(s->ctx, virtio_scsi_dataplane_stop_bh, s);
110
diff --git a/tests/qemu-iotests/081.out b/tests/qemu-iotests/081.out
205
+ if (s->bus.drain_count == 0) {
111
index XXXXXXX..XXXXXXX 100644
206
+ aio_wait_bh_oneshot(s->ctx, virtio_scsi_dataplane_stop_bh, s);
112
--- a/tests/qemu-iotests/081.out
207
+ }
113
+++ b/tests/qemu-iotests/081.out
208
114
@@ -XXX,XX +XXX,XX @@ read 10485760/10485760 bytes at offset 0
209
blk_drain_all(); /* ensure there are no in-flight requests */
115
210
116
== checking the blkverify mode with invalid settings ==
211
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
117
can't open: blkverify=on can only be set if there are exactly two files and vote-threshold is 2
212
index XXXXXXX..XXXXXXX 100644
118
+
213
--- a/hw/scsi/virtio-scsi.c
119
+== dynamically adding a child to a quorum ==
214
+++ b/hw/scsi/virtio-scsi.c
120
+Testing:
215
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_hotunplug(HotplugHandler *hotplug_dev, DeviceState *dev,
121
+QMP_VERSION
216
}
122
+{"return": {}}
217
}
123
+{"return": {}}
218
124
+{"return": {}}
219
+/* Suspend virtqueue ioeventfd processing during drain */
125
+{"return": {}}
220
+static void virtio_scsi_drained_begin(SCSIBus *bus)
126
+{"return": {}}
221
+{
127
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
222
+ VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus);
128
+
223
+ VirtIODevice *vdev = VIRTIO_DEVICE(s);
129
+Testing:
224
+ uint32_t total_queues = VIRTIO_SCSI_VQ_NUM_FIXED +
130
+QMP_VERSION
225
+ s->parent_obj.conf.num_queues;
131
+{"return": {}}
226
+
132
+{"return": {}}
227
+ if (!s->dataplane_started) {
133
+{"return": {}}
228
+ return;
134
+{"error": {"class": "GenericError", "desc": "Cannot add a child to a quorum in blkverify mode"}}
229
+ }
135
+{"return": {}}
230
+
136
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
231
+ for (uint32_t i = 0; i < total_queues; i++) {
137
+
232
+ VirtQueue *vq = virtio_get_queue(vdev, i);
138
+
233
+ virtio_queue_aio_detach_host_notifier(vq, s->ctx);
139
+== dynamically removing a child from a quorum ==
234
+ }
140
+Testing:
235
+}
141
+QMP_VERSION
236
+
142
+{"return": {}}
237
+/* Resume virtqueue ioeventfd processing after drain */
143
+{"return": {}}
238
+static void virtio_scsi_drained_end(SCSIBus *bus)
144
+{"return": {}}
239
+{
145
+{"return": {}}
240
+ VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus);
146
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
241
+ VirtIODevice *vdev = VIRTIO_DEVICE(s);
147
+
242
+ uint32_t total_queues = VIRTIO_SCSI_VQ_NUM_FIXED +
148
+Testing:
243
+ s->parent_obj.conf.num_queues;
149
+QMP_VERSION
244
+
150
+{"return": {}}
245
+ if (!s->dataplane_started) {
151
+{"return": {}}
246
+ return;
152
+{"error": {"class": "GenericError", "desc": "The number of children cannot be lower than the vote threshold 2"}}
247
+ }
153
+{"return": {}}
248
+
154
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
249
+ for (uint32_t i = 0; i < total_queues; i++) {
155
+
250
+ VirtQueue *vq = virtio_get_queue(vdev, i);
156
+Testing:
251
+ virtio_queue_aio_attach_host_notifier(vq, s->ctx);
157
+QMP_VERSION
252
+ }
158
+{"return": {}}
253
+}
159
+{"error": {"class": "GenericError", "desc": "blkverify=on can only be set if there are exactly two files and vote-threshold is 2"}}
254
+
160
+{"error": {"class": "GenericError", "desc": "Cannot find device=drive0-quorum nor node_name=drive0-quorum"}}
255
static struct SCSIBusInfo virtio_scsi_scsi_info = {
161
+{"return": {}}
256
.tcq = true,
162
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
257
.max_channel = VIRTIO_SCSI_MAX_CHANNEL,
163
+
258
@@ -XXX,XX +XXX,XX @@ static struct SCSIBusInfo virtio_scsi_scsi_info = {
164
+Testing:
259
.get_sg_list = virtio_scsi_get_sg_list,
165
+QMP_VERSION
260
.save_request = virtio_scsi_save_request,
166
+{"return": {}}
261
.load_request = virtio_scsi_load_request,
167
+{"return": {}}
262
+ .drained_begin = virtio_scsi_drained_begin,
168
+{"error": {"class": "GenericError", "desc": "The number of children cannot be lower than the vote threshold 2"}}
263
+ .drained_end = virtio_scsi_drained_end,
169
+{"return": {}}
264
};
170
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
265
171
+
266
void virtio_scsi_common_realize(DeviceState *dev,
172
*** done
267
diff --git a/hw/scsi/trace-events b/hw/scsi/trace-events
268
index XXXXXXX..XXXXXXX 100644
269
--- a/hw/scsi/trace-events
270
+++ b/hw/scsi/trace-events
271
@@ -XXX,XX +XXX,XX @@ scsi_req_cancel(int target, int lun, int tag) "target %d lun %d tag %d"
272
scsi_req_data(int target, int lun, int tag, int len) "target %d lun %d tag %d len %d"
273
scsi_req_data_canceled(int target, int lun, int tag, int len) "target %d lun %d tag %d len %d"
274
scsi_req_dequeue(int target, int lun, int tag) "target %d lun %d tag %d"
275
+scsi_bus_drained_begin(void *bus, void *sdev) "bus %p sdev %p"
276
+scsi_bus_drained_end(void *bus, void *sdev) "bus %p sdev %p"
277
scsi_req_continue(int target, int lun, int tag) "target %d lun %d tag %d"
278
scsi_req_continue_canceled(int target, int lun, int tag) "target %d lun %d tag %d"
279
scsi_req_parsed(int target, int lun, int tag, int cmd, int mode, int xfer) "target %d lun %d tag %d command %d dir %d length %d"
173
--
280
--
174
2.19.1
281
2.40.1
175
176
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
Following the example of qemu_opts_print_help(), indent all entries in
3
Host notifiers can now use is_external=false since virtio-blk and
4
the list of character devices.
4
virtio-scsi no longer rely on is_external=true for drained sections.
5
5
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
7
Message-Id: <20230516190238.8401-20-stefanha@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
9
---
10
chardev/char.c | 2 +-
10
hw/virtio/virtio.c | 6 +++---
11
1 file changed, 1 insertion(+), 1 deletion(-)
11
1 file changed, 3 insertions(+), 3 deletions(-)
12
12
13
diff --git a/chardev/char.c b/chardev/char.c
13
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
14
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
15
--- a/chardev/char.c
15
--- a/hw/virtio/virtio.c
16
+++ b/chardev/char.c
16
+++ b/hw/virtio/virtio.c
17
@@ -XXX,XX +XXX,XX @@ help_string_append(const char *name, void *opaque)
17
@@ -XXX,XX +XXX,XX @@ static void virtio_queue_host_notifier_aio_poll_end(EventNotifier *n)
18
19
void virtio_queue_aio_attach_host_notifier(VirtQueue *vq, AioContext *ctx)
18
{
20
{
19
GString *str = opaque;
21
- aio_set_event_notifier(ctx, &vq->host_notifier, true,
20
22
+ aio_set_event_notifier(ctx, &vq->host_notifier, false,
21
- g_string_append_printf(str, "\n%s", name);
23
virtio_queue_host_notifier_read,
22
+ g_string_append_printf(str, "\n %s", name);
24
virtio_queue_host_notifier_aio_poll,
25
virtio_queue_host_notifier_aio_poll_ready);
26
@@ -XXX,XX +XXX,XX @@ void virtio_queue_aio_attach_host_notifier(VirtQueue *vq, AioContext *ctx)
27
*/
28
void virtio_queue_aio_attach_host_notifier_no_poll(VirtQueue *vq, AioContext *ctx)
29
{
30
- aio_set_event_notifier(ctx, &vq->host_notifier, true,
31
+ aio_set_event_notifier(ctx, &vq->host_notifier, false,
32
virtio_queue_host_notifier_read,
33
NULL, NULL);
23
}
34
}
24
35
25
static const char *chardev_alias_translate(const char *name)
36
void virtio_queue_aio_detach_host_notifier(VirtQueue *vq, AioContext *ctx)
37
{
38
- aio_set_event_notifier(ctx, &vq->host_notifier, true, NULL, NULL, NULL);
39
+ aio_set_event_notifier(ctx, &vq->host_notifier, false, NULL, NULL, NULL);
40
}
41
42
void virtio_queue_host_notifier_read(EventNotifier *n)
26
--
43
--
27
2.19.1
44
2.40.1
28
29
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
This is a static function with only one caller, so there's no need to
3
All callers now pass is_external=false to aio_set_fd_handler() and
4
keep it. Inlining the code in quorum_compare() makes it much simpler.
4
aio_set_event_notifier(). The aio_disable_external() API that
5
temporarily disables fd handlers that were registered is_external=true
6
is therefore dead code.
5
7
6
Signed-off-by: Alberto Garcia <berto@igalia.com>
8
Remove aio_disable_external(), aio_enable_external(), and the
7
Reported-by: Markus Armbruster <armbru@redhat.com>
9
is_external arguments to aio_set_fd_handler() and
10
aio_set_event_notifier().
11
12
The entire test-fdmon-epoll test is removed because its sole purpose was
13
testing aio_disable_external().
14
15
Parts of this patch were generated using the following coccinelle
16
(https://coccinelle.lip6.fr/) semantic patch:
17
18
@@
19
expression ctx, fd, is_external, io_read, io_write, io_poll, io_poll_ready, opaque;
20
@@
21
- aio_set_fd_handler(ctx, fd, is_external, io_read, io_write, io_poll, io_poll_ready, opaque)
22
+ aio_set_fd_handler(ctx, fd, io_read, io_write, io_poll, io_poll_ready, opaque)
23
24
@@
25
expression ctx, notifier, is_external, io_read, io_poll, io_poll_ready;
26
@@
27
- aio_set_event_notifier(ctx, notifier, is_external, io_read, io_poll, io_poll_ready)
28
+ aio_set_event_notifier(ctx, notifier, io_read, io_poll, io_poll_ready)
29
30
Reviewed-by: Juan Quintela <quintela@redhat.com>
31
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
32
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
33
Message-Id: <20230516190238.8401-21-stefanha@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
34
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
35
---
10
block/quorum.c | 24 +++++-------------------
36
include/block/aio.h | 57 ------------------------
11
1 file changed, 5 insertions(+), 19 deletions(-)
37
util/aio-posix.h | 1 -
38
block.c | 7 ---
39
block/blkio.c | 15 +++----
40
block/curl.c | 10 ++---
41
block/export/fuse.c | 8 ++--
42
block/export/vduse-blk.c | 10 ++---
43
block/io.c | 2 -
44
block/io_uring.c | 4 +-
45
block/iscsi.c | 3 +-
46
block/linux-aio.c | 4 +-
47
block/nfs.c | 5 +--
48
block/nvme.c | 8 ++--
49
block/ssh.c | 4 +-
50
block/win32-aio.c | 6 +--
51
hw/i386/kvm/xen_xenstore.c | 2 +-
52
hw/virtio/virtio.c | 6 +--
53
hw/xen/xen-bus.c | 8 ++--
54
io/channel-command.c | 6 +--
55
io/channel-file.c | 3 +-
56
io/channel-socket.c | 3 +-
57
migration/rdma.c | 16 +++----
58
tests/unit/test-aio.c | 27 +-----------
59
tests/unit/test-bdrv-drain.c | 1 -
60
tests/unit/test-fdmon-epoll.c | 73 -------------------------------
61
tests/unit/test-nested-aio-poll.c | 9 ++--
62
util/aio-posix.c | 20 +++------
63
util/aio-win32.c | 8 +---
64
util/async.c | 3 +-
65
util/fdmon-epoll.c | 10 -----
66
util/fdmon-io_uring.c | 8 +---
67
util/fdmon-poll.c | 3 +-
68
util/main-loop.c | 7 ++-
69
util/qemu-coroutine-io.c | 7 ++-
70
util/vhost-user-server.c | 11 +++--
71
tests/unit/meson.build | 3 --
72
36 files changed, 80 insertions(+), 298 deletions(-)
73
delete mode 100644 tests/unit/test-fdmon-epoll.c
12
74
13
diff --git a/block/quorum.c b/block/quorum.c
75
diff --git a/include/block/aio.h b/include/block/aio.h
14
index XXXXXXX..XXXXXXX 100644
76
index XXXXXXX..XXXXXXX 100644
15
--- a/block/quorum.c
77
--- a/include/block/aio.h
16
+++ b/block/quorum.c
78
+++ b/include/block/aio.h
17
@@ -XXX,XX +XXX,XX @@ static bool quorum_iovec_compare(QEMUIOVector *a, QEMUIOVector *b)
79
@@ -XXX,XX +XXX,XX @@ struct AioContext {
80
*/
81
QEMUTimerListGroup tlg;
82
83
- int external_disable_cnt;
84
-
85
/* Number of AioHandlers without .io_poll() */
86
int poll_disable_cnt;
87
88
@@ -XXX,XX +XXX,XX @@ bool aio_poll(AioContext *ctx, bool blocking);
89
*/
90
void aio_set_fd_handler(AioContext *ctx,
91
int fd,
92
- bool is_external,
93
IOHandler *io_read,
94
IOHandler *io_write,
95
AioPollFn *io_poll,
96
@@ -XXX,XX +XXX,XX @@ void aio_set_fd_handler(AioContext *ctx,
97
*/
98
void aio_set_event_notifier(AioContext *ctx,
99
EventNotifier *notifier,
100
- bool is_external,
101
EventNotifierHandler *io_read,
102
AioPollFn *io_poll,
103
EventNotifierHandler *io_poll_ready);
104
@@ -XXX,XX +XXX,XX @@ static inline void aio_timer_init(AioContext *ctx,
105
*/
106
int64_t aio_compute_timeout(AioContext *ctx);
107
108
-/**
109
- * aio_disable_external:
110
- * @ctx: the aio context
111
- *
112
- * Disable the further processing of external clients.
113
- */
114
-static inline void aio_disable_external(AioContext *ctx)
115
-{
116
- qatomic_inc(&ctx->external_disable_cnt);
117
-}
118
-
119
-/**
120
- * aio_enable_external:
121
- * @ctx: the aio context
122
- *
123
- * Enable the processing of external clients.
124
- */
125
-static inline void aio_enable_external(AioContext *ctx)
126
-{
127
- int old;
128
-
129
- old = qatomic_fetch_dec(&ctx->external_disable_cnt);
130
- assert(old > 0);
131
- if (old == 1) {
132
- /* Kick event loop so it re-arms file descriptors */
133
- aio_notify(ctx);
134
- }
135
-}
136
-
137
-/**
138
- * aio_external_disabled:
139
- * @ctx: the aio context
140
- *
141
- * Return true if the external clients are disabled.
142
- */
143
-static inline bool aio_external_disabled(AioContext *ctx)
144
-{
145
- return qatomic_read(&ctx->external_disable_cnt);
146
-}
147
-
148
-/**
149
- * aio_node_check:
150
- * @ctx: the aio context
151
- * @is_external: Whether or not the checked node is an external event source.
152
- *
153
- * Check if the node's is_external flag is okay to be polled by the ctx at this
154
- * moment. True means green light.
155
- */
156
-static inline bool aio_node_check(AioContext *ctx, bool is_external)
157
-{
158
- return !is_external || !qatomic_read(&ctx->external_disable_cnt);
159
-}
160
-
161
/**
162
* aio_co_schedule:
163
* @ctx: the aio context
164
diff --git a/util/aio-posix.h b/util/aio-posix.h
165
index XXXXXXX..XXXXXXX 100644
166
--- a/util/aio-posix.h
167
+++ b/util/aio-posix.h
168
@@ -XXX,XX +XXX,XX @@ struct AioHandler {
169
#endif
170
int64_t poll_idle_timeout; /* when to stop userspace polling */
171
bool poll_ready; /* has polling detected an event? */
172
- bool is_external;
173
};
174
175
/* Add a handler to a ready list */
176
diff --git a/block.c b/block.c
177
index XXXXXXX..XXXXXXX 100644
178
--- a/block.c
179
+++ b/block.c
180
@@ -XXX,XX +XXX,XX @@ static void bdrv_detach_aio_context(BlockDriverState *bs)
181
bs->drv->bdrv_detach_aio_context(bs);
182
}
183
184
- if (bs->quiesce_counter) {
185
- aio_enable_external(bs->aio_context);
186
- }
187
bs->aio_context = NULL;
188
}
189
190
@@ -XXX,XX +XXX,XX @@ static void bdrv_attach_aio_context(BlockDriverState *bs,
191
BdrvAioNotifier *ban, *ban_tmp;
192
GLOBAL_STATE_CODE();
193
194
- if (bs->quiesce_counter) {
195
- aio_disable_external(new_context);
196
- }
197
-
198
bs->aio_context = new_context;
199
200
if (bs->drv && bs->drv->bdrv_attach_aio_context) {
201
diff --git a/block/blkio.c b/block/blkio.c
202
index XXXXXXX..XXXXXXX 100644
203
--- a/block/blkio.c
204
+++ b/block/blkio.c
205
@@ -XXX,XX +XXX,XX @@ static void blkio_attach_aio_context(BlockDriverState *bs,
206
{
207
BDRVBlkioState *s = bs->opaque;
208
209
- aio_set_fd_handler(new_context,
210
- s->completion_fd,
211
- false,
212
- blkio_completion_fd_read,
213
- NULL,
214
+ aio_set_fd_handler(new_context, s->completion_fd,
215
+ blkio_completion_fd_read, NULL,
216
blkio_completion_fd_poll,
217
- blkio_completion_fd_poll_ready,
218
- bs);
219
+ blkio_completion_fd_poll_ready, bs);
220
}
221
222
static void blkio_detach_aio_context(BlockDriverState *bs)
223
{
224
BDRVBlkioState *s = bs->opaque;
225
226
- aio_set_fd_handler(bdrv_get_aio_context(bs),
227
- s->completion_fd,
228
- false, NULL, NULL, NULL, NULL, NULL);
229
+ aio_set_fd_handler(bdrv_get_aio_context(bs), s->completion_fd, NULL, NULL,
230
+ NULL, NULL, NULL);
231
}
232
233
/* Call with s->blkio_lock held to submit I/O after enqueuing a new request */
234
diff --git a/block/curl.c b/block/curl.c
235
index XXXXXXX..XXXXXXX 100644
236
--- a/block/curl.c
237
+++ b/block/curl.c
238
@@ -XXX,XX +XXX,XX @@ static gboolean curl_drop_socket(void *key, void *value, void *opaque)
239
CURLSocket *socket = value;
240
BDRVCURLState *s = socket->s;
241
242
- aio_set_fd_handler(s->aio_context, socket->fd, false,
243
+ aio_set_fd_handler(s->aio_context, socket->fd,
244
NULL, NULL, NULL, NULL, NULL);
18
return true;
245
return true;
19
}
246
}
20
247
@@ -XXX,XX +XXX,XX @@ static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
21
-static void GCC_FMT_ATTR(2, 3) quorum_err(QuorumAIOCB *acb,
248
trace_curl_sock_cb(action, (int)fd);
22
- const char *fmt, ...)
249
switch (action) {
250
case CURL_POLL_IN:
251
- aio_set_fd_handler(s->aio_context, fd, false,
252
+ aio_set_fd_handler(s->aio_context, fd,
253
curl_multi_do, NULL, NULL, NULL, socket);
254
break;
255
case CURL_POLL_OUT:
256
- aio_set_fd_handler(s->aio_context, fd, false,
257
+ aio_set_fd_handler(s->aio_context, fd,
258
NULL, curl_multi_do, NULL, NULL, socket);
259
break;
260
case CURL_POLL_INOUT:
261
- aio_set_fd_handler(s->aio_context, fd, false,
262
+ aio_set_fd_handler(s->aio_context, fd,
263
curl_multi_do, curl_multi_do,
264
NULL, NULL, socket);
265
break;
266
case CURL_POLL_REMOVE:
267
- aio_set_fd_handler(s->aio_context, fd, false,
268
+ aio_set_fd_handler(s->aio_context, fd,
269
NULL, NULL, NULL, NULL, NULL);
270
break;
271
}
272
diff --git a/block/export/fuse.c b/block/export/fuse.c
273
index XXXXXXX..XXXXXXX 100644
274
--- a/block/export/fuse.c
275
+++ b/block/export/fuse.c
276
@@ -XXX,XX +XXX,XX @@ static void fuse_export_drained_begin(void *opaque)
277
FuseExport *exp = opaque;
278
279
aio_set_fd_handler(exp->common.ctx,
280
- fuse_session_fd(exp->fuse_session), false,
281
+ fuse_session_fd(exp->fuse_session),
282
NULL, NULL, NULL, NULL, NULL);
283
exp->fd_handler_set_up = false;
284
}
285
@@ -XXX,XX +XXX,XX @@ static void fuse_export_drained_end(void *opaque)
286
exp->common.ctx = blk_get_aio_context(exp->common.blk);
287
288
aio_set_fd_handler(exp->common.ctx,
289
- fuse_session_fd(exp->fuse_session), false,
290
+ fuse_session_fd(exp->fuse_session),
291
read_from_fuse_export, NULL, NULL, NULL, exp);
292
exp->fd_handler_set_up = true;
293
}
294
@@ -XXX,XX +XXX,XX @@ static int setup_fuse_export(FuseExport *exp, const char *mountpoint,
295
g_hash_table_insert(exports, g_strdup(mountpoint), NULL);
296
297
aio_set_fd_handler(exp->common.ctx,
298
- fuse_session_fd(exp->fuse_session), false,
299
+ fuse_session_fd(exp->fuse_session),
300
read_from_fuse_export, NULL, NULL, NULL, exp);
301
exp->fd_handler_set_up = true;
302
303
@@ -XXX,XX +XXX,XX @@ static void fuse_export_shutdown(BlockExport *blk_exp)
304
305
if (exp->fd_handler_set_up) {
306
aio_set_fd_handler(exp->common.ctx,
307
- fuse_session_fd(exp->fuse_session), false,
308
+ fuse_session_fd(exp->fuse_session),
309
NULL, NULL, NULL, NULL, NULL);
310
exp->fd_handler_set_up = false;
311
}
312
diff --git a/block/export/vduse-blk.c b/block/export/vduse-blk.c
313
index XXXXXXX..XXXXXXX 100644
314
--- a/block/export/vduse-blk.c
315
+++ b/block/export/vduse-blk.c
316
@@ -XXX,XX +XXX,XX @@ static void vduse_blk_enable_queue(VduseDev *dev, VduseVirtq *vq)
317
}
318
319
aio_set_fd_handler(vblk_exp->export.ctx, vduse_queue_get_fd(vq),
320
- false, on_vduse_vq_kick, NULL, NULL, NULL, vq);
321
+ on_vduse_vq_kick, NULL, NULL, NULL, vq);
322
/* Make sure we don't miss any kick afer reconnecting */
323
eventfd_write(vduse_queue_get_fd(vq), 1);
324
}
325
@@ -XXX,XX +XXX,XX @@ static void vduse_blk_disable_queue(VduseDev *dev, VduseVirtq *vq)
326
return;
327
}
328
329
- aio_set_fd_handler(vblk_exp->export.ctx, fd, false,
330
+ aio_set_fd_handler(vblk_exp->export.ctx, fd,
331
NULL, NULL, NULL, NULL, NULL);
332
}
333
334
@@ -XXX,XX +XXX,XX @@ static void on_vduse_dev_kick(void *opaque)
335
static void vduse_blk_attach_ctx(VduseBlkExport *vblk_exp, AioContext *ctx)
336
{
337
aio_set_fd_handler(vblk_exp->export.ctx, vduse_dev_get_fd(vblk_exp->dev),
338
- false, on_vduse_dev_kick, NULL, NULL, NULL,
339
+ on_vduse_dev_kick, NULL, NULL, NULL,
340
vblk_exp->dev);
341
342
/* Virtqueues are handled by vduse_blk_drained_end() */
343
@@ -XXX,XX +XXX,XX @@ static void vduse_blk_attach_ctx(VduseBlkExport *vblk_exp, AioContext *ctx)
344
static void vduse_blk_detach_ctx(VduseBlkExport *vblk_exp)
345
{
346
aio_set_fd_handler(vblk_exp->export.ctx, vduse_dev_get_fd(vblk_exp->dev),
347
- false, NULL, NULL, NULL, NULL, NULL);
348
+ NULL, NULL, NULL, NULL, NULL);
349
350
/* Virtqueues are handled by vduse_blk_drained_begin() */
351
}
352
@@ -XXX,XX +XXX,XX @@ static int vduse_blk_exp_create(BlockExport *exp, BlockExportOptions *opts,
353
vduse_dev_setup_queue(vblk_exp->dev, i, queue_size);
354
}
355
356
- aio_set_fd_handler(exp->ctx, vduse_dev_get_fd(vblk_exp->dev), false,
357
+ aio_set_fd_handler(exp->ctx, vduse_dev_get_fd(vblk_exp->dev),
358
on_vduse_dev_kick, NULL, NULL, NULL, vblk_exp->dev);
359
360
blk_add_aio_context_notifier(exp->blk, blk_aio_attached, blk_aio_detach,
361
diff --git a/block/io.c b/block/io.c
362
index XXXXXXX..XXXXXXX 100644
363
--- a/block/io.c
364
+++ b/block/io.c
365
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent,
366
367
/* Stop things in parent-to-child order */
368
if (qatomic_fetch_inc(&bs->quiesce_counter) == 0) {
369
- aio_disable_external(bdrv_get_aio_context(bs));
370
bdrv_parent_drained_begin(bs, parent);
371
if (bs->drv && bs->drv->bdrv_drain_begin) {
372
bs->drv->bdrv_drain_begin(bs);
373
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent)
374
bs->drv->bdrv_drain_end(bs);
375
}
376
bdrv_parent_drained_end(bs, parent);
377
- aio_enable_external(bdrv_get_aio_context(bs));
378
}
379
}
380
381
diff --git a/block/io_uring.c b/block/io_uring.c
382
index XXXXXXX..XXXXXXX 100644
383
--- a/block/io_uring.c
384
+++ b/block/io_uring.c
385
@@ -XXX,XX +XXX,XX @@ int coroutine_fn luring_co_submit(BlockDriverState *bs, int fd, uint64_t offset,
386
387
void luring_detach_aio_context(LuringState *s, AioContext *old_context)
388
{
389
- aio_set_fd_handler(old_context, s->ring.ring_fd, false,
390
+ aio_set_fd_handler(old_context, s->ring.ring_fd,
391
NULL, NULL, NULL, NULL, s);
392
qemu_bh_delete(s->completion_bh);
393
s->aio_context = NULL;
394
@@ -XXX,XX +XXX,XX @@ void luring_attach_aio_context(LuringState *s, AioContext *new_context)
395
{
396
s->aio_context = new_context;
397
s->completion_bh = aio_bh_new(new_context, qemu_luring_completion_bh, s);
398
- aio_set_fd_handler(s->aio_context, s->ring.ring_fd, false,
399
+ aio_set_fd_handler(s->aio_context, s->ring.ring_fd,
400
qemu_luring_completion_cb, NULL,
401
qemu_luring_poll_cb, qemu_luring_poll_ready, s);
402
}
403
diff --git a/block/iscsi.c b/block/iscsi.c
404
index XXXXXXX..XXXXXXX 100644
405
--- a/block/iscsi.c
406
+++ b/block/iscsi.c
407
@@ -XXX,XX +XXX,XX @@ iscsi_set_events(IscsiLun *iscsilun)
408
409
if (ev != iscsilun->events) {
410
aio_set_fd_handler(iscsilun->aio_context, iscsi_get_fd(iscsi),
411
- false,
412
(ev & POLLIN) ? iscsi_process_read : NULL,
413
(ev & POLLOUT) ? iscsi_process_write : NULL,
414
NULL, NULL,
415
@@ -XXX,XX +XXX,XX @@ static void iscsi_detach_aio_context(BlockDriverState *bs)
416
IscsiLun *iscsilun = bs->opaque;
417
418
aio_set_fd_handler(iscsilun->aio_context, iscsi_get_fd(iscsilun->iscsi),
419
- false, NULL, NULL, NULL, NULL, NULL);
420
+ NULL, NULL, NULL, NULL, NULL);
421
iscsilun->events = 0;
422
423
if (iscsilun->nop_timer) {
424
diff --git a/block/linux-aio.c b/block/linux-aio.c
425
index XXXXXXX..XXXXXXX 100644
426
--- a/block/linux-aio.c
427
+++ b/block/linux-aio.c
428
@@ -XXX,XX +XXX,XX @@ int coroutine_fn laio_co_submit(int fd, uint64_t offset, QEMUIOVector *qiov,
429
430
void laio_detach_aio_context(LinuxAioState *s, AioContext *old_context)
431
{
432
- aio_set_event_notifier(old_context, &s->e, false, NULL, NULL, NULL);
433
+ aio_set_event_notifier(old_context, &s->e, NULL, NULL, NULL);
434
qemu_bh_delete(s->completion_bh);
435
s->aio_context = NULL;
436
}
437
@@ -XXX,XX +XXX,XX @@ void laio_attach_aio_context(LinuxAioState *s, AioContext *new_context)
438
{
439
s->aio_context = new_context;
440
s->completion_bh = aio_bh_new(new_context, qemu_laio_completion_bh, s);
441
- aio_set_event_notifier(new_context, &s->e, false,
442
+ aio_set_event_notifier(new_context, &s->e,
443
qemu_laio_completion_cb,
444
qemu_laio_poll_cb,
445
qemu_laio_poll_ready);
446
diff --git a/block/nfs.c b/block/nfs.c
447
index XXXXXXX..XXXXXXX 100644
448
--- a/block/nfs.c
449
+++ b/block/nfs.c
450
@@ -XXX,XX +XXX,XX @@ static void nfs_set_events(NFSClient *client)
451
int ev = nfs_which_events(client->context);
452
if (ev != client->events) {
453
aio_set_fd_handler(client->aio_context, nfs_get_fd(client->context),
454
- false,
455
(ev & POLLIN) ? nfs_process_read : NULL,
456
(ev & POLLOUT) ? nfs_process_write : NULL,
457
NULL, NULL, client);
458
@@ -XXX,XX +XXX,XX @@ static void nfs_detach_aio_context(BlockDriverState *bs)
459
NFSClient *client = bs->opaque;
460
461
aio_set_fd_handler(client->aio_context, nfs_get_fd(client->context),
462
- false, NULL, NULL, NULL, NULL, NULL);
463
+ NULL, NULL, NULL, NULL, NULL);
464
client->events = 0;
465
}
466
467
@@ -XXX,XX +XXX,XX @@ static void nfs_client_close(NFSClient *client)
468
if (client->context) {
469
qemu_mutex_lock(&client->mutex);
470
aio_set_fd_handler(client->aio_context, nfs_get_fd(client->context),
471
- false, NULL, NULL, NULL, NULL, NULL);
472
+ NULL, NULL, NULL, NULL, NULL);
473
qemu_mutex_unlock(&client->mutex);
474
if (client->fh) {
475
nfs_close(client->context, client->fh);
476
diff --git a/block/nvme.c b/block/nvme.c
477
index XXXXXXX..XXXXXXX 100644
478
--- a/block/nvme.c
479
+++ b/block/nvme.c
480
@@ -XXX,XX +XXX,XX @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
481
}
482
aio_set_event_notifier(bdrv_get_aio_context(bs),
483
&s->irq_notifier[MSIX_SHARED_IRQ_IDX],
484
- false, nvme_handle_event, nvme_poll_cb,
485
+ nvme_handle_event, nvme_poll_cb,
486
nvme_poll_ready);
487
488
if (!nvme_identify(bs, namespace, errp)) {
489
@@ -XXX,XX +XXX,XX @@ static void nvme_close(BlockDriverState *bs)
490
g_free(s->queues);
491
aio_set_event_notifier(bdrv_get_aio_context(bs),
492
&s->irq_notifier[MSIX_SHARED_IRQ_IDX],
493
- false, NULL, NULL, NULL);
494
+ NULL, NULL, NULL);
495
event_notifier_cleanup(&s->irq_notifier[MSIX_SHARED_IRQ_IDX]);
496
qemu_vfio_pci_unmap_bar(s->vfio, 0, s->bar0_wo_map,
497
0, sizeof(NvmeBar) + NVME_DOORBELL_SIZE);
498
@@ -XXX,XX +XXX,XX @@ static void nvme_detach_aio_context(BlockDriverState *bs)
499
500
aio_set_event_notifier(bdrv_get_aio_context(bs),
501
&s->irq_notifier[MSIX_SHARED_IRQ_IDX],
502
- false, NULL, NULL, NULL);
503
+ NULL, NULL, NULL);
504
}
505
506
static void nvme_attach_aio_context(BlockDriverState *bs,
507
@@ -XXX,XX +XXX,XX @@ static void nvme_attach_aio_context(BlockDriverState *bs,
508
509
s->aio_context = new_context;
510
aio_set_event_notifier(new_context, &s->irq_notifier[MSIX_SHARED_IRQ_IDX],
511
- false, nvme_handle_event, nvme_poll_cb,
512
+ nvme_handle_event, nvme_poll_cb,
513
nvme_poll_ready);
514
515
for (unsigned i = 0; i < s->queue_count; i++) {
516
diff --git a/block/ssh.c b/block/ssh.c
517
index XXXXXXX..XXXXXXX 100644
518
--- a/block/ssh.c
519
+++ b/block/ssh.c
520
@@ -XXX,XX +XXX,XX @@ static void restart_coroutine(void *opaque)
521
AioContext *ctx = bdrv_get_aio_context(bs);
522
523
trace_ssh_restart_coroutine(restart->co);
524
- aio_set_fd_handler(ctx, s->sock, false, NULL, NULL, NULL, NULL, NULL);
525
+ aio_set_fd_handler(ctx, s->sock, NULL, NULL, NULL, NULL, NULL);
526
527
aio_co_wake(restart->co);
528
}
529
@@ -XXX,XX +XXX,XX @@ static coroutine_fn void co_yield(BDRVSSHState *s, BlockDriverState *bs)
530
trace_ssh_co_yield(s->sock, rd_handler, wr_handler);
531
532
aio_set_fd_handler(bdrv_get_aio_context(bs), s->sock,
533
- false, rd_handler, wr_handler, NULL, NULL, &restart);
534
+ rd_handler, wr_handler, NULL, NULL, &restart);
535
qemu_coroutine_yield();
536
trace_ssh_co_yield_back(s->sock);
537
}
538
diff --git a/block/win32-aio.c b/block/win32-aio.c
539
index XXXXXXX..XXXXXXX 100644
540
--- a/block/win32-aio.c
541
+++ b/block/win32-aio.c
542
@@ -XXX,XX +XXX,XX @@ int win32_aio_attach(QEMUWin32AIOState *aio, HANDLE hfile)
543
void win32_aio_detach_aio_context(QEMUWin32AIOState *aio,
544
AioContext *old_context)
545
{
546
- aio_set_event_notifier(old_context, &aio->e, false, NULL, NULL, NULL);
547
+ aio_set_event_notifier(old_context, &aio->e, NULL, NULL, NULL);
548
aio->aio_ctx = NULL;
549
}
550
551
@@ -XXX,XX +XXX,XX @@ void win32_aio_attach_aio_context(QEMUWin32AIOState *aio,
552
AioContext *new_context)
553
{
554
aio->aio_ctx = new_context;
555
- aio_set_event_notifier(new_context, &aio->e, false,
556
- win32_aio_completion_cb, NULL, NULL);
557
+ aio_set_event_notifier(new_context, &aio->e, win32_aio_completion_cb,
558
+ NULL, NULL);
559
}
560
561
QEMUWin32AIOState *win32_aio_init(void)
562
diff --git a/hw/i386/kvm/xen_xenstore.c b/hw/i386/kvm/xen_xenstore.c
563
index XXXXXXX..XXXXXXX 100644
564
--- a/hw/i386/kvm/xen_xenstore.c
565
+++ b/hw/i386/kvm/xen_xenstore.c
566
@@ -XXX,XX +XXX,XX @@ static void xen_xenstore_realize(DeviceState *dev, Error **errp)
567
error_setg(errp, "Xenstore evtchn port init failed");
568
return;
569
}
570
- aio_set_fd_handler(qemu_get_aio_context(), xen_be_evtchn_fd(s->eh), false,
571
+ aio_set_fd_handler(qemu_get_aio_context(), xen_be_evtchn_fd(s->eh),
572
xen_xenstore_event, NULL, NULL, NULL, s);
573
574
s->impl = xs_impl_create(xen_domid);
575
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
576
index XXXXXXX..XXXXXXX 100644
577
--- a/hw/virtio/virtio.c
578
+++ b/hw/virtio/virtio.c
579
@@ -XXX,XX +XXX,XX @@ static void virtio_queue_host_notifier_aio_poll_end(EventNotifier *n)
580
581
void virtio_queue_aio_attach_host_notifier(VirtQueue *vq, AioContext *ctx)
582
{
583
- aio_set_event_notifier(ctx, &vq->host_notifier, false,
584
+ aio_set_event_notifier(ctx, &vq->host_notifier,
585
virtio_queue_host_notifier_read,
586
virtio_queue_host_notifier_aio_poll,
587
virtio_queue_host_notifier_aio_poll_ready);
588
@@ -XXX,XX +XXX,XX @@ void virtio_queue_aio_attach_host_notifier(VirtQueue *vq, AioContext *ctx)
589
*/
590
void virtio_queue_aio_attach_host_notifier_no_poll(VirtQueue *vq, AioContext *ctx)
591
{
592
- aio_set_event_notifier(ctx, &vq->host_notifier, false,
593
+ aio_set_event_notifier(ctx, &vq->host_notifier,
594
virtio_queue_host_notifier_read,
595
NULL, NULL);
596
}
597
598
void virtio_queue_aio_detach_host_notifier(VirtQueue *vq, AioContext *ctx)
599
{
600
- aio_set_event_notifier(ctx, &vq->host_notifier, false, NULL, NULL, NULL);
601
+ aio_set_event_notifier(ctx, &vq->host_notifier, NULL, NULL, NULL);
602
}
603
604
void virtio_queue_host_notifier_read(EventNotifier *n)
605
diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c
606
index XXXXXXX..XXXXXXX 100644
607
--- a/hw/xen/xen-bus.c
608
+++ b/hw/xen/xen-bus.c
609
@@ -XXX,XX +XXX,XX @@ void xen_device_set_event_channel_context(XenDevice *xendev,
610
}
611
612
if (channel->ctx)
613
- aio_set_fd_handler(channel->ctx, qemu_xen_evtchn_fd(channel->xeh), false,
614
+ aio_set_fd_handler(channel->ctx, qemu_xen_evtchn_fd(channel->xeh),
615
NULL, NULL, NULL, NULL, NULL);
616
617
channel->ctx = ctx;
618
if (ctx) {
619
aio_set_fd_handler(channel->ctx, qemu_xen_evtchn_fd(channel->xeh),
620
- false, xen_device_event, NULL, xen_device_poll,
621
- NULL, channel);
622
+ xen_device_event, NULL, xen_device_poll, NULL,
623
+ channel);
624
}
625
}
626
627
@@ -XXX,XX +XXX,XX @@ void xen_device_unbind_event_channel(XenDevice *xendev,
628
629
QLIST_REMOVE(channel, list);
630
631
- aio_set_fd_handler(channel->ctx, qemu_xen_evtchn_fd(channel->xeh), false,
632
+ aio_set_fd_handler(channel->ctx, qemu_xen_evtchn_fd(channel->xeh),
633
NULL, NULL, NULL, NULL, NULL);
634
635
if (qemu_xen_evtchn_unbind(channel->xeh, channel->local_port) < 0) {
636
diff --git a/io/channel-command.c b/io/channel-command.c
637
index XXXXXXX..XXXXXXX 100644
638
--- a/io/channel-command.c
639
+++ b/io/channel-command.c
640
@@ -XXX,XX +XXX,XX @@ static void qio_channel_command_set_aio_fd_handler(QIOChannel *ioc,
641
void *opaque)
642
{
643
QIOChannelCommand *cioc = QIO_CHANNEL_COMMAND(ioc);
644
- aio_set_fd_handler(ctx, cioc->readfd, false,
645
- io_read, NULL, NULL, NULL, opaque);
646
- aio_set_fd_handler(ctx, cioc->writefd, false,
647
- NULL, io_write, NULL, NULL, opaque);
648
+ aio_set_fd_handler(ctx, cioc->readfd, io_read, NULL, NULL, NULL, opaque);
649
+ aio_set_fd_handler(ctx, cioc->writefd, NULL, io_write, NULL, NULL, opaque);
650
}
651
652
653
diff --git a/io/channel-file.c b/io/channel-file.c
654
index XXXXXXX..XXXXXXX 100644
655
--- a/io/channel-file.c
656
+++ b/io/channel-file.c
657
@@ -XXX,XX +XXX,XX @@ static void qio_channel_file_set_aio_fd_handler(QIOChannel *ioc,
658
void *opaque)
659
{
660
QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
661
- aio_set_fd_handler(ctx, fioc->fd, false, io_read, io_write,
662
- NULL, NULL, opaque);
663
+ aio_set_fd_handler(ctx, fioc->fd, io_read, io_write, NULL, NULL, opaque);
664
}
665
666
static GSource *qio_channel_file_create_watch(QIOChannel *ioc,
667
diff --git a/io/channel-socket.c b/io/channel-socket.c
668
index XXXXXXX..XXXXXXX 100644
669
--- a/io/channel-socket.c
670
+++ b/io/channel-socket.c
671
@@ -XXX,XX +XXX,XX @@ static void qio_channel_socket_set_aio_fd_handler(QIOChannel *ioc,
672
void *opaque)
673
{
674
QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
675
- aio_set_fd_handler(ctx, sioc->fd, false,
676
- io_read, io_write, NULL, NULL, opaque);
677
+ aio_set_fd_handler(ctx, sioc->fd, io_read, io_write, NULL, NULL, opaque);
678
}
679
680
static GSource *qio_channel_socket_create_watch(QIOChannel *ioc,
681
diff --git a/migration/rdma.c b/migration/rdma.c
682
index XXXXXXX..XXXXXXX 100644
683
--- a/migration/rdma.c
684
+++ b/migration/rdma.c
685
@@ -XXX,XX +XXX,XX @@ static void qio_channel_rdma_set_aio_fd_handler(QIOChannel *ioc,
686
{
687
QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(ioc);
688
if (io_read) {
689
- aio_set_fd_handler(ctx, rioc->rdmain->recv_comp_channel->fd,
690
- false, io_read, io_write, NULL, NULL, opaque);
691
- aio_set_fd_handler(ctx, rioc->rdmain->send_comp_channel->fd,
692
- false, io_read, io_write, NULL, NULL, opaque);
693
+ aio_set_fd_handler(ctx, rioc->rdmain->recv_comp_channel->fd, io_read,
694
+ io_write, NULL, NULL, opaque);
695
+ aio_set_fd_handler(ctx, rioc->rdmain->send_comp_channel->fd, io_read,
696
+ io_write, NULL, NULL, opaque);
697
} else {
698
- aio_set_fd_handler(ctx, rioc->rdmaout->recv_comp_channel->fd,
699
- false, io_read, io_write, NULL, NULL, opaque);
700
- aio_set_fd_handler(ctx, rioc->rdmaout->send_comp_channel->fd,
701
- false, io_read, io_write, NULL, NULL, opaque);
702
+ aio_set_fd_handler(ctx, rioc->rdmaout->recv_comp_channel->fd, io_read,
703
+ io_write, NULL, NULL, opaque);
704
+ aio_set_fd_handler(ctx, rioc->rdmaout->send_comp_channel->fd, io_read,
705
+ io_write, NULL, NULL, opaque);
706
}
707
}
708
709
diff --git a/tests/unit/test-aio.c b/tests/unit/test-aio.c
710
index XXXXXXX..XXXXXXX 100644
711
--- a/tests/unit/test-aio.c
712
+++ b/tests/unit/test-aio.c
713
@@ -XXX,XX +XXX,XX @@ static void *test_acquire_thread(void *opaque)
714
static void set_event_notifier(AioContext *ctx, EventNotifier *notifier,
715
EventNotifierHandler *handler)
716
{
717
- aio_set_event_notifier(ctx, notifier, false, handler, NULL, NULL);
718
+ aio_set_event_notifier(ctx, notifier, handler, NULL, NULL);
719
}
720
721
static void dummy_notifier_read(EventNotifier *n)
722
@@ -XXX,XX +XXX,XX @@ static void test_flush_event_notifier(void)
723
event_notifier_cleanup(&data.e);
724
}
725
726
-static void test_aio_external_client(void)
23
-{
727
-{
24
- va_list ap;
728
- int i, j;
25
-
729
-
26
- va_start(ap, fmt);
730
- for (i = 1; i < 3; i++) {
27
- fprintf(stderr, "quorum: offset=%" PRIu64 " bytes=%" PRIu64 " ",
731
- EventNotifierTestData data = { .n = 0, .active = 10, .auto_set = true };
28
- acb->offset, acb->bytes);
732
- event_notifier_init(&data.e, false);
29
- vfprintf(stderr, fmt, ap);
733
- aio_set_event_notifier(ctx, &data.e, true, event_ready_cb, NULL, NULL);
30
- fprintf(stderr, "\n");
734
- event_notifier_set(&data.e);
31
- va_end(ap);
735
- for (j = 0; j < i; j++) {
32
- exit(1);
736
- aio_disable_external(ctx);
737
- }
738
- for (j = 0; j < i; j++) {
739
- assert(!aio_poll(ctx, false));
740
- assert(event_notifier_test_and_clear(&data.e));
741
- event_notifier_set(&data.e);
742
- aio_enable_external(ctx);
743
- }
744
- assert(aio_poll(ctx, false));
745
- set_event_notifier(ctx, &data.e, NULL);
746
- event_notifier_cleanup(&data.e);
747
- }
33
-}
748
-}
34
-
749
-
35
-static bool quorum_compare(QuorumAIOCB *acb,
750
static void test_wait_event_notifier_noflush(void)
36
- QEMUIOVector *a,
751
{
37
- QEMUIOVector *b)
752
EventNotifierTestData data = { .n = 0 };
38
+static bool quorum_compare(QuorumAIOCB *acb, QEMUIOVector *a, QEMUIOVector *b)
753
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
39
{
754
g_test_add_func("/aio/event/wait", test_wait_event_notifier);
40
BDRVQuorumState *s = acb->bs->opaque;
755
g_test_add_func("/aio/event/wait/no-flush-cb", test_wait_event_notifier_noflush);
41
ssize_t offset;
756
g_test_add_func("/aio/event/flush", test_flush_event_notifier);
42
@@ -XXX,XX +XXX,XX @@ static bool quorum_compare(QuorumAIOCB *acb,
757
- g_test_add_func("/aio/external-client", test_aio_external_client);
43
if (s->is_blkverify) {
758
g_test_add_func("/aio/timer/schedule", test_timer_schedule);
44
offset = qemu_iovec_compare(a, b);
759
45
if (offset != -1) {
760
g_test_add_func("/aio/coroutine/queue-chaining", test_queue_chaining);
46
- quorum_err(acb, "contents mismatch at offset %" PRIu64,
761
diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c
47
- acb->offset + offset);
762
index XXXXXXX..XXXXXXX 100644
48
+ fprintf(stderr, "quorum: offset=%" PRIu64 " bytes=%" PRIu64
763
--- a/tests/unit/test-bdrv-drain.c
49
+ " contents mismatch at offset %" PRIu64 "\n",
764
+++ b/tests/unit/test-bdrv-drain.c
50
+ acb->offset, acb->bytes, acb->offset + offset);
765
@@ -XXX,XX +XXX,XX @@ static void test_graph_change_drain_all(void)
51
+ exit(1);
766
767
g_assert_cmpint(bs_b->quiesce_counter, ==, 0);
768
g_assert_cmpint(b_s->drain_count, ==, 0);
769
- g_assert_cmpint(qemu_get_aio_context()->external_disable_cnt, ==, 0);
770
771
bdrv_unref(bs_b);
772
blk_unref(blk_b);
773
diff --git a/tests/unit/test-fdmon-epoll.c b/tests/unit/test-fdmon-epoll.c
774
deleted file mode 100644
775
index XXXXXXX..XXXXXXX
776
--- a/tests/unit/test-fdmon-epoll.c
777
+++ /dev/null
778
@@ -XXX,XX +XXX,XX @@
779
-/* SPDX-License-Identifier: GPL-2.0-or-later */
780
-/*
781
- * fdmon-epoll tests
782
- *
783
- * Copyright (c) 2020 Red Hat, Inc.
784
- */
785
-
786
-#include "qemu/osdep.h"
787
-#include "block/aio.h"
788
-#include "qapi/error.h"
789
-#include "qemu/main-loop.h"
790
-
791
-static AioContext *ctx;
792
-
793
-static void dummy_fd_handler(EventNotifier *notifier)
794
-{
795
- event_notifier_test_and_clear(notifier);
796
-}
797
-
798
-static void add_event_notifiers(EventNotifier *notifiers, size_t n)
799
-{
800
- for (size_t i = 0; i < n; i++) {
801
- event_notifier_init(&notifiers[i], false);
802
- aio_set_event_notifier(ctx, &notifiers[i], false,
803
- dummy_fd_handler, NULL, NULL);
804
- }
805
-}
806
-
807
-static void remove_event_notifiers(EventNotifier *notifiers, size_t n)
808
-{
809
- for (size_t i = 0; i < n; i++) {
810
- aio_set_event_notifier(ctx, &notifiers[i], false, NULL, NULL, NULL);
811
- event_notifier_cleanup(&notifiers[i]);
812
- }
813
-}
814
-
815
-/* Check that fd handlers work when external clients are disabled */
816
-static void test_external_disabled(void)
817
-{
818
- EventNotifier notifiers[100];
819
-
820
- /* fdmon-epoll is only enabled when many fd handlers are registered */
821
- add_event_notifiers(notifiers, G_N_ELEMENTS(notifiers));
822
-
823
- event_notifier_set(&notifiers[0]);
824
- assert(aio_poll(ctx, true));
825
-
826
- aio_disable_external(ctx);
827
- event_notifier_set(&notifiers[0]);
828
- assert(aio_poll(ctx, true));
829
- aio_enable_external(ctx);
830
-
831
- remove_event_notifiers(notifiers, G_N_ELEMENTS(notifiers));
832
-}
833
-
834
-int main(int argc, char **argv)
835
-{
836
- /*
837
- * This code relies on the fact that fdmon-io_uring disables itself when
838
- * the glib main loop is in use. The main loop uses fdmon-poll and upgrades
839
- * to fdmon-epoll when the number of fds exceeds a threshold.
840
- */
841
- qemu_init_main_loop(&error_fatal);
842
- ctx = qemu_get_aio_context();
843
-
844
- while (g_main_context_iteration(NULL, false)) {
845
- /* Do nothing */
846
- }
847
-
848
- g_test_init(&argc, &argv, NULL);
849
- g_test_add_func("/fdmon-epoll/external-disabled", test_external_disabled);
850
- return g_test_run();
851
-}
852
diff --git a/tests/unit/test-nested-aio-poll.c b/tests/unit/test-nested-aio-poll.c
853
index XXXXXXX..XXXXXXX 100644
854
--- a/tests/unit/test-nested-aio-poll.c
855
+++ b/tests/unit/test-nested-aio-poll.c
856
@@ -XXX,XX +XXX,XX @@ static void test(void)
857
858
/* Make the event notifier active (set) right away */
859
event_notifier_init(&td.poll_notifier, 1);
860
- aio_set_event_notifier(td.ctx, &td.poll_notifier, false,
861
+ aio_set_event_notifier(td.ctx, &td.poll_notifier,
862
io_read, io_poll_true, io_poll_ready);
863
864
/* This event notifier will be used later */
865
event_notifier_init(&td.dummy_notifier, 0);
866
- aio_set_event_notifier(td.ctx, &td.dummy_notifier, false,
867
+ aio_set_event_notifier(td.ctx, &td.dummy_notifier,
868
io_read, io_poll_false, io_poll_never_ready);
869
870
/* Consume aio_notify() */
871
@@ -XXX,XX +XXX,XX @@ static void test(void)
872
/* Run io_poll()/io_poll_ready() one more time to show it keeps working */
873
g_assert(aio_poll(td.ctx, true));
874
875
- aio_set_event_notifier(td.ctx, &td.dummy_notifier, false,
876
- NULL, NULL, NULL);
877
- aio_set_event_notifier(td.ctx, &td.poll_notifier, false, NULL, NULL, NULL);
878
+ aio_set_event_notifier(td.ctx, &td.dummy_notifier, NULL, NULL, NULL);
879
+ aio_set_event_notifier(td.ctx, &td.poll_notifier, NULL, NULL, NULL);
880
event_notifier_cleanup(&td.dummy_notifier);
881
event_notifier_cleanup(&td.poll_notifier);
882
aio_context_unref(td.ctx);
883
diff --git a/util/aio-posix.c b/util/aio-posix.c
884
index XXXXXXX..XXXXXXX 100644
885
--- a/util/aio-posix.c
886
+++ b/util/aio-posix.c
887
@@ -XXX,XX +XXX,XX @@ static bool aio_remove_fd_handler(AioContext *ctx, AioHandler *node)
888
889
void aio_set_fd_handler(AioContext *ctx,
890
int fd,
891
- bool is_external,
892
IOHandler *io_read,
893
IOHandler *io_write,
894
AioPollFn *io_poll,
895
@@ -XXX,XX +XXX,XX @@ void aio_set_fd_handler(AioContext *ctx,
896
new_node->io_poll = io_poll;
897
new_node->io_poll_ready = io_poll_ready;
898
new_node->opaque = opaque;
899
- new_node->is_external = is_external;
900
901
if (is_new) {
902
new_node->pfd.fd = fd;
903
@@ -XXX,XX +XXX,XX @@ static void aio_set_fd_poll(AioContext *ctx, int fd,
904
905
void aio_set_event_notifier(AioContext *ctx,
906
EventNotifier *notifier,
907
- bool is_external,
908
EventNotifierHandler *io_read,
909
AioPollFn *io_poll,
910
EventNotifierHandler *io_poll_ready)
911
{
912
- aio_set_fd_handler(ctx, event_notifier_get_fd(notifier), is_external,
913
+ aio_set_fd_handler(ctx, event_notifier_get_fd(notifier),
914
(IOHandler *)io_read, NULL, io_poll,
915
(IOHandler *)io_poll_ready, notifier);
916
}
917
@@ -XXX,XX +XXX,XX @@ bool aio_pending(AioContext *ctx)
918
919
/* TODO should this check poll ready? */
920
revents = node->pfd.revents & node->pfd.events;
921
- if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR) && node->io_read &&
922
- aio_node_check(ctx, node->is_external)) {
923
+ if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR) && node->io_read) {
924
result = true;
925
break;
52
}
926
}
927
- if (revents & (G_IO_OUT | G_IO_ERR) && node->io_write &&
928
- aio_node_check(ctx, node->is_external)) {
929
+ if (revents & (G_IO_OUT | G_IO_ERR) && node->io_write) {
930
result = true;
931
break;
932
}
933
@@ -XXX,XX +XXX,XX @@ static bool aio_dispatch_handler(AioContext *ctx, AioHandler *node)
934
QLIST_INSERT_HEAD(&ctx->poll_aio_handlers, node, node_poll);
935
}
936
if (!QLIST_IS_INSERTED(node, node_deleted) &&
937
- poll_ready && revents == 0 &&
938
- aio_node_check(ctx, node->is_external) &&
939
- node->io_poll_ready) {
940
+ poll_ready && revents == 0 && node->io_poll_ready) {
941
/*
942
* Remove temporarily to avoid infinite loops when ->io_poll_ready()
943
* calls aio_poll() before clearing the condition that made the poll
944
@@ -XXX,XX +XXX,XX @@ static bool aio_dispatch_handler(AioContext *ctx, AioHandler *node)
945
946
if (!QLIST_IS_INSERTED(node, node_deleted) &&
947
(revents & (G_IO_IN | G_IO_HUP | G_IO_ERR)) &&
948
- aio_node_check(ctx, node->is_external) &&
949
node->io_read) {
950
node->io_read(node->opaque);
951
952
@@ -XXX,XX +XXX,XX @@ static bool aio_dispatch_handler(AioContext *ctx, AioHandler *node)
953
}
954
if (!QLIST_IS_INSERTED(node, node_deleted) &&
955
(revents & (G_IO_OUT | G_IO_ERR)) &&
956
- aio_node_check(ctx, node->is_external) &&
957
node->io_write) {
958
node->io_write(node->opaque);
959
progress = true;
960
@@ -XXX,XX +XXX,XX @@ static bool run_poll_handlers_once(AioContext *ctx,
961
AioHandler *tmp;
962
963
QLIST_FOREACH_SAFE(node, &ctx->poll_aio_handlers, node_poll, tmp) {
964
- if (aio_node_check(ctx, node->is_external) &&
965
- node->io_poll(node->opaque)) {
966
+ if (node->io_poll(node->opaque)) {
967
aio_add_poll_ready_handler(ready_list, node);
968
969
node->poll_idle_timeout = now + POLL_IDLE_INTERVAL_NS;
970
diff --git a/util/aio-win32.c b/util/aio-win32.c
971
index XXXXXXX..XXXXXXX 100644
972
--- a/util/aio-win32.c
973
+++ b/util/aio-win32.c
974
@@ -XXX,XX +XXX,XX @@ struct AioHandler {
975
GPollFD pfd;
976
int deleted;
977
void *opaque;
978
- bool is_external;
979
QLIST_ENTRY(AioHandler) node;
980
};
981
982
@@ -XXX,XX +XXX,XX @@ static void aio_remove_fd_handler(AioContext *ctx, AioHandler *node)
983
984
void aio_set_fd_handler(AioContext *ctx,
985
int fd,
986
- bool is_external,
987
IOHandler *io_read,
988
IOHandler *io_write,
989
AioPollFn *io_poll,
990
@@ -XXX,XX +XXX,XX @@ void aio_set_fd_handler(AioContext *ctx,
991
node->opaque = opaque;
992
node->io_read = io_read;
993
node->io_write = io_write;
994
- node->is_external = is_external;
995
996
if (io_read) {
997
bitmask |= FD_READ | FD_ACCEPT | FD_CLOSE;
998
@@ -XXX,XX +XXX,XX @@ void aio_set_fd_handler(AioContext *ctx,
999
1000
void aio_set_event_notifier(AioContext *ctx,
1001
EventNotifier *e,
1002
- bool is_external,
1003
EventNotifierHandler *io_notify,
1004
AioPollFn *io_poll,
1005
EventNotifierHandler *io_poll_ready)
1006
@@ -XXX,XX +XXX,XX @@ void aio_set_event_notifier(AioContext *ctx,
1007
node->e = e;
1008
node->pfd.fd = (uintptr_t)event_notifier_get_handle(e);
1009
node->pfd.events = G_IO_IN;
1010
- node->is_external = is_external;
1011
QLIST_INSERT_HEAD_RCU(&ctx->aio_handlers, node, node);
1012
1013
g_source_add_poll(&ctx->source, &node->pfd);
1014
@@ -XXX,XX +XXX,XX @@ bool aio_poll(AioContext *ctx, bool blocking)
1015
/* fill fd sets */
1016
count = 0;
1017
QLIST_FOREACH_RCU(node, &ctx->aio_handlers, node) {
1018
- if (!node->deleted && node->io_notify
1019
- && aio_node_check(ctx, node->is_external)) {
1020
+ if (!node->deleted && node->io_notify) {
1021
assert(count < MAXIMUM_WAIT_OBJECTS);
1022
events[count++] = event_notifier_get_handle(node->e);
1023
}
1024
diff --git a/util/async.c b/util/async.c
1025
index XXXXXXX..XXXXXXX 100644
1026
--- a/util/async.c
1027
+++ b/util/async.c
1028
@@ -XXX,XX +XXX,XX @@ aio_ctx_finalize(GSource *source)
1029
g_free(bh);
1030
}
1031
1032
- aio_set_event_notifier(ctx, &ctx->notifier, false, NULL, NULL, NULL);
1033
+ aio_set_event_notifier(ctx, &ctx->notifier, NULL, NULL, NULL);
1034
event_notifier_cleanup(&ctx->notifier);
1035
qemu_rec_mutex_destroy(&ctx->lock);
1036
qemu_lockcnt_destroy(&ctx->list_lock);
1037
@@ -XXX,XX +XXX,XX @@ AioContext *aio_context_new(Error **errp)
1038
QSLIST_INIT(&ctx->scheduled_coroutines);
1039
1040
aio_set_event_notifier(ctx, &ctx->notifier,
1041
- false,
1042
aio_context_notifier_cb,
1043
aio_context_notifier_poll,
1044
aio_context_notifier_poll_ready);
1045
diff --git a/util/fdmon-epoll.c b/util/fdmon-epoll.c
1046
index XXXXXXX..XXXXXXX 100644
1047
--- a/util/fdmon-epoll.c
1048
+++ b/util/fdmon-epoll.c
1049
@@ -XXX,XX +XXX,XX @@ static int fdmon_epoll_wait(AioContext *ctx, AioHandlerList *ready_list,
1050
int i, ret = 0;
1051
struct epoll_event events[128];
1052
1053
- /* Fall back while external clients are disabled */
1054
- if (qatomic_read(&ctx->external_disable_cnt)) {
1055
- return fdmon_poll_ops.wait(ctx, ready_list, timeout);
1056
- }
1057
-
1058
if (timeout > 0) {
1059
ret = qemu_poll_ns(&pfd, 1, timeout);
1060
if (ret > 0) {
1061
@@ -XXX,XX +XXX,XX @@ bool fdmon_epoll_try_upgrade(AioContext *ctx, unsigned npfd)
1062
return false;
1063
}
1064
1065
- /* Do not upgrade while external clients are disabled */
1066
- if (qatomic_read(&ctx->external_disable_cnt)) {
1067
- return false;
1068
- }
1069
-
1070
if (npfd < EPOLL_ENABLE_THRESHOLD) {
1071
return false;
1072
}
1073
diff --git a/util/fdmon-io_uring.c b/util/fdmon-io_uring.c
1074
index XXXXXXX..XXXXXXX 100644
1075
--- a/util/fdmon-io_uring.c
1076
+++ b/util/fdmon-io_uring.c
1077
@@ -XXX,XX +XXX,XX @@ static int fdmon_io_uring_wait(AioContext *ctx, AioHandlerList *ready_list,
1078
unsigned wait_nr = 1; /* block until at least one cqe is ready */
1079
int ret;
1080
1081
- /* Fall back while external clients are disabled */
1082
- if (qatomic_read(&ctx->external_disable_cnt)) {
1083
- return fdmon_poll_ops.wait(ctx, ready_list, timeout);
1084
- }
1085
-
1086
if (timeout == 0) {
1087
wait_nr = 0; /* non-blocking */
1088
} else if (timeout > 0) {
1089
@@ -XXX,XX +XXX,XX @@ static bool fdmon_io_uring_need_wait(AioContext *ctx)
53
return true;
1090
return true;
54
}
1091
}
1092
1093
- /* Are we falling back to fdmon-poll? */
1094
- return qatomic_read(&ctx->external_disable_cnt);
1095
+ return false;
1096
}
1097
1098
static const FDMonOps fdmon_io_uring_ops = {
1099
diff --git a/util/fdmon-poll.c b/util/fdmon-poll.c
1100
index XXXXXXX..XXXXXXX 100644
1101
--- a/util/fdmon-poll.c
1102
+++ b/util/fdmon-poll.c
1103
@@ -XXX,XX +XXX,XX @@ static int fdmon_poll_wait(AioContext *ctx, AioHandlerList *ready_list,
1104
assert(npfd == 0);
1105
1106
QLIST_FOREACH_RCU(node, &ctx->aio_handlers, node) {
1107
- if (!QLIST_IS_INSERTED(node, node_deleted) && node->pfd.events
1108
- && aio_node_check(ctx, node->is_external)) {
1109
+ if (!QLIST_IS_INSERTED(node, node_deleted) && node->pfd.events) {
1110
add_pollfd(node);
1111
}
1112
}
1113
diff --git a/util/main-loop.c b/util/main-loop.c
1114
index XXXXXXX..XXXXXXX 100644
1115
--- a/util/main-loop.c
1116
+++ b/util/main-loop.c
1117
@@ -XXX,XX +XXX,XX @@ void qemu_set_fd_handler(int fd,
1118
void *opaque)
1119
{
1120
iohandler_init();
1121
- aio_set_fd_handler(iohandler_ctx, fd, false,
1122
- fd_read, fd_write, NULL, NULL, opaque);
1123
+ aio_set_fd_handler(iohandler_ctx, fd, fd_read, fd_write, NULL, NULL,
1124
+ opaque);
1125
}
1126
1127
void event_notifier_set_handler(EventNotifier *e,
1128
EventNotifierHandler *handler)
1129
{
1130
iohandler_init();
1131
- aio_set_event_notifier(iohandler_ctx, e, false,
1132
- handler, NULL, NULL);
1133
+ aio_set_event_notifier(iohandler_ctx, e, handler, NULL, NULL);
1134
}
1135
diff --git a/util/qemu-coroutine-io.c b/util/qemu-coroutine-io.c
1136
index XXXXXXX..XXXXXXX 100644
1137
--- a/util/qemu-coroutine-io.c
1138
+++ b/util/qemu-coroutine-io.c
1139
@@ -XXX,XX +XXX,XX @@ typedef struct {
1140
static void fd_coroutine_enter(void *opaque)
1141
{
1142
FDYieldUntilData *data = opaque;
1143
- aio_set_fd_handler(data->ctx, data->fd, false,
1144
- NULL, NULL, NULL, NULL, NULL);
1145
+ aio_set_fd_handler(data->ctx, data->fd, NULL, NULL, NULL, NULL, NULL);
1146
qemu_coroutine_enter(data->co);
1147
}
1148
1149
@@ -XXX,XX +XXX,XX @@ void coroutine_fn yield_until_fd_readable(int fd)
1150
data.ctx = qemu_get_current_aio_context();
1151
data.co = qemu_coroutine_self();
1152
data.fd = fd;
1153
- aio_set_fd_handler(
1154
- data.ctx, fd, false, fd_coroutine_enter, NULL, NULL, NULL, &data);
1155
+ aio_set_fd_handler(data.ctx, fd, fd_coroutine_enter, NULL, NULL, NULL,
1156
+ &data);
1157
qemu_coroutine_yield();
1158
}
1159
diff --git a/util/vhost-user-server.c b/util/vhost-user-server.c
1160
index XXXXXXX..XXXXXXX 100644
1161
--- a/util/vhost-user-server.c
1162
+++ b/util/vhost-user-server.c
1163
@@ -XXX,XX +XXX,XX @@ set_watch(VuDev *vu_dev, int fd, int vu_evt,
1164
vu_fd_watch->fd = fd;
1165
vu_fd_watch->cb = cb;
1166
qemu_socket_set_nonblock(fd);
1167
- aio_set_fd_handler(server->ioc->ctx, fd, false, kick_handler,
1168
+ aio_set_fd_handler(server->ioc->ctx, fd, kick_handler,
1169
NULL, NULL, NULL, vu_fd_watch);
1170
vu_fd_watch->vu_dev = vu_dev;
1171
vu_fd_watch->pvt = pvt;
1172
@@ -XXX,XX +XXX,XX @@ static void remove_watch(VuDev *vu_dev, int fd)
1173
if (!vu_fd_watch) {
1174
return;
1175
}
1176
- aio_set_fd_handler(server->ioc->ctx, fd, false,
1177
- NULL, NULL, NULL, NULL, NULL);
1178
+ aio_set_fd_handler(server->ioc->ctx, fd, NULL, NULL, NULL, NULL, NULL);
1179
1180
QTAILQ_REMOVE(&server->vu_fd_watches, vu_fd_watch, next);
1181
g_free(vu_fd_watch);
1182
@@ -XXX,XX +XXX,XX @@ void vhost_user_server_stop(VuServer *server)
1183
VuFdWatch *vu_fd_watch;
1184
1185
QTAILQ_FOREACH(vu_fd_watch, &server->vu_fd_watches, next) {
1186
- aio_set_fd_handler(server->ctx, vu_fd_watch->fd, false,
1187
+ aio_set_fd_handler(server->ctx, vu_fd_watch->fd,
1188
NULL, NULL, NULL, NULL, vu_fd_watch);
1189
}
1190
1191
@@ -XXX,XX +XXX,XX @@ void vhost_user_server_attach_aio_context(VuServer *server, AioContext *ctx)
1192
qio_channel_attach_aio_context(server->ioc, ctx);
1193
1194
QTAILQ_FOREACH(vu_fd_watch, &server->vu_fd_watches, next) {
1195
- aio_set_fd_handler(ctx, vu_fd_watch->fd, false, kick_handler, NULL,
1196
+ aio_set_fd_handler(ctx, vu_fd_watch->fd, kick_handler, NULL,
1197
NULL, NULL, vu_fd_watch);
1198
}
1199
1200
@@ -XXX,XX +XXX,XX @@ void vhost_user_server_detach_aio_context(VuServer *server)
1201
VuFdWatch *vu_fd_watch;
1202
1203
QTAILQ_FOREACH(vu_fd_watch, &server->vu_fd_watches, next) {
1204
- aio_set_fd_handler(server->ctx, vu_fd_watch->fd, false,
1205
+ aio_set_fd_handler(server->ctx, vu_fd_watch->fd,
1206
NULL, NULL, NULL, NULL, vu_fd_watch);
1207
}
1208
1209
diff --git a/tests/unit/meson.build b/tests/unit/meson.build
1210
index XXXXXXX..XXXXXXX 100644
1211
--- a/tests/unit/meson.build
1212
+++ b/tests/unit/meson.build
1213
@@ -XXX,XX +XXX,XX @@ if have_block
1214
if nettle.found() or gcrypt.found()
1215
tests += {'test-crypto-pbkdf': [io]}
1216
endif
1217
- if config_host_data.get('CONFIG_EPOLL_CREATE1')
1218
- tests += {'test-fdmon-epoll': [testblock]}
1219
- endif
1220
endif
1221
1222
if have_system
55
--
1223
--
56
2.19.1
1224
2.40.1
57
1225
58
1226
diff view generated by jsdifflib
Deleted patch
1
Commit e2b8247a322 introduced an error path in qemu_rbd_open() after
2
calling rbd_open(), but neglected to close the image again in this error
3
path. The error path should contain everything that the regular close
4
function qemu_rbd_close() contains.
5
1
6
This adds the missing rbd_close() call.
7
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
10
---
11
block/rbd.c | 1 +
12
1 file changed, 1 insertion(+)
13
14
diff --git a/block/rbd.c b/block/rbd.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/block/rbd.c
17
+++ b/block/rbd.c
18
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
19
"automatically marking the image read-only.");
20
r = bdrv_set_read_only(bs, true, &local_err);
21
if (r < 0) {
22
+ rbd_close(s->image);
23
error_propagate(errp, local_err);
24
goto failed_open;
25
}
26
--
27
2.19.1
28
29
diff view generated by jsdifflib
Deleted patch
1
If read-only=off, but auto-read-only=on is given, open the file
2
read-write if we have the permissions, but instead of erroring out for
3
read-only files, just degrade to read-only.
4
1
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Niels de Vos <ndevos@redhat.com>
7
---
8
block/gluster.c | 12 ++++++++++--
9
1 file changed, 10 insertions(+), 2 deletions(-)
10
11
diff --git a/block/gluster.c b/block/gluster.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/block/gluster.c
14
+++ b/block/gluster.c
15
@@ -XXX,XX +XXX,XX @@ static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
16
qemu_gluster_parse_flags(bdrv_flags, &open_flags);
17
18
s->fd = glfs_open(s->glfs, gconf->path, open_flags);
19
- if (!s->fd) {
20
- ret = -errno;
21
+ ret = s->fd ? 0 : -errno;
22
+
23
+ if (ret == -EACCES || ret == -EROFS) {
24
+ /* Try to degrade to read-only, but if it doesn't work, still use the
25
+ * normal error message. */
26
+ if (bdrv_apply_auto_read_only(bs, NULL, NULL) == 0) {
27
+ open_flags = (open_flags & ~O_RDWR) | O_RDONLY;
28
+ s->fd = glfs_open(s->glfs, gconf->path, open_flags);
29
+ ret = s->fd ? 0 : -errno;
30
+ }
31
}
32
33
s->supports_seek_data = qemu_gluster_test_seek(s->fd);
34
--
35
2.19.1
36
37
diff view generated by jsdifflib
Deleted patch
1
While we want machine interfaces like -blockdev and QMP blockdev-add to
2
add as little auto-detection as possible so that management tools are
3
explicit about their needs, -drive is a convenience option for human
4
users. Enabling auto-read-only=on by default there enables users to use
5
read-only images for read-only guest devices without having to specify
6
read-only=on explicitly. If they try to attach the image to a read-write
7
device, they will still get an error message.
8
1
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Reviewed-by: Eric Blake <eblake@redhat.com>
11
---
12
blockdev.c | 1 +
13
1 file changed, 1 insertion(+)
14
15
diff --git a/blockdev.c b/blockdev.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/blockdev.c
18
+++ b/blockdev.c
19
@@ -XXX,XX +XXX,XX @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
20
qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_NO_FLUSH, "off");
21
qdict_set_default_str(bs_opts, BDRV_OPT_READ_ONLY,
22
read_only ? "on" : "off");
23
+ qdict_set_default_str(bs_opts, BDRV_OPT_AUTO_READ_ONLY, "on");
24
assert((bdrv_flags & BDRV_O_CACHE_MASK) == 0);
25
26
if (runstate_check(RUN_STATE_INMIGRATE)) {
27
--
28
2.19.1
29
30
diff view generated by jsdifflib