1
The following changes since commit b2f7a038bb4c4fc5ce6b8486e8513dfd97665e2a:
1
The following changes since commit 5204b499a6cae4dfd9fe762d5e6e82224892383b:
2
2
3
Merge remote-tracking branch 'remotes/rth/tags/pull-softfloat-20181104' into staging (2018-11-05 10:32:49 +0000)
3
mailmap: Fix Stefan Weil author email (2022-12-13 15:56:57 -0500)
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 2ad19e5dc950d4b340894846b9e71c0b20f9a1cc:
10
10
11
include: Add a comment to explain the origin of sizes' lookup table (2018-11-05 15:29:59 +0100)
11
block: GRAPH_RDLOCK for functions only called by co_wrappers (2022-12-14 13:13:07 +0100)
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
- Code cleanups around block graph modification
17
- Fix help text related qemu-iotests failure (by improving the help text
17
- Simplify drain
18
and updating the reference output)
18
- coroutine_fn correctness fixes, including splitting generated
19
- quorum: Add missing checks when adding/removing child nodes
19
coroutine wrappers into co_wrapper (to be called only from
20
- Don't take address of fields in packed structs
20
non-coroutine context) and co_wrapper_mixed (both coroutine and
21
- vvfat: Fix crash when reporting error about too many files in directory
21
non-coroutine context)
22
- Introduce a block graph rwlock
22
23
23
----------------------------------------------------------------
24
----------------------------------------------------------------
24
Alberto Garcia (7):
25
Emanuele Giuseppe Esposito (21):
25
block: replace "discard" literal with BDRV_OPT_DISCARD macro
26
block-io: introduce coroutine_fn duplicates for bdrv_common_block_status_above callers
26
qcow2: Get the request alignment for encrypted images from QCryptoBlock
27
block-copy: add coroutine_fn annotations
27
quorum: Remove quorum_err()
28
nbd/server.c: add coroutine_fn annotations
28
quorum: Return an error if the blkverify mode has invalid settings
29
block-backend: replace bdrv_*_above with blk_*_above
29
iotest: Test the blkverify mode of the Quorum driver
30
block/vmdk: add coroutine_fn annotations
30
quorum: Forbid adding children in blkverify mode
31
block: avoid duplicating filename string in bdrv_create
31
iotest: Test x-blockdev-change on a Quorum
32
block: distinguish between bdrv_create running in coroutine and not
33
block: bdrv_create_file is a coroutine_fn
34
block: rename generated_co_wrapper in co_wrapper_mixed
35
block-coroutine-wrapper.py: introduce co_wrapper
36
block-coroutine-wrapper.py: support functions without bs arg
37
block-coroutine-wrapper.py: support also basic return types
38
block: convert bdrv_create to co_wrapper
39
block/dirty-bitmap: convert coroutine-only functions to co_wrapper
40
graph-lock: Implement guard macros
41
async: Register/unregister aiocontext in graph lock list
42
block: wrlock in bdrv_replace_child_noperm
43
block: remove unnecessary assert_bdrv_graph_writable()
44
block: assert that graph read and writes are performed correctly
45
block-coroutine-wrapper.py: introduce annotations that take the graph rdlock
46
block: use co_wrapper_mixed_bdrv_rdlock in functions taking the rdlock
32
47
33
Cleber Rosa (1):
48
Kevin Wolf (25):
34
iotests: make 083 specific to raw
49
qed: Don't yield in bdrv_qed_co_drain_begin()
50
test-bdrv-drain: Don't yield in .bdrv_co_drained_begin/end()
51
block: Revert .bdrv_drained_begin/end to non-coroutine_fn
52
block: Remove drained_end_counter
53
block: Inline bdrv_drain_invoke()
54
block: Fix locking for bdrv_reopen_queue_child()
55
block: Drain individual nodes during reopen
56
block: Don't use subtree drains in bdrv_drop_intermediate()
57
stream: Replace subtree drain with a single node drain
58
block: Remove subtree drains
59
block: Call drain callbacks only once
60
block: Remove ignore_bds_parents parameter from drain_begin/end.
61
block: Drop out of coroutine in bdrv_do_drained_begin_quiesce()
62
block: Don't poll in bdrv_replace_child_noperm()
63
block: Remove poll parameter from bdrv_parent_drained_begin_single()
64
block: Factor out bdrv_drain_all_begin_nopoll()
65
Import clang-tsa.h
66
clang-tsa: Add TSA_ASSERT() macro
67
clang-tsa: Add macros for shared locks
68
configure: Enable -Wthread-safety if present
69
test-bdrv-drain: Fix incorrrect drain assumptions
70
block: Fix locking in external_snapshot_prepare()
71
graph-lock: TSA annotations for lock/unlock functions
72
Mark assert_bdrv_graph_readable/writable() GRAPH_RD/WRLOCK
73
block: GRAPH_RDLOCK for functions only called by co_wrappers
35
74
36
Daniel P. Berrangé (1):
75
Paolo Bonzini (1):
37
crypto: initialize sector size even when opening with no IO flag
76
graph-lock: Introduce a lock to protect block graph operations
38
77
39
Kevin Wolf (12):
78
Vladimir Sementsov-Ogievskiy (4):
40
vpc: Don't leak opts in vpc_open()
79
block: Inline bdrv_detach_child()
41
block: Update flags in bdrv_set_read_only()
80
block: drop bdrv_remove_filter_or_cow_child
42
block: Add auto-read-only option
81
block: bdrv_refresh_perms(): allow external tran
43
rbd: Close image in qemu_rbd_open() error path
82
block: refactor bdrv_list_refresh_perms to allow any list of nodes
44
block: Require auto-read-only for existing fallbacks
45
nbd: Support auto-read-only option
46
file-posix: Support auto-read-only option
47
curl: Support auto-read-only option
48
gluster: Support auto-read-only option
49
iscsi: Support auto-read-only option
50
block: Make auto-read-only=on default for -drive
51
qemu-iotests: Test auto-read-only with -drive and -blockdev
52
83
53
Leonid Bloch (2):
84
docs/devel/block-coroutine-wrapper.rst | 6 +-
54
vdi: Use a literal number of bytes for DEFAULT_CLUSTER_SIZE
85
configure | 1 +
55
include: Add a comment to explain the origin of sizes' lookup table
86
block/block-gen.h | 11 +-
56
87
block/coroutines.h | 21 +-
57
Li Qiang (1):
88
include/block/aio.h | 9 +
58
block: change some function return type to bool
89
include/block/block-common.h | 27 ++-
59
90
include/block/block-copy.h | 5 +-
60
Max Reitz (5):
91
include/block/block-global-state.h | 15 +-
61
option: Make option help nicer to read
92
include/block/block-io.h | 136 +++++------
62
chardev: Indent list of chardevs
93
include/block/block_int-common.h | 49 ++--
63
qdev-monitor: Make device options help nicer
94
include/block/block_int-global-state.h | 17 --
64
object: Make option help nicer to read
95
include/block/block_int-io.h | 12 -
65
fw_cfg: Drop newline in @file description
96
include/block/block_int.h | 1 +
66
97
include/block/dirty-bitmap.h | 10 +-
67
Peter Maydell (5):
98
include/block/graph-lock.h | 280 +++++++++++++++++++++++
68
block/qcow2: Don't take address of fields in packed structs
99
include/qemu/clang-tsa.h | 114 ++++++++++
69
block/qcow: Don't take address of fields in packed structs
100
include/sysemu/block-backend-io.h | 77 ++++---
70
block/qcow2-bitmap: Don't take address of fields in packed structs
101
block.c | 404 ++++++++++++++++++---------------
71
block/vhdx: Don't take address of fields in packed structs
102
block/block-backend.c | 25 +-
72
block/vdi: Don't take address of fields in packed structs
103
block/block-copy.c | 21 +-
73
104
block/commit.c | 4 +-
74
Stefan Weil (1):
105
block/crypto.c | 2 +-
75
qemu-io-cmds: Fix two format strings
106
block/dirty-bitmap.c | 88 +------
76
107
block/graph-lock.c | 275 ++++++++++++++++++++++
77
Thomas Huth (1):
108
block/io.c | 367 ++++++++++--------------------
78
block/vvfat: Fix crash when reporting error about too many files in directory
109
block/parallels.c | 2 +-
79
110
block/qcow.c | 2 +-
80
qapi/block-core.json | 7 +
111
block/qcow2.c | 4 +-
81
block/vhdx.h | 12 +-
112
block/qed.c | 28 ++-
82
include/block/block.h | 5 +-
113
block/raw-format.c | 2 +-
83
include/qemu/option.h | 2 +-
114
block/replication.c | 6 -
84
include/qemu/units.h | 18 +
115
block/stream.c | 26 ++-
85
include/sysemu/block-backend.h | 6 +-
116
block/throttle.c | 8 +-
86
block.c | 60 ++-
117
block/vdi.c | 2 +-
87
block/block-backend.c | 8 +-
118
block/vhdx.c | 2 +-
88
block/bochs.c | 17 +-
119
block/vmdk.c | 38 ++--
89
block/cloop.c | 16 +-
120
block/vpc.c | 2 +-
90
block/curl.c | 8 +-
121
blockdev.c | 17 +-
91
block/dmg.c | 16 +-
122
blockjob.c | 2 +-
92
block/file-posix.c | 19 +-
123
nbd/server.c | 47 ++--
93
block/gluster.c | 12 +-
124
stubs/graph-lock.c | 10 +
94
block/iscsi.c | 8 +-
125
tests/unit/test-bdrv-drain.c | 387 +++++++++----------------------
95
block/nbd-client.c | 10 +-
126
util/async.c | 4 +
96
block/qcow.c | 18 +-
127
scripts/block-coroutine-wrapper.py | 133 ++++++++---
97
block/qcow2-bitmap.c | 24 +-
128
block/meson.build | 2 +
98
block/qcow2.c | 66 +--
129
stubs/meson.build | 1 +
99
block/quorum.c | 45 +-
130
46 files changed, 1575 insertions(+), 1127 deletions(-)
100
block/rbd.c | 14 +-
131
create mode 100644 include/block/graph-lock.h
101
block/vdi.c | 68 +--
132
create mode 100644 include/qemu/clang-tsa.h
102
block/vhdx-endian.c | 118 ++---
133
create mode 100644 block/graph-lock.c
103
block/vhdx-log.c | 4 +-
134
create mode 100644 stubs/graph-lock.c
104
block/vhdx.c | 18 +-
105
block/vpc.c | 2 +
106
block/vvfat.c | 15 +-
107
blockdev.c | 3 +-
108
chardev/char.c | 2 +-
109
crypto/block-qcow.c | 2 +
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
New patch
1
From: Vladimir Sementsov-Ogievskiy <vladimir.sementsov-ogievskiy@openvz.org>
1
2
3
The only caller is bdrv_root_unref_child(), let's just do the logic
4
directly in it. It simplifies further conversion of
5
bdrv_root_unref_child() to transaction actions.
6
7
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@openvz.org>
8
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
9
Message-Id: <20221107163558.618889-2-vsementsov@yandex-team.ru>
10
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
13
block.c | 46 +++++++++++++++++++---------------------------
14
1 file changed, 19 insertions(+), 27 deletions(-)
15
16
diff --git a/block.c b/block.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/block.c
19
+++ b/block.c
20
@@ -XXX,XX +XXX,XX @@ static BdrvChild *bdrv_attach_child_noperm(BlockDriverState *parent_bs,
21
tran, errp);
22
}
23
24
-static void bdrv_detach_child(BdrvChild *child)
25
-{
26
- BlockDriverState *old_bs = child->bs;
27
-
28
- GLOBAL_STATE_CODE();
29
- bdrv_replace_child_noperm(child, NULL);
30
- bdrv_child_free(child);
31
-
32
- if (old_bs) {
33
- /*
34
- * Update permissions for old node. We're just taking a parent away, so
35
- * we're loosening restrictions. Errors of permission update are not
36
- * fatal in this case, ignore them.
37
- */
38
- bdrv_refresh_perms(old_bs, NULL);
39
-
40
- /*
41
- * When the parent requiring a non-default AioContext is removed, the
42
- * node moves back to the main AioContext
43
- */
44
- bdrv_try_change_aio_context(old_bs, qemu_get_aio_context(), NULL, NULL);
45
- }
46
-}
47
-
48
/*
49
* This function steals the reference to child_bs from the caller.
50
* That reference is later dropped by bdrv_root_unref_child().
51
@@ -XXX,XX +XXX,XX @@ out:
52
/* Callers must ensure that child->frozen is false. */
53
void bdrv_root_unref_child(BdrvChild *child)
54
{
55
- BlockDriverState *child_bs;
56
+ BlockDriverState *child_bs = child->bs;
57
58
GLOBAL_STATE_CODE();
59
+ bdrv_replace_child_noperm(child, NULL);
60
+ bdrv_child_free(child);
61
+
62
+ if (child_bs) {
63
+ /*
64
+ * Update permissions for old node. We're just taking a parent away, so
65
+ * we're loosening restrictions. Errors of permission update are not
66
+ * fatal in this case, ignore them.
67
+ */
68
+ bdrv_refresh_perms(child_bs, NULL);
69
+
70
+ /*
71
+ * When the parent requiring a non-default AioContext is removed, the
72
+ * node moves back to the main AioContext
73
+ */
74
+ bdrv_try_change_aio_context(child_bs, qemu_get_aio_context(), NULL,
75
+ NULL);
76
+ }
77
78
- child_bs = child->bs;
79
- bdrv_detach_child(child);
80
bdrv_unref(child_bs);
81
}
82
83
--
84
2.38.1
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vladimir.sementsov-ogievskiy@openvz.org>
1
2
3
Drop this simple wrapper used only in one place. We have too many graph
4
modifying functions even without it.
5
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@openvz.org>
7
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
8
Message-Id: <20221107163558.618889-3-vsementsov@yandex-team.ru>
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
12
block.c | 15 +--------------
13
1 file changed, 1 insertion(+), 14 deletions(-)
14
15
diff --git a/block.c b/block.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/block.c
18
+++ b/block.c
19
@@ -XXX,XX +XXX,XX @@ static bool bdrv_recurse_has_child(BlockDriverState *bs,
20
static void bdrv_replace_child_noperm(BdrvChild *child,
21
BlockDriverState *new_bs);
22
static void bdrv_remove_child(BdrvChild *child, Transaction *tran);
23
-static void bdrv_remove_filter_or_cow_child(BlockDriverState *bs,
24
- Transaction *tran);
25
26
static int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
27
BlockReopenQueue *queue,
28
@@ -XXX,XX +XXX,XX @@ static void bdrv_remove_child(BdrvChild *child, Transaction *tran)
29
tran_add(tran, &bdrv_remove_child_drv, child);
30
}
31
32
-/*
33
- * A function to remove backing-chain child of @bs if exists: cow child for
34
- * format nodes (always .backing) and filter child for filters (may be .file or
35
- * .backing)
36
- */
37
-static void bdrv_remove_filter_or_cow_child(BlockDriverState *bs,
38
- Transaction *tran)
39
-{
40
- bdrv_remove_child(bdrv_filter_or_cow_child(bs), tran);
41
-}
42
-
43
static int bdrv_replace_node_noperm(BlockDriverState *from,
44
BlockDriverState *to,
45
bool auto_skip, Transaction *tran,
46
@@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_common(BlockDriverState *from,
47
}
48
49
if (detach_subchain) {
50
- bdrv_remove_filter_or_cow_child(to_cow_parent, tran);
51
+ bdrv_remove_child(bdrv_filter_or_cow_child(to_cow_parent), tran);
52
}
53
54
found = g_hash_table_new(NULL, NULL);
55
--
56
2.38.1
diff view generated by jsdifflib
1
From: Peter Maydell <peter.maydell@linaro.org>
1
From: Vladimir Sementsov-Ogievskiy <vladimir.sementsov-ogievskiy@openvz.org>
2
2
3
Taking the address of a field in a packed struct is a bad idea, because
3
Allow passing external Transaction pointer, stop creating extra
4
it might not be actually aligned enough for that pointer type (and
4
Transaction objects.
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
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@openvz.org>
10
used on something other than a packed struct field; we convert
7
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
11
those anyway, for consistency.
8
Message-Id: <20221107163558.618889-4-vsementsov@yandex-team.ru>
12
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
13
This patch was produced with the following spatch script:
14
15
@@
16
expression E;
17
@@
18
-be16_to_cpus(&E);
19
+E = be16_to_cpu(E);
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
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>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
51
---
11
---
52
block/qcow.c | 18 +++++++++---------
12
block.c | 31 ++++++++++++++++++++-----------
53
1 file changed, 9 insertions(+), 9 deletions(-)
13
1 file changed, 20 insertions(+), 11 deletions(-)
54
14
55
diff --git a/block/qcow.c b/block/qcow.c
15
diff --git a/block.c b/block.c
56
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
57
--- a/block/qcow.c
17
--- a/block.c
58
+++ b/block/qcow.c
18
+++ b/block.c
59
@@ -XXX,XX +XXX,XX @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
19
@@ -XXX,XX +XXX,XX @@ char *bdrv_perm_names(uint64_t perm)
20
}
21
22
23
-static int bdrv_refresh_perms(BlockDriverState *bs, Error **errp)
24
+/* @tran is allowed to be NULL. In this case no rollback is possible */
25
+static int bdrv_refresh_perms(BlockDriverState *bs, Transaction *tran,
26
+ Error **errp)
27
{
28
int ret;
29
- Transaction *tran = tran_new();
30
+ Transaction *local_tran = NULL;
31
g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, bs);
32
GLOBAL_STATE_CODE();
33
34
+ if (!tran) {
35
+ tran = local_tran = tran_new();
36
+ }
37
+
38
ret = bdrv_list_refresh_perms(list, NULL, tran, errp);
39
- tran_finalize(tran, ret);
40
+
41
+ if (local_tran) {
42
+ tran_finalize(local_tran, ret);
43
+ }
44
45
return ret;
46
}
47
@@ -XXX,XX +XXX,XX @@ int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared,
48
49
bdrv_child_set_perm(c, perm, shared, tran);
50
51
- ret = bdrv_refresh_perms(c->bs, &local_err);
52
+ ret = bdrv_refresh_perms(c->bs, tran, &local_err);
53
54
tran_finalize(tran, ret);
55
56
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
57
goto out;
58
}
59
60
- ret = bdrv_refresh_perms(child_bs, errp);
61
+ ret = bdrv_refresh_perms(child_bs, tran, errp);
62
63
out:
64
tran_finalize(tran, ret);
65
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
66
goto out;
67
}
68
69
- ret = bdrv_refresh_perms(parent_bs, errp);
70
+ ret = bdrv_refresh_perms(parent_bs, tran, errp);
60
if (ret < 0) {
71
if (ret < 0) {
61
goto fail;
72
goto out;
62
}
73
}
63
- be32_to_cpus(&header.magic);
74
@@ -XXX,XX +XXX,XX @@ void bdrv_root_unref_child(BdrvChild *child)
64
- be32_to_cpus(&header.version);
75
* we're loosening restrictions. Errors of permission update are not
65
- be64_to_cpus(&header.backing_file_offset);
76
* fatal in this case, ignore them.
66
- be32_to_cpus(&header.backing_file_size);
77
*/
67
- be32_to_cpus(&header.mtime);
78
- bdrv_refresh_perms(child_bs, NULL);
68
- be64_to_cpus(&header.size);
79
+ bdrv_refresh_perms(child_bs, NULL, NULL);
69
- be32_to_cpus(&header.crypt_method);
80
70
- be64_to_cpus(&header.l1_table_offset);
81
/*
71
+ header.magic = be32_to_cpu(header.magic);
82
* When the parent requiring a non-default AioContext is removed, the
72
+ header.version = be32_to_cpu(header.version);
83
@@ -XXX,XX +XXX,XX @@ int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
73
+ header.backing_file_offset = be64_to_cpu(header.backing_file_offset);
84
goto out;
74
+ header.backing_file_size = be32_to_cpu(header.backing_file_size);
75
+ header.mtime = be32_to_cpu(header.mtime);
76
+ header.size = be64_to_cpu(header.size);
77
+ header.crypt_method = be32_to_cpu(header.crypt_method);
78
+ header.l1_table_offset = be64_to_cpu(header.l1_table_offset);
79
80
if (header.magic != QCOW_MAGIC) {
81
error_setg(errp, "Image not in qcow format");
82
@@ -XXX,XX +XXX,XX @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
83
}
85
}
84
86
85
for(i = 0;i < s->l1_size; i++) {
87
- ret = bdrv_refresh_perms(bs, errp);
86
- be64_to_cpus(&s->l1_table[i]);
88
+ ret = bdrv_refresh_perms(bs, tran, errp);
87
+ s->l1_table[i] = be64_to_cpu(s->l1_table[i]);
89
out:
90
tran_finalize(tran, ret);
91
92
@@ -XXX,XX +XXX,XX @@ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
93
goto out;
88
}
94
}
89
95
90
/* alloc L2 cache (max. 64k * 16 * 8 = 8 MB) */
96
- ret = bdrv_refresh_perms(bs_new, errp);
97
+ ret = bdrv_refresh_perms(bs_new, tran, errp);
98
out:
99
tran_finalize(tran, ret);
100
101
@@ -XXX,XX +XXX,XX @@ int bdrv_activate(BlockDriverState *bs, Error **errp)
102
*/
103
if (bs->open_flags & BDRV_O_INACTIVE) {
104
bs->open_flags &= ~BDRV_O_INACTIVE;
105
- ret = bdrv_refresh_perms(bs, errp);
106
+ ret = bdrv_refresh_perms(bs, NULL, errp);
107
if (ret < 0) {
108
bs->open_flags |= BDRV_O_INACTIVE;
109
return ret;
110
@@ -XXX,XX +XXX,XX @@ static int bdrv_inactivate_recurse(BlockDriverState *bs)
111
* We only tried to loosen restrictions, so errors are not fatal, ignore
112
* them.
113
*/
114
- bdrv_refresh_perms(bs, NULL);
115
+ bdrv_refresh_perms(bs, NULL, NULL);
116
117
/* Recursively inactivate children */
118
QLIST_FOREACH(child, &bs->children, next) {
91
--
119
--
92
2.19.1
120
2.38.1
93
94
diff view generated by jsdifflib
1
Some block drivers have traditionally changed their node to read-only
1
From: Vladimir Sementsov-Ogievskiy <vladimir.sementsov-ogievskiy@openvz.org>
2
mode without asking the user. This behaviour has been marked deprecated
3
since 2.11, expecting users to provide an explicit read-only=on option.
4
2
5
Now that we have auto-read-only=on, enable these drivers to make use of
3
We are going to increase usage of collecting nodes in a list to then
6
the option.
4
update, and calling bdrv_topological_dfs() each time is not convenient,
5
and not correct as we are going to interleave graph modifying with
6
filling the node list.
7
7
8
This is the only use of bdrv_set_read_only(), so we can make it a bit
8
So, let's switch to a function that takes any list of nodes, adds all
9
more specific and turn it into a bdrv_apply_auto_read_only() that is
9
their subtrees and do topological sort. And finally, refresh
10
more convenient for drivers to use.
10
permissions.
11
11
12
While being here, make the function public, as we'll want to use it
13
from blockdev.c in near future.
14
15
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@openvz.org>
16
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
17
Message-Id: <20221107163558.618889-5-vsementsov@yandex-team.ru>
18
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Reviewed-by: Eric Blake <eblake@redhat.com>
14
---
20
---
15
include/block/block.h | 3 ++-
21
block.c | 51 ++++++++++++++++++++++++++++++++-------------------
16
block.c | 42 +++++++++++++++++++++++++++---------------
22
1 file changed, 32 insertions(+), 19 deletions(-)
17
block/bochs.c | 17 ++++++-----------
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
23
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
24
diff --git a/block.c b/block.c
39
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
40
--- a/block.c
26
--- a/block.c
41
+++ b/block.c
27
+++ b/block.c
42
@@ -XXX,XX +XXX,XX @@ int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only,
28
@@ -XXX,XX +XXX,XX @@ static int bdrv_node_refresh_perm(BlockDriverState *bs, BlockReopenQueue *q,
43
return 0;
29
return 0;
44
}
30
}
45
31
46
-/* TODO Remove (deprecated since 2.11)
32
-static int bdrv_list_refresh_perms(GSList *list, BlockReopenQueue *q,
47
- * Block drivers are not supposed to automatically change bs->read_only.
33
- Transaction *tran, Error **errp)
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
+/*
34
+/*
53
+ * Called by a driver that can only provide a read-only image.
35
+ * @list is a product of bdrv_topological_dfs() (may be called several times) -
54
+ *
36
+ * a topologically sorted subgraph.
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
+ */
37
+ */
62
+int bdrv_apply_auto_read_only(BlockDriverState *bs, const char *errmsg,
38
+static int bdrv_do_refresh_perms(GSList *list, BlockReopenQueue *q,
63
+ Error **errp)
39
+ Transaction *tran, Error **errp)
64
{
40
{
65
int ret = 0;
41
int ret;
66
42
BlockDriverState *bs;
67
- ret = bdrv_can_set_read_only(bs, read_only, false, errp);
43
@@ -XXX,XX +XXX,XX @@ static int bdrv_list_refresh_perms(GSList *list, BlockReopenQueue *q,
68
- if (ret < 0) {
44
return 0;
69
- return ret;
45
}
70
+ if (!(bs->open_flags & BDRV_O_RDWR)) {
46
71
+ return 0;
47
+/*
72
+ }
48
+ * @list is any list of nodes. List is completed by all subtrees and
73
+ if (!(bs->open_flags & BDRV_O_AUTO_RDONLY)) {
49
+ * topologically sorted. It's not a problem if some node occurs in the @list
74
+ goto fail;
50
+ * several times.
75
}
51
+ */
76
52
+static int bdrv_list_refresh_perms(GSList *list, BlockReopenQueue *q,
77
- bs->read_only = read_only;
53
+ Transaction *tran, Error **errp)
78
-
54
+{
79
- if (read_only) {
55
+ g_autoptr(GHashTable) found = g_hash_table_new(NULL, NULL);
80
- bs->open_flags &= ~BDRV_O_RDWR;
56
+ g_autoptr(GSList) refresh_list = NULL;
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
+
57
+
91
return 0;
58
+ for ( ; list; list = list->next) {
92
+
59
+ refresh_list = bdrv_topological_dfs(refresh_list, found, list->data);
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
+ }
60
+ }
112
+
61
+
113
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
62
+ return bdrv_do_refresh_perms(refresh_list, q, tran, errp);
114
false, errp);
63
+}
115
if (!bs->file) {
64
+
116
return -EINVAL;
65
void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm,
66
uint64_t *shared_perm)
67
{
68
@@ -XXX,XX +XXX,XX @@ static int bdrv_refresh_perms(BlockDriverState *bs, Transaction *tran,
69
tran = local_tran = tran_new();
117
}
70
}
118
71
119
- if (!bdrv_is_read_only(bs)) {
72
- ret = bdrv_list_refresh_perms(list, NULL, tran, errp);
120
- error_report("Opening bochs images without an explicit read-only=on "
73
+ ret = bdrv_do_refresh_perms(list, NULL, tran, errp);
121
- "option is deprecated. Future versions will refuse to "
74
122
- "open the image instead of automatically marking the "
75
if (local_tran) {
123
- "image read-only.");
76
tran_finalize(local_tran, ret);
124
- ret = bdrv_set_read_only(bs, true, errp); /* no write support yet */
77
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
125
- if (ret < 0) {
78
BlockReopenQueueEntry *bs_entry, *next;
126
- return ret;
79
AioContext *ctx;
127
- }
80
Transaction *tran = tran_new();
128
- }
81
- g_autoptr(GHashTable) found = NULL;
129
-
82
g_autoptr(GSList) refresh_list = NULL;
130
ret = bdrv_pread(bs->file, 0, &bochs, sizeof(bochs));
83
131
if (ret < 0) {
84
assert(qemu_get_current_aio_context() == qemu_get_aio_context());
132
return ret;
85
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
133
diff --git a/block/cloop.c b/block/cloop.c
86
bs_entry->prepared = true;
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
}
87
}
151
88
152
- if (!bdrv_is_read_only(bs)) {
89
- found = g_hash_table_new(NULL, NULL);
153
- error_report("Opening cloop images without an explicit read-only=on "
90
QTAILQ_FOREACH(bs_entry, bs_queue, entry) {
154
- "option is deprecated. Future versions will refuse to "
91
BDRVReopenState *state = &bs_entry->state;
155
- "open the image instead of automatically marking the "
92
156
- "image read-only.");
93
- refresh_list = bdrv_topological_dfs(refresh_list, found, state->bs);
157
- ret = bdrv_set_read_only(bs, true, errp);
94
+ refresh_list = g_slist_prepend(refresh_list, state->bs);
158
- if (ret < 0) {
95
if (state->old_backing_bs) {
159
- return ret;
96
- refresh_list = bdrv_topological_dfs(refresh_list, found,
160
- }
97
- state->old_backing_bs);
161
- }
98
+ refresh_list = g_slist_prepend(refresh_list, state->old_backing_bs);
162
-
99
}
163
/* read header */
100
if (state->old_file_bs) {
164
ret = bdrv_pread(bs->file, 128, &s->block_size, 4);
101
- refresh_list = bdrv_topological_dfs(refresh_list, found,
165
if (ret < 0) {
102
- state->old_file_bs);
166
diff --git a/block/dmg.c b/block/dmg.c
103
+ refresh_list = g_slist_prepend(refresh_list, state->old_file_bs);
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
}
104
}
223
}
105
}
224
106
225
diff --git a/block/vvfat.c b/block/vvfat.c
107
@@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_common(BlockDriverState *from,
226
index XXXXXXX..XXXXXXX 100644
108
Error **errp)
227
--- a/block/vvfat.c
109
{
228
+++ b/block/vvfat.c
110
Transaction *tran = tran_new();
229
@@ -XXX,XX +XXX,XX @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
111
- g_autoptr(GHashTable) found = NULL;
230
"Unable to set VVFAT to 'rw' when drive is read-only");
112
g_autoptr(GSList) refresh_list = NULL;
231
goto fail;
113
BlockDriverState *to_cow_parent = NULL;
232
}
114
int ret;
233
- } else if (!bdrv_is_read_only(bs)) {
115
@@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_common(BlockDriverState *from,
234
- error_report("Opening non-rw vvfat images without an explicit "
116
bdrv_remove_child(bdrv_filter_or_cow_child(to_cow_parent), tran);
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
}
117
}
118
119
- found = g_hash_table_new(NULL, NULL);
120
-
121
- refresh_list = bdrv_topological_dfs(refresh_list, found, to);
122
- refresh_list = bdrv_topological_dfs(refresh_list, found, from);
123
+ refresh_list = g_slist_prepend(refresh_list, to);
124
+ refresh_list = g_slist_prepend(refresh_list, from);
125
126
ret = bdrv_list_refresh_perms(refresh_list, NULL, tran, errp);
127
if (ret < 0) {
128
@@ -XXX,XX +XXX,XX @@ int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs,
129
{
130
int ret;
131
Transaction *tran = tran_new();
132
- g_autoptr(GHashTable) found = NULL;
133
g_autoptr(GSList) refresh_list = NULL;
134
BlockDriverState *old_bs = child->bs;
135
136
@@ -XXX,XX +XXX,XX @@ int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs,
137
138
bdrv_replace_child_tran(child, new_bs, tran);
139
140
- found = g_hash_table_new(NULL, NULL);
141
- refresh_list = bdrv_topological_dfs(refresh_list, found, old_bs);
142
- refresh_list = bdrv_topological_dfs(refresh_list, found, new_bs);
143
+ refresh_list = g_slist_prepend(refresh_list, old_bs);
144
+ refresh_list = g_slist_prepend(refresh_list, new_bs);
145
146
ret = bdrv_list_refresh_perms(refresh_list, NULL, tran, errp);
147
247
--
148
--
248
2.19.1
149
2.38.1
249
250
diff view generated by jsdifflib
1
If read-only=off, but auto-read-only=on is given, just degrade to
1
We want to change .bdrv_co_drained_begin() back to be a non-coroutine
2
read-only.
2
callback, so in preparation, avoid yielding in its implementation.
3
4
Because we increase bs->in_flight and bdrv_drained_begin() polls, the
5
behaviour is unchanged.
3
6
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
9
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
10
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
11
Message-Id: <20221118174110.55183-2-kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
13
---
7
block/curl.c | 8 ++++----
14
block/qed.c | 20 +++++++++++++++++---
8
1 file changed, 4 insertions(+), 4 deletions(-)
15
1 file changed, 17 insertions(+), 3 deletions(-)
9
16
10
diff --git a/block/curl.c b/block/curl.c
17
diff --git a/block/qed.c b/block/qed.c
11
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
12
--- a/block/curl.c
19
--- a/block/qed.c
13
+++ b/block/curl.c
20
+++ b/block/qed.c
14
@@ -XXX,XX +XXX,XX @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
21
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn qed_unplug_allocating_write_reqs(BDRVQEDState *s)
15
const char *protocol_delimiter;
22
qemu_co_mutex_unlock(&s->table_lock);
23
}
24
25
-static void coroutine_fn qed_need_check_timer_entry(void *opaque)
26
+static void coroutine_fn qed_need_check_timer(BDRVQEDState *s)
27
{
28
- BDRVQEDState *s = opaque;
16
int ret;
29
int ret;
17
30
18
-
31
trace_qed_need_check_timer_cb(s);
19
- if (flags & BDRV_O_RDWR) {
32
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn qed_need_check_timer_entry(void *opaque)
20
- error_setg(errp, "curl block device does not support writes");
33
(void) ret;
21
- return -EROFS;
34
}
22
+ ret = bdrv_apply_auto_read_only(bs, "curl driver does not support writes",
35
23
+ errp);
36
+static void coroutine_fn qed_need_check_timer_entry(void *opaque)
24
+ if (ret < 0) {
37
+{
25
+ return ret;
38
+ BDRVQEDState *s = opaque;
39
+
40
+ qed_need_check_timer(opaque);
41
+ bdrv_dec_in_flight(s->bs);
42
+}
43
+
44
static void qed_need_check_timer_cb(void *opaque)
45
{
46
+ BDRVQEDState *s = opaque;
47
Coroutine *co = qemu_coroutine_create(qed_need_check_timer_entry, opaque);
48
+
49
+ bdrv_inc_in_flight(s->bs);
50
qemu_coroutine_enter(co);
51
}
52
53
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_qed_co_drain_begin(BlockDriverState *bs)
54
* header is flushed.
55
*/
56
if (s->need_check_timer && timer_pending(s->need_check_timer)) {
57
+ Coroutine *co;
58
+
59
qed_cancel_need_check_timer(s);
60
- qed_need_check_timer_entry(s);
61
+ co = qemu_coroutine_create(qed_need_check_timer_entry, s);
62
+ bdrv_inc_in_flight(bs);
63
+ aio_co_enter(bdrv_get_aio_context(bs), co);
26
}
64
}
27
65
}
28
if (!libcurl_initialized) {
66
29
--
67
--
30
2.19.1
68
2.38.1
31
32
diff view generated by jsdifflib
New patch
1
We want to change .bdrv_co_drained_begin/end() back to be non-coroutine
2
callbacks, so in preparation, avoid yielding in their implementation.
1
3
4
This does almost the same as the existing logic in bdrv_drain_invoke(),
5
by creating and entering coroutines internally. However, since the test
6
case is by far the heaviest user of coroutine code in drain callbacks,
7
it is preferable to have the complexity in the test case rather than the
8
drain core, which is already complicated enough without this.
9
10
The behaviour for bdrv_drain_begin() is unchanged because we increase
11
bs->in_flight and this is still polled. However, bdrv_drain_end()
12
doesn't wait for the spawned coroutine to complete any more. This is
13
fine, we don't rely on bdrv_drain_end() restarting all operations
14
immediately before the next aio_poll().
15
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
18
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
19
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
20
Message-Id: <20221118174110.55183-3-kwolf@redhat.com>
21
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
22
---
23
tests/unit/test-bdrv-drain.c | 64 ++++++++++++++++++++++++++----------
24
1 file changed, 46 insertions(+), 18 deletions(-)
25
26
diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c
27
index XXXXXXX..XXXXXXX 100644
28
--- a/tests/unit/test-bdrv-drain.c
29
+++ b/tests/unit/test-bdrv-drain.c
30
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVTestState {
31
bool sleep_in_drain_begin;
32
} BDRVTestState;
33
34
+static void coroutine_fn sleep_in_drain_begin(void *opaque)
35
+{
36
+ BlockDriverState *bs = opaque;
37
+
38
+ qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 100000);
39
+ bdrv_dec_in_flight(bs);
40
+}
41
+
42
static void coroutine_fn bdrv_test_co_drain_begin(BlockDriverState *bs)
43
{
44
BDRVTestState *s = bs->opaque;
45
s->drain_count++;
46
if (s->sleep_in_drain_begin) {
47
- qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 100000);
48
+ Coroutine *co = qemu_coroutine_create(sleep_in_drain_begin, bs);
49
+ bdrv_inc_in_flight(bs);
50
+ aio_co_enter(bdrv_get_aio_context(bs), co);
51
}
52
}
53
54
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_replace_test_co_preadv(BlockDriverState *bs,
55
return 0;
56
}
57
58
+static void coroutine_fn bdrv_replace_test_drain_co(void *opaque)
59
+{
60
+ BlockDriverState *bs = opaque;
61
+ BDRVReplaceTestState *s = bs->opaque;
62
+
63
+ /* Keep waking io_co up until it is done */
64
+ while (s->io_co) {
65
+ aio_co_wake(s->io_co);
66
+ s->io_co = NULL;
67
+ qemu_coroutine_yield();
68
+ }
69
+ s->drain_co = NULL;
70
+ bdrv_dec_in_flight(bs);
71
+}
72
+
73
/**
74
* If .drain_count is 0, wake up .io_co if there is one; and set
75
* .was_drained.
76
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_replace_test_co_drain_begin(BlockDriverState *bs)
77
BDRVReplaceTestState *s = bs->opaque;
78
79
if (!s->drain_count) {
80
- /* Keep waking io_co up until it is done */
81
- s->drain_co = qemu_coroutine_self();
82
- while (s->io_co) {
83
- aio_co_wake(s->io_co);
84
- s->io_co = NULL;
85
- qemu_coroutine_yield();
86
- }
87
- s->drain_co = NULL;
88
-
89
+ s->drain_co = qemu_coroutine_create(bdrv_replace_test_drain_co, bs);
90
+ bdrv_inc_in_flight(bs);
91
+ aio_co_enter(bdrv_get_aio_context(bs), s->drain_co);
92
s->was_drained = true;
93
}
94
s->drain_count++;
95
}
96
97
+static void coroutine_fn bdrv_replace_test_read_entry(void *opaque)
98
+{
99
+ BlockDriverState *bs = opaque;
100
+ char data;
101
+ QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, &data, 1);
102
+ int ret;
103
+
104
+ /* Queue a read request post-drain */
105
+ ret = bdrv_replace_test_co_preadv(bs, 0, 1, &qiov, 0);
106
+ g_assert(ret >= 0);
107
+ bdrv_dec_in_flight(bs);
108
+}
109
+
110
/**
111
* Reduce .drain_count, set .was_undrained once it reaches 0.
112
* If .drain_count reaches 0 and the node has a backing file, issue a
113
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_replace_test_co_drain_end(BlockDriverState *bs)
114
115
g_assert(s->drain_count > 0);
116
if (!--s->drain_count) {
117
- int ret;
118
-
119
s->was_undrained = true;
120
121
if (bs->backing) {
122
- char data;
123
- QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, &data, 1);
124
-
125
- /* Queue a read request post-drain */
126
- ret = bdrv_replace_test_co_preadv(bs, 0, 1, &qiov, 0);
127
- g_assert(ret >= 0);
128
+ Coroutine *co = qemu_coroutine_create(bdrv_replace_test_read_entry,
129
+ bs);
130
+ bdrv_inc_in_flight(bs);
131
+ aio_co_enter(bdrv_get_aio_context(bs), co);
132
}
133
}
134
}
135
--
136
2.38.1
diff view generated by jsdifflib
New patch
1
1
Polling during bdrv_drained_end() can be problematic (and in the future,
2
we may get cases for bdrv_drained_begin() where polling is forbidden,
3
and we don't care about already in-flight requests, but just want to
4
prevent new requests from arriving).
5
6
The .bdrv_drained_begin/end callbacks running in a coroutine is the only
7
reason why we have to do this polling, so make them non-coroutine
8
callbacks again. None of the callers actually yield any more.
9
10
This means that bdrv_drained_end() effectively doesn't poll any more,
11
even if AIO_WAIT_WHILE() loops are still there (their condition is false
12
from the beginning). This is generally not a problem, but in
13
test-bdrv-drain, some additional explicit aio_poll() calls need to be
14
added because the test case wants to verify the final state after BHs
15
have executed.
16
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
19
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
20
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
21
Message-Id: <20221118174110.55183-4-kwolf@redhat.com>
22
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
23
---
24
include/block/block_int-common.h | 10 ++++---
25
block.c | 4 +--
26
block/io.c | 49 +++++---------------------------
27
block/qed.c | 6 ++--
28
block/throttle.c | 8 +++---
29
tests/unit/test-bdrv-drain.c | 18 ++++++------
30
6 files changed, 32 insertions(+), 63 deletions(-)
31
32
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
33
index XXXXXXX..XXXXXXX 100644
34
--- a/include/block/block_int-common.h
35
+++ b/include/block/block_int-common.h
36
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
37
void (*bdrv_io_unplug)(BlockDriverState *bs);
38
39
/**
40
- * bdrv_co_drain_begin is called if implemented in the beginning of a
41
+ * bdrv_drain_begin is called if implemented in the beginning of a
42
* drain operation to drain and stop any internal sources of requests in
43
* the driver.
44
- * bdrv_co_drain_end is called if implemented at the end of the drain.
45
+ * bdrv_drain_end is called if implemented at the end of the drain.
46
*
47
* They should be used by the driver to e.g. manage scheduled I/O
48
* requests, or toggle an internal state. After the end of the drain new
49
* requests will continue normally.
50
+ *
51
+ * Implementations of both functions must not call aio_poll().
52
*/
53
- void coroutine_fn (*bdrv_co_drain_begin)(BlockDriverState *bs);
54
- void coroutine_fn (*bdrv_co_drain_end)(BlockDriverState *bs);
55
+ void (*bdrv_drain_begin)(BlockDriverState *bs);
56
+ void (*bdrv_drain_end)(BlockDriverState *bs);
57
58
bool (*bdrv_supports_persistent_dirty_bitmap)(BlockDriverState *bs);
59
bool coroutine_fn (*bdrv_co_can_store_new_dirty_bitmap)(
60
diff --git a/block.c b/block.c
61
index XXXXXXX..XXXXXXX 100644
62
--- a/block.c
63
+++ b/block.c
64
@@ -XXX,XX +XXX,XX @@ static int bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv,
65
assert(is_power_of_2(bs->bl.request_alignment));
66
67
for (i = 0; i < bs->quiesce_counter; i++) {
68
- if (drv->bdrv_co_drain_begin) {
69
- drv->bdrv_co_drain_begin(bs);
70
+ if (drv->bdrv_drain_begin) {
71
+ drv->bdrv_drain_begin(bs);
72
}
73
}
74
75
diff --git a/block/io.c b/block/io.c
76
index XXXXXXX..XXXXXXX 100644
77
--- a/block/io.c
78
+++ b/block/io.c
79
@@ -XXX,XX +XXX,XX @@ typedef struct {
80
int *drained_end_counter;
81
} BdrvCoDrainData;
82
83
-static void coroutine_fn bdrv_drain_invoke_entry(void *opaque)
84
-{
85
- BdrvCoDrainData *data = opaque;
86
- BlockDriverState *bs = data->bs;
87
-
88
- if (data->begin) {
89
- bs->drv->bdrv_co_drain_begin(bs);
90
- } else {
91
- bs->drv->bdrv_co_drain_end(bs);
92
- }
93
-
94
- /* Set data->done and decrement drained_end_counter before bdrv_wakeup() */
95
- qatomic_mb_set(&data->done, true);
96
- if (!data->begin) {
97
- qatomic_dec(data->drained_end_counter);
98
- }
99
- bdrv_dec_in_flight(bs);
100
-
101
- g_free(data);
102
-}
103
-
104
-/* Recursively call BlockDriver.bdrv_co_drain_begin/end callbacks */
105
+/* Recursively call BlockDriver.bdrv_drain_begin/end callbacks */
106
static void bdrv_drain_invoke(BlockDriverState *bs, bool begin,
107
int *drained_end_counter)
108
{
109
- BdrvCoDrainData *data;
110
-
111
- if (!bs->drv || (begin && !bs->drv->bdrv_co_drain_begin) ||
112
- (!begin && !bs->drv->bdrv_co_drain_end)) {
113
+ if (!bs->drv || (begin && !bs->drv->bdrv_drain_begin) ||
114
+ (!begin && !bs->drv->bdrv_drain_end)) {
115
return;
116
}
117
118
- data = g_new(BdrvCoDrainData, 1);
119
- *data = (BdrvCoDrainData) {
120
- .bs = bs,
121
- .done = false,
122
- .begin = begin,
123
- .drained_end_counter = drained_end_counter,
124
- };
125
-
126
- if (!begin) {
127
- qatomic_inc(drained_end_counter);
128
+ if (begin) {
129
+ bs->drv->bdrv_drain_begin(bs);
130
+ } else {
131
+ bs->drv->bdrv_drain_end(bs);
132
}
133
-
134
- /* Make sure the driver callback completes during the polling phase for
135
- * drain_begin. */
136
- bdrv_inc_in_flight(bs);
137
- data->co = qemu_coroutine_create(bdrv_drain_invoke_entry, data);
138
- aio_co_schedule(bdrv_get_aio_context(bs), data->co);
139
}
140
141
/* Returns true if BDRV_POLL_WHILE() should go into a blocking aio_poll() */
142
diff --git a/block/qed.c b/block/qed.c
143
index XXXXXXX..XXXXXXX 100644
144
--- a/block/qed.c
145
+++ b/block/qed.c
146
@@ -XXX,XX +XXX,XX @@ static bool coroutine_fn qed_plug_allocating_write_reqs(BDRVQEDState *s)
147
assert(!s->allocating_write_reqs_plugged);
148
if (s->allocating_acb != NULL) {
149
/* Another allocating write came concurrently. This cannot happen
150
- * from bdrv_qed_co_drain_begin, but it can happen when the timer runs.
151
+ * from bdrv_qed_drain_begin, but it can happen when the timer runs.
152
*/
153
qemu_co_mutex_unlock(&s->table_lock);
154
return false;
155
@@ -XXX,XX +XXX,XX @@ static void bdrv_qed_attach_aio_context(BlockDriverState *bs,
156
}
157
}
158
159
-static void coroutine_fn bdrv_qed_co_drain_begin(BlockDriverState *bs)
160
+static void bdrv_qed_drain_begin(BlockDriverState *bs)
161
{
162
BDRVQEDState *s = bs->opaque;
163
164
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_qed = {
165
.bdrv_co_check = bdrv_qed_co_check,
166
.bdrv_detach_aio_context = bdrv_qed_detach_aio_context,
167
.bdrv_attach_aio_context = bdrv_qed_attach_aio_context,
168
- .bdrv_co_drain_begin = bdrv_qed_co_drain_begin,
169
+ .bdrv_drain_begin = bdrv_qed_drain_begin,
170
};
171
172
static void bdrv_qed_init(void)
173
diff --git a/block/throttle.c b/block/throttle.c
174
index XXXXXXX..XXXXXXX 100644
175
--- a/block/throttle.c
176
+++ b/block/throttle.c
177
@@ -XXX,XX +XXX,XX @@ static void throttle_reopen_abort(BDRVReopenState *reopen_state)
178
reopen_state->opaque = NULL;
179
}
180
181
-static void coroutine_fn throttle_co_drain_begin(BlockDriverState *bs)
182
+static void throttle_drain_begin(BlockDriverState *bs)
183
{
184
ThrottleGroupMember *tgm = bs->opaque;
185
if (qatomic_fetch_inc(&tgm->io_limits_disabled) == 0) {
186
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn throttle_co_drain_begin(BlockDriverState *bs)
187
}
188
}
189
190
-static void coroutine_fn throttle_co_drain_end(BlockDriverState *bs)
191
+static void throttle_drain_end(BlockDriverState *bs)
192
{
193
ThrottleGroupMember *tgm = bs->opaque;
194
assert(tgm->io_limits_disabled);
195
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_throttle = {
196
.bdrv_reopen_commit = throttle_reopen_commit,
197
.bdrv_reopen_abort = throttle_reopen_abort,
198
199
- .bdrv_co_drain_begin = throttle_co_drain_begin,
200
- .bdrv_co_drain_end = throttle_co_drain_end,
201
+ .bdrv_drain_begin = throttle_drain_begin,
202
+ .bdrv_drain_end = throttle_drain_end,
203
204
.is_filter = true,
205
.strong_runtime_opts = throttle_strong_runtime_opts,
206
diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c
207
index XXXXXXX..XXXXXXX 100644
208
--- a/tests/unit/test-bdrv-drain.c
209
+++ b/tests/unit/test-bdrv-drain.c
210
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn sleep_in_drain_begin(void *opaque)
211
bdrv_dec_in_flight(bs);
212
}
213
214
-static void coroutine_fn bdrv_test_co_drain_begin(BlockDriverState *bs)
215
+static void bdrv_test_drain_begin(BlockDriverState *bs)
216
{
217
BDRVTestState *s = bs->opaque;
218
s->drain_count++;
219
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_test_co_drain_begin(BlockDriverState *bs)
220
}
221
}
222
223
-static void coroutine_fn bdrv_test_co_drain_end(BlockDriverState *bs)
224
+static void bdrv_test_drain_end(BlockDriverState *bs)
225
{
226
BDRVTestState *s = bs->opaque;
227
s->drain_count--;
228
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_test = {
229
.bdrv_close = bdrv_test_close,
230
.bdrv_co_preadv = bdrv_test_co_preadv,
231
232
- .bdrv_co_drain_begin = bdrv_test_co_drain_begin,
233
- .bdrv_co_drain_end = bdrv_test_co_drain_end,
234
+ .bdrv_drain_begin = bdrv_test_drain_begin,
235
+ .bdrv_drain_end = bdrv_test_drain_end,
236
237
.bdrv_child_perm = bdrv_default_perms,
238
239
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_commit_by_drained_end(void)
240
bdrv_drained_begin(bs_child);
241
g_assert(!job_has_completed);
242
bdrv_drained_end(bs_child);
243
+ aio_poll(qemu_get_aio_context(), false);
244
g_assert(job_has_completed);
245
246
bdrv_unref(bs_parents[0]);
247
@@ -XXX,XX +XXX,XX @@ static void test_drop_intermediate_poll(void)
248
249
g_assert(!job_has_completed);
250
ret = bdrv_drop_intermediate(chain[1], chain[0], NULL);
251
+ aio_poll(qemu_get_aio_context(), false);
252
g_assert(ret == 0);
253
g_assert(job_has_completed);
254
255
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_replace_test_drain_co(void *opaque)
256
* .was_drained.
257
* Increment .drain_count.
258
*/
259
-static void coroutine_fn bdrv_replace_test_co_drain_begin(BlockDriverState *bs)
260
+static void bdrv_replace_test_drain_begin(BlockDriverState *bs)
261
{
262
BDRVReplaceTestState *s = bs->opaque;
263
264
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_replace_test_read_entry(void *opaque)
265
* If .drain_count reaches 0 and the node has a backing file, issue a
266
* read request.
267
*/
268
-static void coroutine_fn bdrv_replace_test_co_drain_end(BlockDriverState *bs)
269
+static void bdrv_replace_test_drain_end(BlockDriverState *bs)
270
{
271
BDRVReplaceTestState *s = bs->opaque;
272
273
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_replace_test = {
274
.bdrv_close = bdrv_replace_test_close,
275
.bdrv_co_preadv = bdrv_replace_test_co_preadv,
276
277
- .bdrv_co_drain_begin = bdrv_replace_test_co_drain_begin,
278
- .bdrv_co_drain_end = bdrv_replace_test_co_drain_end,
279
+ .bdrv_drain_begin = bdrv_replace_test_drain_begin,
280
+ .bdrv_drain_end = bdrv_replace_test_drain_end,
281
282
.bdrv_child_perm = bdrv_default_perms,
283
};
284
--
285
2.38.1
diff view generated by jsdifflib
New patch
1
drained_end_counter is unused now, nobody changes its value any more. It
2
can be removed.
1
3
4
In cases where we had two almost identical functions that only differed
5
in whether the caller passes drained_end_counter, or whether they would
6
poll for a local drained_end_counter to reach 0, these become a single
7
function.
8
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
11
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
12
Message-Id: <20221118174110.55183-5-kwolf@redhat.com>
13
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
16
include/block/block-io.h | 24 --------
17
include/block/block_int-common.h | 6 +-
18
block.c | 5 +-
19
block/block-backend.c | 4 +-
20
block/io.c | 98 ++++++++------------------------
21
blockjob.c | 2 +-
22
6 files changed, 30 insertions(+), 109 deletions(-)
23
24
diff --git a/include/block/block-io.h b/include/block/block-io.h
25
index XXXXXXX..XXXXXXX 100644
26
--- a/include/block/block-io.h
27
+++ b/include/block/block-io.h
28
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_copy_range(BdrvChild *src, int64_t src_offset,
29
int64_t bytes, BdrvRequestFlags read_flags,
30
BdrvRequestFlags write_flags);
31
32
-/**
33
- * bdrv_drained_end_no_poll:
34
- *
35
- * Same as bdrv_drained_end(), but do not poll for the subgraph to
36
- * actually become unquiesced. Therefore, no graph changes will occur
37
- * with this function.
38
- *
39
- * *drained_end_counter is incremented for every background operation
40
- * that is scheduled, and will be decremented for every operation once
41
- * it settles. The caller must poll until it reaches 0. The counter
42
- * should be accessed using atomic operations only.
43
- */
44
-void bdrv_drained_end_no_poll(BlockDriverState *bs, int *drained_end_counter);
45
-
46
-
47
/*
48
* "I/O or GS" API functions. These functions can run without
49
* the BQL, but only in one specific iothread/main loop.
50
@@ -XXX,XX +XXX,XX @@ void bdrv_parent_drained_begin_single(BdrvChild *c, bool poll);
51
* bdrv_parent_drained_end_single:
52
*
53
* End a quiesced section for the parent of @c.
54
- *
55
- * This polls @bs's AioContext until all scheduled sub-drained_ends
56
- * have settled, which may result in graph changes.
57
*/
58
void bdrv_parent_drained_end_single(BdrvChild *c);
59
60
@@ -XXX,XX +XXX,XX @@ void bdrv_subtree_drained_begin(BlockDriverState *bs);
61
* bdrv_drained_end:
62
*
63
* End a quiescent section started by bdrv_drained_begin().
64
- *
65
- * This polls @bs's AioContext until all scheduled sub-drained_ends
66
- * have settled. On one hand, that may result in graph changes. On
67
- * the other, this requires that the caller either runs in the main
68
- * loop; or that all involved nodes (@bs and all of its parents) are
69
- * in the caller's AioContext.
70
*/
71
void bdrv_drained_end(BlockDriverState *bs);
72
73
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
74
index XXXXXXX..XXXXXXX 100644
75
--- a/include/block/block_int-common.h
76
+++ b/include/block/block_int-common.h
77
@@ -XXX,XX +XXX,XX @@ struct BdrvChildClass {
78
* These functions must not change the graph (and therefore also must not
79
* call aio_poll(), which could change the graph indirectly).
80
*
81
- * If drained_end() schedules background operations, it must atomically
82
- * increment *drained_end_counter for each such operation and atomically
83
- * decrement it once the operation has settled.
84
- *
85
* Note that this can be nested. If drained_begin() was called twice, new
86
* I/O is allowed only after drained_end() was called twice, too.
87
*/
88
void (*drained_begin)(BdrvChild *child);
89
- void (*drained_end)(BdrvChild *child, int *drained_end_counter);
90
+ void (*drained_end)(BdrvChild *child);
91
92
/*
93
* Returns whether the parent has pending requests for the child. This
94
diff --git a/block.c b/block.c
95
index XXXXXXX..XXXXXXX 100644
96
--- a/block.c
97
+++ b/block.c
98
@@ -XXX,XX +XXX,XX @@ static bool bdrv_child_cb_drained_poll(BdrvChild *child)
99
return bdrv_drain_poll(bs, false, NULL, false);
100
}
101
102
-static void bdrv_child_cb_drained_end(BdrvChild *child,
103
- int *drained_end_counter)
104
+static void bdrv_child_cb_drained_end(BdrvChild *child)
105
{
106
BlockDriverState *bs = child->opaque;
107
- bdrv_drained_end_no_poll(bs, drained_end_counter);
108
+ bdrv_drained_end(bs);
109
}
110
111
static int bdrv_child_cb_inactivate(BdrvChild *child)
112
diff --git a/block/block-backend.c b/block/block-backend.c
113
index XXXXXXX..XXXXXXX 100644
114
--- a/block/block-backend.c
115
+++ b/block/block-backend.c
116
@@ -XXX,XX +XXX,XX @@ static void blk_root_inherit_options(BdrvChildRole role, bool parent_is_format,
117
}
118
static void blk_root_drained_begin(BdrvChild *child);
119
static bool blk_root_drained_poll(BdrvChild *child);
120
-static void blk_root_drained_end(BdrvChild *child, int *drained_end_counter);
121
+static void blk_root_drained_end(BdrvChild *child);
122
123
static void blk_root_change_media(BdrvChild *child, bool load);
124
static void blk_root_resize(BdrvChild *child);
125
@@ -XXX,XX +XXX,XX @@ static bool blk_root_drained_poll(BdrvChild *child)
126
return busy || !!blk->in_flight;
127
}
128
129
-static void blk_root_drained_end(BdrvChild *child, int *drained_end_counter)
130
+static void blk_root_drained_end(BdrvChild *child)
131
{
132
BlockBackend *blk = child->opaque;
133
assert(blk->quiesce_counter);
134
diff --git a/block/io.c b/block/io.c
135
index XXXXXXX..XXXXXXX 100644
136
--- a/block/io.c
137
+++ b/block/io.c
138
@@ -XXX,XX +XXX,XX @@ static void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore,
139
}
140
}
141
142
-static void bdrv_parent_drained_end_single_no_poll(BdrvChild *c,
143
- int *drained_end_counter)
144
+void bdrv_parent_drained_end_single(BdrvChild *c)
145
{
146
+ IO_OR_GS_CODE();
147
+
148
assert(c->parent_quiesce_counter > 0);
149
c->parent_quiesce_counter--;
150
if (c->klass->drained_end) {
151
- c->klass->drained_end(c, drained_end_counter);
152
+ c->klass->drained_end(c);
153
}
154
}
155
156
-void bdrv_parent_drained_end_single(BdrvChild *c)
157
-{
158
- int drained_end_counter = 0;
159
- AioContext *ctx = bdrv_child_get_parent_aio_context(c);
160
- IO_OR_GS_CODE();
161
- bdrv_parent_drained_end_single_no_poll(c, &drained_end_counter);
162
- AIO_WAIT_WHILE(ctx, qatomic_read(&drained_end_counter) > 0);
163
-}
164
-
165
static void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore,
166
- bool ignore_bds_parents,
167
- int *drained_end_counter)
168
+ bool ignore_bds_parents)
169
{
170
BdrvChild *c;
171
172
@@ -XXX,XX +XXX,XX @@ static void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore,
173
if (c == ignore || (ignore_bds_parents && c->klass->parent_is_bds)) {
174
continue;
175
}
176
- bdrv_parent_drained_end_single_no_poll(c, drained_end_counter);
177
+ bdrv_parent_drained_end_single(c);
178
}
179
}
180
181
@@ -XXX,XX +XXX,XX @@ typedef struct {
182
bool poll;
183
BdrvChild *parent;
184
bool ignore_bds_parents;
185
- int *drained_end_counter;
186
} BdrvCoDrainData;
187
188
/* Recursively call BlockDriver.bdrv_drain_begin/end callbacks */
189
-static void bdrv_drain_invoke(BlockDriverState *bs, bool begin,
190
- int *drained_end_counter)
191
+static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
192
{
193
if (!bs->drv || (begin && !bs->drv->bdrv_drain_begin) ||
194
(!begin && !bs->drv->bdrv_drain_end)) {
195
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
196
BdrvChild *parent, bool ignore_bds_parents,
197
bool poll);
198
static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
199
- BdrvChild *parent, bool ignore_bds_parents,
200
- int *drained_end_counter);
201
+ BdrvChild *parent, bool ignore_bds_parents);
202
203
static void bdrv_co_drain_bh_cb(void *opaque)
204
{
205
@@ -XXX,XX +XXX,XX @@ static void bdrv_co_drain_bh_cb(void *opaque)
206
aio_context_acquire(ctx);
207
bdrv_dec_in_flight(bs);
208
if (data->begin) {
209
- assert(!data->drained_end_counter);
210
bdrv_do_drained_begin(bs, data->recursive, data->parent,
211
data->ignore_bds_parents, data->poll);
212
} else {
213
assert(!data->poll);
214
bdrv_do_drained_end(bs, data->recursive, data->parent,
215
- data->ignore_bds_parents,
216
- data->drained_end_counter);
217
+ data->ignore_bds_parents);
218
}
219
aio_context_release(ctx);
220
} else {
221
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
222
bool begin, bool recursive,
223
BdrvChild *parent,
224
bool ignore_bds_parents,
225
- bool poll,
226
- int *drained_end_counter)
227
+ bool poll)
228
{
229
BdrvCoDrainData data;
230
Coroutine *self = qemu_coroutine_self();
231
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
232
.parent = parent,
233
.ignore_bds_parents = ignore_bds_parents,
234
.poll = poll,
235
- .drained_end_counter = drained_end_counter,
236
};
237
238
if (bs) {
239
@@ -XXX,XX +XXX,XX @@ void bdrv_do_drained_begin_quiesce(BlockDriverState *bs,
240
}
241
242
bdrv_parent_drained_begin(bs, parent, ignore_bds_parents);
243
- bdrv_drain_invoke(bs, true, NULL);
244
+ bdrv_drain_invoke(bs, true);
245
}
246
247
static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
248
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
249
250
if (qemu_in_coroutine()) {
251
bdrv_co_yield_to_drain(bs, true, recursive, parent, ignore_bds_parents,
252
- poll, NULL);
253
+ poll);
254
return;
255
}
256
257
@@ -XXX,XX +XXX,XX @@ void bdrv_subtree_drained_begin(BlockDriverState *bs)
258
259
/**
260
* This function does not poll, nor must any of its recursively called
261
- * functions. The *drained_end_counter pointee will be incremented
262
- * once for every background operation scheduled, and decremented once
263
- * the operation settles. Therefore, the pointer must remain valid
264
- * until the pointee reaches 0. That implies that whoever sets up the
265
- * pointee has to poll until it is 0.
266
- *
267
- * We use atomic operations to access *drained_end_counter, because
268
- * (1) when called from bdrv_set_aio_context_ignore(), the subgraph of
269
- * @bs may contain nodes in different AioContexts,
270
- * (2) bdrv_drain_all_end() uses the same counter for all nodes,
271
- * regardless of which AioContext they are in.
272
+ * functions.
273
*/
274
static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
275
- BdrvChild *parent, bool ignore_bds_parents,
276
- int *drained_end_counter)
277
+ BdrvChild *parent, bool ignore_bds_parents)
278
{
279
BdrvChild *child;
280
int old_quiesce_counter;
281
282
- assert(drained_end_counter != NULL);
283
-
284
if (qemu_in_coroutine()) {
285
bdrv_co_yield_to_drain(bs, false, recursive, parent, ignore_bds_parents,
286
- false, drained_end_counter);
287
+ false);
288
return;
289
}
290
assert(bs->quiesce_counter > 0);
291
292
/* Re-enable things in child-to-parent order */
293
- bdrv_drain_invoke(bs, false, drained_end_counter);
294
- bdrv_parent_drained_end(bs, parent, ignore_bds_parents,
295
- drained_end_counter);
296
+ bdrv_drain_invoke(bs, false);
297
+ bdrv_parent_drained_end(bs, parent, ignore_bds_parents);
298
299
old_quiesce_counter = qatomic_fetch_dec(&bs->quiesce_counter);
300
if (old_quiesce_counter == 1) {
301
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
302
assert(!ignore_bds_parents);
303
bs->recursive_quiesce_counter--;
304
QLIST_FOREACH(child, &bs->children, next) {
305
- bdrv_do_drained_end(child->bs, true, child, ignore_bds_parents,
306
- drained_end_counter);
307
+ bdrv_do_drained_end(child->bs, true, child, ignore_bds_parents);
308
}
309
}
310
}
311
312
void bdrv_drained_end(BlockDriverState *bs)
313
{
314
- int drained_end_counter = 0;
315
IO_OR_GS_CODE();
316
- bdrv_do_drained_end(bs, false, NULL, false, &drained_end_counter);
317
- BDRV_POLL_WHILE(bs, qatomic_read(&drained_end_counter) > 0);
318
-}
319
-
320
-void bdrv_drained_end_no_poll(BlockDriverState *bs, int *drained_end_counter)
321
-{
322
- IO_CODE();
323
- bdrv_do_drained_end(bs, false, NULL, false, drained_end_counter);
324
+ bdrv_do_drained_end(bs, false, NULL, false);
325
}
326
327
void bdrv_subtree_drained_end(BlockDriverState *bs)
328
{
329
- int drained_end_counter = 0;
330
IO_OR_GS_CODE();
331
- bdrv_do_drained_end(bs, true, NULL, false, &drained_end_counter);
332
- BDRV_POLL_WHILE(bs, qatomic_read(&drained_end_counter) > 0);
333
+ bdrv_do_drained_end(bs, true, NULL, false);
334
}
335
336
void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent)
337
@@ -XXX,XX +XXX,XX @@ void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent)
338
339
void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent)
340
{
341
- int drained_end_counter = 0;
342
int i;
343
IO_OR_GS_CODE();
344
345
for (i = 0; i < old_parent->recursive_quiesce_counter; i++) {
346
- bdrv_do_drained_end(child->bs, true, child, false,
347
- &drained_end_counter);
348
+ bdrv_do_drained_end(child->bs, true, child, false);
349
}
350
-
351
- BDRV_POLL_WHILE(child->bs, qatomic_read(&drained_end_counter) > 0);
352
}
353
354
void bdrv_drain(BlockDriverState *bs)
355
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
356
GLOBAL_STATE_CODE();
357
358
if (qemu_in_coroutine()) {
359
- bdrv_co_yield_to_drain(NULL, true, false, NULL, true, true, NULL);
360
+ bdrv_co_yield_to_drain(NULL, true, false, NULL, true, true);
361
return;
362
}
363
364
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
365
366
void bdrv_drain_all_end_quiesce(BlockDriverState *bs)
367
{
368
- int drained_end_counter = 0;
369
GLOBAL_STATE_CODE();
370
371
g_assert(bs->quiesce_counter > 0);
372
g_assert(!bs->refcnt);
373
374
while (bs->quiesce_counter) {
375
- bdrv_do_drained_end(bs, false, NULL, true, &drained_end_counter);
376
+ bdrv_do_drained_end(bs, false, NULL, true);
377
}
378
- BDRV_POLL_WHILE(bs, qatomic_read(&drained_end_counter) > 0);
379
}
380
381
void bdrv_drain_all_end(void)
382
{
383
BlockDriverState *bs = NULL;
384
- int drained_end_counter = 0;
385
GLOBAL_STATE_CODE();
386
387
/*
388
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
389
AioContext *aio_context = bdrv_get_aio_context(bs);
390
391
aio_context_acquire(aio_context);
392
- bdrv_do_drained_end(bs, false, NULL, true, &drained_end_counter);
393
+ bdrv_do_drained_end(bs, false, NULL, true);
394
aio_context_release(aio_context);
395
}
396
397
assert(qemu_get_current_aio_context() == qemu_get_aio_context());
398
- AIO_WAIT_WHILE(NULL, qatomic_read(&drained_end_counter) > 0);
399
-
400
assert(bdrv_drain_all_count > 0);
401
bdrv_drain_all_count--;
402
}
403
diff --git a/blockjob.c b/blockjob.c
404
index XXXXXXX..XXXXXXX 100644
405
--- a/blockjob.c
406
+++ b/blockjob.c
407
@@ -XXX,XX +XXX,XX @@ static bool child_job_drained_poll(BdrvChild *c)
408
}
409
}
410
411
-static void child_job_drained_end(BdrvChild *c, int *drained_end_counter)
412
+static void child_job_drained_end(BdrvChild *c)
413
{
414
BlockJob *job = c->opaque;
415
job_resume(&job->job);
416
--
417
2.38.1
diff view generated by jsdifflib
1
If read-only=off, but auto-read-only=on is given, open the volume
1
bdrv_drain_invoke() has now two entirely separate cases that share no
2
read-write if we have the permissions, but instead of erroring out for
2
code any more and are selected depending on a bool parameter. Each case
3
read-only volumes, just degrade to read-only.
3
has only one caller. Just inline the function.
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
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
9
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
10
Message-Id: <20221118174110.55183-6-kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
12
---
8
block/iscsi.c | 8 +++++---
13
block/io.c | 23 ++++++-----------------
9
1 file changed, 5 insertions(+), 3 deletions(-)
14
1 file changed, 6 insertions(+), 17 deletions(-)
10
15
11
diff --git a/block/iscsi.c b/block/iscsi.c
16
diff --git a/block/io.c b/block/io.c
12
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
13
--- a/block/iscsi.c
18
--- a/block/io.c
14
+++ b/block/iscsi.c
19
+++ b/block/io.c
15
@@ -XXX,XX +XXX,XX @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
20
@@ -XXX,XX +XXX,XX @@ typedef struct {
16
/* Check the write protect flag of the LUN if we want to write */
21
bool ignore_bds_parents;
17
if (iscsilun->type == TYPE_DISK && (flags & BDRV_O_RDWR) &&
22
} BdrvCoDrainData;
18
iscsilun->write_protected) {
23
19
- error_setg(errp, "Cannot open a write protected LUN as read-write");
24
-/* Recursively call BlockDriver.bdrv_drain_begin/end callbacks */
20
- ret = -EACCES;
25
-static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
21
- goto out;
26
-{
22
+ ret = bdrv_apply_auto_read_only(bs, "LUN is write protected", errp);
27
- if (!bs->drv || (begin && !bs->drv->bdrv_drain_begin) ||
23
+ if (ret < 0) {
28
- (!begin && !bs->drv->bdrv_drain_end)) {
24
+ goto out;
29
- return;
25
+ }
30
- }
26
+ flags &= ~BDRV_O_RDWR;
31
-
32
- if (begin) {
33
- bs->drv->bdrv_drain_begin(bs);
34
- } else {
35
- bs->drv->bdrv_drain_end(bs);
36
- }
37
-}
38
-
39
/* Returns true if BDRV_POLL_WHILE() should go into a blocking aio_poll() */
40
bool bdrv_drain_poll(BlockDriverState *bs, bool recursive,
41
BdrvChild *ignore_parent, bool ignore_bds_parents)
42
@@ -XXX,XX +XXX,XX @@ void bdrv_do_drained_begin_quiesce(BlockDriverState *bs,
27
}
43
}
28
44
29
iscsi_readcapacity_sync(iscsilun, &local_err);
45
bdrv_parent_drained_begin(bs, parent, ignore_bds_parents);
46
- bdrv_drain_invoke(bs, true);
47
+ if (bs->drv && bs->drv->bdrv_drain_begin) {
48
+ bs->drv->bdrv_drain_begin(bs);
49
+ }
50
}
51
52
static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
53
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
54
assert(bs->quiesce_counter > 0);
55
56
/* Re-enable things in child-to-parent order */
57
- bdrv_drain_invoke(bs, false);
58
+ if (bs->drv && bs->drv->bdrv_drain_end) {
59
+ bs->drv->bdrv_drain_end(bs);
60
+ }
61
bdrv_parent_drained_end(bs, parent, ignore_bds_parents);
62
63
old_quiesce_counter = qatomic_fetch_dec(&bs->quiesce_counter);
30
--
64
--
31
2.19.1
65
2.38.1
32
33
diff view generated by jsdifflib
New patch
1
Callers don't agree whether bdrv_reopen_queue_child() should be called
2
with the AioContext lock held or not. Standardise on holding the lock
3
(as done by QMP blockdev-reopen and the replication block driver) and
4
fix bdrv_reopen() to do the same.
1
5
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Message-Id: <20221118174110.55183-7-kwolf@redhat.com>
8
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
9
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
12
block.c | 7 +++++--
13
1 file changed, 5 insertions(+), 2 deletions(-)
14
15
diff --git a/block.c b/block.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/block.c
18
+++ b/block.c
19
@@ -XXX,XX +XXX,XX @@ static bool bdrv_recurse_has_child(BlockDriverState *bs,
20
* bs_queue, or the existing bs_queue being used.
21
*
22
* bs must be drained between bdrv_reopen_queue() and bdrv_reopen_multiple().
23
+ *
24
+ * To be called with bs->aio_context locked.
25
*/
26
static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
27
BlockDriverState *bs,
28
@@ -XXX,XX +XXX,XX @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
29
return bs_queue;
30
}
31
32
+/* To be called with bs->aio_context locked */
33
BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
34
BlockDriverState *bs,
35
QDict *options, bool keep_old_opts)
36
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen(BlockDriverState *bs, QDict *opts, bool keep_old_opts,
37
GLOBAL_STATE_CODE();
38
39
bdrv_subtree_drained_begin(bs);
40
+ queue = bdrv_reopen_queue(NULL, bs, opts, keep_old_opts);
41
+
42
if (ctx != qemu_get_aio_context()) {
43
aio_context_release(ctx);
44
}
45
-
46
- queue = bdrv_reopen_queue(NULL, bs, opts, keep_old_opts);
47
ret = bdrv_reopen_multiple(queue, errp);
48
49
if (ctx != qemu_get_aio_context()) {
50
--
51
2.38.1
diff view generated by jsdifflib
1
While we want machine interfaces like -blockdev and QMP blockdev-add to
1
bdrv_reopen() and friends use subtree drains as a lazy way of covering
2
add as little auto-detection as possible so that management tools are
2
all the nodes they touch. Turns out that this lazy way is a lot more
3
explicit about their needs, -drive is a convenience option for human
3
complicated than just draining the nodes individually, even not
4
users. Enabling auto-read-only=on by default there enables users to use
4
accounting for the additional complexity in the drain mechanism itself.
5
read-only images for read-only guest devices without having to specify
5
6
read-only=on explicitly. If they try to attach the image to a read-write
6
Simplify the code by switching to draining the individual nodes that are
7
device, they will still get an error message.
7
already managed in the BlockReopenQueue anyway.
8
8
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Message-Id: <20221118174110.55183-8-kwolf@redhat.com>
11
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
12
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
14
---
12
blockdev.c | 1 +
15
block.c | 16 +++++++++-------
13
1 file changed, 1 insertion(+)
16
block/replication.c | 6 ------
17
blockdev.c | 13 -------------
18
3 files changed, 9 insertions(+), 26 deletions(-)
14
19
20
diff --git a/block.c b/block.c
21
index XXXXXXX..XXXXXXX 100644
22
--- a/block.c
23
+++ b/block.c
24
@@ -XXX,XX +XXX,XX @@ static bool bdrv_recurse_has_child(BlockDriverState *bs,
25
* returns a pointer to bs_queue, which is either the newly allocated
26
* bs_queue, or the existing bs_queue being used.
27
*
28
- * bs must be drained between bdrv_reopen_queue() and bdrv_reopen_multiple().
29
+ * bs is drained here and undrained by bdrv_reopen_queue_free().
30
*
31
* To be called with bs->aio_context locked.
32
*/
33
@@ -XXX,XX +XXX,XX @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
34
int flags;
35
QemuOpts *opts;
36
37
- /* Make sure that the caller remembered to use a drained section. This is
38
- * important to avoid graph changes between the recursive queuing here and
39
- * bdrv_reopen_multiple(). */
40
- assert(bs->quiesce_counter > 0);
41
GLOBAL_STATE_CODE();
42
43
+ bdrv_drained_begin(bs);
44
+
45
if (bs_queue == NULL) {
46
bs_queue = g_new0(BlockReopenQueue, 1);
47
QTAILQ_INIT(bs_queue);
48
@@ -XXX,XX +XXX,XX @@ void bdrv_reopen_queue_free(BlockReopenQueue *bs_queue)
49
if (bs_queue) {
50
BlockReopenQueueEntry *bs_entry, *next;
51
QTAILQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) {
52
+ AioContext *ctx = bdrv_get_aio_context(bs_entry->state.bs);
53
+
54
+ aio_context_acquire(ctx);
55
+ bdrv_drained_end(bs_entry->state.bs);
56
+ aio_context_release(ctx);
57
+
58
qobject_unref(bs_entry->state.explicit_options);
59
qobject_unref(bs_entry->state.options);
60
g_free(bs_entry);
61
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen(BlockDriverState *bs, QDict *opts, bool keep_old_opts,
62
63
GLOBAL_STATE_CODE();
64
65
- bdrv_subtree_drained_begin(bs);
66
queue = bdrv_reopen_queue(NULL, bs, opts, keep_old_opts);
67
68
if (ctx != qemu_get_aio_context()) {
69
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen(BlockDriverState *bs, QDict *opts, bool keep_old_opts,
70
if (ctx != qemu_get_aio_context()) {
71
aio_context_acquire(ctx);
72
}
73
- bdrv_subtree_drained_end(bs);
74
75
return ret;
76
}
77
diff --git a/block/replication.c b/block/replication.c
78
index XXXXXXX..XXXXXXX 100644
79
--- a/block/replication.c
80
+++ b/block/replication.c
81
@@ -XXX,XX +XXX,XX @@ static void reopen_backing_file(BlockDriverState *bs, bool writable,
82
s->orig_secondary_read_only = bdrv_is_read_only(secondary_disk->bs);
83
}
84
85
- bdrv_subtree_drained_begin(hidden_disk->bs);
86
- bdrv_subtree_drained_begin(secondary_disk->bs);
87
-
88
if (s->orig_hidden_read_only) {
89
QDict *opts = qdict_new();
90
qdict_put_bool(opts, BDRV_OPT_READ_ONLY, !writable);
91
@@ -XXX,XX +XXX,XX @@ static void reopen_backing_file(BlockDriverState *bs, bool writable,
92
aio_context_acquire(ctx);
93
}
94
}
95
-
96
- bdrv_subtree_drained_end(hidden_disk->bs);
97
- bdrv_subtree_drained_end(secondary_disk->bs);
98
}
99
100
static void backup_job_cleanup(BlockDriverState *bs)
15
diff --git a/blockdev.c b/blockdev.c
101
diff --git a/blockdev.c b/blockdev.c
16
index XXXXXXX..XXXXXXX 100644
102
index XXXXXXX..XXXXXXX 100644
17
--- a/blockdev.c
103
--- a/blockdev.c
18
+++ b/blockdev.c
104
+++ b/blockdev.c
19
@@ -XXX,XX +XXX,XX @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
105
@@ -XXX,XX +XXX,XX @@ fail:
20
qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_NO_FLUSH, "off");
106
void qmp_blockdev_reopen(BlockdevOptionsList *reopen_list, Error **errp)
21
qdict_set_default_str(bs_opts, BDRV_OPT_READ_ONLY,
107
{
22
read_only ? "on" : "off");
108
BlockReopenQueue *queue = NULL;
23
+ qdict_set_default_str(bs_opts, BDRV_OPT_AUTO_READ_ONLY, "on");
109
- GSList *drained = NULL;
24
assert((bdrv_flags & BDRV_O_CACHE_MASK) == 0);
110
- GSList *p;
25
111
26
if (runstate_check(RUN_STATE_INMIGRATE)) {
112
/* Add each one of the BDS that we want to reopen to the queue */
113
for (; reopen_list != NULL; reopen_list = reopen_list->next) {
114
@@ -XXX,XX +XXX,XX @@ void qmp_blockdev_reopen(BlockdevOptionsList *reopen_list, Error **errp)
115
ctx = bdrv_get_aio_context(bs);
116
aio_context_acquire(ctx);
117
118
- bdrv_subtree_drained_begin(bs);
119
queue = bdrv_reopen_queue(queue, bs, qdict, false);
120
- drained = g_slist_prepend(drained, bs);
121
122
aio_context_release(ctx);
123
}
124
@@ -XXX,XX +XXX,XX @@ void qmp_blockdev_reopen(BlockdevOptionsList *reopen_list, Error **errp)
125
126
fail:
127
bdrv_reopen_queue_free(queue);
128
- for (p = drained; p; p = p->next) {
129
- BlockDriverState *bs = p->data;
130
- AioContext *ctx = bdrv_get_aio_context(bs);
131
-
132
- aio_context_acquire(ctx);
133
- bdrv_subtree_drained_end(bs);
134
- aio_context_release(ctx);
135
- }
136
- g_slist_free(drained);
137
}
138
139
void qmp_blockdev_del(const char *node_name, Error **errp)
27
--
140
--
28
2.19.1
141
2.38.1
29
30
diff view generated by jsdifflib
1
From: Leonid Bloch <lbloch@janustech.com>
1
Instead of using a subtree drain from the top node (which also drains
2
child nodes of base that we're not even interested in), use a normal
3
drain for base, which automatically drains all of the parents, too.
2
4
3
If an expression is used to define DEFAULT_CLUSTER_SIZE, when compiled,
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
it will be embedded as a literal expression in the binary (as the
6
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
5
default value) because it is stringified to mark the size of the default
7
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
6
value. Now this is fixed by using a defined number to define this value.
8
Message-Id: <20221118174110.55183-9-kwolf@redhat.com>
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 | 4 ++--
13
1 file changed, 2 insertions(+), 2 deletions(-)
12
1 file changed, 2 insertions(+), 2 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 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
20
#define BLOCK_OPT_STATIC "static"
19
GLOBAL_STATE_CODE();
21
20
22
#define SECTOR_SIZE 512
21
bdrv_ref(top);
23
-#define DEFAULT_CLUSTER_SIZE (1 * MiB)
22
- bdrv_subtree_drained_begin(top);
24
+#define DEFAULT_CLUSTER_SIZE S_1MiB
23
+ bdrv_drained_begin(base);
25
24
26
#if defined(CONFIG_VDI_DEBUG)
25
if (!top->drv || !base->drv) {
27
#define VDI_DEBUG 1
26
goto exit;
28
@@ -XXX,XX +XXX,XX @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
27
@@ -XXX,XX +XXX,XX @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
29
goto fail;
28
30
} else if (header.block_size != DEFAULT_CLUSTER_SIZE) {
29
ret = 0;
31
error_setg(errp, "unsupported VDI image (block size %" PRIu32
30
exit:
32
- " is not %" PRIu64 ")",
31
- bdrv_subtree_drained_end(top);
33
+ " is not %" PRIu32 ")",
32
+ bdrv_drained_end(base);
34
header.block_size, DEFAULT_CLUSTER_SIZE);
33
bdrv_unref(top);
35
ret = -ENOTSUP;
34
return ret;
36
goto fail;
35
}
37
--
36
--
38
2.19.1
37
2.38.1
39
40
diff view generated by jsdifflib
1
To fully change the read-only state of a node, we must not only change
1
The subtree drain was introduced in commit b1e1af394d9 as a way to avoid
2
bs->read_only, but also update bs->open_flags.
2
graph changes between finding the base node and changing the block graph
3
as necessary on completion of the image streaming job.
4
5
The block graph could change between these two points because
6
bdrv_set_backing_hd() first drains the parent node, which involved
7
polling and can do anything.
8
9
Subtree draining was an imperfect way to make this less likely (because
10
with it, fewer callbacks are called during this window). Everyone agreed
11
that it's not really the right solution, and it was only committed as a
12
stopgap solution.
13
14
This replaces the subtree drain with a solution that simply drains the
15
parent node before we try to find the base node, and then call a version
16
of bdrv_set_backing_hd() that doesn't drain, but just asserts that the
17
parent node is already drained.
18
19
This way, any graph changes caused by draining happen before we start
20
looking at the graph and things stay consistent between finding the base
21
node and changing the graph.
3
22
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
23
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Eric Blake <eblake@redhat.com>
24
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
6
Reviewed-by: Alberto Garcia <berto@igalia.com>
25
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
26
Message-Id: <20221118174110.55183-10-kwolf@redhat.com>
27
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
28
---
8
block.c | 7 +++++++
29
include/block/block-global-state.h | 3 +++
9
1 file changed, 7 insertions(+)
30
block.c | 17 ++++++++++++++---
31
block/stream.c | 26 ++++++++++++++++----------
32
3 files changed, 33 insertions(+), 13 deletions(-)
10
33
34
diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h
35
index XXXXXXX..XXXXXXX 100644
36
--- a/include/block/block-global-state.h
37
+++ b/include/block/block-global-state.h
38
@@ -XXX,XX +XXX,XX @@ int bdrv_open_file_child(const char *filename,
39
BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp);
40
int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
41
Error **errp);
42
+int bdrv_set_backing_hd_drained(BlockDriverState *bs,
43
+ BlockDriverState *backing_hd,
44
+ Error **errp);
45
int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
46
const char *bdref_key, Error **errp);
47
BlockDriverState *bdrv_open(const char *filename, const char *reference,
11
diff --git a/block.c b/block.c
48
diff --git a/block.c b/block.c
12
index XXXXXXX..XXXXXXX 100644
49
index XXXXXXX..XXXXXXX 100644
13
--- a/block.c
50
--- a/block.c
14
+++ b/block.c
51
+++ b/block.c
15
@@ -XXX,XX +XXX,XX @@ int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
52
@@ -XXX,XX +XXX,XX @@ static int bdrv_set_backing_noperm(BlockDriverState *bs,
53
return bdrv_set_file_or_backing_noperm(bs, backing_hd, true, tran, errp);
54
}
55
56
-int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
57
- Error **errp)
58
+int bdrv_set_backing_hd_drained(BlockDriverState *bs,
59
+ BlockDriverState *backing_hd,
60
+ Error **errp)
61
{
62
int ret;
63
Transaction *tran = tran_new();
64
65
GLOBAL_STATE_CODE();
66
- bdrv_drained_begin(bs);
67
+ assert(bs->quiesce_counter > 0);
68
69
ret = bdrv_set_backing_noperm(bs, backing_hd, tran, errp);
70
if (ret < 0) {
71
@@ -XXX,XX +XXX,XX @@ int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
72
ret = bdrv_refresh_perms(bs, tran, errp);
73
out:
74
tran_finalize(tran, ret);
75
+ return ret;
76
+}
77
78
+int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
79
+ Error **errp)
80
+{
81
+ int ret;
82
+ GLOBAL_STATE_CODE();
83
+
84
+ bdrv_drained_begin(bs);
85
+ ret = bdrv_set_backing_hd_drained(bs, backing_hd, errp);
86
bdrv_drained_end(bs);
87
88
return ret;
89
diff --git a/block/stream.c b/block/stream.c
90
index XXXXXXX..XXXXXXX 100644
91
--- a/block/stream.c
92
+++ b/block/stream.c
93
@@ -XXX,XX +XXX,XX @@ static int stream_prepare(Job *job)
94
bdrv_cor_filter_drop(s->cor_filter_bs);
95
s->cor_filter_bs = NULL;
96
97
- bdrv_subtree_drained_begin(s->above_base);
98
+ /*
99
+ * bdrv_set_backing_hd() requires that unfiltered_bs is drained. Drain
100
+ * already here and use bdrv_set_backing_hd_drained() instead because
101
+ * the polling during drained_begin() might change the graph, and if we do
102
+ * this only later, we may end up working with the wrong base node (or it
103
+ * might even have gone away by the time we want to use it).
104
+ */
105
+ bdrv_drained_begin(unfiltered_bs);
106
107
base = bdrv_filter_or_cow_bs(s->above_base);
108
- if (base) {
109
- bdrv_ref(base);
110
- }
111
-
112
unfiltered_base = bdrv_skip_filters(base);
113
114
if (bdrv_cow_child(unfiltered_bs)) {
115
@@ -XXX,XX +XXX,XX @@ static int stream_prepare(Job *job)
116
}
117
}
118
119
- bdrv_set_backing_hd(unfiltered_bs, base, &local_err);
120
+ bdrv_set_backing_hd_drained(unfiltered_bs, base, &local_err);
121
+
122
+ /*
123
+ * This call will do I/O, so the graph can change again from here on.
124
+ * We have already completed the graph change, so we are not in danger
125
+ * of operating on the wrong node any more if this happens.
126
+ */
127
ret = bdrv_change_backing_file(unfiltered_bs, base_id, base_fmt, false);
128
if (local_err) {
129
error_report_err(local_err);
130
@@ -XXX,XX +XXX,XX @@ static int stream_prepare(Job *job)
16
}
131
}
17
132
18
bs->read_only = read_only;
133
out:
19
+
134
- if (base) {
20
+ if (read_only) {
135
- bdrv_unref(base);
21
+ bs->open_flags &= ~BDRV_O_RDWR;
136
- }
22
+ } else {
137
- bdrv_subtree_drained_end(s->above_base);
23
+ bs->open_flags |= BDRV_O_RDWR;
138
+ bdrv_drained_end(unfiltered_bs);
24
+ }
139
return ret;
25
+
26
return 0;
27
}
140
}
28
141
29
--
142
--
30
2.19.1
143
2.38.1
31
32
diff view generated by jsdifflib
New patch
1
Subtree drains are not used any more. Remove them.
1
2
3
After this, BdrvChildClass.attach/detach() don't poll any more.
4
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
7
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
8
Message-Id: <20221118174110.55183-11-kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
include/block/block-io.h | 18 +--
12
include/block/block_int-common.h | 1 -
13
include/block/block_int-io.h | 12 --
14
block.c | 20 +--
15
block/io.c | 121 +++-----------
16
tests/unit/test-bdrv-drain.c | 261 ++-----------------------------
17
6 files changed, 44 insertions(+), 389 deletions(-)
18
19
diff --git a/include/block/block-io.h b/include/block/block-io.h
20
index XXXXXXX..XXXXXXX 100644
21
--- a/include/block/block-io.h
22
+++ b/include/block/block-io.h
23
@@ -XXX,XX +XXX,XX @@ void bdrv_parent_drained_end_single(BdrvChild *c);
24
/**
25
* bdrv_drain_poll:
26
*
27
- * Poll for pending requests in @bs, its parents (except for @ignore_parent),
28
- * and if @recursive is true its children as well (used for subtree drain).
29
+ * Poll for pending requests in @bs and its parents (except for @ignore_parent).
30
*
31
* If @ignore_bds_parents is true, parents that are BlockDriverStates must
32
* ignore the drain request because they will be drained separately (used for
33
@@ -XXX,XX +XXX,XX @@ void bdrv_parent_drained_end_single(BdrvChild *c);
34
*
35
* This is part of bdrv_drained_begin.
36
*/
37
-bool bdrv_drain_poll(BlockDriverState *bs, bool recursive,
38
- BdrvChild *ignore_parent, bool ignore_bds_parents);
39
+bool bdrv_drain_poll(BlockDriverState *bs, BdrvChild *ignore_parent,
40
+ bool ignore_bds_parents);
41
42
/**
43
* bdrv_drained_begin:
44
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs);
45
void bdrv_do_drained_begin_quiesce(BlockDriverState *bs,
46
BdrvChild *parent, bool ignore_bds_parents);
47
48
-/**
49
- * Like bdrv_drained_begin, but recursively begins a quiesced section for
50
- * exclusive access to all child nodes as well.
51
- */
52
-void bdrv_subtree_drained_begin(BlockDriverState *bs);
53
-
54
/**
55
* bdrv_drained_end:
56
*
57
@@ -XXX,XX +XXX,XX @@ void bdrv_subtree_drained_begin(BlockDriverState *bs);
58
*/
59
void bdrv_drained_end(BlockDriverState *bs);
60
61
-/**
62
- * End a quiescent section started by bdrv_subtree_drained_begin().
63
- */
64
-void bdrv_subtree_drained_end(BlockDriverState *bs);
65
-
66
#endif /* BLOCK_IO_H */
67
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
68
index XXXXXXX..XXXXXXX 100644
69
--- a/include/block/block_int-common.h
70
+++ b/include/block/block_int-common.h
71
@@ -XXX,XX +XXX,XX @@ struct BlockDriverState {
72
73
/* Accessed with atomic ops. */
74
int quiesce_counter;
75
- int recursive_quiesce_counter;
76
77
unsigned int write_gen; /* Current data generation */
78
79
diff --git a/include/block/block_int-io.h b/include/block/block_int-io.h
80
index XXXXXXX..XXXXXXX 100644
81
--- a/include/block/block_int-io.h
82
+++ b/include/block/block_int-io.h
83
@@ -XXX,XX +XXX,XX @@ void bdrv_bsc_invalidate_range(BlockDriverState *bs,
84
*/
85
void bdrv_bsc_fill(BlockDriverState *bs, int64_t offset, int64_t bytes);
86
87
-
88
-/*
89
- * "I/O or GS" API functions. These functions can run without
90
- * the BQL, but only in one specific iothread/main loop.
91
- *
92
- * See include/block/block-io.h for more information about
93
- * the "I/O or GS" API.
94
- */
95
-
96
-void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent);
97
-void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent);
98
-
99
#endif /* BLOCK_INT_IO_H */
100
diff --git a/block.c b/block.c
101
index XXXXXXX..XXXXXXX 100644
102
--- a/block.c
103
+++ b/block.c
104
@@ -XXX,XX +XXX,XX @@ static void bdrv_child_cb_drained_begin(BdrvChild *child)
105
static bool bdrv_child_cb_drained_poll(BdrvChild *child)
106
{
107
BlockDriverState *bs = child->opaque;
108
- return bdrv_drain_poll(bs, false, NULL, false);
109
+ return bdrv_drain_poll(bs, NULL, false);
110
}
111
112
static void bdrv_child_cb_drained_end(BdrvChild *child)
113
@@ -XXX,XX +XXX,XX @@ static void bdrv_child_cb_attach(BdrvChild *child)
114
assert(!bs->file);
115
bs->file = child;
116
}
117
-
118
- bdrv_apply_subtree_drain(child, bs);
119
}
120
121
static void bdrv_child_cb_detach(BdrvChild *child)
122
@@ -XXX,XX +XXX,XX @@ static void bdrv_child_cb_detach(BdrvChild *child)
123
bdrv_backing_detach(child);
124
}
125
126
- bdrv_unapply_subtree_drain(child, bs);
127
-
128
assert_bdrv_graph_writable(bs);
129
QLIST_REMOVE(child, next);
130
if (child == bs->backing) {
131
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child,
132
}
133
134
if (old_bs) {
135
- /* Detach first so that the recursive drain sections coming from @child
136
- * are already gone and we only end the drain sections that came from
137
- * elsewhere. */
138
if (child->klass->detach) {
139
child->klass->detach(child);
140
}
141
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child,
142
QLIST_INSERT_HEAD(&new_bs->parents, child, next_parent);
143
144
/*
145
- * Detaching the old node may have led to the new node's
146
- * quiesce_counter having been decreased. Not a problem, we
147
- * just need to recognize this here and then invoke
148
- * drained_end appropriately more often.
149
+ * Polling in bdrv_parent_drained_begin_single() may have led to the new
150
+ * node's quiesce_counter having been decreased. Not a problem, we just
151
+ * need to recognize this here and then invoke drained_end appropriately
152
+ * more often.
153
*/
154
assert(new_bs->quiesce_counter <= new_bs_quiesce_counter);
155
drain_saldo += new_bs->quiesce_counter - new_bs_quiesce_counter;
156
157
- /* Attach only after starting new drained sections, so that recursive
158
- * drain sections coming from @child don't get an extra .drained_begin
159
- * callback. */
160
if (child->klass->attach) {
161
child->klass->attach(child);
162
}
163
diff --git a/block/io.c b/block/io.c
164
index XXXXXXX..XXXXXXX 100644
165
--- a/block/io.c
166
+++ b/block/io.c
167
@@ -XXX,XX +XXX,XX @@ typedef struct {
168
BlockDriverState *bs;
169
bool done;
170
bool begin;
171
- bool recursive;
172
bool poll;
173
BdrvChild *parent;
174
bool ignore_bds_parents;
175
} BdrvCoDrainData;
176
177
/* Returns true if BDRV_POLL_WHILE() should go into a blocking aio_poll() */
178
-bool bdrv_drain_poll(BlockDriverState *bs, bool recursive,
179
- BdrvChild *ignore_parent, bool ignore_bds_parents)
180
+bool bdrv_drain_poll(BlockDriverState *bs, BdrvChild *ignore_parent,
181
+ bool ignore_bds_parents)
182
{
183
- BdrvChild *child, *next;
184
IO_OR_GS_CODE();
185
186
if (bdrv_parent_drained_poll(bs, ignore_parent, ignore_bds_parents)) {
187
@@ -XXX,XX +XXX,XX @@ bool bdrv_drain_poll(BlockDriverState *bs, bool recursive,
188
return true;
189
}
190
191
- if (recursive) {
192
- assert(!ignore_bds_parents);
193
- QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
194
- if (bdrv_drain_poll(child->bs, recursive, child, false)) {
195
- return true;
196
- }
197
- }
198
- }
199
-
200
return false;
201
}
202
203
-static bool bdrv_drain_poll_top_level(BlockDriverState *bs, bool recursive,
204
+static bool bdrv_drain_poll_top_level(BlockDriverState *bs,
205
BdrvChild *ignore_parent)
206
{
207
- return bdrv_drain_poll(bs, recursive, ignore_parent, false);
208
+ return bdrv_drain_poll(bs, ignore_parent, false);
209
}
210
211
-static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
212
- BdrvChild *parent, bool ignore_bds_parents,
213
- bool poll);
214
-static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
215
- BdrvChild *parent, bool ignore_bds_parents);
216
+static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent,
217
+ bool ignore_bds_parents, bool poll);
218
+static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent,
219
+ bool ignore_bds_parents);
220
221
static void bdrv_co_drain_bh_cb(void *opaque)
222
{
223
@@ -XXX,XX +XXX,XX @@ static void bdrv_co_drain_bh_cb(void *opaque)
224
aio_context_acquire(ctx);
225
bdrv_dec_in_flight(bs);
226
if (data->begin) {
227
- bdrv_do_drained_begin(bs, data->recursive, data->parent,
228
- data->ignore_bds_parents, data->poll);
229
+ bdrv_do_drained_begin(bs, data->parent, data->ignore_bds_parents,
230
+ data->poll);
231
} else {
232
assert(!data->poll);
233
- bdrv_do_drained_end(bs, data->recursive, data->parent,
234
- data->ignore_bds_parents);
235
+ bdrv_do_drained_end(bs, data->parent, data->ignore_bds_parents);
236
}
237
aio_context_release(ctx);
238
} else {
239
@@ -XXX,XX +XXX,XX @@ static void bdrv_co_drain_bh_cb(void *opaque)
240
}
241
242
static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
243
- bool begin, bool recursive,
244
+ bool begin,
245
BdrvChild *parent,
246
bool ignore_bds_parents,
247
bool poll)
248
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
249
.bs = bs,
250
.done = false,
251
.begin = begin,
252
- .recursive = recursive,
253
.parent = parent,
254
.ignore_bds_parents = ignore_bds_parents,
255
.poll = poll,
256
@@ -XXX,XX +XXX,XX @@ void bdrv_do_drained_begin_quiesce(BlockDriverState *bs,
257
}
258
}
259
260
-static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
261
- BdrvChild *parent, bool ignore_bds_parents,
262
- bool poll)
263
+static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent,
264
+ bool ignore_bds_parents, bool poll)
265
{
266
- BdrvChild *child, *next;
267
-
268
if (qemu_in_coroutine()) {
269
- bdrv_co_yield_to_drain(bs, true, recursive, parent, ignore_bds_parents,
270
- poll);
271
+ bdrv_co_yield_to_drain(bs, true, parent, ignore_bds_parents, poll);
272
return;
273
}
274
275
bdrv_do_drained_begin_quiesce(bs, parent, ignore_bds_parents);
276
277
- if (recursive) {
278
- assert(!ignore_bds_parents);
279
- bs->recursive_quiesce_counter++;
280
- QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
281
- bdrv_do_drained_begin(child->bs, true, child, ignore_bds_parents,
282
- false);
283
- }
284
- }
285
-
286
/*
287
* Wait for drained requests to finish.
288
*
289
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
290
*/
291
if (poll) {
292
assert(!ignore_bds_parents);
293
- BDRV_POLL_WHILE(bs, bdrv_drain_poll_top_level(bs, recursive, parent));
294
+ BDRV_POLL_WHILE(bs, bdrv_drain_poll_top_level(bs, parent));
295
}
296
}
297
298
void bdrv_drained_begin(BlockDriverState *bs)
299
{
300
IO_OR_GS_CODE();
301
- bdrv_do_drained_begin(bs, false, NULL, false, true);
302
-}
303
-
304
-void bdrv_subtree_drained_begin(BlockDriverState *bs)
305
-{
306
- IO_OR_GS_CODE();
307
- bdrv_do_drained_begin(bs, true, NULL, false, true);
308
+ bdrv_do_drained_begin(bs, NULL, false, true);
309
}
310
311
/**
312
* This function does not poll, nor must any of its recursively called
313
* functions.
314
*/
315
-static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
316
- BdrvChild *parent, bool ignore_bds_parents)
317
+static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent,
318
+ bool ignore_bds_parents)
319
{
320
- BdrvChild *child;
321
int old_quiesce_counter;
322
323
if (qemu_in_coroutine()) {
324
- bdrv_co_yield_to_drain(bs, false, recursive, parent, ignore_bds_parents,
325
- false);
326
+ bdrv_co_yield_to_drain(bs, false, parent, ignore_bds_parents, false);
327
return;
328
}
329
assert(bs->quiesce_counter > 0);
330
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
331
if (old_quiesce_counter == 1) {
332
aio_enable_external(bdrv_get_aio_context(bs));
333
}
334
-
335
- if (recursive) {
336
- assert(!ignore_bds_parents);
337
- bs->recursive_quiesce_counter--;
338
- QLIST_FOREACH(child, &bs->children, next) {
339
- bdrv_do_drained_end(child->bs, true, child, ignore_bds_parents);
340
- }
341
- }
342
}
343
344
void bdrv_drained_end(BlockDriverState *bs)
345
{
346
IO_OR_GS_CODE();
347
- bdrv_do_drained_end(bs, false, NULL, false);
348
-}
349
-
350
-void bdrv_subtree_drained_end(BlockDriverState *bs)
351
-{
352
- IO_OR_GS_CODE();
353
- bdrv_do_drained_end(bs, true, NULL, false);
354
-}
355
-
356
-void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent)
357
-{
358
- int i;
359
- IO_OR_GS_CODE();
360
-
361
- for (i = 0; i < new_parent->recursive_quiesce_counter; i++) {
362
- bdrv_do_drained_begin(child->bs, true, child, false, true);
363
- }
364
-}
365
-
366
-void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent)
367
-{
368
- int i;
369
- IO_OR_GS_CODE();
370
-
371
- for (i = 0; i < old_parent->recursive_quiesce_counter; i++) {
372
- bdrv_do_drained_end(child->bs, true, child, false);
373
- }
374
+ bdrv_do_drained_end(bs, NULL, false);
375
}
376
377
void bdrv_drain(BlockDriverState *bs)
378
@@ -XXX,XX +XXX,XX @@ static bool bdrv_drain_all_poll(void)
379
while ((bs = bdrv_next_all_states(bs))) {
380
AioContext *aio_context = bdrv_get_aio_context(bs);
381
aio_context_acquire(aio_context);
382
- result |= bdrv_drain_poll(bs, false, NULL, true);
383
+ result |= bdrv_drain_poll(bs, NULL, true);
384
aio_context_release(aio_context);
385
}
386
387
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
388
GLOBAL_STATE_CODE();
389
390
if (qemu_in_coroutine()) {
391
- bdrv_co_yield_to_drain(NULL, true, false, NULL, true, true);
392
+ bdrv_co_yield_to_drain(NULL, true, NULL, true, true);
393
return;
394
}
395
396
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
397
AioContext *aio_context = bdrv_get_aio_context(bs);
398
399
aio_context_acquire(aio_context);
400
- bdrv_do_drained_begin(bs, false, NULL, true, false);
401
+ bdrv_do_drained_begin(bs, NULL, true, false);
402
aio_context_release(aio_context);
403
}
404
405
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end_quiesce(BlockDriverState *bs)
406
g_assert(!bs->refcnt);
407
408
while (bs->quiesce_counter) {
409
- bdrv_do_drained_end(bs, false, NULL, true);
410
+ bdrv_do_drained_end(bs, NULL, true);
411
}
412
}
413
414
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
415
AioContext *aio_context = bdrv_get_aio_context(bs);
416
417
aio_context_acquire(aio_context);
418
- bdrv_do_drained_end(bs, false, NULL, true);
419
+ bdrv_do_drained_end(bs, NULL, true);
420
aio_context_release(aio_context);
421
}
422
423
diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c
424
index XXXXXXX..XXXXXXX 100644
425
--- a/tests/unit/test-bdrv-drain.c
426
+++ b/tests/unit/test-bdrv-drain.c
427
@@ -XXX,XX +XXX,XX @@ static void call_in_coroutine(void (*entry)(void))
428
enum drain_type {
429
BDRV_DRAIN_ALL,
430
BDRV_DRAIN,
431
- BDRV_SUBTREE_DRAIN,
432
DRAIN_TYPE_MAX,
433
};
434
435
@@ -XXX,XX +XXX,XX @@ static void do_drain_begin(enum drain_type drain_type, BlockDriverState *bs)
436
switch (drain_type) {
437
case BDRV_DRAIN_ALL: bdrv_drain_all_begin(); break;
438
case BDRV_DRAIN: bdrv_drained_begin(bs); break;
439
- case BDRV_SUBTREE_DRAIN: bdrv_subtree_drained_begin(bs); break;
440
default: g_assert_not_reached();
441
}
442
}
443
@@ -XXX,XX +XXX,XX @@ static void do_drain_end(enum drain_type drain_type, BlockDriverState *bs)
444
switch (drain_type) {
445
case BDRV_DRAIN_ALL: bdrv_drain_all_end(); break;
446
case BDRV_DRAIN: bdrv_drained_end(bs); break;
447
- case BDRV_SUBTREE_DRAIN: bdrv_subtree_drained_end(bs); break;
448
default: g_assert_not_reached();
449
}
450
}
451
@@ -XXX,XX +XXX,XX @@ static void test_drv_cb_drain(void)
452
test_drv_cb_common(BDRV_DRAIN, false);
453
}
454
455
-static void test_drv_cb_drain_subtree(void)
456
-{
457
- test_drv_cb_common(BDRV_SUBTREE_DRAIN, true);
458
-}
459
-
460
static void test_drv_cb_co_drain_all(void)
461
{
462
call_in_coroutine(test_drv_cb_drain_all);
463
@@ -XXX,XX +XXX,XX @@ static void test_drv_cb_co_drain(void)
464
call_in_coroutine(test_drv_cb_drain);
465
}
466
467
-static void test_drv_cb_co_drain_subtree(void)
468
-{
469
- call_in_coroutine(test_drv_cb_drain_subtree);
470
-}
471
-
472
static void test_quiesce_common(enum drain_type drain_type, bool recursive)
473
{
474
BlockBackend *blk;
475
@@ -XXX,XX +XXX,XX @@ static void test_quiesce_drain(void)
476
test_quiesce_common(BDRV_DRAIN, false);
477
}
478
479
-static void test_quiesce_drain_subtree(void)
480
-{
481
- test_quiesce_common(BDRV_SUBTREE_DRAIN, true);
482
-}
483
-
484
static void test_quiesce_co_drain_all(void)
485
{
486
call_in_coroutine(test_quiesce_drain_all);
487
@@ -XXX,XX +XXX,XX @@ static void test_quiesce_co_drain(void)
488
call_in_coroutine(test_quiesce_drain);
489
}
490
491
-static void test_quiesce_co_drain_subtree(void)
492
-{
493
- call_in_coroutine(test_quiesce_drain_subtree);
494
-}
495
-
496
static void test_nested(void)
497
{
498
BlockBackend *blk;
499
@@ -XXX,XX +XXX,XX @@ static void test_nested(void)
500
blk_unref(blk);
501
}
502
503
-static void test_multiparent(void)
504
-{
505
- BlockBackend *blk_a, *blk_b;
506
- BlockDriverState *bs_a, *bs_b, *backing;
507
- BDRVTestState *a_s, *b_s, *backing_s;
508
-
509
- blk_a = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
510
- bs_a = bdrv_new_open_driver(&bdrv_test, "test-node-a", BDRV_O_RDWR,
511
- &error_abort);
512
- a_s = bs_a->opaque;
513
- blk_insert_bs(blk_a, bs_a, &error_abort);
514
-
515
- blk_b = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
516
- bs_b = bdrv_new_open_driver(&bdrv_test, "test-node-b", BDRV_O_RDWR,
517
- &error_abort);
518
- b_s = bs_b->opaque;
519
- blk_insert_bs(blk_b, bs_b, &error_abort);
520
-
521
- backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort);
522
- backing_s = backing->opaque;
523
- bdrv_set_backing_hd(bs_a, backing, &error_abort);
524
- bdrv_set_backing_hd(bs_b, backing, &error_abort);
525
-
526
- g_assert_cmpint(bs_a->quiesce_counter, ==, 0);
527
- g_assert_cmpint(bs_b->quiesce_counter, ==, 0);
528
- g_assert_cmpint(backing->quiesce_counter, ==, 0);
529
- g_assert_cmpint(a_s->drain_count, ==, 0);
530
- g_assert_cmpint(b_s->drain_count, ==, 0);
531
- g_assert_cmpint(backing_s->drain_count, ==, 0);
532
-
533
- do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a);
534
-
535
- g_assert_cmpint(bs_a->quiesce_counter, ==, 1);
536
- g_assert_cmpint(bs_b->quiesce_counter, ==, 1);
537
- g_assert_cmpint(backing->quiesce_counter, ==, 1);
538
- g_assert_cmpint(a_s->drain_count, ==, 1);
539
- g_assert_cmpint(b_s->drain_count, ==, 1);
540
- g_assert_cmpint(backing_s->drain_count, ==, 1);
541
-
542
- do_drain_begin(BDRV_SUBTREE_DRAIN, bs_b);
543
-
544
- g_assert_cmpint(bs_a->quiesce_counter, ==, 2);
545
- g_assert_cmpint(bs_b->quiesce_counter, ==, 2);
546
- g_assert_cmpint(backing->quiesce_counter, ==, 2);
547
- g_assert_cmpint(a_s->drain_count, ==, 2);
548
- g_assert_cmpint(b_s->drain_count, ==, 2);
549
- g_assert_cmpint(backing_s->drain_count, ==, 2);
550
-
551
- do_drain_end(BDRV_SUBTREE_DRAIN, bs_b);
552
-
553
- g_assert_cmpint(bs_a->quiesce_counter, ==, 1);
554
- g_assert_cmpint(bs_b->quiesce_counter, ==, 1);
555
- g_assert_cmpint(backing->quiesce_counter, ==, 1);
556
- g_assert_cmpint(a_s->drain_count, ==, 1);
557
- g_assert_cmpint(b_s->drain_count, ==, 1);
558
- g_assert_cmpint(backing_s->drain_count, ==, 1);
559
-
560
- do_drain_end(BDRV_SUBTREE_DRAIN, bs_a);
561
-
562
- g_assert_cmpint(bs_a->quiesce_counter, ==, 0);
563
- g_assert_cmpint(bs_b->quiesce_counter, ==, 0);
564
- g_assert_cmpint(backing->quiesce_counter, ==, 0);
565
- g_assert_cmpint(a_s->drain_count, ==, 0);
566
- g_assert_cmpint(b_s->drain_count, ==, 0);
567
- g_assert_cmpint(backing_s->drain_count, ==, 0);
568
-
569
- bdrv_unref(backing);
570
- bdrv_unref(bs_a);
571
- bdrv_unref(bs_b);
572
- blk_unref(blk_a);
573
- blk_unref(blk_b);
574
-}
575
-
576
-static void test_graph_change_drain_subtree(void)
577
-{
578
- BlockBackend *blk_a, *blk_b;
579
- BlockDriverState *bs_a, *bs_b, *backing;
580
- BDRVTestState *a_s, *b_s, *backing_s;
581
-
582
- blk_a = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
583
- bs_a = bdrv_new_open_driver(&bdrv_test, "test-node-a", BDRV_O_RDWR,
584
- &error_abort);
585
- a_s = bs_a->opaque;
586
- blk_insert_bs(blk_a, bs_a, &error_abort);
587
-
588
- blk_b = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
589
- bs_b = bdrv_new_open_driver(&bdrv_test, "test-node-b", BDRV_O_RDWR,
590
- &error_abort);
591
- b_s = bs_b->opaque;
592
- blk_insert_bs(blk_b, bs_b, &error_abort);
593
-
594
- backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort);
595
- backing_s = backing->opaque;
596
- bdrv_set_backing_hd(bs_a, backing, &error_abort);
597
-
598
- g_assert_cmpint(bs_a->quiesce_counter, ==, 0);
599
- g_assert_cmpint(bs_b->quiesce_counter, ==, 0);
600
- g_assert_cmpint(backing->quiesce_counter, ==, 0);
601
- g_assert_cmpint(a_s->drain_count, ==, 0);
602
- g_assert_cmpint(b_s->drain_count, ==, 0);
603
- g_assert_cmpint(backing_s->drain_count, ==, 0);
604
-
605
- do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a);
606
- do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a);
607
- do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a);
608
- do_drain_begin(BDRV_SUBTREE_DRAIN, bs_b);
609
- do_drain_begin(BDRV_SUBTREE_DRAIN, bs_b);
610
-
611
- bdrv_set_backing_hd(bs_b, backing, &error_abort);
612
- g_assert_cmpint(bs_a->quiesce_counter, ==, 5);
613
- g_assert_cmpint(bs_b->quiesce_counter, ==, 5);
614
- g_assert_cmpint(backing->quiesce_counter, ==, 5);
615
- g_assert_cmpint(a_s->drain_count, ==, 5);
616
- g_assert_cmpint(b_s->drain_count, ==, 5);
617
- g_assert_cmpint(backing_s->drain_count, ==, 5);
618
-
619
- bdrv_set_backing_hd(bs_b, NULL, &error_abort);
620
- g_assert_cmpint(bs_a->quiesce_counter, ==, 3);
621
- g_assert_cmpint(bs_b->quiesce_counter, ==, 2);
622
- g_assert_cmpint(backing->quiesce_counter, ==, 3);
623
- g_assert_cmpint(a_s->drain_count, ==, 3);
624
- g_assert_cmpint(b_s->drain_count, ==, 2);
625
- g_assert_cmpint(backing_s->drain_count, ==, 3);
626
-
627
- bdrv_set_backing_hd(bs_b, backing, &error_abort);
628
- g_assert_cmpint(bs_a->quiesce_counter, ==, 5);
629
- g_assert_cmpint(bs_b->quiesce_counter, ==, 5);
630
- g_assert_cmpint(backing->quiesce_counter, ==, 5);
631
- g_assert_cmpint(a_s->drain_count, ==, 5);
632
- g_assert_cmpint(b_s->drain_count, ==, 5);
633
- g_assert_cmpint(backing_s->drain_count, ==, 5);
634
-
635
- do_drain_end(BDRV_SUBTREE_DRAIN, bs_b);
636
- do_drain_end(BDRV_SUBTREE_DRAIN, bs_b);
637
- do_drain_end(BDRV_SUBTREE_DRAIN, bs_a);
638
- do_drain_end(BDRV_SUBTREE_DRAIN, bs_a);
639
- do_drain_end(BDRV_SUBTREE_DRAIN, bs_a);
640
-
641
- g_assert_cmpint(bs_a->quiesce_counter, ==, 0);
642
- g_assert_cmpint(bs_b->quiesce_counter, ==, 0);
643
- g_assert_cmpint(backing->quiesce_counter, ==, 0);
644
- g_assert_cmpint(a_s->drain_count, ==, 0);
645
- g_assert_cmpint(b_s->drain_count, ==, 0);
646
- g_assert_cmpint(backing_s->drain_count, ==, 0);
647
-
648
- bdrv_unref(backing);
649
- bdrv_unref(bs_a);
650
- bdrv_unref(bs_b);
651
- blk_unref(blk_a);
652
- blk_unref(blk_b);
653
-}
654
-
655
static void test_graph_change_drain_all(void)
656
{
657
BlockBackend *blk_a, *blk_b;
658
@@ -XXX,XX +XXX,XX @@ static void test_iothread_drain(void)
659
test_iothread_common(BDRV_DRAIN, 1);
660
}
661
662
-static void test_iothread_drain_subtree(void)
663
-{
664
- test_iothread_common(BDRV_SUBTREE_DRAIN, 0);
665
- test_iothread_common(BDRV_SUBTREE_DRAIN, 1);
666
-}
667
-
668
669
typedef struct TestBlockJob {
670
BlockJob common;
671
@@ -XXX,XX +XXX,XX @@ enum test_job_result {
672
enum test_job_drain_node {
673
TEST_JOB_DRAIN_SRC,
674
TEST_JOB_DRAIN_SRC_CHILD,
675
- TEST_JOB_DRAIN_SRC_PARENT,
676
};
677
678
static void test_blockjob_common_drain_node(enum drain_type drain_type,
679
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
680
case TEST_JOB_DRAIN_SRC_CHILD:
681
drain_bs = src_backing;
682
break;
683
- case TEST_JOB_DRAIN_SRC_PARENT:
684
- drain_bs = src_overlay;
685
- break;
686
default:
687
g_assert_not_reached();
688
}
689
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common(enum drain_type drain_type, bool use_iothread,
690
TEST_JOB_DRAIN_SRC);
691
test_blockjob_common_drain_node(drain_type, use_iothread, result,
692
TEST_JOB_DRAIN_SRC_CHILD);
693
- if (drain_type == BDRV_SUBTREE_DRAIN) {
694
- test_blockjob_common_drain_node(drain_type, use_iothread, result,
695
- TEST_JOB_DRAIN_SRC_PARENT);
696
- }
697
}
698
699
static void test_blockjob_drain_all(void)
700
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_drain(void)
701
test_blockjob_common(BDRV_DRAIN, false, TEST_JOB_SUCCESS);
702
}
703
704
-static void test_blockjob_drain_subtree(void)
705
-{
706
- test_blockjob_common(BDRV_SUBTREE_DRAIN, false, TEST_JOB_SUCCESS);
707
-}
708
-
709
static void test_blockjob_error_drain_all(void)
710
{
711
test_blockjob_common(BDRV_DRAIN_ALL, false, TEST_JOB_FAIL_RUN);
712
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_error_drain(void)
713
test_blockjob_common(BDRV_DRAIN, false, TEST_JOB_FAIL_PREPARE);
714
}
715
716
-static void test_blockjob_error_drain_subtree(void)
717
-{
718
- test_blockjob_common(BDRV_SUBTREE_DRAIN, false, TEST_JOB_FAIL_RUN);
719
- test_blockjob_common(BDRV_SUBTREE_DRAIN, false, TEST_JOB_FAIL_PREPARE);
720
-}
721
-
722
static void test_blockjob_iothread_drain_all(void)
723
{
724
test_blockjob_common(BDRV_DRAIN_ALL, true, TEST_JOB_SUCCESS);
725
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_iothread_drain(void)
726
test_blockjob_common(BDRV_DRAIN, true, TEST_JOB_SUCCESS);
727
}
728
729
-static void test_blockjob_iothread_drain_subtree(void)
730
-{
731
- test_blockjob_common(BDRV_SUBTREE_DRAIN, true, TEST_JOB_SUCCESS);
732
-}
733
-
734
static void test_blockjob_iothread_error_drain_all(void)
735
{
736
test_blockjob_common(BDRV_DRAIN_ALL, true, TEST_JOB_FAIL_RUN);
737
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_iothread_error_drain(void)
738
test_blockjob_common(BDRV_DRAIN, true, TEST_JOB_FAIL_PREPARE);
739
}
740
741
-static void test_blockjob_iothread_error_drain_subtree(void)
742
-{
743
- test_blockjob_common(BDRV_SUBTREE_DRAIN, true, TEST_JOB_FAIL_RUN);
744
- test_blockjob_common(BDRV_SUBTREE_DRAIN, true, TEST_JOB_FAIL_PREPARE);
745
-}
746
-
747
748
typedef struct BDRVTestTopState {
749
BdrvChild *wait_child;
750
@@ -XXX,XX +XXX,XX @@ static void do_test_delete_by_drain(bool detach_instead_of_delete,
751
bdrv_drain(child_bs);
752
bdrv_unref(child_bs);
753
break;
754
- case BDRV_SUBTREE_DRAIN:
755
- /* Would have to ref/unref bs here for !detach_instead_of_delete, but
756
- * then the whole test becomes pointless because the graph changes
757
- * don't occur during the drain any more. */
758
- assert(detach_instead_of_delete);
759
- bdrv_subtree_drained_begin(bs);
760
- bdrv_subtree_drained_end(bs);
761
- break;
762
case BDRV_DRAIN_ALL:
763
bdrv_drain_all_begin();
764
bdrv_drain_all_end();
765
@@ -XXX,XX +XXX,XX @@ static void test_detach_by_drain(void)
766
do_test_delete_by_drain(true, BDRV_DRAIN);
767
}
768
769
-static void test_detach_by_drain_subtree(void)
770
-{
771
- do_test_delete_by_drain(true, BDRV_SUBTREE_DRAIN);
772
-}
773
-
774
775
struct detach_by_parent_data {
776
BlockDriverState *parent_b;
777
@@ -XXX,XX +XXX,XX @@ static void test_detach_indirect(bool by_parent_cb)
778
g_assert(acb != NULL);
779
780
/* Drain and check the expected result */
781
- bdrv_subtree_drained_begin(parent_b);
782
+ bdrv_drained_begin(parent_b);
783
+ bdrv_drained_begin(a);
784
+ bdrv_drained_begin(b);
785
+ bdrv_drained_begin(c);
786
787
g_assert(detach_by_parent_data.child_c != NULL);
788
789
@@ -XXX,XX +XXX,XX @@ static void test_detach_indirect(bool by_parent_cb)
790
g_assert(QLIST_NEXT(child_a, next) == NULL);
791
792
g_assert_cmpint(parent_a->quiesce_counter, ==, 1);
793
- g_assert_cmpint(parent_b->quiesce_counter, ==, 1);
794
+ g_assert_cmpint(parent_b->quiesce_counter, ==, 3);
795
g_assert_cmpint(a->quiesce_counter, ==, 1);
796
- g_assert_cmpint(b->quiesce_counter, ==, 0);
797
+ g_assert_cmpint(b->quiesce_counter, ==, 1);
798
g_assert_cmpint(c->quiesce_counter, ==, 1);
799
800
- bdrv_subtree_drained_end(parent_b);
801
+ bdrv_drained_end(parent_b);
802
+ bdrv_drained_end(a);
803
+ bdrv_drained_end(b);
804
+ bdrv_drained_end(c);
805
806
bdrv_unref(parent_b);
807
blk_unref(blk);
808
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
809
810
g_test_add_func("/bdrv-drain/driver-cb/drain_all", test_drv_cb_drain_all);
811
g_test_add_func("/bdrv-drain/driver-cb/drain", test_drv_cb_drain);
812
- g_test_add_func("/bdrv-drain/driver-cb/drain_subtree",
813
- test_drv_cb_drain_subtree);
814
815
g_test_add_func("/bdrv-drain/driver-cb/co/drain_all",
816
test_drv_cb_co_drain_all);
817
g_test_add_func("/bdrv-drain/driver-cb/co/drain", test_drv_cb_co_drain);
818
- g_test_add_func("/bdrv-drain/driver-cb/co/drain_subtree",
819
- test_drv_cb_co_drain_subtree);
820
-
821
822
g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all);
823
g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain);
824
- g_test_add_func("/bdrv-drain/quiesce/drain_subtree",
825
- test_quiesce_drain_subtree);
826
827
g_test_add_func("/bdrv-drain/quiesce/co/drain_all",
828
test_quiesce_co_drain_all);
829
g_test_add_func("/bdrv-drain/quiesce/co/drain", test_quiesce_co_drain);
830
- g_test_add_func("/bdrv-drain/quiesce/co/drain_subtree",
831
- test_quiesce_co_drain_subtree);
832
833
g_test_add_func("/bdrv-drain/nested", test_nested);
834
- g_test_add_func("/bdrv-drain/multiparent", test_multiparent);
835
836
- g_test_add_func("/bdrv-drain/graph-change/drain_subtree",
837
- test_graph_change_drain_subtree);
838
g_test_add_func("/bdrv-drain/graph-change/drain_all",
839
test_graph_change_drain_all);
840
841
g_test_add_func("/bdrv-drain/iothread/drain_all", test_iothread_drain_all);
842
g_test_add_func("/bdrv-drain/iothread/drain", test_iothread_drain);
843
- g_test_add_func("/bdrv-drain/iothread/drain_subtree",
844
- test_iothread_drain_subtree);
845
846
g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all);
847
g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain);
848
- g_test_add_func("/bdrv-drain/blockjob/drain_subtree",
849
- test_blockjob_drain_subtree);
850
851
g_test_add_func("/bdrv-drain/blockjob/error/drain_all",
852
test_blockjob_error_drain_all);
853
g_test_add_func("/bdrv-drain/blockjob/error/drain",
854
test_blockjob_error_drain);
855
- g_test_add_func("/bdrv-drain/blockjob/error/drain_subtree",
856
- test_blockjob_error_drain_subtree);
857
858
g_test_add_func("/bdrv-drain/blockjob/iothread/drain_all",
859
test_blockjob_iothread_drain_all);
860
g_test_add_func("/bdrv-drain/blockjob/iothread/drain",
861
test_blockjob_iothread_drain);
862
- g_test_add_func("/bdrv-drain/blockjob/iothread/drain_subtree",
863
- test_blockjob_iothread_drain_subtree);
864
865
g_test_add_func("/bdrv-drain/blockjob/iothread/error/drain_all",
866
test_blockjob_iothread_error_drain_all);
867
g_test_add_func("/bdrv-drain/blockjob/iothread/error/drain",
868
test_blockjob_iothread_error_drain);
869
- g_test_add_func("/bdrv-drain/blockjob/iothread/error/drain_subtree",
870
- test_blockjob_iothread_error_drain_subtree);
871
872
g_test_add_func("/bdrv-drain/deletion/drain", test_delete_by_drain);
873
g_test_add_func("/bdrv-drain/detach/drain_all", test_detach_by_drain_all);
874
g_test_add_func("/bdrv-drain/detach/drain", test_detach_by_drain);
875
- g_test_add_func("/bdrv-drain/detach/drain_subtree", test_detach_by_drain_subtree);
876
g_test_add_func("/bdrv-drain/detach/parent_cb", test_detach_by_parent_cb);
877
g_test_add_func("/bdrv-drain/detach/driver_cb", test_detach_by_driver_cb);
878
879
--
880
2.38.1
diff view generated by jsdifflib
1
If read-only=off, but auto-read-only=on is given, open a read-write NBD
1
We only need to call both the BlockDriver's callback and the parent
2
connection if the server provides a read-write export, but instead of
2
callbacks when going from undrained to drained or vice versa. A second
3
erroring out for read-only exports, just degrade to read-only.
3
drain section doesn't make a difference for the driver or the parent,
4
they weren't supposed to send new requests before and after the second
5
drain.
6
7
One thing that gets in the way is the 'ignore_bds_parents' parameter in
8
bdrv_do_drained_begin_quiesce() and bdrv_do_drained_end(): It means that
9
bdrv_drain_all_begin() increases bs->quiesce_counter, but does not
10
quiesce the parent through BdrvChildClass callbacks. If an additional
11
drain section is started now, bs->quiesce_counter will be non-zero, but
12
we would still need to quiesce the parent through BdrvChildClass in
13
order to keep things consistent (and unquiesce it on the matching
14
bdrv_drained_end(), even though the counter would not reach 0 yet as
15
long as the bdrv_drain_all() section is still active).
16
17
Instead of keeping track of this, let's just get rid of the parameter.
18
It was introduced in commit 6cd5c9d7b2d as an optimisation so that
19
during bdrv_drain_all(), we wouldn't recursively drain all parents up to
20
the root for each node, resulting in quadratic complexity. As it happens,
21
calling the callbacks only once solves the same problem, so as of this
22
patch, we'll still have O(n) complexity and ignore_bds_parents is not
23
needed any more.
24
25
This patch only ignores the 'ignore_bds_parents' parameter. It will be
26
removed in a separate patch.
4
27
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
28
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
29
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
30
Message-Id: <20221118174110.55183-12-kwolf@redhat.com>
31
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
32
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
33
---
8
block/nbd-client.c | 10 +++++-----
34
include/block/block_int-common.h | 8 ++++----
9
1 file changed, 5 insertions(+), 5 deletions(-)
35
block.c | 25 +++++++------------------
10
36
block/io.c | 30 ++++++++++++++++++------------
11
diff --git a/block/nbd-client.c b/block/nbd-client.c
37
tests/unit/test-bdrv-drain.c | 16 ++++++++++------
12
index XXXXXXX..XXXXXXX 100644
38
4 files changed, 39 insertions(+), 40 deletions(-)
13
--- a/block/nbd-client.c
39
14
+++ b/block/nbd-client.c
40
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
15
@@ -XXX,XX +XXX,XX @@ int nbd_client_init(BlockDriverState *bs,
41
index XXXXXXX..XXXXXXX 100644
16
logout("Failed to negotiate with the NBD server\n");
42
--- a/include/block/block_int-common.h
17
return ret;
43
+++ b/include/block/block_int-common.h
18
}
44
@@ -XXX,XX +XXX,XX @@ struct BdrvChild {
19
- if (client->info.flags & NBD_FLAG_READ_ONLY &&
45
bool frozen;
20
- !bdrv_is_read_only(bs)) {
46
21
- error_setg(errp,
47
/*
22
- "request for write access conflicts with read-only export");
48
- * How many times the parent of this child has been drained
23
- return -EACCES;
49
+ * True if the parent of this child has been drained by this BdrvChild
24
+ if (client->info.flags & NBD_FLAG_READ_ONLY) {
50
* (through klass->drained_*).
25
+ ret = bdrv_apply_auto_read_only(bs, "NBD export is read-only", errp);
51
- * Usually, this is equal to bs->quiesce_counter (potentially
26
+ if (ret < 0) {
52
- * reduced by bdrv_drain_all_count). It may differ while the
27
+ return ret;
53
+ *
54
+ * It is generally true if bs->quiesce_counter > 0. It may differ while the
55
* child is entering or leaving a drained section.
56
*/
57
- int parent_quiesce_counter;
58
+ bool quiesced_parent;
59
60
QLIST_ENTRY(BdrvChild) next;
61
QLIST_ENTRY(BdrvChild) next_parent;
62
diff --git a/block.c b/block.c
63
index XXXXXXX..XXXXXXX 100644
64
--- a/block.c
65
+++ b/block.c
66
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child,
67
{
68
BlockDriverState *old_bs = child->bs;
69
int new_bs_quiesce_counter;
70
- int drain_saldo;
71
72
assert(!child->frozen);
73
assert(old_bs != new_bs);
74
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child,
75
assert(bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs));
76
}
77
78
- new_bs_quiesce_counter = (new_bs ? new_bs->quiesce_counter : 0);
79
- drain_saldo = new_bs_quiesce_counter - child->parent_quiesce_counter;
80
-
81
/*
82
* If the new child node is drained but the old one was not, flush
83
* all outstanding requests to the old child node.
84
*/
85
- while (drain_saldo > 0 && child->klass->drained_begin) {
86
+ new_bs_quiesce_counter = (new_bs ? new_bs->quiesce_counter : 0);
87
+ if (new_bs_quiesce_counter && !child->quiesced_parent) {
88
bdrv_parent_drained_begin_single(child, true);
89
- drain_saldo--;
90
}
91
92
if (old_bs) {
93
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child,
94
if (new_bs) {
95
assert_bdrv_graph_writable(new_bs);
96
QLIST_INSERT_HEAD(&new_bs->parents, child, next_parent);
97
-
98
- /*
99
- * Polling in bdrv_parent_drained_begin_single() may have led to the new
100
- * node's quiesce_counter having been decreased. Not a problem, we just
101
- * need to recognize this here and then invoke drained_end appropriately
102
- * more often.
103
- */
104
- assert(new_bs->quiesce_counter <= new_bs_quiesce_counter);
105
- drain_saldo += new_bs->quiesce_counter - new_bs_quiesce_counter;
106
-
107
if (child->klass->attach) {
108
child->klass->attach(child);
109
}
110
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child,
111
/*
112
* If the old child node was drained but the new one is not, allow
113
* requests to come in only after the new node has been attached.
114
+ *
115
+ * Update new_bs_quiesce_counter because bdrv_parent_drained_begin_single()
116
+ * polls, which could have changed the value.
117
*/
118
- while (drain_saldo < 0 && child->klass->drained_end) {
119
+ new_bs_quiesce_counter = (new_bs ? new_bs->quiesce_counter : 0);
120
+ if (!new_bs_quiesce_counter && child->quiesced_parent) {
121
bdrv_parent_drained_end_single(child);
122
- drain_saldo++;
123
}
124
}
125
126
diff --git a/block/io.c b/block/io.c
127
index XXXXXXX..XXXXXXX 100644
128
--- a/block/io.c
129
+++ b/block/io.c
130
@@ -XXX,XX +XXX,XX @@ void bdrv_parent_drained_end_single(BdrvChild *c)
131
{
132
IO_OR_GS_CODE();
133
134
- assert(c->parent_quiesce_counter > 0);
135
- c->parent_quiesce_counter--;
136
+ assert(c->quiesced_parent);
137
+ c->quiesced_parent = false;
138
+
139
if (c->klass->drained_end) {
140
c->klass->drained_end(c);
141
}
142
@@ -XXX,XX +XXX,XX @@ void bdrv_parent_drained_begin_single(BdrvChild *c, bool poll)
143
{
144
AioContext *ctx = bdrv_child_get_parent_aio_context(c);
145
IO_OR_GS_CODE();
146
- c->parent_quiesce_counter++;
147
+
148
+ assert(!c->quiesced_parent);
149
+ c->quiesced_parent = true;
150
+
151
if (c->klass->drained_begin) {
152
c->klass->drained_begin(c);
153
}
154
@@ -XXX,XX +XXX,XX @@ void bdrv_do_drained_begin_quiesce(BlockDriverState *bs,
155
/* Stop things in parent-to-child order */
156
if (qatomic_fetch_inc(&bs->quiesce_counter) == 0) {
157
aio_disable_external(bdrv_get_aio_context(bs));
158
- }
159
160
- bdrv_parent_drained_begin(bs, parent, ignore_bds_parents);
161
- if (bs->drv && bs->drv->bdrv_drain_begin) {
162
- bs->drv->bdrv_drain_begin(bs);
163
+ /* TODO Remove ignore_bds_parents, we don't consider it any more */
164
+ bdrv_parent_drained_begin(bs, parent, false);
165
+ if (bs->drv && bs->drv->bdrv_drain_begin) {
166
+ bs->drv->bdrv_drain_begin(bs);
28
+ }
167
+ }
29
}
168
}
30
if (client->info.flags & NBD_FLAG_SEND_FUA) {
169
}
31
bs->supported_write_flags = BDRV_REQ_FUA;
170
171
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent,
172
assert(bs->quiesce_counter > 0);
173
174
/* Re-enable things in child-to-parent order */
175
- if (bs->drv && bs->drv->bdrv_drain_end) {
176
- bs->drv->bdrv_drain_end(bs);
177
- }
178
- bdrv_parent_drained_end(bs, parent, ignore_bds_parents);
179
-
180
old_quiesce_counter = qatomic_fetch_dec(&bs->quiesce_counter);
181
if (old_quiesce_counter == 1) {
182
+ if (bs->drv && bs->drv->bdrv_drain_end) {
183
+ bs->drv->bdrv_drain_end(bs);
184
+ }
185
+ /* TODO Remove ignore_bds_parents, we don't consider it any more */
186
+ bdrv_parent_drained_end(bs, parent, false);
187
+
188
aio_enable_external(bdrv_get_aio_context(bs));
189
}
190
}
191
diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c
192
index XXXXXXX..XXXXXXX 100644
193
--- a/tests/unit/test-bdrv-drain.c
194
+++ b/tests/unit/test-bdrv-drain.c
195
@@ -XXX,XX +XXX,XX @@ static void test_quiesce_common(enum drain_type drain_type, bool recursive)
196
197
do_drain_begin(drain_type, bs);
198
199
- g_assert_cmpint(bs->quiesce_counter, ==, 1);
200
+ if (drain_type == BDRV_DRAIN_ALL) {
201
+ g_assert_cmpint(bs->quiesce_counter, ==, 2);
202
+ } else {
203
+ g_assert_cmpint(bs->quiesce_counter, ==, 1);
204
+ }
205
g_assert_cmpint(backing->quiesce_counter, ==, !!recursive);
206
207
do_drain_end(drain_type, bs);
208
@@ -XXX,XX +XXX,XX @@ static void test_nested(void)
209
210
for (outer = 0; outer < DRAIN_TYPE_MAX; outer++) {
211
for (inner = 0; inner < DRAIN_TYPE_MAX; inner++) {
212
- int backing_quiesce = (outer != BDRV_DRAIN) +
213
- (inner != BDRV_DRAIN);
214
+ int backing_quiesce = (outer == BDRV_DRAIN_ALL) +
215
+ (inner == BDRV_DRAIN_ALL);
216
217
g_assert_cmpint(bs->quiesce_counter, ==, 0);
218
g_assert_cmpint(backing->quiesce_counter, ==, 0);
219
@@ -XXX,XX +XXX,XX @@ static void test_nested(void)
220
do_drain_begin(outer, bs);
221
do_drain_begin(inner, bs);
222
223
- g_assert_cmpint(bs->quiesce_counter, ==, 2);
224
+ g_assert_cmpint(bs->quiesce_counter, ==, 2 + !!backing_quiesce);
225
g_assert_cmpint(backing->quiesce_counter, ==, backing_quiesce);
226
- g_assert_cmpint(s->drain_count, ==, 2);
227
- g_assert_cmpint(backing_s->drain_count, ==, backing_quiesce);
228
+ g_assert_cmpint(s->drain_count, ==, 1);
229
+ g_assert_cmpint(backing_s->drain_count, ==, !!backing_quiesce);
230
231
do_drain_end(inner, bs);
232
do_drain_end(outer, bs);
32
--
233
--
33
2.19.1
234
2.38.1
34
35
diff view generated by jsdifflib
New patch
1
ignore_bds_parents is now ignored during drain_begin and drain_end, so
2
we can just remove it there. It is still a valid optimisation for
3
drain_all in bdrv_drained_poll(), so leave it around there.
1
4
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Message-Id: <20221118174110.55183-13-kwolf@redhat.com>
7
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
8
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
include/block/block-io.h | 3 +--
12
block.c | 2 +-
13
block/io.c | 58 +++++++++++++++-------------------------
14
3 files changed, 24 insertions(+), 39 deletions(-)
15
16
diff --git a/include/block/block-io.h b/include/block/block-io.h
17
index XXXXXXX..XXXXXXX 100644
18
--- a/include/block/block-io.h
19
+++ b/include/block/block-io.h
20
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs);
21
* Quiesces a BDS like bdrv_drained_begin(), but does not wait for already
22
* running requests to complete.
23
*/
24
-void bdrv_do_drained_begin_quiesce(BlockDriverState *bs,
25
- BdrvChild *parent, bool ignore_bds_parents);
26
+void bdrv_do_drained_begin_quiesce(BlockDriverState *bs, BdrvChild *parent);
27
28
/**
29
* bdrv_drained_end:
30
diff --git a/block.c b/block.c
31
index XXXXXXX..XXXXXXX 100644
32
--- a/block.c
33
+++ b/block.c
34
@@ -XXX,XX +XXX,XX @@ static char *bdrv_child_get_parent_desc(BdrvChild *c)
35
static void bdrv_child_cb_drained_begin(BdrvChild *child)
36
{
37
BlockDriverState *bs = child->opaque;
38
- bdrv_do_drained_begin_quiesce(bs, NULL, false);
39
+ bdrv_do_drained_begin_quiesce(bs, NULL);
40
}
41
42
static bool bdrv_child_cb_drained_poll(BdrvChild *child)
43
diff --git a/block/io.c b/block/io.c
44
index XXXXXXX..XXXXXXX 100644
45
--- a/block/io.c
46
+++ b/block/io.c
47
@@ -XXX,XX +XXX,XX @@ static void bdrv_parent_cb_resize(BlockDriverState *bs);
48
static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
49
int64_t offset, int64_t bytes, BdrvRequestFlags flags);
50
51
-static void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore,
52
- bool ignore_bds_parents)
53
+static void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore)
54
{
55
BdrvChild *c, *next;
56
57
QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) {
58
- if (c == ignore || (ignore_bds_parents && c->klass->parent_is_bds)) {
59
+ if (c == ignore) {
60
continue;
61
}
62
bdrv_parent_drained_begin_single(c, false);
63
@@ -XXX,XX +XXX,XX @@ void bdrv_parent_drained_end_single(BdrvChild *c)
64
}
65
}
66
67
-static void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore,
68
- bool ignore_bds_parents)
69
+static void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore)
70
{
71
BdrvChild *c;
72
73
QLIST_FOREACH(c, &bs->parents, next_parent) {
74
- if (c == ignore || (ignore_bds_parents && c->klass->parent_is_bds)) {
75
+ if (c == ignore) {
76
continue;
77
}
78
bdrv_parent_drained_end_single(c);
79
@@ -XXX,XX +XXX,XX @@ typedef struct {
80
bool begin;
81
bool poll;
82
BdrvChild *parent;
83
- bool ignore_bds_parents;
84
} BdrvCoDrainData;
85
86
/* Returns true if BDRV_POLL_WHILE() should go into a blocking aio_poll() */
87
@@ -XXX,XX +XXX,XX @@ static bool bdrv_drain_poll_top_level(BlockDriverState *bs,
88
}
89
90
static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent,
91
- bool ignore_bds_parents, bool poll);
92
-static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent,
93
- bool ignore_bds_parents);
94
+ bool poll);
95
+static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent);
96
97
static void bdrv_co_drain_bh_cb(void *opaque)
98
{
99
@@ -XXX,XX +XXX,XX @@ static void bdrv_co_drain_bh_cb(void *opaque)
100
aio_context_acquire(ctx);
101
bdrv_dec_in_flight(bs);
102
if (data->begin) {
103
- bdrv_do_drained_begin(bs, data->parent, data->ignore_bds_parents,
104
- data->poll);
105
+ bdrv_do_drained_begin(bs, data->parent, data->poll);
106
} else {
107
assert(!data->poll);
108
- bdrv_do_drained_end(bs, data->parent, data->ignore_bds_parents);
109
+ bdrv_do_drained_end(bs, data->parent);
110
}
111
aio_context_release(ctx);
112
} else {
113
@@ -XXX,XX +XXX,XX @@ static void bdrv_co_drain_bh_cb(void *opaque)
114
static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
115
bool begin,
116
BdrvChild *parent,
117
- bool ignore_bds_parents,
118
bool poll)
119
{
120
BdrvCoDrainData data;
121
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
122
.done = false,
123
.begin = begin,
124
.parent = parent,
125
- .ignore_bds_parents = ignore_bds_parents,
126
.poll = poll,
127
};
128
129
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
130
}
131
}
132
133
-void bdrv_do_drained_begin_quiesce(BlockDriverState *bs,
134
- BdrvChild *parent, bool ignore_bds_parents)
135
+void bdrv_do_drained_begin_quiesce(BlockDriverState *bs, BdrvChild *parent)
136
{
137
IO_OR_GS_CODE();
138
assert(!qemu_in_coroutine());
139
@@ -XXX,XX +XXX,XX @@ void bdrv_do_drained_begin_quiesce(BlockDriverState *bs,
140
/* Stop things in parent-to-child order */
141
if (qatomic_fetch_inc(&bs->quiesce_counter) == 0) {
142
aio_disable_external(bdrv_get_aio_context(bs));
143
-
144
- /* TODO Remove ignore_bds_parents, we don't consider it any more */
145
- bdrv_parent_drained_begin(bs, parent, false);
146
+ bdrv_parent_drained_begin(bs, parent);
147
if (bs->drv && bs->drv->bdrv_drain_begin) {
148
bs->drv->bdrv_drain_begin(bs);
149
}
150
@@ -XXX,XX +XXX,XX @@ void bdrv_do_drained_begin_quiesce(BlockDriverState *bs,
151
}
152
153
static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent,
154
- bool ignore_bds_parents, bool poll)
155
+ bool poll)
156
{
157
if (qemu_in_coroutine()) {
158
- bdrv_co_yield_to_drain(bs, true, parent, ignore_bds_parents, poll);
159
+ bdrv_co_yield_to_drain(bs, true, parent, poll);
160
return;
161
}
162
163
- bdrv_do_drained_begin_quiesce(bs, parent, ignore_bds_parents);
164
+ bdrv_do_drained_begin_quiesce(bs, parent);
165
166
/*
167
* Wait for drained requests to finish.
168
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent,
169
* nodes.
170
*/
171
if (poll) {
172
- assert(!ignore_bds_parents);
173
BDRV_POLL_WHILE(bs, bdrv_drain_poll_top_level(bs, parent));
174
}
175
}
176
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent,
177
void bdrv_drained_begin(BlockDriverState *bs)
178
{
179
IO_OR_GS_CODE();
180
- bdrv_do_drained_begin(bs, NULL, false, true);
181
+ bdrv_do_drained_begin(bs, NULL, true);
182
}
183
184
/**
185
* This function does not poll, nor must any of its recursively called
186
* functions.
187
*/
188
-static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent,
189
- bool ignore_bds_parents)
190
+static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent)
191
{
192
int old_quiesce_counter;
193
194
if (qemu_in_coroutine()) {
195
- bdrv_co_yield_to_drain(bs, false, parent, ignore_bds_parents, false);
196
+ bdrv_co_yield_to_drain(bs, false, parent, false);
197
return;
198
}
199
assert(bs->quiesce_counter > 0);
200
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent,
201
if (bs->drv && bs->drv->bdrv_drain_end) {
202
bs->drv->bdrv_drain_end(bs);
203
}
204
- /* TODO Remove ignore_bds_parents, we don't consider it any more */
205
- bdrv_parent_drained_end(bs, parent, false);
206
-
207
+ bdrv_parent_drained_end(bs, parent);
208
aio_enable_external(bdrv_get_aio_context(bs));
209
}
210
}
211
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent,
212
void bdrv_drained_end(BlockDriverState *bs)
213
{
214
IO_OR_GS_CODE();
215
- bdrv_do_drained_end(bs, NULL, false);
216
+ bdrv_do_drained_end(bs, NULL);
217
}
218
219
void bdrv_drain(BlockDriverState *bs)
220
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
221
GLOBAL_STATE_CODE();
222
223
if (qemu_in_coroutine()) {
224
- bdrv_co_yield_to_drain(NULL, true, NULL, true, true);
225
+ bdrv_co_yield_to_drain(NULL, true, NULL, true);
226
return;
227
}
228
229
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
230
AioContext *aio_context = bdrv_get_aio_context(bs);
231
232
aio_context_acquire(aio_context);
233
- bdrv_do_drained_begin(bs, NULL, true, false);
234
+ bdrv_do_drained_begin(bs, NULL, false);
235
aio_context_release(aio_context);
236
}
237
238
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end_quiesce(BlockDriverState *bs)
239
g_assert(!bs->refcnt);
240
241
while (bs->quiesce_counter) {
242
- bdrv_do_drained_end(bs, NULL, true);
243
+ bdrv_do_drained_end(bs, NULL);
244
}
245
}
246
247
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
248
AioContext *aio_context = bdrv_get_aio_context(bs);
249
250
aio_context_acquire(aio_context);
251
- bdrv_do_drained_end(bs, NULL, true);
252
+ bdrv_do_drained_end(bs, NULL);
253
aio_context_release(aio_context);
254
}
255
256
--
257
2.38.1
diff view generated by jsdifflib
1
From: Li Qiang <liq3ea@163.com>
1
The next patch adds a parent drain to bdrv_attach_child_common(), which
2
shouldn't be, but is currently called from coroutines in some cases (e.g.
3
.bdrv_co_create implementations generally open new nodes). Therefore,
4
the assertion that we're not in a coroutine doesn't hold true any more.
2
5
3
Signed-off-by: Li Qiang <liq3ea@163.com>
6
We could just remove the assertion because there is nothing in the
4
Reviewed-by: Alberto Garcia <berto@igalia.com>
7
function that should be in conflict with running in a coroutine, but
8
just to be on the safe side, we can reverse the caller relationship
9
between bdrv_do_drained_begin() and bdrv_do_drained_begin_quiesce() so
10
that the latter also just drops out of coroutine context and we can
11
still be certain in the future that any drain code doesn't run in
12
coroutines.
13
14
As a nice side effect, the structure of bdrv_do_drained_begin() is now
15
symmetrical with bdrv_do_drained_end().
16
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
Message-Id: <20221118174110.55183-14-kwolf@redhat.com>
19
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
20
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
21
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
22
---
7
include/sysemu/block-backend.h | 6 +++---
23
block/io.c | 25 ++++++++++++-------------
8
block/block-backend.c | 8 ++++----
24
1 file changed, 12 insertions(+), 13 deletions(-)
9
2 files changed, 7 insertions(+), 7 deletions(-)
10
25
11
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
26
diff --git a/block/io.c b/block/io.c
12
index XXXXXXX..XXXXXXX 100644
27
index XXXXXXX..XXXXXXX 100644
13
--- a/include/sysemu/block-backend.h
28
--- a/block/io.c
14
+++ b/include/sysemu/block-backend.h
29
+++ b/block/io.c
15
@@ -XXX,XX +XXX,XX @@ BlockErrorAction blk_get_error_action(BlockBackend *blk, bool is_read,
30
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
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
29
index XXXXXXX..XXXXXXX 100644
30
--- a/block/block-backend.c
31
+++ b/block/block-backend.c
32
@@ -XXX,XX +XXX,XX @@ void blk_error_action(BlockBackend *blk, BlockErrorAction action,
33
}
31
}
34
}
32
}
35
33
36
-int blk_is_read_only(BlockBackend *blk)
34
-void bdrv_do_drained_begin_quiesce(BlockDriverState *bs, BdrvChild *parent)
37
+bool blk_is_read_only(BlockBackend *blk)
35
+static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent,
36
+ bool poll)
38
{
37
{
39
BlockDriverState *bs = blk_bs(blk);
38
IO_OR_GS_CODE();
40
39
- assert(!qemu_in_coroutine());
41
@@ -XXX,XX +XXX,XX @@ int blk_is_read_only(BlockBackend *blk)
40
+
41
+ if (qemu_in_coroutine()) {
42
+ bdrv_co_yield_to_drain(bs, true, parent, poll);
43
+ return;
44
+ }
45
46
/* Stop things in parent-to-child order */
47
if (qatomic_fetch_inc(&bs->quiesce_counter) == 0) {
48
@@ -XXX,XX +XXX,XX @@ void bdrv_do_drained_begin_quiesce(BlockDriverState *bs, BdrvChild *parent)
49
bs->drv->bdrv_drain_begin(bs);
50
}
51
}
52
-}
53
-
54
-static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent,
55
- bool poll)
56
-{
57
- if (qemu_in_coroutine()) {
58
- bdrv_co_yield_to_drain(bs, true, parent, poll);
59
- return;
60
- }
61
-
62
- bdrv_do_drained_begin_quiesce(bs, parent);
63
64
/*
65
* Wait for drained requests to finish.
66
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent,
42
}
67
}
43
}
68
}
44
69
45
-int blk_is_sg(BlockBackend *blk)
70
+void bdrv_do_drained_begin_quiesce(BlockDriverState *bs, BdrvChild *parent)
46
+bool blk_is_sg(BlockBackend *blk)
71
+{
72
+ bdrv_do_drained_begin(bs, parent, false);
73
+}
74
+
75
void bdrv_drained_begin(BlockDriverState *bs)
47
{
76
{
48
BlockDriverState *bs = blk_bs(blk);
77
IO_OR_GS_CODE();
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
--
78
--
64
2.19.1
79
2.38.1
65
66
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
In order to make sure that bdrv_replace_child_noperm() doesn't have to
2
2
poll any more, get rid of the bdrv_parent_drained_begin_single() call.
3
The blkverify mode of Quorum only works when the number of children is
3
4
exactly two, so any attempt to add a new one must return an error.
4
This is possible now because we can require that the parent is already
5
5
drained through the child in question when the function is called and we
6
quorum_del_child() on the other hand doesn't need any additional check
6
don't call the parent drain callbacks more than once.
7
because decreasing the number of children would make it go under the
7
8
vote threshold.
8
The additional drain calls needed in callers cause the test case to run
9
9
its code in the drain handler too early (bdrv_attach_child() drains
10
Signed-off-by: Alberto Garcia <berto@igalia.com>
10
now), so modify it to only enable the code after the test setup has
11
Reported-by: Kevin Wolf <kwolf@redhat.com>
11
completed.
12
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Message-Id: <20221118174110.55183-15-kwolf@redhat.com>
15
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
16
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
18
---
14
block/quorum.c | 8 ++++++++
19
include/block/block-io.h | 8 +++
15
1 file changed, 8 insertions(+)
20
block.c | 103 ++++++++++++++++++++++++++++++-----
16
21
block/io.c | 2 +-
17
diff --git a/block/quorum.c b/block/quorum.c
22
tests/unit/test-bdrv-drain.c | 10 ++++
18
index XXXXXXX..XXXXXXX 100644
23
4 files changed, 108 insertions(+), 15 deletions(-)
19
--- a/block/quorum.c
24
20
+++ b/block/quorum.c
25
diff --git a/include/block/block-io.h b/include/block/block-io.h
21
@@ -XXX,XX +XXX,XX @@ static void quorum_add_child(BlockDriverState *bs, BlockDriverState *child_bs,
26
index XXXXXXX..XXXXXXX 100644
22
char indexstr[32];
27
--- a/include/block/block-io.h
23
int ret;
28
+++ b/include/block/block-io.h
24
29
@@ -XXX,XX +XXX,XX @@ bdrv_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos);
25
+ if (s->is_blkverify) {
30
*/
26
+ error_setg(errp, "Cannot add a child to a quorum in blkverify mode");
31
void bdrv_parent_drained_begin_single(BdrvChild *c, bool poll);
32
33
+/**
34
+ * bdrv_parent_drained_poll_single:
35
+ *
36
+ * Returns true if there is any pending activity to cease before @c can be
37
+ * called quiesced, false otherwise.
38
+ */
39
+bool bdrv_parent_drained_poll_single(BdrvChild *c);
40
+
41
/**
42
* bdrv_parent_drained_end_single:
43
*
44
diff --git a/block.c b/block.c
45
index XXXXXXX..XXXXXXX 100644
46
--- a/block.c
47
+++ b/block.c
48
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_abort(void *opaque)
49
50
GLOBAL_STATE_CODE();
51
/* old_bs reference is transparently moved from @s to @s->child */
52
+ if (!s->child->bs) {
53
+ /*
54
+ * The parents were undrained when removing old_bs from the child. New
55
+ * requests can't have been made, though, because the child was empty.
56
+ *
57
+ * TODO Make bdrv_replace_child_noperm() transactionable to avoid
58
+ * undraining the parent in the first place. Once this is done, having
59
+ * new_bs drained when calling bdrv_replace_child_tran() is not a
60
+ * requirement any more.
61
+ */
62
+ bdrv_parent_drained_begin_single(s->child, false);
63
+ assert(!bdrv_parent_drained_poll_single(s->child));
64
+ }
65
+ assert(s->child->quiesced_parent);
66
bdrv_replace_child_noperm(s->child, s->old_bs);
67
bdrv_unref(new_bs);
68
}
69
@@ -XXX,XX +XXX,XX @@ static TransactionActionDrv bdrv_replace_child_drv = {
70
*
71
* Note: real unref of old_bs is done only on commit.
72
*
73
+ * Both @child->bs and @new_bs (if non-NULL) must be drained. @new_bs must be
74
+ * kept drained until the transaction is completed.
75
+ *
76
* The function doesn't update permissions, caller is responsible for this.
77
*/
78
static void bdrv_replace_child_tran(BdrvChild *child, BlockDriverState *new_bs,
79
Transaction *tran)
80
{
81
BdrvReplaceChildState *s = g_new(BdrvReplaceChildState, 1);
82
+
83
+ assert(child->quiesced_parent);
84
+ assert(!new_bs || new_bs->quiesce_counter);
85
+
86
*s = (BdrvReplaceChildState) {
87
.child = child,
88
.old_bs = child->bs,
89
@@ -XXX,XX +XXX,XX @@ uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm)
90
return permissions[qapi_perm];
91
}
92
93
+/*
94
+ * Replaces the node that a BdrvChild points to without updating permissions.
95
+ *
96
+ * If @new_bs is non-NULL, the parent of @child must already be drained through
97
+ * @child.
98
+ *
99
+ * This function does not poll.
100
+ */
101
static void bdrv_replace_child_noperm(BdrvChild *child,
102
BlockDriverState *new_bs)
103
{
104
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child,
105
int new_bs_quiesce_counter;
106
107
assert(!child->frozen);
108
+
109
+ /*
110
+ * If we want to change the BdrvChild to point to a drained node as its new
111
+ * child->bs, we need to make sure that its new parent is drained, too. In
112
+ * other words, either child->quiesce_parent must already be true or we must
113
+ * be able to set it and keep the parent's quiesce_counter consistent with
114
+ * that, but without polling or starting new requests (this function
115
+ * guarantees that it doesn't poll, and starting new requests would be
116
+ * against the invariants of drain sections).
117
+ *
118
+ * To keep things simple, we pick the first option (child->quiesce_parent
119
+ * must already be true). We also generalise the rule a bit to make it
120
+ * easier to verify in callers and more likely to be covered in test cases:
121
+ * The parent must be quiesced through this child even if new_bs isn't
122
+ * currently drained.
123
+ *
124
+ * The only exception is for callers that always pass new_bs == NULL. In
125
+ * this case, we obviously never need to consider the case of a drained
126
+ * new_bs, so we can keep the callers simpler by allowing them not to drain
127
+ * the parent.
128
+ */
129
+ assert(!new_bs || child->quiesced_parent);
130
assert(old_bs != new_bs);
131
GLOBAL_STATE_CODE();
132
133
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child,
134
assert(bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs));
135
}
136
137
- /*
138
- * If the new child node is drained but the old one was not, flush
139
- * all outstanding requests to the old child node.
140
- */
141
- new_bs_quiesce_counter = (new_bs ? new_bs->quiesce_counter : 0);
142
- if (new_bs_quiesce_counter && !child->quiesced_parent) {
143
- bdrv_parent_drained_begin_single(child, true);
144
- }
145
-
146
if (old_bs) {
147
if (child->klass->detach) {
148
child->klass->detach(child);
149
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child,
150
}
151
152
/*
153
- * If the old child node was drained but the new one is not, allow
154
- * requests to come in only after the new node has been attached.
155
- *
156
- * Update new_bs_quiesce_counter because bdrv_parent_drained_begin_single()
157
- * polls, which could have changed the value.
158
+ * If the parent was drained through this BdrvChild previously, but new_bs
159
+ * is not drained, allow requests to come in only after the new node has
160
+ * been attached.
161
*/
162
new_bs_quiesce_counter = (new_bs ? new_bs->quiesce_counter : 0);
163
if (!new_bs_quiesce_counter && child->quiesced_parent) {
164
@@ -XXX,XX +XXX,XX @@ static BdrvChild *bdrv_attach_child_common(BlockDriverState *child_bs,
165
}
166
167
bdrv_ref(child_bs);
168
+ /*
169
+ * Let every new BdrvChild start with a drained parent. Inserting the child
170
+ * in the graph with bdrv_replace_child_noperm() will undrain it if
171
+ * @child_bs is not drained.
172
+ *
173
+ * The child was only just created and is not yet visible in global state
174
+ * until bdrv_replace_child_noperm() inserts it into the graph, so nobody
175
+ * could have sent requests and polling is not necessary.
176
+ *
177
+ * Note that this means that the parent isn't fully drained yet, we only
178
+ * stop new requests from coming in. This is fine, we don't care about the
179
+ * old requests here, they are not for this child. If another place enters a
180
+ * drain section for the same parent, but wants it to be fully quiesced, it
181
+ * will not run most of the the code in .drained_begin() again (which is not
182
+ * a problem, we already did this), but it will still poll until the parent
183
+ * is fully quiesced, so it will not be negatively affected either.
184
+ */
185
+ bdrv_parent_drained_begin_single(new_child, false);
186
bdrv_replace_child_noperm(new_child, child_bs);
187
188
BdrvAttachChildCommonState *s = g_new(BdrvAttachChildCommonState, 1);
189
@@ -XXX,XX +XXX,XX @@ static void bdrv_remove_child(BdrvChild *child, Transaction *tran)
190
}
191
192
if (child->bs) {
193
+ BlockDriverState *bs = child->bs;
194
+ bdrv_drained_begin(bs);
195
bdrv_replace_child_tran(child, NULL, tran);
196
+ bdrv_drained_end(bs);
197
}
198
199
tran_add(tran, &bdrv_remove_child_drv, child);
200
}
201
202
+static void undrain_on_clean_cb(void *opaque)
203
+{
204
+ bdrv_drained_end(opaque);
205
+}
206
+
207
+static TransactionActionDrv undrain_on_clean = {
208
+ .clean = undrain_on_clean_cb,
209
+};
210
+
211
static int bdrv_replace_node_noperm(BlockDriverState *from,
212
BlockDriverState *to,
213
bool auto_skip, Transaction *tran,
214
@@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_noperm(BlockDriverState *from,
215
216
GLOBAL_STATE_CODE();
217
218
+ bdrv_drained_begin(from);
219
+ bdrv_drained_begin(to);
220
+ tran_add(tran, &undrain_on_clean, from);
221
+ tran_add(tran, &undrain_on_clean, to);
222
+
223
QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) {
224
assert(c->bs == from);
225
if (!should_update_child(c, to)) {
226
diff --git a/block/io.c b/block/io.c
227
index XXXXXXX..XXXXXXX 100644
228
--- a/block/io.c
229
+++ b/block/io.c
230
@@ -XXX,XX +XXX,XX @@ static void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore)
231
}
232
}
233
234
-static bool bdrv_parent_drained_poll_single(BdrvChild *c)
235
+bool bdrv_parent_drained_poll_single(BdrvChild *c)
236
{
237
if (c->klass->drained_poll) {
238
return c->klass->drained_poll(c);
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 @@ static void test_drop_intermediate_poll(void)
244
245
246
typedef struct BDRVReplaceTestState {
247
+ bool setup_completed;
248
bool was_drained;
249
bool was_undrained;
250
bool has_read;
251
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_test_drain_begin(BlockDriverState *bs)
252
{
253
BDRVReplaceTestState *s = bs->opaque;
254
255
+ if (!s->setup_completed) {
27
+ return;
256
+ return;
28
+ }
257
+ }
29
+
258
+
30
assert(s->num_children <= INT_MAX / sizeof(BdrvChild *));
259
if (!s->drain_count) {
31
if (s->num_children == INT_MAX / sizeof(BdrvChild *) ||
260
s->drain_co = qemu_coroutine_create(bdrv_replace_test_drain_co, bs);
32
s->next_child_index == UINT_MAX) {
261
bdrv_inc_in_flight(bs);
33
@@ -XXX,XX +XXX,XX @@ static void quorum_del_child(BlockDriverState *bs, BdrvChild *child,
262
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_test_drain_end(BlockDriverState *bs)
34
return;
263
{
35
}
264
BDRVReplaceTestState *s = bs->opaque;
36
265
37
+ /* We know now that num_children > threshold, so blkverify must be false */
266
+ if (!s->setup_completed) {
38
+ assert(!s->is_blkverify);
267
+ return;
39
+
268
+ }
40
bdrv_drained_begin(bs);
269
+
41
270
g_assert(s->drain_count > 0);
42
/* We can safely remove this child now */
271
if (!--s->drain_count) {
272
s->was_undrained = true;
273
@@ -XXX,XX +XXX,XX @@ static void do_test_replace_child_mid_drain(int old_drain_count,
274
bdrv_ref(old_child_bs);
275
bdrv_attach_child(parent_bs, old_child_bs, "child", &child_of_bds,
276
BDRV_CHILD_COW, &error_abort);
277
+ parent_s->setup_completed = true;
278
279
for (i = 0; i < old_drain_count; i++) {
280
bdrv_drained_begin(old_child_bs);
43
--
281
--
44
2.19.1
282
2.38.1
45
46
diff view generated by jsdifflib
1
From: Peter Maydell <peter.maydell@linaro.org>
1
All callers of bdrv_parent_drained_begin_single() pass poll=false now,
2
so we don't need the parameter any more.
2
3
3
Taking the address of a field in a packed struct is a bad idea, because
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
it might not be actually aligned enough for that pointer type (and
5
Message-Id: <20221118174110.55183-16-kwolf@redhat.com>
5
thus cause a crash on dereference on some host architectures). Newer
6
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
6
versions of clang warn about this. Avoid the bug by not using the
7
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
7
"modify in place" byte swapping functions.
8
9
There are a few places where the in-place swap function is
10
used on something other than a packed struct field; we convert
11
those anyway, for consistency.
12
13
This patch was produced with the following spatch script:
14
15
@@
16
expression E;
17
@@
18
-be16_to_cpus(&E);
19
+E = be16_to_cpu(E);
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
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>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
51
---
9
---
52
block/qcow2-bitmap.c | 24 ++++++++++++------------
10
include/block/block-io.h | 5 ++---
53
1 file changed, 12 insertions(+), 12 deletions(-)
11
block.c | 4 ++--
12
block/io.c | 8 ++------
13
3 files changed, 6 insertions(+), 11 deletions(-)
54
14
55
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
15
diff --git a/include/block/block-io.h b/include/block/block-io.h
56
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
57
--- a/block/qcow2-bitmap.c
17
--- a/include/block/block-io.h
58
+++ b/block/qcow2-bitmap.c
18
+++ b/include/block/block-io.h
59
@@ -XXX,XX +XXX,XX @@ static inline void bitmap_table_to_be(uint64_t *bitmap_table, size_t size)
19
@@ -XXX,XX +XXX,XX @@ bdrv_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos);
60
size_t i;
20
/**
61
21
* bdrv_parent_drained_begin_single:
62
for (i = 0; i < size; ++i) {
22
*
63
- cpu_to_be64s(&bitmap_table[i]);
23
- * Begin a quiesced section for the parent of @c. If @poll is true, wait for
64
+ bitmap_table[i] = cpu_to_be64(bitmap_table[i]);
24
- * any pending activity to cease.
25
+ * Begin a quiesced section for the parent of @c.
26
*/
27
-void bdrv_parent_drained_begin_single(BdrvChild *c, bool poll);
28
+void bdrv_parent_drained_begin_single(BdrvChild *c);
29
30
/**
31
* bdrv_parent_drained_poll_single:
32
diff --git a/block.c b/block.c
33
index XXXXXXX..XXXXXXX 100644
34
--- a/block.c
35
+++ b/block.c
36
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_abort(void *opaque)
37
* new_bs drained when calling bdrv_replace_child_tran() is not a
38
* requirement any more.
39
*/
40
- bdrv_parent_drained_begin_single(s->child, false);
41
+ bdrv_parent_drained_begin_single(s->child);
42
assert(!bdrv_parent_drained_poll_single(s->child));
43
}
44
assert(s->child->quiesced_parent);
45
@@ -XXX,XX +XXX,XX @@ static BdrvChild *bdrv_attach_child_common(BlockDriverState *child_bs,
46
* a problem, we already did this), but it will still poll until the parent
47
* is fully quiesced, so it will not be negatively affected either.
48
*/
49
- bdrv_parent_drained_begin_single(new_child, false);
50
+ bdrv_parent_drained_begin_single(new_child);
51
bdrv_replace_child_noperm(new_child, child_bs);
52
53
BdrvAttachChildCommonState *s = g_new(BdrvAttachChildCommonState, 1);
54
diff --git a/block/io.c b/block/io.c
55
index XXXXXXX..XXXXXXX 100644
56
--- a/block/io.c
57
+++ b/block/io.c
58
@@ -XXX,XX +XXX,XX @@ static void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore)
59
if (c == ignore) {
60
continue;
61
}
62
- bdrv_parent_drained_begin_single(c, false);
63
+ bdrv_parent_drained_begin_single(c);
65
}
64
}
66
}
65
}
67
66
68
@@ -XXX,XX +XXX,XX @@ static int bitmap_table_load(BlockDriverState *bs, Qcow2BitmapTable *tb,
67
@@ -XXX,XX +XXX,XX @@ static bool bdrv_parent_drained_poll(BlockDriverState *bs, BdrvChild *ignore,
68
return busy;
69
}
70
71
-void bdrv_parent_drained_begin_single(BdrvChild *c, bool poll)
72
+void bdrv_parent_drained_begin_single(BdrvChild *c)
73
{
74
- AioContext *ctx = bdrv_child_get_parent_aio_context(c);
75
IO_OR_GS_CODE();
76
77
assert(!c->quiesced_parent);
78
@@ -XXX,XX +XXX,XX @@ void bdrv_parent_drained_begin_single(BdrvChild *c, bool poll)
79
if (c->klass->drained_begin) {
80
c->klass->drained_begin(c);
69
}
81
}
70
82
- if (poll) {
71
for (i = 0; i < tb->size; ++i) {
83
- AIO_WAIT_WHILE(ctx, bdrv_parent_drained_poll_single(c));
72
- be64_to_cpus(&table[i]);
84
- }
73
+ table[i] = be64_to_cpu(table[i]);
74
ret = check_table_entry(table[i], s->cluster_size);
75
if (ret < 0) {
76
goto fail;
77
@@ -XXX,XX +XXX,XX @@ fail:
78
79
static inline void bitmap_dir_entry_to_cpu(Qcow2BitmapDirEntry *entry)
80
{
81
- be64_to_cpus(&entry->bitmap_table_offset);
82
- be32_to_cpus(&entry->bitmap_table_size);
83
- be32_to_cpus(&entry->flags);
84
- be16_to_cpus(&entry->name_size);
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
}
85
}
92
86
93
static inline void bitmap_dir_entry_to_be(Qcow2BitmapDirEntry *entry)
87
static void bdrv_merge_limits(BlockLimits *dst, const BlockLimits *src)
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
--
88
--
109
2.19.1
89
2.38.1
110
111
diff view generated by jsdifflib
1
From: Stefan Weil <sw@weilnetz.de>
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
2
2
3
Use %zu instead of %zd for unsigned numbers.
3
bdrv_common_block_status_above() is a g_c_w, and it is being called by
4
many "wrapper" functions like bdrv_is_allocated(),
5
bdrv_is_allocated_above() and bdrv_block_status_above().
4
6
5
This fixes two error messages from the LSTM static code analyzer:
7
Because we want to eventually split the coroutine from non-coroutine
8
case in g_c_w, create duplicate wrappers that take care of directly
9
calling the same coroutine functions called in the g_c_w.
6
10
7
This argument should be of type 'ssize_t' but is of type 'unsigned long'
11
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
8
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Stefan Weil <sw@weilnetz.de>
13
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
10
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
14
Message-Id: <20221128142337.657646-2-eesposit@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
16
---
13
qemu-io-cmds.c | 4 ++--
17
include/block/block-io.h | 15 +++++++++++
14
1 file changed, 2 insertions(+), 2 deletions(-)
18
block/io.c | 58 +++++++++++++++++++++++++++++++++++++---
19
2 files changed, 70 insertions(+), 3 deletions(-)
15
20
16
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
21
diff --git a/include/block/block-io.h b/include/block/block-io.h
17
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
18
--- a/qemu-io-cmds.c
23
--- a/include/block/block-io.h
19
+++ b/qemu-io-cmds.c
24
+++ b/include/block/block-io.h
20
@@ -XXX,XX +XXX,XX @@ static int readv_f(BlockBackend *blk, int argc, char **argv)
25
@@ -XXX,XX +XXX,XX @@ bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs);
21
memset(cmp_buf, pattern, qiov.size);
26
int bdrv_block_status(BlockDriverState *bs, int64_t offset,
22
if (memcmp(buf, cmp_buf, qiov.size)) {
27
int64_t bytes, int64_t *pnum, int64_t *map,
23
printf("Pattern verification failed at offset %"
28
BlockDriverState **file);
24
- PRId64 ", %zd bytes\n", offset, qiov.size);
29
+
25
+ PRId64 ", %zu bytes\n", offset, qiov.size);
30
+int coroutine_fn bdrv_co_block_status_above(BlockDriverState *bs,
26
ret = -EINVAL;
31
+ BlockDriverState *base,
27
}
32
+ int64_t offset, int64_t bytes,
28
g_free(cmp_buf);
33
+ int64_t *pnum, int64_t *map,
29
@@ -XXX,XX +XXX,XX @@ static void aio_read_done(void *opaque, int ret)
34
+ BlockDriverState **file);
30
memset(cmp_buf, ctx->pattern, ctx->qiov.size);
35
int bdrv_block_status_above(BlockDriverState *bs, BlockDriverState *base,
31
if (memcmp(ctx->buf, cmp_buf, ctx->qiov.size)) {
36
int64_t offset, int64_t bytes, int64_t *pnum,
32
printf("Pattern verification failed at offset %"
37
int64_t *map, BlockDriverState **file);
33
- PRId64 ", %zd bytes\n", ctx->offset, ctx->qiov.size);
38
+
34
+ PRId64 ", %zu bytes\n", ctx->offset, ctx->qiov.size);
39
+int coroutine_fn bdrv_co_is_allocated(BlockDriverState *bs, int64_t offset,
35
}
40
+ int64_t bytes, int64_t *pnum);
36
g_free(cmp_buf);
41
int bdrv_is_allocated(BlockDriverState *bs, int64_t offset, int64_t bytes,
42
int64_t *pnum);
43
+
44
+int coroutine_fn bdrv_co_is_allocated_above(BlockDriverState *top,
45
+ BlockDriverState *base,
46
+ bool include_base, int64_t offset,
47
+ int64_t bytes, int64_t *pnum);
48
int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
49
bool include_base, int64_t offset, int64_t bytes,
50
int64_t *pnum);
51
+
52
int coroutine_fn bdrv_co_is_zero_fast(BlockDriverState *bs, int64_t offset,
53
int64_t bytes);
54
55
diff --git a/block/io.c b/block/io.c
56
index XXXXXXX..XXXXXXX 100644
57
--- a/block/io.c
58
+++ b/block/io.c
59
@@ -XXX,XX +XXX,XX @@ bdrv_co_common_block_status_above(BlockDriverState *bs,
60
return ret;
61
}
62
63
+int coroutine_fn bdrv_co_block_status_above(BlockDriverState *bs,
64
+ BlockDriverState *base,
65
+ int64_t offset, int64_t bytes,
66
+ int64_t *pnum, int64_t *map,
67
+ BlockDriverState **file)
68
+{
69
+ IO_CODE();
70
+ return bdrv_co_common_block_status_above(bs, base, false, true, offset,
71
+ bytes, pnum, map, file, NULL);
72
+}
73
+
74
int bdrv_block_status_above(BlockDriverState *bs, BlockDriverState *base,
75
int64_t offset, int64_t bytes, int64_t *pnum,
76
int64_t *map, BlockDriverState **file)
77
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_is_zero_fast(BlockDriverState *bs, int64_t offset,
78
return (pnum == bytes) && (ret & BDRV_BLOCK_ZERO);
79
}
80
81
+int coroutine_fn bdrv_co_is_allocated(BlockDriverState *bs, int64_t offset,
82
+ int64_t bytes, int64_t *pnum)
83
+{
84
+ int ret;
85
+ int64_t dummy;
86
+ IO_CODE();
87
+
88
+ ret = bdrv_co_common_block_status_above(bs, bs, true, false, offset,
89
+ bytes, pnum ? pnum : &dummy, NULL,
90
+ NULL, NULL);
91
+ if (ret < 0) {
92
+ return ret;
93
+ }
94
+ return !!(ret & BDRV_BLOCK_ALLOCATED);
95
+}
96
+
97
int bdrv_is_allocated(BlockDriverState *bs, int64_t offset, int64_t bytes,
98
int64_t *pnum)
99
{
100
@@ -XXX,XX +XXX,XX @@ int bdrv_is_allocated(BlockDriverState *bs, int64_t offset, int64_t bytes,
101
return !!(ret & BDRV_BLOCK_ALLOCATED);
102
}
103
104
+/* See bdrv_is_allocated_above for documentation */
105
+int coroutine_fn bdrv_co_is_allocated_above(BlockDriverState *top,
106
+ BlockDriverState *base,
107
+ bool include_base, int64_t offset,
108
+ int64_t bytes, int64_t *pnum)
109
+{
110
+ int depth;
111
+ int ret;
112
+ IO_CODE();
113
+
114
+ ret = bdrv_co_common_block_status_above(top, base, include_base, false,
115
+ offset, bytes, pnum, NULL, NULL,
116
+ &depth);
117
+ if (ret < 0) {
118
+ return ret;
119
+ }
120
+
121
+ if (ret & BDRV_BLOCK_ALLOCATED) {
122
+ return depth;
123
+ }
124
+ return 0;
125
+}
126
+
127
/*
128
* Given an image chain: ... -> [BASE] -> [INTER1] -> [INTER2] -> [TOP]
129
*
130
@@ -XXX,XX +XXX,XX @@ int bdrv_is_allocated_above(BlockDriverState *top,
131
int64_t bytes, int64_t *pnum)
132
{
133
int depth;
134
- int ret = bdrv_common_block_status_above(top, base, include_base, false,
135
- offset, bytes, pnum, NULL, NULL,
136
- &depth);
137
+ int ret;
138
IO_CODE();
139
+
140
+ ret = bdrv_common_block_status_above(top, base, include_base, false,
141
+ offset, bytes, pnum, NULL, NULL,
142
+ &depth);
143
if (ret < 0) {
144
return ret;
37
}
145
}
38
--
146
--
39
2.19.1
147
2.38.1
40
41
diff view generated by jsdifflib
New patch
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
1
2
3
These functions end up calling bdrv_common_block_status_above(), a
4
generated_co_wrapper function.
5
In addition, they also happen to be always called in coroutine context,
6
meaning all callers are coroutine_fn.
7
This means that the g_c_w function will enter the qemu_in_coroutine()
8
case and eventually suspend (or in other words call qemu_coroutine_yield()).
9
Therefore we can mark such functions coroutine_fn too.
10
11
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
12
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
13
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
14
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
15
Message-Id: <20221128142337.657646-3-eesposit@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
---
18
include/block/block-copy.h | 5 +++--
19
block/block-copy.c | 21 ++++++++++++---------
20
2 files changed, 15 insertions(+), 11 deletions(-)
21
22
diff --git a/include/block/block-copy.h b/include/block/block-copy.h
23
index XXXXXXX..XXXXXXX 100644
24
--- a/include/block/block-copy.h
25
+++ b/include/block/block-copy.h
26
@@ -XXX,XX +XXX,XX @@ void block_copy_set_progress_meter(BlockCopyState *s, ProgressMeter *pm);
27
void block_copy_state_free(BlockCopyState *s);
28
29
void block_copy_reset(BlockCopyState *s, int64_t offset, int64_t bytes);
30
-int64_t block_copy_reset_unallocated(BlockCopyState *s,
31
- int64_t offset, int64_t *count);
32
+int64_t coroutine_fn block_copy_reset_unallocated(BlockCopyState *s,
33
+ int64_t offset,
34
+ int64_t *count);
35
36
int coroutine_fn block_copy(BlockCopyState *s, int64_t offset, int64_t bytes,
37
bool ignore_ratelimit, uint64_t timeout_ns,
38
diff --git a/block/block-copy.c b/block/block-copy.c
39
index XXXXXXX..XXXXXXX 100644
40
--- a/block/block-copy.c
41
+++ b/block/block-copy.c
42
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int block_copy_task_entry(AioTask *task)
43
return ret;
44
}
45
46
-static int block_copy_block_status(BlockCopyState *s, int64_t offset,
47
- int64_t bytes, int64_t *pnum)
48
+static coroutine_fn int block_copy_block_status(BlockCopyState *s,
49
+ int64_t offset,
50
+ int64_t bytes, int64_t *pnum)
51
{
52
int64_t num;
53
BlockDriverState *base;
54
@@ -XXX,XX +XXX,XX @@ static int block_copy_block_status(BlockCopyState *s, int64_t offset,
55
base = NULL;
56
}
57
58
- ret = bdrv_block_status_above(s->source->bs, base, offset, bytes, &num,
59
- NULL, NULL);
60
+ ret = bdrv_co_block_status_above(s->source->bs, base, offset, bytes, &num,
61
+ NULL, NULL);
62
if (ret < 0 || num < s->cluster_size) {
63
/*
64
* On error or if failed to obtain large enough chunk just fallback to
65
@@ -XXX,XX +XXX,XX @@ static int block_copy_block_status(BlockCopyState *s, int64_t offset,
66
* Check if the cluster starting at offset is allocated or not.
67
* return via pnum the number of contiguous clusters sharing this allocation.
68
*/
69
-static int block_copy_is_cluster_allocated(BlockCopyState *s, int64_t offset,
70
- int64_t *pnum)
71
+static int coroutine_fn block_copy_is_cluster_allocated(BlockCopyState *s,
72
+ int64_t offset,
73
+ int64_t *pnum)
74
{
75
BlockDriverState *bs = s->source->bs;
76
int64_t count, total_count = 0;
77
@@ -XXX,XX +XXX,XX @@ static int block_copy_is_cluster_allocated(BlockCopyState *s, int64_t offset,
78
assert(QEMU_IS_ALIGNED(offset, s->cluster_size));
79
80
while (true) {
81
- ret = bdrv_is_allocated(bs, offset, bytes, &count);
82
+ ret = bdrv_co_is_allocated(bs, offset, bytes, &count);
83
if (ret < 0) {
84
return ret;
85
}
86
@@ -XXX,XX +XXX,XX @@ void block_copy_reset(BlockCopyState *s, int64_t offset, int64_t bytes)
87
* @return 0 when the cluster at @offset was unallocated,
88
* 1 otherwise, and -ret on error.
89
*/
90
-int64_t block_copy_reset_unallocated(BlockCopyState *s,
91
- int64_t offset, int64_t *count)
92
+int64_t coroutine_fn block_copy_reset_unallocated(BlockCopyState *s,
93
+ int64_t offset,
94
+ int64_t *count)
95
{
96
int ret;
97
int64_t clusters, bytes;
98
--
99
2.38.1
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
2
2
3
This adds some whitespace into the option help (including indentation)
3
These functions end up calling bdrv_*() implemented as generated_co_wrapper
4
and puts angle brackets around the type names. Furthermore, the list
4
functions.
5
name is no longer printed as part of every line, but only once in
5
In addition, they also happen to be always called in coroutine context,
6
advance, and only if the caller did not print a caption already.
6
meaning all callers are coroutine_fn.
7
This means that the g_c_w function will enter the qemu_in_coroutine()
8
case and eventually suspend (or in other words call qemu_coroutine_yield()).
9
Therefore we can mark such functions coroutine_fn too.
7
10
8
This patch also restores the description alignment we had before commit
11
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
9
9cbef9d68ee1d8d0, just at 24 instead of 16 characters like we used to.
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
10
This increase is because now we have the type and two spaces of
13
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
11
indentation before the description, and with a usual type name length of
14
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
12
three chracters, this sums up to eight additional characters -- which
15
Message-Id: <20221128142337.657646-4-eesposit@redhat.com>
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
17
Finally, this patch amends the reference output of iotest 082 to match
18
the changes (and thus makes it pass again).
19
20
Signed-off-by: Max Reitz <mreitz@redhat.com>
21
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
22
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
23
---
17
---
24
include/qemu/option.h | 2 +-
18
nbd/server.c | 29 ++++++++++++++++-------------
25
qemu-img.c | 4 +-
19
1 file changed, 16 insertions(+), 13 deletions(-)
26
util/qemu-option.c | 32 +-
27
tests/qemu-iotests/082.out | 956 ++++++++++++++++++-------------------
28
4 files changed, 507 insertions(+), 487 deletions(-)
29
20
30
diff --git a/include/qemu/option.h b/include/qemu/option.h
21
diff --git a/nbd/server.c b/nbd/server.c
31
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
32
--- a/include/qemu/option.h
23
--- a/nbd/server.c
33
+++ b/include/qemu/option.h
24
+++ b/nbd/server.c
34
@@ -XXX,XX +XXX,XX @@ typedef int (*qemu_opts_loopfunc)(void *opaque, QemuOpts *opts, Error **errp);
25
@@ -XXX,XX +XXX,XX @@ static int nbd_extent_array_add(NBDExtentArray *ea,
35
int qemu_opts_foreach(QemuOptsList *list, qemu_opts_loopfunc func,
36
void *opaque, Error **errp);
37
void qemu_opts_print(QemuOpts *opts, const char *sep);
38
-void qemu_opts_print_help(QemuOptsList *list);
39
+void qemu_opts_print_help(QemuOptsList *list, bool print_caption);
40
void qemu_opts_free(QemuOptsList *list);
41
QemuOptsList *qemu_opts_append(QemuOptsList *dst, QemuOptsList *list);
42
43
diff --git a/qemu-img.c b/qemu-img.c
44
index XXXXXXX..XXXXXXX 100644
45
--- a/qemu-img.c
46
+++ b/qemu-img.c
47
@@ -XXX,XX +XXX,XX @@ static int print_block_option_help(const char *filename, const char *fmt)
48
}
49
50
printf("Supported options:\n");
51
- qemu_opts_print_help(create_opts);
52
+ qemu_opts_print_help(create_opts, false);
53
qemu_opts_free(create_opts);
54
return 0;
26
return 0;
55
}
27
}
56
@@ -XXX,XX +XXX,XX @@ static int print_amend_option_help(const char *format)
28
57
assert(drv->create_opts);
29
-static int blockstatus_to_extents(BlockDriverState *bs, uint64_t offset,
58
30
- uint64_t bytes, NBDExtentArray *ea)
59
printf("Creation options for '%s':\n", format);
31
+static int coroutine_fn blockstatus_to_extents(BlockDriverState *bs,
60
- qemu_opts_print_help(drv->create_opts);
32
+ uint64_t offset, uint64_t bytes,
61
+ qemu_opts_print_help(drv->create_opts, false);
33
+ NBDExtentArray *ea)
62
printf("\nNote that not all of these options may be amendable.\n");
34
{
35
while (bytes) {
36
uint32_t flags;
37
int64_t num;
38
- int ret = bdrv_block_status_above(bs, NULL, offset, bytes, &num,
39
- NULL, NULL);
40
+ int ret = bdrv_co_block_status_above(bs, NULL, offset, bytes, &num,
41
+ NULL, NULL);
42
43
if (ret < 0) {
44
return ret;
45
@@ -XXX,XX +XXX,XX @@ static int blockstatus_to_extents(BlockDriverState *bs, uint64_t offset,
63
return 0;
46
return 0;
64
}
47
}
65
diff --git a/util/qemu-option.c b/util/qemu-option.c
48
66
index XXXXXXX..XXXXXXX 100644
49
-static int blockalloc_to_extents(BlockDriverState *bs, uint64_t offset,
67
--- a/util/qemu-option.c
50
- uint64_t bytes, NBDExtentArray *ea)
68
+++ b/util/qemu-option.c
51
+static int coroutine_fn blockalloc_to_extents(BlockDriverState *bs,
69
@@ -XXX,XX +XXX,XX @@ static const char *opt_type_to_string(enum QemuOptType type)
52
+ uint64_t offset, uint64_t bytes,
70
g_assert_not_reached();
53
+ NBDExtentArray *ea)
54
{
55
while (bytes) {
56
int64_t num;
57
- int ret = bdrv_is_allocated_above(bs, NULL, false, offset, bytes,
58
- &num);
59
+ int ret = bdrv_co_is_allocated_above(bs, NULL, false, offset, bytes,
60
+ &num);
61
62
if (ret < 0) {
63
return ret;
64
@@ -XXX,XX +XXX,XX @@ static int nbd_co_send_extents(NBDClient *client, uint64_t handle,
71
}
65
}
72
66
73
-void qemu_opts_print_help(QemuOptsList *list)
67
/* Get block status from the exported device and send it to the client */
74
+/**
68
-static int nbd_co_send_block_status(NBDClient *client, uint64_t handle,
75
+ * Print the list of options available in the given list. If
69
- BlockDriverState *bs, uint64_t offset,
76
+ * @print_caption is true, a caption (including the list name, if it
70
- uint32_t length, bool dont_fragment,
77
+ * exists) is printed. The options itself will be indented, so
71
- bool last, uint32_t context_id,
78
+ * @print_caption should only be set to false if the caller prints its
72
- Error **errp)
79
+ * own custom caption (so that the indentation makes sense).
73
+static int
80
+ */
74
+coroutine_fn nbd_co_send_block_status(NBDClient *client, uint64_t handle,
81
+void qemu_opts_print_help(QemuOptsList *list, bool print_caption)
75
+ BlockDriverState *bs, uint64_t offset,
76
+ uint32_t length, bool dont_fragment,
77
+ bool last, uint32_t context_id,
78
+ Error **errp)
82
{
79
{
83
QemuOptDesc *desc;
80
int ret;
84
int i;
81
unsigned int nb_extents = dont_fragment ? 1 : NBD_MAX_BLOCK_STATUS_EXTENTS;
85
@@ -XXX,XX +XXX,XX @@ void qemu_opts_print_help(QemuOptsList *list)
86
desc = list->desc;
87
while (desc && desc->name) {
88
GString *str = g_string_new(NULL);
89
- if (list->name) {
90
- g_string_append_printf(str, "%s.", list->name);
91
- }
92
- g_string_append_printf(str, "%s=%s", desc->name,
93
+ g_string_append_printf(str, " %s=<%s>", desc->name,
94
opt_type_to_string(desc->type));
95
if (desc->help) {
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
}
104
105
g_ptr_array_sort(array, (GCompareFunc)qemu_pstrcmp0);
106
+ if (print_caption && array->len > 0) {
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
}
122
@@ -XXX,XX +XXX,XX @@ QemuOpts *qemu_opts_parse_noisily(QemuOptsList *list, const char *params,
123
opts = opts_parse(list, params, permit_abbrev, false, &invalidp, &err);
124
if (err) {
125
if (invalidp && has_help_option(params)) {
126
- qemu_opts_print_help(list);
127
+ qemu_opts_print_help(list, true);
128
error_free(err);
129
} else {
130
error_report_err(err);
131
diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out
132
index XXXXXXX..XXXXXXX 100644
133
--- a/tests/qemu-iotests/082.out
134
+++ b/tests/qemu-iotests/082.out
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
--
82
--
1222
2.19.1
83
2.38.1
1223
1224
diff view generated by jsdifflib
New patch
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
1
2
3
Avoid mixing bdrv_* functions with blk_*, so create blk_* counterparts
4
for bdrv_block_status_above and bdrv_is_allocated_above.
5
6
Note that since blk_co_block_status_above only calls the g_c_w function
7
bdrv_common_block_status_above and is marked as coroutine_fn, call
8
directly bdrv_co_common_block_status_above() to avoid using a g_c_w.
9
Same applies to blk_co_is_allocated_above.
10
11
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
12
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
13
Message-Id: <20221128142337.657646-5-eesposit@redhat.com>
14
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
---
17
include/sysemu/block-backend-io.h | 9 +++++++++
18
block/block-backend.c | 21 ++++++++++++++++++++
19
block/commit.c | 4 ++--
20
nbd/server.c | 32 +++++++++++++++----------------
21
4 files changed, 48 insertions(+), 18 deletions(-)
22
23
diff --git a/include/sysemu/block-backend-io.h b/include/sysemu/block-backend-io.h
24
index XXXXXXX..XXXXXXX 100644
25
--- a/include/sysemu/block-backend-io.h
26
+++ b/include/sysemu/block-backend-io.h
27
@@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in,
28
int64_t bytes, BdrvRequestFlags read_flags,
29
BdrvRequestFlags write_flags);
30
31
+int coroutine_fn blk_co_block_status_above(BlockBackend *blk,
32
+ BlockDriverState *base,
33
+ int64_t offset, int64_t bytes,
34
+ int64_t *pnum, int64_t *map,
35
+ BlockDriverState **file);
36
+int coroutine_fn blk_co_is_allocated_above(BlockBackend *blk,
37
+ BlockDriverState *base,
38
+ bool include_base, int64_t offset,
39
+ int64_t bytes, int64_t *pnum);
40
41
/*
42
* "I/O or GS" API functions. These functions can run without
43
diff --git a/block/block-backend.c b/block/block-backend.c
44
index XXXXXXX..XXXXXXX 100644
45
--- a/block/block-backend.c
46
+++ b/block/block-backend.c
47
@@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_pwritev(BlockBackend *blk, int64_t offset,
48
return blk_co_pwritev_part(blk, offset, bytes, qiov, 0, flags);
49
}
50
51
+int coroutine_fn blk_co_block_status_above(BlockBackend *blk,
52
+ BlockDriverState *base,
53
+ int64_t offset, int64_t bytes,
54
+ int64_t *pnum, int64_t *map,
55
+ BlockDriverState **file)
56
+{
57
+ IO_CODE();
58
+ return bdrv_co_block_status_above(blk_bs(blk), base, offset, bytes, pnum,
59
+ map, file);
60
+}
61
+
62
+int coroutine_fn blk_co_is_allocated_above(BlockBackend *blk,
63
+ BlockDriverState *base,
64
+ bool include_base, int64_t offset,
65
+ int64_t bytes, int64_t *pnum)
66
+{
67
+ IO_CODE();
68
+ return bdrv_co_is_allocated_above(blk_bs(blk), base, include_base, offset,
69
+ bytes, pnum);
70
+}
71
+
72
typedef struct BlkRwCo {
73
BlockBackend *blk;
74
int64_t offset;
75
diff --git a/block/commit.c b/block/commit.c
76
index XXXXXXX..XXXXXXX 100644
77
--- a/block/commit.c
78
+++ b/block/commit.c
79
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn commit_run(Job *job, Error **errp)
80
break;
81
}
82
/* Copy if allocated above the base */
83
- ret = bdrv_is_allocated_above(blk_bs(s->top), s->base_overlay, true,
84
- offset, COMMIT_BUFFER_SIZE, &n);
85
+ ret = blk_co_is_allocated_above(s->top, s->base_overlay, true,
86
+ offset, COMMIT_BUFFER_SIZE, &n);
87
copy = (ret > 0);
88
trace_commit_one_iteration(s, offset, n, ret);
89
if (copy) {
90
diff --git a/nbd/server.c b/nbd/server.c
91
index XXXXXXX..XXXXXXX 100644
92
--- a/nbd/server.c
93
+++ b/nbd/server.c
94
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn nbd_co_send_structured_error(NBDClient *client,
95
}
96
97
/* Do a sparse read and send the structured reply to the client.
98
- * Returns -errno if sending fails. bdrv_block_status_above() failure is
99
+ * Returns -errno if sending fails. blk_co_block_status_above() failure is
100
* reported to the client, at which point this function succeeds.
101
*/
102
static int coroutine_fn nbd_co_send_sparse_read(NBDClient *client,
103
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn nbd_co_send_sparse_read(NBDClient *client,
104
105
while (progress < size) {
106
int64_t pnum;
107
- int status = bdrv_block_status_above(blk_bs(exp->common.blk), NULL,
108
- offset + progress,
109
- size - progress, &pnum, NULL,
110
- NULL);
111
+ int status = blk_co_block_status_above(exp->common.blk, NULL,
112
+ offset + progress,
113
+ size - progress, &pnum, NULL,
114
+ NULL);
115
bool final;
116
117
if (status < 0) {
118
@@ -XXX,XX +XXX,XX @@ static int nbd_extent_array_add(NBDExtentArray *ea,
119
return 0;
120
}
121
122
-static int coroutine_fn blockstatus_to_extents(BlockDriverState *bs,
123
+static int coroutine_fn blockstatus_to_extents(BlockBackend *blk,
124
uint64_t offset, uint64_t bytes,
125
NBDExtentArray *ea)
126
{
127
while (bytes) {
128
uint32_t flags;
129
int64_t num;
130
- int ret = bdrv_co_block_status_above(bs, NULL, offset, bytes, &num,
131
- NULL, NULL);
132
+ int ret = blk_co_block_status_above(blk, NULL, offset, bytes, &num,
133
+ NULL, NULL);
134
135
if (ret < 0) {
136
return ret;
137
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn blockstatus_to_extents(BlockDriverState *bs,
138
return 0;
139
}
140
141
-static int coroutine_fn blockalloc_to_extents(BlockDriverState *bs,
142
+static int coroutine_fn blockalloc_to_extents(BlockBackend *blk,
143
uint64_t offset, uint64_t bytes,
144
NBDExtentArray *ea)
145
{
146
while (bytes) {
147
int64_t num;
148
- int ret = bdrv_co_is_allocated_above(bs, NULL, false, offset, bytes,
149
- &num);
150
+ int ret = blk_co_is_allocated_above(blk, NULL, false, offset, bytes,
151
+ &num);
152
153
if (ret < 0) {
154
return ret;
155
@@ -XXX,XX +XXX,XX @@ static int nbd_co_send_extents(NBDClient *client, uint64_t handle,
156
/* Get block status from the exported device and send it to the client */
157
static int
158
coroutine_fn nbd_co_send_block_status(NBDClient *client, uint64_t handle,
159
- BlockDriverState *bs, uint64_t offset,
160
+ BlockBackend *blk, uint64_t offset,
161
uint32_t length, bool dont_fragment,
162
bool last, uint32_t context_id,
163
Error **errp)
164
@@ -XXX,XX +XXX,XX @@ coroutine_fn nbd_co_send_block_status(NBDClient *client, uint64_t handle,
165
g_autoptr(NBDExtentArray) ea = nbd_extent_array_new(nb_extents);
166
167
if (context_id == NBD_META_ID_BASE_ALLOCATION) {
168
- ret = blockstatus_to_extents(bs, offset, length, ea);
169
+ ret = blockstatus_to_extents(blk, offset, length, ea);
170
} else {
171
- ret = blockalloc_to_extents(bs, offset, length, ea);
172
+ ret = blockalloc_to_extents(blk, offset, length, ea);
173
}
174
if (ret < 0) {
175
return nbd_co_send_structured_error(
176
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int nbd_handle_request(NBDClient *client,
177
178
if (client->export_meta.base_allocation) {
179
ret = nbd_co_send_block_status(client, request->handle,
180
- blk_bs(exp->common.blk),
181
+ exp->common.blk,
182
request->from,
183
request->len, dont_fragment,
184
!--contexts_remaining,
185
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int nbd_handle_request(NBDClient *client,
186
187
if (client->export_meta.allocation_depth) {
188
ret = nbd_co_send_block_status(client, request->handle,
189
- blk_bs(exp->common.blk),
190
+ exp->common.blk,
191
request->from, request->len,
192
dont_fragment,
193
!--contexts_remaining,
194
--
195
2.38.1
diff view generated by jsdifflib
New patch
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
1
2
3
These functions end up calling bdrv_create() implemented as generated_co_wrapper
4
functions.
5
In addition, they also happen to be always called in coroutine context,
6
meaning all callers are coroutine_fn.
7
This means that the g_c_w function will enter the qemu_in_coroutine()
8
case and eventually suspend (or in other words call qemu_coroutine_yield()).
9
Therefore we can mark such functions coroutine_fn too.
10
11
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
12
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
13
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
14
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
15
Message-Id: <20221128142337.657646-6-eesposit@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
---
18
block/vmdk.c | 36 +++++++++++++++++++-----------------
19
1 file changed, 19 insertions(+), 17 deletions(-)
20
21
diff --git a/block/vmdk.c b/block/vmdk.c
22
index XXXXXXX..XXXXXXX 100644
23
--- a/block/vmdk.c
24
+++ b/block/vmdk.c
25
@@ -XXX,XX +XXX,XX @@ exit:
26
return ret;
27
}
28
29
-static int vmdk_create_extent(const char *filename, int64_t filesize,
30
- bool flat, bool compress, bool zeroed_grain,
31
- BlockBackend **pbb,
32
- QemuOpts *opts, Error **errp)
33
+static int coroutine_fn vmdk_create_extent(const char *filename,
34
+ int64_t filesize, bool flat,
35
+ bool compress, bool zeroed_grain,
36
+ BlockBackend **pbb,
37
+ QemuOpts *opts, Error **errp)
38
{
39
int ret;
40
BlockBackend *blk = NULL;
41
@@ -XXX,XX +XXX,XX @@ static int filename_decompose(const char *filename, char *path, char *prefix,
42
* non-split format.
43
* idx >= 1: get the n-th extent if in a split subformat
44
*/
45
-typedef BlockBackend *(*vmdk_create_extent_fn)(int64_t size,
46
- int idx,
47
- bool flat,
48
- bool split,
49
- bool compress,
50
- bool zeroed_grain,
51
- void *opaque,
52
- Error **errp);
53
+typedef BlockBackend * coroutine_fn (*vmdk_create_extent_fn)(int64_t size,
54
+ int idx,
55
+ bool flat,
56
+ bool split,
57
+ bool compress,
58
+ bool zeroed_grain,
59
+ void *opaque,
60
+ Error **errp);
61
62
static void vmdk_desc_add_extent(GString *desc,
63
const char *extent_line_fmt,
64
@@ -XXX,XX +XXX,XX @@ typedef struct {
65
QemuOpts *opts;
66
} VMDKCreateOptsData;
67
68
-static BlockBackend *vmdk_co_create_opts_cb(int64_t size, int idx,
69
+static BlockBackend * coroutine_fn vmdk_co_create_opts_cb(int64_t size, int idx,
70
bool flat, bool split, bool compress,
71
bool zeroed_grain, void *opaque,
72
Error **errp)
73
@@ -XXX,XX +XXX,XX @@ exit:
74
return ret;
75
}
76
77
-static BlockBackend *vmdk_co_create_cb(int64_t size, int idx,
78
- bool flat, bool split, bool compress,
79
- bool zeroed_grain, void *opaque,
80
- Error **errp)
81
+static BlockBackend * coroutine_fn vmdk_co_create_cb(int64_t size, int idx,
82
+ bool flat, bool split,
83
+ bool compress,
84
+ bool zeroed_grain,
85
+ void *opaque, Error **errp)
86
{
87
int ret;
88
BlockDriverState *bs;
89
--
90
2.38.1
diff view generated by jsdifflib
1
From: Peter Maydell <peter.maydell@linaro.org>
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
2
2
3
Taking the address of a field in a packed struct is a bad idea, because
3
We know that the string will stay around until the function
4
it might not be actually aligned enough for that pointer type (and
4
returns, and the parameter of drv->bdrv_co_create_opts is const char*,
5
thus cause a crash on dereference on some host architectures). Newer
5
so it must not be modified either.
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
Suggested-by: Kevin Wolf <kwolf@redhat.com>
10
used on something other than a packed struct field; we convert
8
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
11
those anyway, for consistency.
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
12
10
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
13
This patch was produced with the following spatch script
11
Message-Id: <20221128142337.657646-7-eesposit@redhat.com>
14
(and hand-editing to fold a few resulting overlength lines):
15
16
@@
17
expression E;
18
@@
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>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
52
---
13
---
53
block/qcow2.c | 64 +++++++++++++++++++++++++++------------------------
14
block.c | 7 ++-----
54
1 file changed, 34 insertions(+), 30 deletions(-)
15
1 file changed, 2 insertions(+), 5 deletions(-)
55
16
56
diff --git a/block/qcow2.c b/block/qcow2.c
17
diff --git a/block.c b/block.c
57
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
58
--- a/block/qcow2.c
19
--- a/block.c
59
+++ b/block/qcow2.c
20
+++ b/block.c
60
@@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
21
@@ -XXX,XX +XXX,XX @@ int bdrv_create(BlockDriver *drv, const char* filename,
61
"pread fail from offset %" PRIu64, offset);
22
Coroutine *co;
62
return 1;
23
CreateCo cco = {
63
}
24
.drv = drv,
64
- be32_to_cpus(&ext.magic);
25
- .filename = g_strdup(filename),
65
- be32_to_cpus(&ext.len);
26
+ .filename = filename,
66
+ ext.magic = be32_to_cpu(ext.magic);
27
.opts = opts,
67
+ ext.len = be32_to_cpu(ext.len);
28
.ret = NOT_DONE,
68
offset += sizeof(ext);
29
.err = NULL,
69
#ifdef DEBUG_EXT
30
@@ -XXX,XX +XXX,XX @@ int bdrv_create(BlockDriver *drv, const char* filename,
70
printf("ext.magic = 0x%x\n", ext.magic);
31
71
@@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
32
if (!drv->bdrv_co_create_opts) {
72
"Unable to read CRYPTO header extension");
33
error_setg(errp, "Driver '%s' does not support image creation", drv->format_name);
73
return ret;
34
- ret = -ENOTSUP;
74
}
35
- goto out;
75
- be64_to_cpus(&s->crypto_header.offset);
36
+ return -ENOTSUP;
76
- be64_to_cpus(&s->crypto_header.length);
77
+ s->crypto_header.offset = be64_to_cpu(s->crypto_header.offset);
78
+ s->crypto_header.length = be64_to_cpu(s->crypto_header.length);
79
80
if ((s->crypto_header.offset % s->cluster_size) != 0) {
81
error_setg(errp, "Encryption header offset '%" PRIu64 "' is "
82
@@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
83
return -EINVAL;
84
}
85
86
- be32_to_cpus(&bitmaps_ext.nb_bitmaps);
87
- be64_to_cpus(&bitmaps_ext.bitmap_directory_size);
88
- be64_to_cpus(&bitmaps_ext.bitmap_directory_offset);
89
+ bitmaps_ext.nb_bitmaps = be32_to_cpu(bitmaps_ext.nb_bitmaps);
90
+ bitmaps_ext.bitmap_directory_size =
91
+ be64_to_cpu(bitmaps_ext.bitmap_directory_size);
92
+ bitmaps_ext.bitmap_directory_offset =
93
+ be64_to_cpu(bitmaps_ext.bitmap_directory_offset);
94
95
if (bitmaps_ext.nb_bitmaps > QCOW2_MAX_BITMAPS) {
96
error_setg(errp,
97
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
98
error_setg_errno(errp, -ret, "Could not read qcow2 header");
99
goto fail;
100
}
37
}
101
- be32_to_cpus(&header.magic);
38
102
- be32_to_cpus(&header.version);
39
if (qemu_in_coroutine()) {
103
- be64_to_cpus(&header.backing_file_offset);
40
@@ -XXX,XX +XXX,XX @@ int bdrv_create(BlockDriver *drv, const char* filename,
104
- be32_to_cpus(&header.backing_file_size);
105
- be64_to_cpus(&header.size);
106
- be32_to_cpus(&header.cluster_bits);
107
- be32_to_cpus(&header.crypt_method);
108
- be64_to_cpus(&header.l1_table_offset);
109
- be32_to_cpus(&header.l1_size);
110
- be64_to_cpus(&header.refcount_table_offset);
111
- be32_to_cpus(&header.refcount_table_clusters);
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
}
41
}
156
}
42
}
157
43
158
@@ -XXX,XX +XXX,XX @@ int qcow2_update_header(BlockDriverState *bs)
44
-out:
159
45
- g_free(cco.filename);
160
/* Full disk encryption header pointer extension */
46
return ret;
161
if (s->crypto_header.offset != 0) {
47
}
162
- cpu_to_be64s(&s->crypto_header.offset);
48
163
- cpu_to_be64s(&s->crypto_header.length);
164
+ s->crypto_header.offset = cpu_to_be64(s->crypto_header.offset);
165
+ s->crypto_header.length = cpu_to_be64(s->crypto_header.length);
166
ret = header_ext_add(buf, QCOW2_EXT_MAGIC_CRYPTO_HEADER,
167
&s->crypto_header, sizeof(s->crypto_header),
168
buflen);
169
- be64_to_cpus(&s->crypto_header.offset);
170
- be64_to_cpus(&s->crypto_header.length);
171
+ s->crypto_header.offset = be64_to_cpu(s->crypto_header.offset);
172
+ s->crypto_header.length = be64_to_cpu(s->crypto_header.length);
173
if (ret < 0) {
174
goto fail;
175
}
176
--
49
--
177
2.19.1
50
2.38.1
178
179
diff view generated by jsdifflib
New patch
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
1
2
3
Call two different functions depending on whether bdrv_create
4
is in coroutine or not, following the same pattern as
5
generated_co_wrapper functions.
6
7
This allows to also call the coroutine function directly,
8
without using CreateCo or relying in bdrv_create().
9
10
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
11
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
12
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
13
Message-Id: <20221128142337.657646-8-eesposit@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
16
block.c | 69 ++++++++++++++++++++++++++++-----------------------------
17
1 file changed, 34 insertions(+), 35 deletions(-)
18
19
diff --git a/block.c b/block.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/block.c
22
+++ b/block.c
23
@@ -XXX,XX +XXX,XX @@ typedef struct CreateCo {
24
Error *err;
25
} CreateCo;
26
27
-static void coroutine_fn bdrv_create_co_entry(void *opaque)
28
+static int coroutine_fn bdrv_co_create(BlockDriver *drv, const char *filename,
29
+ QemuOpts *opts, Error **errp)
30
{
31
- Error *local_err = NULL;
32
int ret;
33
+ GLOBAL_STATE_CODE();
34
+ ERRP_GUARD();
35
36
+ if (!drv->bdrv_co_create_opts) {
37
+ error_setg(errp, "Driver '%s' does not support image creation",
38
+ drv->format_name);
39
+ return -ENOTSUP;
40
+ }
41
+
42
+ ret = drv->bdrv_co_create_opts(drv, filename, opts, errp);
43
+ if (ret < 0 && !*errp) {
44
+ error_setg_errno(errp, -ret, "Could not create image");
45
+ }
46
+
47
+ return ret;
48
+}
49
+
50
+static void coroutine_fn bdrv_create_co_entry(void *opaque)
51
+{
52
CreateCo *cco = opaque;
53
- assert(cco->drv);
54
GLOBAL_STATE_CODE();
55
56
- ret = cco->drv->bdrv_co_create_opts(cco->drv,
57
- cco->filename, cco->opts, &local_err);
58
- error_propagate(&cco->err, local_err);
59
- cco->ret = ret;
60
+ cco->ret = bdrv_co_create(cco->drv, cco->filename, cco->opts, &cco->err);
61
+ aio_wait_kick();
62
}
63
64
int bdrv_create(BlockDriver *drv, const char* filename,
65
QemuOpts *opts, Error **errp)
66
{
67
- int ret;
68
-
69
GLOBAL_STATE_CODE();
70
71
- Coroutine *co;
72
- CreateCo cco = {
73
- .drv = drv,
74
- .filename = filename,
75
- .opts = opts,
76
- .ret = NOT_DONE,
77
- .err = NULL,
78
- };
79
-
80
- if (!drv->bdrv_co_create_opts) {
81
- error_setg(errp, "Driver '%s' does not support image creation", drv->format_name);
82
- return -ENOTSUP;
83
- }
84
-
85
if (qemu_in_coroutine()) {
86
/* Fast-path if already in coroutine context */
87
- bdrv_create_co_entry(&cco);
88
+ return bdrv_co_create(drv, filename, opts, errp);
89
} else {
90
+ Coroutine *co;
91
+ CreateCo cco = {
92
+ .drv = drv,
93
+ .filename = filename,
94
+ .opts = opts,
95
+ .ret = NOT_DONE,
96
+ .err = NULL,
97
+ };
98
+
99
co = qemu_coroutine_create(bdrv_create_co_entry, &cco);
100
qemu_coroutine_enter(co);
101
while (cco.ret == NOT_DONE) {
102
aio_poll(qemu_get_aio_context(), true);
103
}
104
+ error_propagate(errp, cco.err);
105
+ return cco.ret;
106
}
107
-
108
- ret = cco.ret;
109
- if (ret < 0) {
110
- if (cco.err) {
111
- error_propagate(errp, cco.err);
112
- } else {
113
- error_setg_errno(errp, -ret, "Could not create image");
114
- }
115
- }
116
-
117
- return ret;
118
}
119
120
/**
121
--
122
2.38.1
diff view generated by jsdifflib
1
From: Peter Maydell <peter.maydell@linaro.org>
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
2
2
3
Taking the address of a field in a packed struct is a bad idea, because
3
It is always called in coroutine_fn callbacks, therefore
4
it might not be actually aligned enough for that pointer type (and
4
it can directly call bdrv_co_create().
5
thus cause a crash on dereference on some host architectures). Newer
5
6
versions of clang warn about this. Avoid the bug by not using the
6
Rename it to bdrv_co_create_file too.
7
"modify in place" byte swapping functions.
7
8
8
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
9
There are a few places where the in-place swap function is
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
10
used on something other than a packed struct field; we convert
10
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
11
those anyway, for consistency.
11
Message-Id: <20221128142337.657646-9-eesposit@redhat.com>
12
13
Patch produced with scripts/coccinelle/inplace-byteswaps.cocci.
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>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
22
---
13
---
23
block/vdi.c | 64 ++++++++++++++++++++++++++---------------------------
14
include/block/block-global-state.h | 3 ++-
24
1 file changed, 32 insertions(+), 32 deletions(-)
15
block.c | 5 +++--
25
16
block/crypto.c | 2 +-
17
block/parallels.c | 2 +-
18
block/qcow.c | 2 +-
19
block/qcow2.c | 4 ++--
20
block/qed.c | 2 +-
21
block/raw-format.c | 2 +-
22
block/vdi.c | 2 +-
23
block/vhdx.c | 2 +-
24
block/vmdk.c | 2 +-
25
block/vpc.c | 2 +-
26
12 files changed, 16 insertions(+), 14 deletions(-)
27
28
diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h
29
index XXXXXXX..XXXXXXX 100644
30
--- a/include/block/block-global-state.h
31
+++ b/include/block/block-global-state.h
32
@@ -XXX,XX +XXX,XX @@ BlockDriver *bdrv_find_protocol(const char *filename,
33
BlockDriver *bdrv_find_format(const char *format_name);
34
int bdrv_create(BlockDriver *drv, const char* filename,
35
QemuOpts *opts, Error **errp);
36
-int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp);
37
+int coroutine_fn bdrv_co_create_file(const char *filename, QemuOpts *opts,
38
+ Error **errp);
39
40
BlockDriverState *bdrv_new(void);
41
int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
42
diff --git a/block.c b/block.c
43
index XXXXXXX..XXXXXXX 100644
44
--- a/block.c
45
+++ b/block.c
46
@@ -XXX,XX +XXX,XX @@ out:
47
return ret;
48
}
49
50
-int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp)
51
+int coroutine_fn bdrv_co_create_file(const char *filename, QemuOpts *opts,
52
+ Error **errp)
53
{
54
QemuOpts *protocol_opts;
55
BlockDriver *drv;
56
@@ -XXX,XX +XXX,XX @@ int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp)
57
goto out;
58
}
59
60
- ret = bdrv_create(drv, filename, protocol_opts, errp);
61
+ ret = bdrv_co_create(drv, filename, protocol_opts, errp);
62
out:
63
qemu_opts_del(protocol_opts);
64
qobject_unref(qdict);
65
diff --git a/block/crypto.c b/block/crypto.c
66
index XXXXXXX..XXXXXXX 100644
67
--- a/block/crypto.c
68
+++ b/block/crypto.c
69
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn block_crypto_co_create_opts_luks(BlockDriver *drv,
70
}
71
72
/* Create protocol layer */
73
- ret = bdrv_create_file(filename, opts, errp);
74
+ ret = bdrv_co_create_file(filename, opts, errp);
75
if (ret < 0) {
76
goto fail;
77
}
78
diff --git a/block/parallels.c b/block/parallels.c
79
index XXXXXXX..XXXXXXX 100644
80
--- a/block/parallels.c
81
+++ b/block/parallels.c
82
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn parallels_co_create_opts(BlockDriver *drv,
83
}
84
85
/* Create and open the file (protocol layer) */
86
- ret = bdrv_create_file(filename, opts, errp);
87
+ ret = bdrv_co_create_file(filename, opts, errp);
88
if (ret < 0) {
89
goto done;
90
}
91
diff --git a/block/qcow.c b/block/qcow.c
92
index XXXXXXX..XXXXXXX 100644
93
--- a/block/qcow.c
94
+++ b/block/qcow.c
95
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow_co_create_opts(BlockDriver *drv,
96
}
97
98
/* Create and open the file (protocol layer) */
99
- ret = bdrv_create_file(filename, opts, errp);
100
+ ret = bdrv_co_create_file(filename, opts, errp);
101
if (ret < 0) {
102
goto fail;
103
}
104
diff --git a/block/qcow2.c b/block/qcow2.c
105
index XXXXXXX..XXXXXXX 100644
106
--- a/block/qcow2.c
107
+++ b/block/qcow2.c
108
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(BlockDriver *drv,
109
}
110
111
/* Create and open the file (protocol layer) */
112
- ret = bdrv_create_file(filename, opts, errp);
113
+ ret = bdrv_co_create_file(filename, opts, errp);
114
if (ret < 0) {
115
goto finish;
116
}
117
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(BlockDriver *drv,
118
/* Create and open an external data file (protocol layer) */
119
val = qdict_get_try_str(qdict, BLOCK_OPT_DATA_FILE);
120
if (val) {
121
- ret = bdrv_create_file(val, opts, errp);
122
+ ret = bdrv_co_create_file(val, opts, errp);
123
if (ret < 0) {
124
goto finish;
125
}
126
diff --git a/block/qed.c b/block/qed.c
127
index XXXXXXX..XXXXXXX 100644
128
--- a/block/qed.c
129
+++ b/block/qed.c
130
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_create_opts(BlockDriver *drv,
131
}
132
133
/* Create and open the file (protocol layer) */
134
- ret = bdrv_create_file(filename, opts, errp);
135
+ ret = bdrv_co_create_file(filename, opts, errp);
136
if (ret < 0) {
137
goto fail;
138
}
139
diff --git a/block/raw-format.c b/block/raw-format.c
140
index XXXXXXX..XXXXXXX 100644
141
--- a/block/raw-format.c
142
+++ b/block/raw-format.c
143
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_create_opts(BlockDriver *drv,
144
QemuOpts *opts,
145
Error **errp)
146
{
147
- return bdrv_create_file(filename, opts, errp);
148
+ return bdrv_co_create_file(filename, opts, errp);
149
}
150
151
static int raw_open(BlockDriverState *bs, QDict *options, int flags,
26
diff --git a/block/vdi.c b/block/vdi.c
152
diff --git a/block/vdi.c b/block/vdi.c
27
index XXXXXXX..XXXXXXX 100644
153
index XXXXXXX..XXXXXXX 100644
28
--- a/block/vdi.c
154
--- a/block/vdi.c
29
+++ b/block/vdi.c
155
+++ b/block/vdi.c
30
@@ -XXX,XX +XXX,XX @@ typedef struct {
156
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_create_opts(BlockDriver *drv,
31
157
qdict = qemu_opts_to_qdict_filtered(opts, NULL, &vdi_create_opts, true);
32
static void vdi_header_to_cpu(VdiHeader *header)
158
33
{
159
/* Create and open the file (protocol layer) */
34
- le32_to_cpus(&header->signature);
160
- ret = bdrv_create_file(filename, opts, errp);
35
- le32_to_cpus(&header->version);
161
+ ret = bdrv_co_create_file(filename, opts, errp);
36
- le32_to_cpus(&header->header_size);
162
if (ret < 0) {
37
- le32_to_cpus(&header->image_type);
163
goto done;
38
- le32_to_cpus(&header->image_flags);
164
}
39
- le32_to_cpus(&header->offset_bmap);
165
diff --git a/block/vhdx.c b/block/vhdx.c
40
- le32_to_cpus(&header->offset_data);
166
index XXXXXXX..XXXXXXX 100644
41
- le32_to_cpus(&header->cylinders);
167
--- a/block/vhdx.c
42
- le32_to_cpus(&header->heads);
168
+++ b/block/vhdx.c
43
- le32_to_cpus(&header->sectors);
169
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vhdx_co_create_opts(BlockDriver *drv,
44
- le32_to_cpus(&header->sector_size);
170
}
45
- le64_to_cpus(&header->disk_size);
171
46
- le32_to_cpus(&header->block_size);
172
/* Create and open the file (protocol layer) */
47
- le32_to_cpus(&header->block_extra);
173
- ret = bdrv_create_file(filename, opts, errp);
48
- le32_to_cpus(&header->blocks_in_image);
174
+ ret = bdrv_co_create_file(filename, opts, errp);
49
- le32_to_cpus(&header->blocks_allocated);
175
if (ret < 0) {
50
+ header->signature = le32_to_cpu(header->signature);
176
goto fail;
51
+ header->version = le32_to_cpu(header->version);
177
}
52
+ header->header_size = le32_to_cpu(header->header_size);
178
diff --git a/block/vmdk.c b/block/vmdk.c
53
+ header->image_type = le32_to_cpu(header->image_type);
179
index XXXXXXX..XXXXXXX 100644
54
+ header->image_flags = le32_to_cpu(header->image_flags);
180
--- a/block/vmdk.c
55
+ header->offset_bmap = le32_to_cpu(header->offset_bmap);
181
+++ b/block/vmdk.c
56
+ header->offset_data = le32_to_cpu(header->offset_data);
182
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vmdk_create_extent(const char *filename,
57
+ header->cylinders = le32_to_cpu(header->cylinders);
183
int ret;
58
+ header->heads = le32_to_cpu(header->heads);
184
BlockBackend *blk = NULL;
59
+ header->sectors = le32_to_cpu(header->sectors);
185
60
+ header->sector_size = le32_to_cpu(header->sector_size);
186
- ret = bdrv_create_file(filename, opts, errp);
61
+ header->disk_size = le64_to_cpu(header->disk_size);
187
+ ret = bdrv_co_create_file(filename, opts, errp);
62
+ header->block_size = le32_to_cpu(header->block_size);
188
if (ret < 0) {
63
+ header->block_extra = le32_to_cpu(header->block_extra);
189
goto exit;
64
+ header->blocks_in_image = le32_to_cpu(header->blocks_in_image);
190
}
65
+ header->blocks_allocated = le32_to_cpu(header->blocks_allocated);
191
diff --git a/block/vpc.c b/block/vpc.c
66
qemu_uuid_bswap(&header->uuid_image);
192
index XXXXXXX..XXXXXXX 100644
67
qemu_uuid_bswap(&header->uuid_last_snap);
193
--- a/block/vpc.c
68
qemu_uuid_bswap(&header->uuid_link);
194
+++ b/block/vpc.c
69
@@ -XXX,XX +XXX,XX @@ static void vdi_header_to_cpu(VdiHeader *header)
195
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_create_opts(BlockDriver *drv,
70
196
}
71
static void vdi_header_to_le(VdiHeader *header)
197
72
{
198
/* Create and open the file (protocol layer) */
73
- cpu_to_le32s(&header->signature);
199
- ret = bdrv_create_file(filename, opts, errp);
74
- cpu_to_le32s(&header->version);
200
+ ret = bdrv_co_create_file(filename, opts, errp);
75
- cpu_to_le32s(&header->header_size);
201
if (ret < 0) {
76
- cpu_to_le32s(&header->image_type);
202
goto fail;
77
- cpu_to_le32s(&header->image_flags);
203
}
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
--
204
--
109
2.19.1
205
2.38.1
110
111
diff view generated by jsdifflib
New patch
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
1
2
3
In preparation to the incoming new function specifiers,
4
rename g_c_w with a more meaningful name and document it.
5
6
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
7
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
8
Message-Id: <20221128142337.657646-10-eesposit@redhat.com>
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
12
docs/devel/block-coroutine-wrapper.rst | 6 +--
13
block/coroutines.h | 4 +-
14
include/block/block-common.h | 11 +++--
15
include/block/block-io.h | 44 ++++++++---------
16
include/sysemu/block-backend-io.h | 68 +++++++++++++-------------
17
scripts/block-coroutine-wrapper.py | 6 +--
18
6 files changed, 71 insertions(+), 68 deletions(-)
19
20
diff --git a/docs/devel/block-coroutine-wrapper.rst b/docs/devel/block-coroutine-wrapper.rst
21
index XXXXXXX..XXXXXXX 100644
22
--- a/docs/devel/block-coroutine-wrapper.rst
23
+++ b/docs/devel/block-coroutine-wrapper.rst
24
@@ -XXX,XX +XXX,XX @@ called ``bdrv_foo(<same args>)``. In this case the script can help. To
25
trigger the generation:
26
27
1. You need ``bdrv_foo`` declaration somewhere (for example, in
28
- ``block/coroutines.h``) with the ``generated_co_wrapper`` mark,
29
+ ``block/coroutines.h``) with the ``co_wrapper_mixed`` mark,
30
like this:
31
32
.. code-block:: c
33
34
- int generated_co_wrapper bdrv_foo(<some args>);
35
+ int co_wrapper_mixed bdrv_foo(<some args>);
36
37
2. You need to feed this declaration to block-coroutine-wrapper script.
38
For this, add the .h (or .c) file with the declaration to the
39
@@ -XXX,XX +XXX,XX @@ Links
40
41
1. The script location is ``scripts/block-coroutine-wrapper.py``.
42
43
-2. Generic place for private ``generated_co_wrapper`` declarations is
44
+2. Generic place for private ``co_wrapper_mixed`` declarations is
45
``block/coroutines.h``, for public declarations:
46
``include/block/block.h``
47
48
diff --git a/block/coroutines.h b/block/coroutines.h
49
index XXXXXXX..XXXXXXX 100644
50
--- a/block/coroutines.h
51
+++ b/block/coroutines.h
52
@@ -XXX,XX +XXX,XX @@ nbd_co_do_establish_connection(BlockDriverState *bs, bool blocking,
53
* the "I/O or GS" API.
54
*/
55
56
-int generated_co_wrapper
57
+int co_wrapper_mixed
58
bdrv_common_block_status_above(BlockDriverState *bs,
59
BlockDriverState *base,
60
bool include_base,
61
@@ -XXX,XX +XXX,XX @@ bdrv_common_block_status_above(BlockDriverState *bs,
62
int64_t *map,
63
BlockDriverState **file,
64
int *depth);
65
-int generated_co_wrapper
66
+int co_wrapper_mixed
67
nbd_do_establish_connection(BlockDriverState *bs, bool blocking, Error **errp);
68
69
#endif /* BLOCK_COROUTINES_H */
70
diff --git a/include/block/block-common.h b/include/block/block-common.h
71
index XXXXXXX..XXXXXXX 100644
72
--- a/include/block/block-common.h
73
+++ b/include/block/block-common.h
74
@@ -XXX,XX +XXX,XX @@
75
#include "qemu/transactions.h"
76
77
/*
78
- * generated_co_wrapper
79
+ * co_wrapper{*}: Function specifiers used by block-coroutine-wrapper.py
80
*
81
- * Function specifier, which does nothing but mark functions to be
82
+ * Function specifiers, which do nothing but mark functions to be
83
* generated by scripts/block-coroutine-wrapper.py
84
*
85
- * Read more in docs/devel/block-coroutine-wrapper.rst
86
+ * Usage: read docs/devel/block-coroutine-wrapper.rst
87
+ *
88
+ * co_wrapper_mixed functions can be called by both coroutine and
89
+ * non-coroutine context.
90
*/
91
-#define generated_co_wrapper
92
+#define co_wrapper_mixed
93
94
/* block.c */
95
typedef struct BlockDriver BlockDriver;
96
diff --git a/include/block/block-io.h b/include/block/block-io.h
97
index XXXXXXX..XXXXXXX 100644
98
--- a/include/block/block-io.h
99
+++ b/include/block/block-io.h
100
@@ -XXX,XX +XXX,XX @@
101
* to catch when they are accidentally called by the wrong API.
102
*/
103
104
-int generated_co_wrapper bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset,
105
- int64_t bytes,
106
- BdrvRequestFlags flags);
107
+int co_wrapper_mixed bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset,
108
+ int64_t bytes,
109
+ BdrvRequestFlags flags);
110
int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags);
111
-int generated_co_wrapper bdrv_pread(BdrvChild *child, int64_t offset,
112
- int64_t bytes, void *buf,
113
- BdrvRequestFlags flags);
114
-int generated_co_wrapper bdrv_pwrite(BdrvChild *child, int64_t offset,
115
- int64_t bytes, const void *buf,
116
- BdrvRequestFlags flags);
117
-int generated_co_wrapper bdrv_pwrite_sync(BdrvChild *child, int64_t offset,
118
- int64_t bytes, const void *buf,
119
- BdrvRequestFlags flags);
120
+int co_wrapper_mixed bdrv_pread(BdrvChild *child, int64_t offset,
121
+ int64_t bytes, void *buf,
122
+ BdrvRequestFlags flags);
123
+int co_wrapper_mixed bdrv_pwrite(BdrvChild *child, int64_t offset,
124
+ int64_t bytes, const void *buf,
125
+ BdrvRequestFlags flags);
126
+int co_wrapper_mixed bdrv_pwrite_sync(BdrvChild *child, int64_t offset,
127
+ int64_t bytes, const void *buf,
128
+ BdrvRequestFlags flags);
129
int coroutine_fn bdrv_co_pwrite_sync(BdrvChild *child, int64_t offset,
130
int64_t bytes, const void *buf,
131
BdrvRequestFlags flags);
132
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_copy_range(BdrvChild *src, int64_t src_offset,
133
134
void bdrv_drain(BlockDriverState *bs);
135
136
-int generated_co_wrapper
137
+int co_wrapper_mixed
138
bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
139
PreallocMode prealloc, BdrvRequestFlags flags, Error **errp);
140
141
-int generated_co_wrapper bdrv_check(BlockDriverState *bs, BdrvCheckResult *res,
142
- BdrvCheckMode fix);
143
+int co_wrapper_mixed bdrv_check(BlockDriverState *bs, BdrvCheckResult *res,
144
+ BdrvCheckMode fix);
145
146
/* Invalidate any cached metadata used by image formats */
147
-int generated_co_wrapper bdrv_invalidate_cache(BlockDriverState *bs,
148
- Error **errp);
149
-int generated_co_wrapper bdrv_flush(BlockDriverState *bs);
150
-int generated_co_wrapper bdrv_pdiscard(BdrvChild *child, int64_t offset,
151
- int64_t bytes);
152
-int generated_co_wrapper
153
+int co_wrapper_mixed bdrv_invalidate_cache(BlockDriverState *bs,
154
+ Error **errp);
155
+int co_wrapper_mixed bdrv_flush(BlockDriverState *bs);
156
+int co_wrapper_mixed bdrv_pdiscard(BdrvChild *child, int64_t offset,
157
+ int64_t bytes);
158
+int co_wrapper_mixed
159
bdrv_readv_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos);
160
-int generated_co_wrapper
161
+int co_wrapper_mixed
162
bdrv_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos);
163
164
/**
165
diff --git a/include/sysemu/block-backend-io.h b/include/sysemu/block-backend-io.h
166
index XXXXXXX..XXXXXXX 100644
167
--- a/include/sysemu/block-backend-io.h
168
+++ b/include/sysemu/block-backend-io.h
169
@@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_is_allocated_above(BlockBackend *blk,
170
* the "I/O or GS" API.
171
*/
172
173
-int generated_co_wrapper blk_pread(BlockBackend *blk, int64_t offset,
174
- int64_t bytes, void *buf,
175
- BdrvRequestFlags flags);
176
+int co_wrapper_mixed blk_pread(BlockBackend *blk, int64_t offset,
177
+ int64_t bytes, void *buf,
178
+ BdrvRequestFlags flags);
179
int coroutine_fn blk_co_pread(BlockBackend *blk, int64_t offset, int64_t bytes,
180
void *buf, BdrvRequestFlags flags);
181
182
-int generated_co_wrapper blk_preadv(BlockBackend *blk, int64_t offset,
183
- int64_t bytes, QEMUIOVector *qiov,
184
- BdrvRequestFlags flags);
185
+int co_wrapper_mixed blk_preadv(BlockBackend *blk, int64_t offset,
186
+ int64_t bytes, QEMUIOVector *qiov,
187
+ BdrvRequestFlags flags);
188
int coroutine_fn blk_co_preadv(BlockBackend *blk, int64_t offset,
189
int64_t bytes, QEMUIOVector *qiov,
190
BdrvRequestFlags flags);
191
192
-int generated_co_wrapper blk_preadv_part(BlockBackend *blk, int64_t offset,
193
- int64_t bytes, QEMUIOVector *qiov,
194
- size_t qiov_offset,
195
- BdrvRequestFlags flags);
196
+int co_wrapper_mixed blk_preadv_part(BlockBackend *blk, int64_t offset,
197
+ int64_t bytes, QEMUIOVector *qiov,
198
+ size_t qiov_offset,
199
+ BdrvRequestFlags flags);
200
int coroutine_fn blk_co_preadv_part(BlockBackend *blk, int64_t offset,
201
int64_t bytes, QEMUIOVector *qiov,
202
size_t qiov_offset, BdrvRequestFlags flags);
203
204
-int generated_co_wrapper blk_pwrite(BlockBackend *blk, int64_t offset,
205
- int64_t bytes, const void *buf,
206
- BdrvRequestFlags flags);
207
+int co_wrapper_mixed blk_pwrite(BlockBackend *blk, int64_t offset,
208
+ int64_t bytes, const void *buf,
209
+ BdrvRequestFlags flags);
210
int coroutine_fn blk_co_pwrite(BlockBackend *blk, int64_t offset, int64_t bytes,
211
const void *buf, BdrvRequestFlags flags);
212
213
-int generated_co_wrapper blk_pwritev(BlockBackend *blk, int64_t offset,
214
- int64_t bytes, QEMUIOVector *qiov,
215
- BdrvRequestFlags flags);
216
+int co_wrapper_mixed blk_pwritev(BlockBackend *blk, int64_t offset,
217
+ int64_t bytes, QEMUIOVector *qiov,
218
+ BdrvRequestFlags flags);
219
int coroutine_fn blk_co_pwritev(BlockBackend *blk, int64_t offset,
220
int64_t bytes, QEMUIOVector *qiov,
221
BdrvRequestFlags flags);
222
223
-int generated_co_wrapper blk_pwritev_part(BlockBackend *blk, int64_t offset,
224
- int64_t bytes, QEMUIOVector *qiov,
225
- size_t qiov_offset,
226
- BdrvRequestFlags flags);
227
+int co_wrapper_mixed blk_pwritev_part(BlockBackend *blk, int64_t offset,
228
+ int64_t bytes, QEMUIOVector *qiov,
229
+ size_t qiov_offset,
230
+ BdrvRequestFlags flags);
231
int coroutine_fn blk_co_pwritev_part(BlockBackend *blk, int64_t offset,
232
int64_t bytes,
233
QEMUIOVector *qiov, size_t qiov_offset,
234
BdrvRequestFlags flags);
235
236
-int generated_co_wrapper blk_pwrite_compressed(BlockBackend *blk,
237
- int64_t offset, int64_t bytes,
238
- const void *buf);
239
+int co_wrapper_mixed blk_pwrite_compressed(BlockBackend *blk,
240
+ int64_t offset, int64_t bytes,
241
+ const void *buf);
242
int coroutine_fn blk_co_pwrite_compressed(BlockBackend *blk, int64_t offset,
243
int64_t bytes, const void *buf);
244
245
-int generated_co_wrapper blk_pwrite_zeroes(BlockBackend *blk, int64_t offset,
246
- int64_t bytes,
247
- BdrvRequestFlags flags);
248
+int co_wrapper_mixed blk_pwrite_zeroes(BlockBackend *blk, int64_t offset,
249
+ int64_t bytes,
250
+ BdrvRequestFlags flags);
251
int coroutine_fn blk_co_pwrite_zeroes(BlockBackend *blk, int64_t offset,
252
int64_t bytes, BdrvRequestFlags flags);
253
254
-int generated_co_wrapper blk_pdiscard(BlockBackend *blk, int64_t offset,
255
- int64_t bytes);
256
+int co_wrapper_mixed blk_pdiscard(BlockBackend *blk, int64_t offset,
257
+ int64_t bytes);
258
int coroutine_fn blk_co_pdiscard(BlockBackend *blk, int64_t offset,
259
int64_t bytes);
260
261
-int generated_co_wrapper blk_flush(BlockBackend *blk);
262
+int co_wrapper_mixed blk_flush(BlockBackend *blk);
263
int coroutine_fn blk_co_flush(BlockBackend *blk);
264
265
-int generated_co_wrapper blk_ioctl(BlockBackend *blk, unsigned long int req,
266
- void *buf);
267
+int co_wrapper_mixed blk_ioctl(BlockBackend *blk, unsigned long int req,
268
+ void *buf);
269
int coroutine_fn blk_co_ioctl(BlockBackend *blk, unsigned long int req,
270
void *buf);
271
272
-int generated_co_wrapper blk_truncate(BlockBackend *blk, int64_t offset,
273
- bool exact, PreallocMode prealloc,
274
- BdrvRequestFlags flags, Error **errp);
275
+int co_wrapper_mixed blk_truncate(BlockBackend *blk, int64_t offset,
276
+ bool exact, PreallocMode prealloc,
277
+ BdrvRequestFlags flags, Error **errp);
278
int coroutine_fn blk_co_truncate(BlockBackend *blk, int64_t offset, bool exact,
279
PreallocMode prealloc, BdrvRequestFlags flags,
280
Error **errp);
281
diff --git a/scripts/block-coroutine-wrapper.py b/scripts/block-coroutine-wrapper.py
282
index XXXXXXX..XXXXXXX 100644
283
--- a/scripts/block-coroutine-wrapper.py
284
+++ b/scripts/block-coroutine-wrapper.py
285
@@ -XXX,XX +XXX,XX @@
286
"""Generate coroutine wrappers for block subsystem.
287
288
The program parses one or several concatenated c files from stdin,
289
-searches for functions with the 'generated_co_wrapper' specifier
290
+searches for functions with the 'co_wrapper_mixed' specifier
291
and generates corresponding wrappers on stdout.
292
293
Usage: block-coroutine-wrapper.py generated-file.c FILE.[ch]...
294
@@ -XXX,XX +XXX,XX @@ def gen_block(self, format: str) -> str:
295
return '\n'.join(format.format_map(arg.__dict__) for arg in self.args)
296
297
298
-# Match wrappers declared with a generated_co_wrapper mark
299
-func_decl_re = re.compile(r'^int\s*generated_co_wrapper\s*'
300
+# Match wrappers declared with a co_wrapper_mixed mark
301
+func_decl_re = re.compile(r'^int\s*co_wrapper_mixed\s*'
302
r'(?P<wrapper_name>[a-z][a-z0-9_]*)'
303
r'\((?P<args>[^)]*)\);$', re.MULTILINE)
304
305
--
306
2.38.1
diff view generated by jsdifflib
New patch
1
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
2
3
This new annotation starts just a function wrapper that creates
4
a new coroutine. It assumes the caller is not a coroutine.
5
It will be the default annotation to be used in the future.
6
7
This is much better as c_w_mixed, because it is clear if the caller
8
is a coroutine or not, and provides the advantage of automating
9
the code creation. In the future all c_w_mixed functions will be
10
substituted by co_wrapper.
11
12
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
13
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
14
Message-Id: <20221128142337.657646-11-eesposit@redhat.com>
15
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
---
18
docs/devel/block-coroutine-wrapper.rst | 6 +-
19
include/block/block-common.h | 8 +-
20
scripts/block-coroutine-wrapper.py | 110 +++++++++++++++++--------
21
3 files changed, 86 insertions(+), 38 deletions(-)
22
23
diff --git a/docs/devel/block-coroutine-wrapper.rst b/docs/devel/block-coroutine-wrapper.rst
24
index XXXXXXX..XXXXXXX 100644
25
--- a/docs/devel/block-coroutine-wrapper.rst
26
+++ b/docs/devel/block-coroutine-wrapper.rst
27
@@ -XXX,XX +XXX,XX @@ called ``bdrv_foo(<same args>)``. In this case the script can help. To
28
trigger the generation:
29
30
1. You need ``bdrv_foo`` declaration somewhere (for example, in
31
- ``block/coroutines.h``) with the ``co_wrapper_mixed`` mark,
32
+ ``block/coroutines.h``) with the ``co_wrapper`` mark,
33
like this:
34
35
.. code-block:: c
36
37
- int co_wrapper_mixed bdrv_foo(<some args>);
38
+ int co_wrapper bdrv_foo(<some args>);
39
40
2. You need to feed this declaration to block-coroutine-wrapper script.
41
For this, add the .h (or .c) file with the declaration to the
42
@@ -XXX,XX +XXX,XX @@ Links
43
44
1. The script location is ``scripts/block-coroutine-wrapper.py``.
45
46
-2. Generic place for private ``co_wrapper_mixed`` declarations is
47
+2. Generic place for private ``co_wrapper`` declarations is
48
``block/coroutines.h``, for public declarations:
49
``include/block/block.h``
50
51
diff --git a/include/block/block-common.h b/include/block/block-common.h
52
index XXXXXXX..XXXXXXX 100644
53
--- a/include/block/block-common.h
54
+++ b/include/block/block-common.h
55
@@ -XXX,XX +XXX,XX @@
56
*
57
* Usage: read docs/devel/block-coroutine-wrapper.rst
58
*
59
- * co_wrapper_mixed functions can be called by both coroutine and
60
- * non-coroutine context.
61
+ * There are 2 kind of specifiers:
62
+ * - co_wrapper functions can be called by only non-coroutine context, because
63
+ * they always generate a new coroutine.
64
+ * - co_wrapper_mixed functions can be called by both coroutine and
65
+ * non-coroutine context.
66
*/
67
+#define co_wrapper
68
#define co_wrapper_mixed
69
70
/* block.c */
71
diff --git a/scripts/block-coroutine-wrapper.py b/scripts/block-coroutine-wrapper.py
72
index XXXXXXX..XXXXXXX 100644
73
--- a/scripts/block-coroutine-wrapper.py
74
+++ b/scripts/block-coroutine-wrapper.py
75
@@ -XXX,XX +XXX,XX @@
76
"""Generate coroutine wrappers for block subsystem.
77
78
The program parses one or several concatenated c files from stdin,
79
-searches for functions with the 'co_wrapper_mixed' specifier
80
+searches for functions with the 'co_wrapper' specifier
81
and generates corresponding wrappers on stdout.
82
83
Usage: block-coroutine-wrapper.py generated-file.c FILE.[ch]...
84
@@ -XXX,XX +XXX,XX @@ def __init__(self, param_decl: str) -> None:
85
86
87
class FuncDecl:
88
- def __init__(self, return_type: str, name: str, args: str) -> None:
89
+ def __init__(self, return_type: str, name: str, args: str,
90
+ variant: str) -> None:
91
self.return_type = return_type.strip()
92
self.name = name.strip()
93
+ self.struct_name = snake_to_camel(self.name)
94
self.args = [ParamDecl(arg.strip()) for arg in args.split(',')]
95
+ self.create_only_co = 'mixed' not in variant
96
+
97
+ subsystem, subname = self.name.split('_', 1)
98
+ self.co_name = f'{subsystem}_co_{subname}'
99
+
100
+ t = self.args[0].type
101
+ if t == 'BlockDriverState *':
102
+ bs = 'bs'
103
+ elif t == 'BdrvChild *':
104
+ bs = 'child->bs'
105
+ else:
106
+ bs = 'blk_bs(blk)'
107
+ self.bs = bs
108
109
def gen_list(self, format: str) -> str:
110
return ', '.join(format.format_map(arg.__dict__) for arg in self.args)
111
@@ -XXX,XX +XXX,XX @@ def gen_block(self, format: str) -> str:
112
return '\n'.join(format.format_map(arg.__dict__) for arg in self.args)
113
114
115
-# Match wrappers declared with a co_wrapper_mixed mark
116
-func_decl_re = re.compile(r'^int\s*co_wrapper_mixed\s*'
117
+# Match wrappers declared with a co_wrapper mark
118
+func_decl_re = re.compile(r'^int\s*co_wrapper'
119
+ r'(?P<variant>(_[a-z][a-z0-9_]*)?)\s*'
120
r'(?P<wrapper_name>[a-z][a-z0-9_]*)'
121
r'\((?P<args>[^)]*)\);$', re.MULTILINE)
122
123
@@ -XXX,XX +XXX,XX @@ def func_decl_iter(text: str) -> Iterator:
124
for m in func_decl_re.finditer(text):
125
yield FuncDecl(return_type='int',
126
name=m.group('wrapper_name'),
127
- args=m.group('args'))
128
+ args=m.group('args'),
129
+ variant=m.group('variant'))
130
131
132
def snake_to_camel(func_name: str) -> str:
133
@@ -XXX,XX +XXX,XX @@ def snake_to_camel(func_name: str) -> str:
134
return ''.join(words)
135
136
137
+def create_mixed_wrapper(func: FuncDecl) -> str:
138
+ """
139
+ Checks if we are already in coroutine
140
+ """
141
+ name = func.co_name
142
+ struct_name = func.struct_name
143
+ return f"""\
144
+int {func.name}({ func.gen_list('{decl}') })
145
+{{
146
+ if (qemu_in_coroutine()) {{
147
+ return {name}({ func.gen_list('{name}') });
148
+ }} else {{
149
+ {struct_name} s = {{
150
+ .poll_state.bs = {func.bs},
151
+ .poll_state.in_progress = true,
152
+
153
+{ func.gen_block(' .{name} = {name},') }
154
+ }};
155
+
156
+ s.poll_state.co = qemu_coroutine_create({name}_entry, &s);
157
+
158
+ return bdrv_poll_co(&s.poll_state);
159
+ }}
160
+}}"""
161
+
162
+
163
+def create_co_wrapper(func: FuncDecl) -> str:
164
+ """
165
+ Assumes we are not in coroutine, and creates one
166
+ """
167
+ name = func.co_name
168
+ struct_name = func.struct_name
169
+ return f"""\
170
+int {func.name}({ func.gen_list('{decl}') })
171
+{{
172
+ {struct_name} s = {{
173
+ .poll_state.bs = {func.bs},
174
+ .poll_state.in_progress = true,
175
+
176
+{ func.gen_block(' .{name} = {name},') }
177
+ }};
178
+ assert(!qemu_in_coroutine());
179
+
180
+ s.poll_state.co = qemu_coroutine_create({name}_entry, &s);
181
+
182
+ return bdrv_poll_co(&s.poll_state);
183
+}}"""
184
+
185
+
186
def gen_wrapper(func: FuncDecl) -> str:
187
assert not '_co_' in func.name
188
assert func.return_type == 'int'
189
assert func.args[0].type in ['BlockDriverState *', 'BdrvChild *',
190
'BlockBackend *']
191
192
- subsystem, subname = func.name.split('_', 1)
193
-
194
- name = f'{subsystem}_co_{subname}'
195
+ name = func.co_name
196
+ struct_name = func.struct_name
197
198
- t = func.args[0].type
199
- if t == 'BlockDriverState *':
200
- bs = 'bs'
201
- elif t == 'BdrvChild *':
202
- bs = 'child->bs'
203
- else:
204
- bs = 'blk_bs(blk)'
205
- struct_name = snake_to_camel(name)
206
+ creation_function = create_mixed_wrapper
207
+ if func.create_only_co:
208
+ creation_function = create_co_wrapper
209
210
return f"""\
211
/*
212
@@ -XXX,XX +XXX,XX @@ def gen_wrapper(func: FuncDecl) -> str:
213
aio_wait_kick();
214
}}
215
216
-int {func.name}({ func.gen_list('{decl}') })
217
-{{
218
- if (qemu_in_coroutine()) {{
219
- return {name}({ func.gen_list('{name}') });
220
- }} else {{
221
- {struct_name} s = {{
222
- .poll_state.bs = {bs},
223
- .poll_state.in_progress = true,
224
-
225
-{ func.gen_block(' .{name} = {name},') }
226
- }};
227
-
228
- s.poll_state.co = qemu_coroutine_create({name}_entry, &s);
229
-
230
- return bdrv_poll_co(&s.poll_state);
231
- }}
232
-}}"""
233
+{creation_function(func)}"""
234
235
236
def gen_wrappers(input_code: str) -> str:
237
--
238
2.38.1
diff view generated by jsdifflib
New patch
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
1
2
3
Right now, we take the first parameter of the function to get the
4
BlockDriverState to pass to bdrv_poll_co(), that internally calls
5
functions that figure in which aiocontext the coroutine should run.
6
7
However, it is useless to pass a bs just to get its own AioContext,
8
so instead pass it directly, and default to the main loop if no
9
BlockDriverState is passed as parameter.
10
11
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
12
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
13
Message-Id: <20221128142337.657646-12-eesposit@redhat.com>
14
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
---
17
block/block-gen.h | 6 +++---
18
scripts/block-coroutine-wrapper.py | 16 ++++++++--------
19
2 files changed, 11 insertions(+), 11 deletions(-)
20
21
diff --git a/block/block-gen.h b/block/block-gen.h
22
index XXXXXXX..XXXXXXX 100644
23
--- a/block/block-gen.h
24
+++ b/block/block-gen.h
25
@@ -XXX,XX +XXX,XX @@
26
27
/* Base structure for argument packing structures */
28
typedef struct BdrvPollCo {
29
- BlockDriverState *bs;
30
+ AioContext *ctx;
31
bool in_progress;
32
int ret;
33
Coroutine *co; /* Keep pointer here for debugging */
34
@@ -XXX,XX +XXX,XX @@ static inline int bdrv_poll_co(BdrvPollCo *s)
35
{
36
assert(!qemu_in_coroutine());
37
38
- bdrv_coroutine_enter(s->bs, s->co);
39
- BDRV_POLL_WHILE(s->bs, s->in_progress);
40
+ aio_co_enter(s->ctx, s->co);
41
+ AIO_WAIT_WHILE(s->ctx, s->in_progress);
42
43
return s->ret;
44
}
45
diff --git a/scripts/block-coroutine-wrapper.py b/scripts/block-coroutine-wrapper.py
46
index XXXXXXX..XXXXXXX 100644
47
--- a/scripts/block-coroutine-wrapper.py
48
+++ b/scripts/block-coroutine-wrapper.py
49
@@ -XXX,XX +XXX,XX @@ def __init__(self, return_type: str, name: str, args: str,
50
51
t = self.args[0].type
52
if t == 'BlockDriverState *':
53
- bs = 'bs'
54
+ ctx = 'bdrv_get_aio_context(bs)'
55
elif t == 'BdrvChild *':
56
- bs = 'child->bs'
57
+ ctx = 'bdrv_get_aio_context(child->bs)'
58
+ elif t == 'BlockBackend *':
59
+ ctx = 'blk_get_aio_context(blk)'
60
else:
61
- bs = 'blk_bs(blk)'
62
- self.bs = bs
63
+ ctx = 'qemu_get_aio_context()'
64
+ self.ctx = ctx
65
66
def gen_list(self, format: str) -> str:
67
return ', '.join(format.format_map(arg.__dict__) for arg in self.args)
68
@@ -XXX,XX +XXX,XX @@ def create_mixed_wrapper(func: FuncDecl) -> str:
69
return {name}({ func.gen_list('{name}') });
70
}} else {{
71
{struct_name} s = {{
72
- .poll_state.bs = {func.bs},
73
+ .poll_state.ctx = {func.ctx},
74
.poll_state.in_progress = true,
75
76
{ func.gen_block(' .{name} = {name},') }
77
@@ -XXX,XX +XXX,XX @@ def create_co_wrapper(func: FuncDecl) -> str:
78
int {func.name}({ func.gen_list('{decl}') })
79
{{
80
{struct_name} s = {{
81
- .poll_state.bs = {func.bs},
82
+ .poll_state.ctx = {func.ctx},
83
.poll_state.in_progress = true,
84
85
{ func.gen_block(' .{name} = {name},') }
86
@@ -XXX,XX +XXX,XX @@ def create_co_wrapper(func: FuncDecl) -> str:
87
def gen_wrapper(func: FuncDecl) -> str:
88
assert not '_co_' in func.name
89
assert func.return_type == 'int'
90
- assert func.args[0].type in ['BlockDriverState *', 'BdrvChild *',
91
- 'BlockBackend *']
92
93
name = func.co_name
94
struct_name = func.struct_name
95
--
96
2.38.1
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
2
2
3
There is no good reason why there should be a newline in this
3
Extend the regex to cover also return type, pointers included.
4
description, so remove it.
4
This implies that the value returned by the function cannot be
5
a simple "int" anymore, but the custom return type.
6
Therefore remove poll_state->ret and instead use a per-function
7
custom "ret" field.
5
8
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
10
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
8
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
11
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
12
Message-Id: <20221128142337.657646-13-eesposit@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
14
---
11
vl.c | 2 +-
15
block/block-gen.h | 5 +----
12
1 file changed, 1 insertion(+), 1 deletion(-)
16
scripts/block-coroutine-wrapper.py | 19 +++++++++++--------
17
2 files changed, 12 insertions(+), 12 deletions(-)
13
18
14
diff --git a/vl.c b/vl.c
19
diff --git a/block/block-gen.h b/block/block-gen.h
15
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
16
--- a/vl.c
21
--- a/block/block-gen.h
17
+++ b/vl.c
22
+++ b/block/block-gen.h
18
@@ -XXX,XX +XXX,XX @@ static QemuOptsList qemu_fw_cfg_opts = {
23
@@ -XXX,XX +XXX,XX @@
19
}, {
24
typedef struct BdrvPollCo {
20
.name = "file",
25
AioContext *ctx;
21
.type = QEMU_OPT_STRING,
26
bool in_progress;
22
- .help = "Sets the name of the file from which\n"
27
- int ret;
23
+ .help = "Sets the name of the file from which "
28
Coroutine *co; /* Keep pointer here for debugging */
24
"the fw_cfg blob will be loaded",
29
} BdrvPollCo;
25
}, {
30
26
.name = "string",
31
-static inline int bdrv_poll_co(BdrvPollCo *s)
32
+static inline void bdrv_poll_co(BdrvPollCo *s)
33
{
34
assert(!qemu_in_coroutine());
35
36
aio_co_enter(s->ctx, s->co);
37
AIO_WAIT_WHILE(s->ctx, s->in_progress);
38
-
39
- return s->ret;
40
}
41
42
#endif /* BLOCK_BLOCK_GEN_H */
43
diff --git a/scripts/block-coroutine-wrapper.py b/scripts/block-coroutine-wrapper.py
44
index XXXXXXX..XXXXXXX 100644
45
--- a/scripts/block-coroutine-wrapper.py
46
+++ b/scripts/block-coroutine-wrapper.py
47
@@ -XXX,XX +XXX,XX @@ def gen_block(self, format: str) -> str:
48
49
50
# Match wrappers declared with a co_wrapper mark
51
-func_decl_re = re.compile(r'^int\s*co_wrapper'
52
+func_decl_re = re.compile(r'^(?P<return_type>[a-zA-Z][a-zA-Z0-9_]* [\*]?)'
53
+ r'\s*co_wrapper'
54
r'(?P<variant>(_[a-z][a-z0-9_]*)?)\s*'
55
r'(?P<wrapper_name>[a-z][a-z0-9_]*)'
56
r'\((?P<args>[^)]*)\);$', re.MULTILINE)
57
@@ -XXX,XX +XXX,XX @@ def gen_block(self, format: str) -> str:
58
59
def func_decl_iter(text: str) -> Iterator:
60
for m in func_decl_re.finditer(text):
61
- yield FuncDecl(return_type='int',
62
+ yield FuncDecl(return_type=m.group('return_type'),
63
name=m.group('wrapper_name'),
64
args=m.group('args'),
65
variant=m.group('variant'))
66
@@ -XXX,XX +XXX,XX @@ def create_mixed_wrapper(func: FuncDecl) -> str:
67
name = func.co_name
68
struct_name = func.struct_name
69
return f"""\
70
-int {func.name}({ func.gen_list('{decl}') })
71
+{func.return_type} {func.name}({ func.gen_list('{decl}') })
72
{{
73
if (qemu_in_coroutine()) {{
74
return {name}({ func.gen_list('{name}') });
75
@@ -XXX,XX +XXX,XX @@ def create_mixed_wrapper(func: FuncDecl) -> str:
76
77
s.poll_state.co = qemu_coroutine_create({name}_entry, &s);
78
79
- return bdrv_poll_co(&s.poll_state);
80
+ bdrv_poll_co(&s.poll_state);
81
+ return s.ret;
82
}}
83
}}"""
84
85
@@ -XXX,XX +XXX,XX @@ def create_co_wrapper(func: FuncDecl) -> str:
86
name = func.co_name
87
struct_name = func.struct_name
88
return f"""\
89
-int {func.name}({ func.gen_list('{decl}') })
90
+{func.return_type} {func.name}({ func.gen_list('{decl}') })
91
{{
92
{struct_name} s = {{
93
.poll_state.ctx = {func.ctx},
94
@@ -XXX,XX +XXX,XX @@ def create_co_wrapper(func: FuncDecl) -> str:
95
96
s.poll_state.co = qemu_coroutine_create({name}_entry, &s);
97
98
- return bdrv_poll_co(&s.poll_state);
99
+ bdrv_poll_co(&s.poll_state);
100
+ return s.ret;
101
}}"""
102
103
104
def gen_wrapper(func: FuncDecl) -> str:
105
assert not '_co_' in func.name
106
- assert func.return_type == 'int'
107
108
name = func.co_name
109
struct_name = func.struct_name
110
@@ -XXX,XX +XXX,XX @@ def gen_wrapper(func: FuncDecl) -> str:
111
112
typedef struct {struct_name} {{
113
BdrvPollCo poll_state;
114
+ {func.return_type} ret;
115
{ func.gen_block(' {decl};') }
116
}} {struct_name};
117
118
@@ -XXX,XX +XXX,XX @@ def gen_wrapper(func: FuncDecl) -> str:
119
{{
120
{struct_name} *s = opaque;
121
122
- s->poll_state.ret = {name}({ func.gen_list('s->{name}') });
123
+ s->ret = {name}({ func.gen_list('s->{name}') });
124
s->poll_state.in_progress = false;
125
126
aio_wait_kick();
27
--
127
--
28
2.19.1
128
2.38.1
29
30
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
2
2
3
This is a static function with only one caller, so there's no need to
3
This function is never called in coroutine context, therefore
4
keep it. Inlining the code in quorum_compare() makes it much simpler.
4
instead of manually creating a new coroutine, delegate it to the
5
block-coroutine-wrapper script, defining it as co_wrapper.
5
6
6
Signed-off-by: Alberto Garcia <berto@igalia.com>
7
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
7
Reported-by: Markus Armbruster <armbru@redhat.com>
8
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
10
Message-Id: <20221128142337.657646-14-eesposit@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
12
---
10
block/quorum.c | 24 +++++-------------------
13
include/block/block-global-state.h | 8 ++++--
11
1 file changed, 5 insertions(+), 19 deletions(-)
14
block.c | 41 ++----------------------------
15
2 files changed, 8 insertions(+), 41 deletions(-)
12
16
13
diff --git a/block/quorum.c b/block/quorum.c
17
diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h
14
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
15
--- a/block/quorum.c
19
--- a/include/block/block-global-state.h
16
+++ b/block/quorum.c
20
+++ b/include/block/block-global-state.h
17
@@ -XXX,XX +XXX,XX @@ static bool quorum_iovec_compare(QEMUIOVector *a, QEMUIOVector *b)
21
@@ -XXX,XX +XXX,XX @@ BlockDriver *bdrv_find_protocol(const char *filename,
18
return true;
22
bool allow_protocol_prefix,
23
Error **errp);
24
BlockDriver *bdrv_find_format(const char *format_name);
25
-int bdrv_create(BlockDriver *drv, const char* filename,
26
- QemuOpts *opts, Error **errp);
27
+
28
+int coroutine_fn bdrv_co_create(BlockDriver *drv, const char *filename,
29
+ QemuOpts *opts, Error **errp);
30
+int co_wrapper bdrv_create(BlockDriver *drv, const char *filename,
31
+ QemuOpts *opts, Error **errp);
32
+
33
int coroutine_fn bdrv_co_create_file(const char *filename, QemuOpts *opts,
34
Error **errp);
35
36
diff --git a/block.c b/block.c
37
index XXXXXXX..XXXXXXX 100644
38
--- a/block.c
39
+++ b/block.c
40
@@ -XXX,XX +XXX,XX @@ typedef struct CreateCo {
41
Error *err;
42
} CreateCo;
43
44
-static int coroutine_fn bdrv_co_create(BlockDriver *drv, const char *filename,
45
- QemuOpts *opts, Error **errp)
46
+int coroutine_fn bdrv_co_create(BlockDriver *drv, const char *filename,
47
+ QemuOpts *opts, Error **errp)
48
{
49
int ret;
50
GLOBAL_STATE_CODE();
51
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_create(BlockDriver *drv, const char *filename,
52
return ret;
19
}
53
}
20
54
21
-static void GCC_FMT_ATTR(2, 3) quorum_err(QuorumAIOCB *acb,
55
-static void coroutine_fn bdrv_create_co_entry(void *opaque)
22
- const char *fmt, ...)
23
-{
56
-{
24
- va_list ap;
57
- CreateCo *cco = opaque;
58
- GLOBAL_STATE_CODE();
25
-
59
-
26
- va_start(ap, fmt);
60
- cco->ret = bdrv_co_create(cco->drv, cco->filename, cco->opts, &cco->err);
27
- fprintf(stderr, "quorum: offset=%" PRIu64 " bytes=%" PRIu64 " ",
61
- aio_wait_kick();
28
- acb->offset, acb->bytes);
29
- vfprintf(stderr, fmt, ap);
30
- fprintf(stderr, "\n");
31
- va_end(ap);
32
- exit(1);
33
-}
62
-}
34
-
63
-
35
-static bool quorum_compare(QuorumAIOCB *acb,
64
-int bdrv_create(BlockDriver *drv, const char* filename,
36
- QEMUIOVector *a,
65
- QemuOpts *opts, Error **errp)
37
- QEMUIOVector *b)
66
-{
38
+static bool quorum_compare(QuorumAIOCB *acb, QEMUIOVector *a, QEMUIOVector *b)
67
- GLOBAL_STATE_CODE();
39
{
68
-
40
BDRVQuorumState *s = acb->bs->opaque;
69
- if (qemu_in_coroutine()) {
41
ssize_t offset;
70
- /* Fast-path if already in coroutine context */
42
@@ -XXX,XX +XXX,XX @@ static bool quorum_compare(QuorumAIOCB *acb,
71
- return bdrv_co_create(drv, filename, opts, errp);
43
if (s->is_blkverify) {
72
- } else {
44
offset = qemu_iovec_compare(a, b);
73
- Coroutine *co;
45
if (offset != -1) {
74
- CreateCo cco = {
46
- quorum_err(acb, "contents mismatch at offset %" PRIu64,
75
- .drv = drv,
47
- acb->offset + offset);
76
- .filename = filename,
48
+ fprintf(stderr, "quorum: offset=%" PRIu64 " bytes=%" PRIu64
77
- .opts = opts,
49
+ " contents mismatch at offset %" PRIu64 "\n",
78
- .ret = NOT_DONE,
50
+ acb->offset, acb->bytes, acb->offset + offset);
79
- .err = NULL,
51
+ exit(1);
80
- };
52
}
81
-
53
return true;
82
- co = qemu_coroutine_create(bdrv_create_co_entry, &cco);
54
}
83
- qemu_coroutine_enter(co);
84
- while (cco.ret == NOT_DONE) {
85
- aio_poll(qemu_get_aio_context(), true);
86
- }
87
- error_propagate(errp, cco.err);
88
- return cco.ret;
89
- }
90
-}
91
-
92
/**
93
* Helper function for bdrv_create_file_fallback(): Resize @blk to at
94
* least the given @minimum_size.
55
--
95
--
56
2.19.1
96
2.38.1
57
58
diff view generated by jsdifflib
1
From: Peter Maydell <peter.maydell@linaro.org>
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
2
2
3
Taking the address of a field in a packed struct is a bad idea, because
3
bdrv_can_store_new_dirty_bitmap and bdrv_remove_persistent_dirty_bitmap
4
it might not be actually aligned enough for that pointer type (and
4
check if they are running in a coroutine, directly calling the
5
thus cause a crash on dereference on some host architectures). Newer
5
coroutine callback if it's the case.
6
versions of clang warn about this. Avoid the bug by not using the
6
Except that no coroutine calls such functions, therefore that check
7
"modify in place" byte swapping functions.
7
can be removed, and function creation can be offloaded to
8
c_w.
8
9
9
There are a few places where the in-place swap function is
10
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
10
used on something other than a packed struct field; we convert
11
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
11
those anyway, for consistency.
12
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
12
13
Message-Id: <20221128142337.657646-15-eesposit@redhat.com>
13
Patch produced with scripts/coccinelle/inplace-byteswaps.cocci.
14
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
---
15
---
19
block/vhdx.h | 12 ++---
16
include/block/block-common.h | 5 +-
20
block/vhdx-endian.c | 118 ++++++++++++++++++++++----------------------
17
include/block/block-io.h | 10 +++-
21
block/vhdx-log.c | 4 +-
18
include/block/dirty-bitmap.h | 10 +++-
22
block/vhdx.c | 18 +++----
19
block/dirty-bitmap.c | 88 +-----------------------------------
23
4 files changed, 76 insertions(+), 76 deletions(-)
20
block/meson.build | 1 +
21
5 files changed, 22 insertions(+), 92 deletions(-)
24
22
25
diff --git a/block/vhdx.h b/block/vhdx.h
23
diff --git a/include/block/block-common.h b/include/block/block-common.h
26
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
27
--- a/block/vhdx.h
25
--- a/include/block/block-common.h
28
+++ b/block/vhdx.h
26
+++ b/include/block/block-common.h
29
@@ -XXX,XX +XXX,XX @@ int vhdx_log_write_and_flush(BlockDriverState *bs, BDRVVHDXState *s,
27
@@ -XXX,XX +XXX,XX @@
30
28
#include "qemu/iov.h"
31
static inline void leguid_to_cpus(MSGUID *guid)
29
#include "qemu/coroutine.h"
32
{
30
#include "block/accounting.h"
33
- le32_to_cpus(&guid->data1);
31
-#include "block/dirty-bitmap.h"
34
- le16_to_cpus(&guid->data2);
32
-#include "block/blockjob.h"
35
- le16_to_cpus(&guid->data3);
33
#include "qemu/hbitmap.h"
36
+ guid->data1 = le32_to_cpu(guid->data1);
34
#include "qemu/transactions.h"
37
+ guid->data2 = le16_to_cpu(guid->data2);
35
38
+ guid->data3 = le16_to_cpu(guid->data3);
36
@@ -XXX,XX +XXX,XX @@
37
#define co_wrapper
38
#define co_wrapper_mixed
39
40
+#include "block/dirty-bitmap.h"
41
+#include "block/blockjob.h"
42
+
43
/* block.c */
44
typedef struct BlockDriver BlockDriver;
45
typedef struct BdrvChild BdrvChild;
46
diff --git a/include/block/block-io.h b/include/block/block-io.h
47
index XXXXXXX..XXXXXXX 100644
48
--- a/include/block/block-io.h
49
+++ b/include/block/block-io.h
50
@@ -XXX,XX +XXX,XX @@ AioContext *child_of_bds_get_parent_aio_context(BdrvChild *c);
51
void bdrv_io_plug(BlockDriverState *bs);
52
void bdrv_io_unplug(BlockDriverState *bs);
53
54
-bool bdrv_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name,
55
- uint32_t granularity, Error **errp);
56
+bool coroutine_fn bdrv_co_can_store_new_dirty_bitmap(BlockDriverState *bs,
57
+ const char *name,
58
+ uint32_t granularity,
59
+ Error **errp);
60
+bool co_wrapper bdrv_can_store_new_dirty_bitmap(BlockDriverState *bs,
61
+ const char *name,
62
+ uint32_t granularity,
63
+ Error **errp);
64
65
/**
66
*
67
diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
68
index XXXXXXX..XXXXXXX 100644
69
--- a/include/block/dirty-bitmap.h
70
+++ b/include/block/dirty-bitmap.h
71
@@ -XXX,XX +XXX,XX @@ int bdrv_dirty_bitmap_check(const BdrvDirtyBitmap *bitmap, uint32_t flags,
72
Error **errp);
73
void bdrv_release_dirty_bitmap(BdrvDirtyBitmap *bitmap);
74
void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs);
75
-int bdrv_remove_persistent_dirty_bitmap(BlockDriverState *bs, const char *name,
76
- Error **errp);
77
+
78
+int coroutine_fn bdrv_co_remove_persistent_dirty_bitmap(BlockDriverState *bs,
79
+ const char *name,
80
+ Error **errp);
81
+int co_wrapper bdrv_remove_persistent_dirty_bitmap(BlockDriverState *bs,
82
+ const char *name,
83
+ Error **errp);
84
+
85
void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap);
86
void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap);
87
void bdrv_enable_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap);
88
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
89
index XXXXXXX..XXXXXXX 100644
90
--- a/block/dirty-bitmap.c
91
+++ b/block/dirty-bitmap.c
92
@@ -XXX,XX +XXX,XX @@ void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs)
93
* not fail.
94
* This function doesn't release corresponding BdrvDirtyBitmap.
95
*/
96
-static int coroutine_fn
97
+int coroutine_fn
98
bdrv_co_remove_persistent_dirty_bitmap(BlockDriverState *bs, const char *name,
99
Error **errp)
100
{
101
@@ -XXX,XX +XXX,XX @@ bdrv_co_remove_persistent_dirty_bitmap(BlockDriverState *bs, const char *name,
102
return 0;
39
}
103
}
40
104
41
static inline void cpu_to_leguids(MSGUID *guid)
105
-typedef struct BdrvRemovePersistentDirtyBitmapCo {
42
{
106
- BlockDriverState *bs;
43
- cpu_to_le32s(&guid->data1);
107
- const char *name;
44
- cpu_to_le16s(&guid->data2);
108
- Error **errp;
45
- cpu_to_le16s(&guid->data3);
109
- int ret;
46
+ guid->data1 = cpu_to_le32(guid->data1);
110
-} BdrvRemovePersistentDirtyBitmapCo;
47
+ guid->data2 = cpu_to_le16(guid->data2);
111
-
48
+ guid->data3 = cpu_to_le16(guid->data3);
112
-static void coroutine_fn
113
-bdrv_co_remove_persistent_dirty_bitmap_entry(void *opaque)
114
-{
115
- BdrvRemovePersistentDirtyBitmapCo *s = opaque;
116
-
117
- s->ret = bdrv_co_remove_persistent_dirty_bitmap(s->bs, s->name, s->errp);
118
- aio_wait_kick();
119
-}
120
-
121
-int bdrv_remove_persistent_dirty_bitmap(BlockDriverState *bs, const char *name,
122
- Error **errp)
123
-{
124
- if (qemu_in_coroutine()) {
125
- return bdrv_co_remove_persistent_dirty_bitmap(bs, name, errp);
126
- } else {
127
- Coroutine *co;
128
- BdrvRemovePersistentDirtyBitmapCo s = {
129
- .bs = bs,
130
- .name = name,
131
- .errp = errp,
132
- .ret = -EINPROGRESS,
133
- };
134
-
135
- co = qemu_coroutine_create(bdrv_co_remove_persistent_dirty_bitmap_entry,
136
- &s);
137
- bdrv_coroutine_enter(bs, co);
138
- BDRV_POLL_WHILE(bs, s.ret == -EINPROGRESS);
139
-
140
- return s.ret;
141
- }
142
-}
143
-
144
bool
145
bdrv_supports_persistent_dirty_bitmap(BlockDriverState *bs)
146
{
147
@@ -XXX,XX +XXX,XX @@ bdrv_supports_persistent_dirty_bitmap(BlockDriverState *bs)
148
return false;
49
}
149
}
50
150
51
void vhdx_header_le_import(VHDXHeader *h);
151
-static bool coroutine_fn
52
diff --git a/block/vhdx-endian.c b/block/vhdx-endian.c
152
+bool coroutine_fn
53
index XXXXXXX..XXXXXXX 100644
153
bdrv_co_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name,
54
--- a/block/vhdx-endian.c
154
uint32_t granularity, Error **errp)
55
+++ b/block/vhdx-endian.c
155
{
56
@@ -XXX,XX +XXX,XX @@ void vhdx_header_le_import(VHDXHeader *h)
156
@@ -XXX,XX +XXX,XX @@ bdrv_co_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name,
57
{
157
return drv->bdrv_co_can_store_new_dirty_bitmap(bs, name, granularity, errp);
58
assert(h != NULL);
59
60
- le32_to_cpus(&h->signature);
61
- le32_to_cpus(&h->checksum);
62
- le64_to_cpus(&h->sequence_number);
63
+ h->signature = le32_to_cpu(h->signature);
64
+ h->checksum = le32_to_cpu(h->checksum);
65
+ h->sequence_number = le64_to_cpu(h->sequence_number);
66
67
leguid_to_cpus(&h->file_write_guid);
68
leguid_to_cpus(&h->data_write_guid);
69
leguid_to_cpus(&h->log_guid);
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
}
158
}
80
159
81
void vhdx_header_le_export(VHDXHeader *orig_h, VHDXHeader *new_h)
160
-typedef struct BdrvCanStoreNewDirtyBitmapCo {
82
@@ -XXX,XX +XXX,XX @@ void vhdx_log_desc_le_import(VHDXLogDescriptor *d)
161
- BlockDriverState *bs;
83
{
162
- const char *name;
84
assert(d != NULL);
163
- uint32_t granularity;
85
164
- Error **errp;
86
- le32_to_cpus(&d->signature);
165
- bool ret;
87
- le64_to_cpus(&d->file_offset);
166
-
88
- le64_to_cpus(&d->sequence_number);
167
- bool in_progress;
89
+ d->signature = le32_to_cpu(d->signature);
168
-} BdrvCanStoreNewDirtyBitmapCo;
90
+ d->file_offset = le64_to_cpu(d->file_offset);
169
-
91
+ d->sequence_number = le64_to_cpu(d->sequence_number);
170
-static void coroutine_fn bdrv_co_can_store_new_dirty_bitmap_entry(void *opaque)
92
}
171
-{
93
172
- BdrvCanStoreNewDirtyBitmapCo *s = opaque;
94
void vhdx_log_desc_le_export(VHDXLogDescriptor *d)
173
-
95
{
174
- s->ret = bdrv_co_can_store_new_dirty_bitmap(s->bs, s->name, s->granularity,
96
assert(d != NULL);
175
- s->errp);
97
176
- s->in_progress = false;
98
- cpu_to_le32s(&d->signature);
177
- aio_wait_kick();
99
- cpu_to_le32s(&d->trailing_bytes);
178
-}
100
- cpu_to_le64s(&d->leading_bytes);
179
-
101
- cpu_to_le64s(&d->file_offset);
180
-bool bdrv_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name,
102
- cpu_to_le64s(&d->sequence_number);
181
- uint32_t granularity, Error **errp)
103
+ d->signature = cpu_to_le32(d->signature);
182
-{
104
+ d->trailing_bytes = cpu_to_le32(d->trailing_bytes);
183
- IO_CODE();
105
+ d->leading_bytes = cpu_to_le64(d->leading_bytes);
184
- if (qemu_in_coroutine()) {
106
+ d->file_offset = cpu_to_le64(d->file_offset);
185
- return bdrv_co_can_store_new_dirty_bitmap(bs, name, granularity, errp);
107
+ d->sequence_number = cpu_to_le64(d->sequence_number);
186
- } else {
108
}
187
- Coroutine *co;
109
188
- BdrvCanStoreNewDirtyBitmapCo s = {
110
void vhdx_log_data_le_import(VHDXLogDataSector *d)
189
- .bs = bs,
111
{
190
- .name = name,
112
assert(d != NULL);
191
- .granularity = granularity,
113
192
- .errp = errp,
114
- le32_to_cpus(&d->data_signature);
193
- .in_progress = true,
115
- le32_to_cpus(&d->sequence_high);
194
- };
116
- le32_to_cpus(&d->sequence_low);
195
-
117
+ d->data_signature = le32_to_cpu(d->data_signature);
196
- co = qemu_coroutine_create(bdrv_co_can_store_new_dirty_bitmap_entry,
118
+ d->sequence_high = le32_to_cpu(d->sequence_high);
197
- &s);
119
+ d->sequence_low = le32_to_cpu(d->sequence_low);
198
- bdrv_coroutine_enter(bs, co);
120
}
199
- BDRV_POLL_WHILE(bs, s.in_progress);
121
200
-
122
void vhdx_log_data_le_export(VHDXLogDataSector *d)
201
- return s.ret;
123
{
202
- }
124
assert(d != NULL);
203
-}
125
204
-
126
- cpu_to_le32s(&d->data_signature);
205
void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
127
- cpu_to_le32s(&d->sequence_high);
206
{
128
- cpu_to_le32s(&d->sequence_low);
207
bdrv_dirty_bitmaps_lock(bitmap->bs);
129
+ d->data_signature = cpu_to_le32(d->data_signature);
208
diff --git a/block/meson.build b/block/meson.build
130
+ d->sequence_high = cpu_to_le32(d->sequence_high);
209
index XXXXXXX..XXXXXXX 100644
131
+ d->sequence_low = cpu_to_le32(d->sequence_low);
210
--- a/block/meson.build
132
}
211
+++ b/block/meson.build
133
212
@@ -XXX,XX +XXX,XX @@ block_gen_c = custom_target('block-gen.c',
134
void vhdx_log_entry_hdr_le_import(VHDXLogEntryHeader *hdr)
213
output: 'block-gen.c',
135
{
214
input: files(
136
assert(hdr != NULL);
215
'../include/block/block-io.h',
137
216
+ '../include/block/dirty-bitmap.h',
138
- le32_to_cpus(&hdr->signature);
217
'../include/block/block-global-state.h',
139
- le32_to_cpus(&hdr->checksum);
218
'../include/sysemu/block-backend-io.h',
140
- le32_to_cpus(&hdr->entry_length);
219
'coroutines.h'
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
--
220
--
359
2.19.1
221
2.38.1
360
361
diff view generated by jsdifflib
1
If read-only=off, but auto-read-only=on is given, open the file
1
Provide a separate function that just quiesces the users of a node to
2
read-write if we have the permissions, but instead of erroring out for
2
prevent new requests from coming in, but without waiting for the already
3
read-only files, just degrade to read-only.
3
in-flight I/O to complete.
4
5
This function can be used in contexts where polling is not allowed.
4
6
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Message-Id: <20221207131838.239125-2-kwolf@redhat.com>
9
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
11
---
8
block/file-posix.c | 19 ++++++++++++++++---
12
include/block/block-global-state.h | 1 +
9
1 file changed, 16 insertions(+), 3 deletions(-)
13
block/io.c | 19 +++++++++++++------
14
2 files changed, 14 insertions(+), 6 deletions(-)
10
15
11
diff --git a/block/file-posix.c b/block/file-posix.c
16
diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h
12
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
13
--- a/block/file-posix.c
18
--- a/include/block/block-global-state.h
14
+++ b/block/file-posix.c
19
+++ b/include/block/block-global-state.h
15
@@ -XXX,XX +XXX,XX @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
20
@@ -XXX,XX +XXX,XX @@ int bdrv_inactivate_all(void);
16
21
int bdrv_flush_all(void);
17
s->fd = -1;
22
void bdrv_close_all(void);
18
fd = qemu_open(filename, s->open_flags, 0644);
23
void bdrv_drain_all_begin(void);
19
- if (fd < 0) {
24
+void bdrv_drain_all_begin_nopoll(void);
20
- ret = -errno;
25
void bdrv_drain_all_end(void);
21
- error_setg_errno(errp, errno, "Could not open '%s'", filename);
26
void bdrv_drain_all(void);
22
+ ret = fd < 0 ? -errno : 0;
27
28
diff --git a/block/io.c b/block/io.c
29
index XXXXXXX..XXXXXXX 100644
30
--- a/block/io.c
31
+++ b/block/io.c
32
@@ -XXX,XX +XXX,XX @@ static bool bdrv_drain_all_poll(void)
33
* NOTE: no new block jobs or BlockDriverStates can be created between
34
* the bdrv_drain_all_begin() and bdrv_drain_all_end() calls.
35
*/
36
-void bdrv_drain_all_begin(void)
37
+void bdrv_drain_all_begin_nopoll(void)
38
{
39
BlockDriverState *bs = NULL;
40
GLOBAL_STATE_CODE();
41
42
- if (qemu_in_coroutine()) {
43
- bdrv_co_yield_to_drain(NULL, true, NULL, true);
44
- return;
45
- }
46
-
47
/*
48
* bdrv queue is managed by record/replay,
49
* waiting for finishing the I/O requests may
50
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
51
bdrv_do_drained_begin(bs, NULL, false);
52
aio_context_release(aio_context);
53
}
54
+}
23
+
55
+
24
+ if (ret == -EACCES || ret == -EROFS) {
56
+void bdrv_drain_all_begin(void)
25
+ /* Try to degrade to read-only, but if it doesn't work, still use the
57
+{
26
+ * normal error message. */
58
+ BlockDriverState *bs = NULL;
27
+ if (bdrv_apply_auto_read_only(bs, NULL, NULL) == 0) {
59
+
28
+ bdrv_flags &= ~BDRV_O_RDWR;
60
+ if (qemu_in_coroutine()) {
29
+ raw_parse_flags(bdrv_flags, &s->open_flags);
61
+ bdrv_co_yield_to_drain(NULL, true, NULL, true);
30
+ assert(!(s->open_flags & O_CREAT));
62
+ return;
31
+ fd = qemu_open(filename, s->open_flags);
32
+ ret = fd < 0 ? -errno : 0;
33
+ }
34
+ }
63
+ }
35
+
64
+
36
+ if (ret < 0) {
65
+ bdrv_drain_all_begin_nopoll();
37
+ error_setg_errno(errp, -ret, "Could not open '%s'", filename);
66
38
if (ret == -EROFS) {
67
/* Now poll the in-flight requests */
39
ret = -EACCES;
68
AIO_WAIT_WHILE(NULL, bdrv_drain_all_poll());
40
}
41
--
69
--
42
2.19.1
70
2.38.1
43
44
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
This patch tests that you can add and remove drives from a Quorum
3
Block layer graph operations are always run under BQL in the main loop.
4
using the x-blockdev-change command.
4
This is proved by the assertion qemu_in_main_thread() and its wrapper
5
5
macro GLOBAL_STATE_CODE.
6
Signed-off-by: Alberto Garcia <berto@igalia.com>
6
7
However, there are also concurrent coroutines running in other iothreads
8
that always try to traverse the graph. Currently this is protected
9
(among various other things) by the AioContext lock, but once this is
10
removed, we need to make sure that reads do not happen while modifying
11
the graph.
12
13
We distinguish between writer (main loop, under BQL) that modifies the
14
graph, and readers (all other coroutines running in various AioContext),
15
that go through the graph edges, reading ->parents and->children.
16
17
The writer (main loop) has "exclusive" access, so it first waits for any
18
current read to finish, and then prevents incoming ones from entering
19
while it has the exclusive access.
20
21
The readers (coroutines in multiple AioContext) are free to access the
22
graph as long the writer is not modifying the graph. In case it is, they
23
go in a CoQueue and sleep until the writer is done.
24
25
If a coroutine changes AioContext, the counter in the original and new
26
AioContext are left intact, since the writer does not care where the
27
reader is, but only if there is one.
28
29
As a result, some AioContexts might have a negative reader count, to
30
balance the positive count of the AioContext that took the lock. This
31
also means that when an AioContext is deleted it may have a nonzero
32
reader count. In that case we transfer the count to a global shared
33
counter so that the writer is always aware of all readers.
34
35
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
36
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
37
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
38
Message-Id: <20221207131838.239125-3-kwolf@redhat.com>
39
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
40
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
41
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
42
---
9
tests/qemu-iotests/081 | 86 ++++++++++++++++++++++++++++++++++++++
43
include/block/aio.h | 9 ++
10
tests/qemu-iotests/081.out | 54 ++++++++++++++++++++++++
44
include/block/block_int.h | 1 +
11
2 files changed, 140 insertions(+)
45
include/block/graph-lock.h | 139 ++++++++++++++++++++
12
46
block/graph-lock.c | 261 +++++++++++++++++++++++++++++++++++++
13
diff --git a/tests/qemu-iotests/081 b/tests/qemu-iotests/081
47
block/meson.build | 1 +
14
index XXXXXXX..XXXXXXX 100755
48
5 files changed, 411 insertions(+)
15
--- a/tests/qemu-iotests/081
49
create mode 100644 include/block/graph-lock.h
16
+++ b/tests/qemu-iotests/081
50
create mode 100644 block/graph-lock.c
17
@@ -XXX,XX +XXX,XX @@ quorum="$quorum,file.children.2.driver=raw"
51
18
52
diff --git a/include/block/aio.h b/include/block/aio.h
19
$QEMU_IO -c "open -o $quorum" | _filter_qemu_io
53
index XXXXXXX..XXXXXXX 100644
20
54
--- a/include/block/aio.h
21
+echo
55
+++ b/include/block/aio.h
22
+echo "== dynamically adding a child to a quorum =="
56
@@ -XXX,XX +XXX,XX @@
23
+
57
#include "qemu/event_notifier.h"
24
+for verify in false true; do
58
#include "qemu/thread.h"
25
+ run_qemu <<EOF
59
#include "qemu/timer.h"
26
+ { "execute": "qmp_capabilities" }
60
+#include "block/graph-lock.h"
27
+ { "execute": "blockdev-add",
61
28
+ "arguments": {
62
typedef struct BlockAIOCB BlockAIOCB;
29
+ "driver": "quorum",
63
typedef void BlockCompletionFunc(void *opaque, int ret);
30
+ "node-name": "drive0-quorum",
64
@@ -XXX,XX +XXX,XX @@ struct AioContext {
31
+ "vote-threshold": 2,
65
/* Used by AioContext users to protect from multi-threaded access. */
32
+ "blkverify": ${verify},
66
QemuRecMutex lock;
33
+ "children": [
67
34
+ {
68
+ /*
35
+ "driver": "$IMGFMT",
69
+ * Keep track of readers and writers of the block layer graph.
36
+ "file": {
70
+ * This is essential to avoid performing additions and removal
37
+ "driver": "file",
71
+ * of nodes and edges from block graph while some
38
+ "filename": "$TEST_DIR/1.raw"
72
+ * other thread is traversing it.
39
+ }
73
+ */
40
+ },
74
+ BdrvGraphRWlock *bdrv_graph;
41
+ {
75
+
42
+ "driver": "$IMGFMT",
76
/* The list of registered AIO handlers. Protected by ctx->list_lock. */
43
+ "file": {
77
AioHandlerList aio_handlers;
44
+ "driver": "file",
78
45
+ "filename": "$TEST_DIR/2.raw"
79
diff --git a/include/block/block_int.h b/include/block/block_int.h
46
+ }
80
index XXXXXXX..XXXXXXX 100644
47
+ }
81
--- a/include/block/block_int.h
48
+ ]
82
+++ b/include/block/block_int.h
83
@@ -XXX,XX +XXX,XX @@
84
85
#include "block_int-global-state.h"
86
#include "block_int-io.h"
87
+#include "block/graph-lock.h"
88
89
/* DO NOT ADD ANYTHING IN HERE. USE ONE OF THE HEADERS INCLUDED ABOVE */
90
91
diff --git a/include/block/graph-lock.h b/include/block/graph-lock.h
92
new file mode 100644
93
index XXXXXXX..XXXXXXX
94
--- /dev/null
95
+++ b/include/block/graph-lock.h
96
@@ -XXX,XX +XXX,XX @@
97
+/*
98
+ * Graph lock: rwlock to protect block layer graph manipulations (add/remove
99
+ * edges and nodes)
100
+ *
101
+ * Copyright (c) 2022 Red Hat
102
+ *
103
+ * This library is free software; you can redistribute it and/or
104
+ * modify it under the terms of the GNU Lesser General Public
105
+ * License as published by the Free Software Foundation; either
106
+ * version 2.1 of the License, or (at your option) any later version.
107
+ *
108
+ * This library is distributed in the hope that it will be useful,
109
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
110
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
111
+ * Lesser General Public License for more details.
112
+ *
113
+ * You should have received a copy of the GNU Lesser General Public
114
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
115
+ */
116
+#ifndef GRAPH_LOCK_H
117
+#define GRAPH_LOCK_H
118
+
119
+#include "qemu/osdep.h"
120
+
121
+#include "qemu/coroutine.h"
122
+
123
+/**
124
+ * Graph Lock API
125
+ * This API provides a rwlock used to protect block layer
126
+ * graph modifications like edge (BdrvChild) and node (BlockDriverState)
127
+ * addition and removal.
128
+ * Currently we have 1 writer only, the Main loop, and many
129
+ * readers, mostly coroutines running in other AioContext thus other threads.
130
+ *
131
+ * We distinguish between writer (main loop, under BQL) that modifies the
132
+ * graph, and readers (all other coroutines running in various AioContext),
133
+ * that go through the graph edges, reading
134
+ * BlockDriverState ->parents and->children.
135
+ *
136
+ * The writer (main loop) has an "exclusive" access, so it first waits for
137
+ * current read to finish, and then prevents incoming ones from
138
+ * entering while it has the exclusive access.
139
+ *
140
+ * The readers (coroutines in multiple AioContext) are free to
141
+ * access the graph as long the writer is not modifying the graph.
142
+ * In case it is, they go in a CoQueue and sleep until the writer
143
+ * is done.
144
+ *
145
+ * If a coroutine changes AioContext, the counter in the original and new
146
+ * AioContext are left intact, since the writer does not care where is the
147
+ * reader, but only if there is one.
148
+ * As a result, some AioContexts might have a negative reader count, to
149
+ * balance the positive count of the AioContext that took the lock.
150
+ * This also means that when an AioContext is deleted it may have a nonzero
151
+ * reader count. In that case we transfer the count to a global shared counter
152
+ * so that the writer is always aware of all readers.
153
+ */
154
+typedef struct BdrvGraphRWlock BdrvGraphRWlock;
155
+
156
+/*
157
+ * register_aiocontext:
158
+ * Add AioContext @ctx to the list of AioContext.
159
+ * This list is used to obtain the total number of readers
160
+ * currently running the graph.
161
+ */
162
+void register_aiocontext(AioContext *ctx);
163
+
164
+/*
165
+ * unregister_aiocontext:
166
+ * Removes AioContext @ctx to the list of AioContext.
167
+ */
168
+void unregister_aiocontext(AioContext *ctx);
169
+
170
+/*
171
+ * bdrv_graph_wrlock:
172
+ * Start an exclusive write operation to modify the graph. This means we are
173
+ * adding or removing an edge or a node in the block layer graph. Nobody else
174
+ * is allowed to access the graph.
175
+ *
176
+ * Must only be called from outside bdrv_graph_co_rdlock.
177
+ *
178
+ * The wrlock can only be taken from the main loop, with BQL held, as only the
179
+ * main loop is allowed to modify the graph.
180
+ *
181
+ * This function polls. Callers must not hold the lock of any AioContext other
182
+ * than the current one.
183
+ */
184
+void bdrv_graph_wrlock(void);
185
+
186
+/*
187
+ * bdrv_graph_wrunlock:
188
+ * Write finished, reset global has_writer to 0 and restart
189
+ * all readers that are waiting.
190
+ */
191
+void bdrv_graph_wrunlock(void);
192
+
193
+/*
194
+ * bdrv_graph_co_rdlock:
195
+ * Read the bs graph. This usually means traversing all nodes in
196
+ * the graph, therefore it can't happen while another thread is
197
+ * modifying it.
198
+ * Increases the reader counter of the current aiocontext,
199
+ * and if has_writer is set, it means that the writer is modifying
200
+ * the graph, therefore wait in a coroutine queue.
201
+ * The writer will then wake this coroutine once it is done.
202
+ *
203
+ * This lock should be taken from Iothreads (IO_CODE() class of functions)
204
+ * because it signals the writer that there are some
205
+ * readers currently running, or waits until the current
206
+ * write is finished before continuing.
207
+ * Calling this function from the Main Loop with BQL held
208
+ * is not necessary, since the Main Loop itself is the only
209
+ * writer, thus won't be able to read and write at the same time.
210
+ * The only exception to that is when we can't take the lock in the
211
+ * function/coroutine itself, and need to delegate the caller (usually main
212
+ * loop) to take it and wait that the coroutine ends, so that
213
+ * we always signal that a reader is running.
214
+ */
215
+void coroutine_fn bdrv_graph_co_rdlock(void);
216
+
217
+/*
218
+ * bdrv_graph_rdunlock:
219
+ * Read terminated, decrease the count of readers in the current aiocontext.
220
+ * If the writer is waiting for reads to finish (has_writer == 1), signal
221
+ * the writer that we are done via aio_wait_kick() to let it continue.
222
+ */
223
+void coroutine_fn bdrv_graph_co_rdunlock(void);
224
+
225
+/*
226
+ * bdrv_graph_rd{un}lock_main_loop:
227
+ * Just a placeholder to mark where the graph rdlock should be taken
228
+ * in the main loop. It is just asserting that we are not
229
+ * in a coroutine and in GLOBAL_STATE_CODE.
230
+ */
231
+void bdrv_graph_rdlock_main_loop(void);
232
+void bdrv_graph_rdunlock_main_loop(void);
233
+
234
+#endif /* GRAPH_LOCK_H */
235
+
236
diff --git a/block/graph-lock.c b/block/graph-lock.c
237
new file mode 100644
238
index XXXXXXX..XXXXXXX
239
--- /dev/null
240
+++ b/block/graph-lock.c
241
@@ -XXX,XX +XXX,XX @@
242
+/*
243
+ * Graph lock: rwlock to protect block layer graph manipulations (add/remove
244
+ * edges and nodes)
245
+ *
246
+ * Copyright (c) 2022 Red Hat
247
+ *
248
+ * This library is free software; you can redistribute it and/or
249
+ * modify it under the terms of the GNU Lesser General Public
250
+ * License as published by the Free Software Foundation; either
251
+ * version 2.1 of the License, or (at your option) any later version.
252
+ *
253
+ * This library is distributed in the hope that it will be useful,
254
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
255
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
256
+ * Lesser General Public License for more details.
257
+ *
258
+ * You should have received a copy of the GNU Lesser General Public
259
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
260
+ */
261
+
262
+#include "qemu/osdep.h"
263
+#include "qemu/main-loop.h"
264
+#include "block/graph-lock.h"
265
+#include "block/block.h"
266
+#include "block/block_int.h"
267
+
268
+/* Protects the list of aiocontext and orphaned_reader_count */
269
+static QemuMutex aio_context_list_lock;
270
+
271
+/* Written and read with atomic operations. */
272
+static int has_writer;
273
+
274
+/*
275
+ * A reader coroutine could move from an AioContext to another.
276
+ * If this happens, there is no problem from the point of view of
277
+ * counters. The problem is that the total count becomes
278
+ * unbalanced if one of the two AioContexts gets deleted.
279
+ * The count of readers must remain correct, so the AioContext's
280
+ * balance is transferred to this glboal variable.
281
+ * Protected by aio_context_list_lock.
282
+ */
283
+static uint32_t orphaned_reader_count;
284
+
285
+/* Queue of readers waiting for the writer to finish */
286
+static CoQueue reader_queue;
287
+
288
+struct BdrvGraphRWlock {
289
+ /* How many readers are currently reading the graph. */
290
+ uint32_t reader_count;
291
+
292
+ /*
293
+ * List of BdrvGraphRWlock kept in graph-lock.c
294
+ * Protected by aio_context_list_lock
295
+ */
296
+ QTAILQ_ENTRY(BdrvGraphRWlock) next_aio;
297
+};
298
+
299
+/*
300
+ * List of BdrvGraphRWlock. This list ensures that each BdrvGraphRWlock
301
+ * can safely modify only its own counter, avoid reading/writing
302
+ * others and thus improving performances by avoiding cacheline bounces.
303
+ */
304
+static QTAILQ_HEAD(, BdrvGraphRWlock) aio_context_list =
305
+ QTAILQ_HEAD_INITIALIZER(aio_context_list);
306
+
307
+static void __attribute__((__constructor__)) bdrv_init_graph_lock(void)
308
+{
309
+ qemu_mutex_init(&aio_context_list_lock);
310
+ qemu_co_queue_init(&reader_queue);
311
+}
312
+
313
+void register_aiocontext(AioContext *ctx)
314
+{
315
+ ctx->bdrv_graph = g_new0(BdrvGraphRWlock, 1);
316
+ QEMU_LOCK_GUARD(&aio_context_list_lock);
317
+ assert(ctx->bdrv_graph->reader_count == 0);
318
+ QTAILQ_INSERT_TAIL(&aio_context_list, ctx->bdrv_graph, next_aio);
319
+}
320
+
321
+void unregister_aiocontext(AioContext *ctx)
322
+{
323
+ QEMU_LOCK_GUARD(&aio_context_list_lock);
324
+ orphaned_reader_count += ctx->bdrv_graph->reader_count;
325
+ QTAILQ_REMOVE(&aio_context_list, ctx->bdrv_graph, next_aio);
326
+ g_free(ctx->bdrv_graph);
327
+}
328
+
329
+static uint32_t reader_count(void)
330
+{
331
+ BdrvGraphRWlock *brdv_graph;
332
+ uint32_t rd;
333
+
334
+ QEMU_LOCK_GUARD(&aio_context_list_lock);
335
+
336
+ /* rd can temporarly be negative, but the total will *always* be >= 0 */
337
+ rd = orphaned_reader_count;
338
+ QTAILQ_FOREACH(brdv_graph, &aio_context_list, next_aio) {
339
+ rd += qatomic_read(&brdv_graph->reader_count);
340
+ }
341
+
342
+ /* shouldn't overflow unless there are 2^31 readers */
343
+ assert((int32_t)rd >= 0);
344
+ return rd;
345
+}
346
+
347
+void bdrv_graph_wrlock(void)
348
+{
349
+ GLOBAL_STATE_CODE();
350
+ assert(!qatomic_read(&has_writer));
351
+
352
+ /* Make sure that constantly arriving new I/O doesn't cause starvation */
353
+ bdrv_drain_all_begin_nopoll();
354
+
355
+ /*
356
+ * reader_count == 0: this means writer will read has_reader as 1
357
+ * reader_count >= 1: we don't know if writer read has_writer == 0 or 1,
358
+ * but we need to wait.
359
+ * Wait by allowing other coroutine (and possible readers) to continue.
360
+ */
361
+ do {
362
+ /*
363
+ * has_writer must be 0 while polling, otherwise we get a deadlock if
364
+ * any callback involved during AIO_WAIT_WHILE() tries to acquire the
365
+ * reader lock.
366
+ */
367
+ qatomic_set(&has_writer, 0);
368
+ AIO_WAIT_WHILE(qemu_get_aio_context(), reader_count() >= 1);
369
+ qatomic_set(&has_writer, 1);
370
+
371
+ /*
372
+ * We want to only check reader_count() after has_writer = 1 is visible
373
+ * to other threads. That way no more readers can sneak in after we've
374
+ * determined reader_count() == 0.
375
+ */
376
+ smp_mb();
377
+ } while (reader_count() >= 1);
378
+
379
+ bdrv_drain_all_end();
380
+}
381
+
382
+void bdrv_graph_wrunlock(void)
383
+{
384
+ GLOBAL_STATE_CODE();
385
+ QEMU_LOCK_GUARD(&aio_context_list_lock);
386
+ assert(qatomic_read(&has_writer));
387
+
388
+ /*
389
+ * No need for memory barriers, this works in pair with
390
+ * the slow path of rdlock() and both take the lock.
391
+ */
392
+ qatomic_store_release(&has_writer, 0);
393
+
394
+ /* Wake up all coroutine that are waiting to read the graph */
395
+ qemu_co_enter_all(&reader_queue, &aio_context_list_lock);
396
+}
397
+
398
+void coroutine_fn bdrv_graph_co_rdlock(void)
399
+{
400
+ BdrvGraphRWlock *bdrv_graph;
401
+ bdrv_graph = qemu_get_current_aio_context()->bdrv_graph;
402
+
403
+ /* Do not lock if in main thread */
404
+ if (qemu_in_main_thread()) {
405
+ return;
406
+ }
407
+
408
+ for (;;) {
409
+ qatomic_set(&bdrv_graph->reader_count,
410
+ bdrv_graph->reader_count + 1);
411
+ /* make sure writer sees reader_count before we check has_writer */
412
+ smp_mb();
413
+
414
+ /*
415
+ * has_writer == 0: this means writer will read reader_count as >= 1
416
+ * has_writer == 1: we don't know if writer read reader_count == 0
417
+ * or > 0, but we need to wait anyways because
418
+ * it will write.
419
+ */
420
+ if (!qatomic_read(&has_writer)) {
421
+ break;
422
+ }
423
+
424
+ /*
425
+ * Synchronize access with reader_count() in bdrv_graph_wrlock().
426
+ * Case 1:
427
+ * If this critical section gets executed first, reader_count will
428
+ * decrease and the reader will go to sleep.
429
+ * Then the writer will read reader_count that does not take into
430
+ * account this reader, and if there's no other reader it will
431
+ * enter the write section.
432
+ * Case 2:
433
+ * If reader_count() critical section gets executed first,
434
+ * then writer will read reader_count >= 1.
435
+ * It will wait in AIO_WAIT_WHILE(), but once it releases the lock
436
+ * we will enter this critical section and call aio_wait_kick().
437
+ */
438
+ WITH_QEMU_LOCK_GUARD(&aio_context_list_lock) {
439
+ /*
440
+ * Additional check when we use the above lock to synchronize
441
+ * with bdrv_graph_wrunlock().
442
+ * Case 1:
443
+ * If this gets executed first, has_writer is still 1, so we reduce
444
+ * reader_count and go to sleep.
445
+ * Then the writer will set has_writer to 0 and wake up all readers,
446
+ * us included.
447
+ * Case 2:
448
+ * If bdrv_graph_wrunlock() critical section gets executed first,
449
+ * then it will set has_writer to 0 and wake up all other readers.
450
+ * Then we execute this critical section, and therefore must check
451
+ * again for has_writer, otherwise we sleep without any writer
452
+ * actually running.
453
+ */
454
+ if (!qatomic_read(&has_writer)) {
455
+ return;
456
+ }
457
+
458
+ /* slow path where reader sleeps */
459
+ bdrv_graph->reader_count--;
460
+ aio_wait_kick();
461
+ qemu_co_queue_wait(&reader_queue, &aio_context_list_lock);
49
+ }
462
+ }
50
+ }
463
+ }
51
+ { "execute": "blockdev-add",
464
+}
52
+ "arguments": {
465
+
53
+ "node-name": "drive3",
466
+void coroutine_fn bdrv_graph_co_rdunlock(void)
54
+ "driver": "$IMGFMT",
467
+{
55
+ "file": {
468
+ BdrvGraphRWlock *bdrv_graph;
56
+ "driver": "file",
469
+ bdrv_graph = qemu_get_current_aio_context()->bdrv_graph;
57
+ "filename": "$TEST_DIR/2.raw"
470
+
58
+ }
471
+ /* Do not lock if in main thread */
59
+ }
472
+ if (qemu_in_main_thread()) {
473
+ return;
60
+ }
474
+ }
61
+ { "execute": "x-blockdev-change",
475
+
62
+ "arguments": { "parent": "drive0-quorum",
476
+ qatomic_store_release(&bdrv_graph->reader_count,
63
+ "node": "drive3" } }
477
+ bdrv_graph->reader_count - 1);
64
+ { "execute": "quit" }
478
+ /* make sure writer sees reader_count before we check has_writer */
65
+EOF
479
+ smp_mb();
66
+done
480
+
67
+
481
+ /*
68
+echo
482
+ * has_writer == 0: this means reader will read reader_count decreased
69
+echo "== dynamically removing a child from a quorum =="
483
+ * has_writer == 1: we don't know if writer read reader_count old or
70
+
484
+ * new. Therefore, kick again so on next iteration
71
+for verify in false true; do
485
+ * writer will for sure read the updated value.
72
+ for vote_threshold in 1 2; do
486
+ */
73
+ run_qemu <<EOF
487
+ if (qatomic_read(&has_writer)) {
74
+ { "execute": "qmp_capabilities" }
488
+ aio_wait_kick();
75
+ { "execute": "blockdev-add",
489
+ }
76
+ "arguments": {
490
+}
77
+ "driver": "quorum",
491
+
78
+ "node-name": "drive0-quorum",
492
+void bdrv_graph_rdlock_main_loop(void)
79
+ "vote-threshold": ${vote_threshold},
493
+{
80
+ "blkverify": ${verify},
494
+ GLOBAL_STATE_CODE();
81
+ "children": [
495
+ assert(!qemu_in_coroutine());
82
+ {
496
+}
83
+ "driver": "$IMGFMT",
497
+
84
+ "file": {
498
+void bdrv_graph_rdunlock_main_loop(void)
85
+ "driver": "file",
499
+{
86
+ "filename": "$TEST_DIR/1.raw"
500
+ GLOBAL_STATE_CODE();
87
+ }
501
+ assert(!qemu_in_coroutine());
88
+ },
502
+}
89
+ {
503
diff --git a/block/meson.build b/block/meson.build
90
+ "driver": "$IMGFMT",
91
+ "file": {
92
+ "driver": "file",
93
+ "filename": "$TEST_DIR/2.raw"
94
+ }
95
+ }
96
+ ]
97
+ }
98
+ }
99
+ { "execute": "x-blockdev-change",
100
+ "arguments": { "parent": "drive0-quorum",
101
+ "child": "children.1" } }
102
+ { "execute": "quit" }
103
+EOF
104
+ done
105
+done
106
+
107
# success, all done
108
echo "*** done"
109
rm -f $seq.full
110
diff --git a/tests/qemu-iotests/081.out b/tests/qemu-iotests/081.out
111
index XXXXXXX..XXXXXXX 100644
504
index XXXXXXX..XXXXXXX 100644
112
--- a/tests/qemu-iotests/081.out
505
--- a/block/meson.build
113
+++ b/tests/qemu-iotests/081.out
506
+++ b/block/meson.build
114
@@ -XXX,XX +XXX,XX @@ read 10485760/10485760 bytes at offset 0
507
@@ -XXX,XX +XXX,XX @@ block_ss.add(files(
115
508
'blkverify.c',
116
== checking the blkverify mode with invalid settings ==
509
'block-backend.c',
117
can't open: blkverify=on can only be set if there are exactly two files and vote-threshold is 2
510
'block-copy.c',
118
+
511
+ 'graph-lock.c',
119
+== dynamically adding a child to a quorum ==
512
'commit.c',
120
+Testing:
513
'copy-on-read.c',
121
+QMP_VERSION
514
'preallocate.c',
122
+{"return": {}}
123
+{"return": {}}
124
+{"return": {}}
125
+{"return": {}}
126
+{"return": {}}
127
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
128
+
129
+Testing:
130
+QMP_VERSION
131
+{"return": {}}
132
+{"return": {}}
133
+{"return": {}}
134
+{"error": {"class": "GenericError", "desc": "Cannot add a child to a quorum in blkverify mode"}}
135
+{"return": {}}
136
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
137
+
138
+
139
+== dynamically removing a child from a quorum ==
140
+Testing:
141
+QMP_VERSION
142
+{"return": {}}
143
+{"return": {}}
144
+{"return": {}}
145
+{"return": {}}
146
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
147
+
148
+Testing:
149
+QMP_VERSION
150
+{"return": {}}
151
+{"return": {}}
152
+{"error": {"class": "GenericError", "desc": "The number of children cannot be lower than the vote threshold 2"}}
153
+{"return": {}}
154
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
155
+
156
+Testing:
157
+QMP_VERSION
158
+{"return": {}}
159
+{"error": {"class": "GenericError", "desc": "blkverify=on can only be set if there are exactly two files and vote-threshold is 2"}}
160
+{"error": {"class": "GenericError", "desc": "Cannot find device=drive0-quorum nor node_name=drive0-quorum"}}
161
+{"return": {}}
162
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
163
+
164
+Testing:
165
+QMP_VERSION
166
+{"return": {}}
167
+{"return": {}}
168
+{"error": {"class": "GenericError", "desc": "The number of children cannot be lower than the vote threshold 2"}}
169
+{"return": {}}
170
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
171
+
172
*** done
173
--
515
--
174
2.19.1
516
2.38.1
175
176
diff view generated by jsdifflib
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
2
3
Similar to the implementation in lockable.h, implement macros to
4
automatically take and release the rdlock.
5
6
Create the empty GraphLockable and GraphLockableMainloop structs only to
7
use it as a type for G_DEFINE_AUTOPTR_CLEANUP_FUNC.
8
9
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Reviewed-by: Eric Blake <eblake@redhat.com>
11
Message-Id: <20221207131838.239125-4-kwolf@redhat.com>
12
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
3
---
14
---
4
tests/qemu-iotests/232 | 147 +++++++++++++++++++++++++++++++++++++
15
include/block/graph-lock.h | 66 ++++++++++++++++++++++++++++++++++++++
5
tests/qemu-iotests/232.out | 59 +++++++++++++++
16
1 file changed, 66 insertions(+)
6
tests/qemu-iotests/group | 1 +
7
3 files changed, 207 insertions(+)
8
create mode 100755 tests/qemu-iotests/232
9
create mode 100644 tests/qemu-iotests/232.out
10
17
11
diff --git a/tests/qemu-iotests/232 b/tests/qemu-iotests/232
18
diff --git a/include/block/graph-lock.h b/include/block/graph-lock.h
12
new file mode 100755
19
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX
20
--- a/include/block/graph-lock.h
14
--- /dev/null
21
+++ b/include/block/graph-lock.h
15
+++ b/tests/qemu-iotests/232
22
@@ -XXX,XX +XXX,XX @@ void coroutine_fn bdrv_graph_co_rdunlock(void);
16
@@ -XXX,XX +XXX,XX @@
23
void bdrv_graph_rdlock_main_loop(void);
17
+#!/bin/bash
24
void bdrv_graph_rdunlock_main_loop(void);
18
+#
25
19
+# Test for auto-read-only
26
+typedef struct GraphLockable { } GraphLockable;
20
+#
21
+# Copyright (C) 2018 Red Hat, Inc.
22
+#
23
+# 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
25
+# the Free Software Foundation; either version 2 of the License, or
26
+# (at your option) any later version.
27
+#
28
+# This program is distributed in the hope that it will be useful,
29
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
30
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31
+# GNU General Public License for more details.
32
+#
33
+# 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/>.
35
+#
36
+
27
+
37
+# creator
28
+/*
38
+owner=kwolf@redhat.com
29
+ * In C, compound literals have the lifetime of an automatic variable.
30
+ * In C++ it would be different, but then C++ wouldn't need QemuLockable
31
+ * either...
32
+ */
33
+#define GML_OBJ_() (&(GraphLockable) { })
39
+
34
+
40
+seq=`basename $0`
35
+static inline GraphLockable *graph_lockable_auto_lock(GraphLockable *x)
41
+echo "QA output created by $seq"
42
+
43
+here=`pwd`
44
+status=1    # failure is the default!
45
+
46
+_cleanup()
47
+{
36
+{
48
+ _cleanup_test_img
37
+ bdrv_graph_co_rdlock();
49
+ rm -f $TEST_IMG.snap
38
+ return x;
50
+}
51
+trap "_cleanup; exit \$status" 0 1 2 3 15
52
+
53
+# get standard environment, filters and checks
54
+. ./common.rc
55
+. ./common.filter
56
+
57
+_supported_fmt generic
58
+_supported_proto file
59
+_supported_os Linux
60
+
61
+function do_run_qemu()
62
+{
63
+ echo Testing: "$@"
64
+ (
65
+ if ! test -t 0; then
66
+ while read cmd; do
67
+ echo $cmd
68
+ done
69
+ fi
70
+ echo quit
71
+ ) | $QEMU -nographic -monitor stdio -nodefaults "$@"
72
+ echo
73
+}
39
+}
74
+
40
+
75
+function run_qemu()
41
+static inline void graph_lockable_auto_unlock(GraphLockable *x)
76
+{
42
+{
77
+ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_hmp |
43
+ bdrv_graph_co_rdunlock();
78
+ _filter_generated_node_ids | _filter_imgfmt
79
+}
44
+}
80
+
45
+
81
+function run_qemu_info_block()
46
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GraphLockable, graph_lockable_auto_unlock)
47
+
48
+#define WITH_GRAPH_RDLOCK_GUARD_(var) \
49
+ for (g_autoptr(GraphLockable) var = graph_lockable_auto_lock(GML_OBJ_()); \
50
+ var; \
51
+ graph_lockable_auto_unlock(var), var = NULL)
52
+
53
+#define WITH_GRAPH_RDLOCK_GUARD() \
54
+ WITH_GRAPH_RDLOCK_GUARD_(glue(graph_lockable_auto, __COUNTER__))
55
+
56
+#define GRAPH_RDLOCK_GUARD(x) \
57
+ g_autoptr(GraphLockable) \
58
+ glue(graph_lockable_auto, __COUNTER__) G_GNUC_UNUSED = \
59
+ graph_lockable_auto_lock(GML_OBJ_())
60
+
61
+
62
+typedef struct GraphLockableMainloop { } GraphLockableMainloop;
63
+
64
+/*
65
+ * In C, compound literals have the lifetime of an automatic variable.
66
+ * In C++ it would be different, but then C++ wouldn't need QemuLockable
67
+ * either...
68
+ */
69
+#define GMLML_OBJ_() (&(GraphLockableMainloop) { })
70
+
71
+static inline GraphLockableMainloop *
72
+graph_lockable_auto_lock_mainloop(GraphLockableMainloop *x)
82
+{
73
+{
83
+ echo "info block -n" | run_qemu "$@" | grep -e "(file" -e "QEMU_PROG"
74
+ bdrv_graph_rdlock_main_loop();
75
+ return x;
84
+}
76
+}
85
+
77
+
86
+size=128M
78
+static inline void
79
+graph_lockable_auto_unlock_mainloop(GraphLockableMainloop *x)
80
+{
81
+ bdrv_graph_rdunlock_main_loop();
82
+}
87
+
83
+
88
+_make_test_img $size
84
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GraphLockableMainloop,
85
+ graph_lockable_auto_unlock_mainloop)
89
+
86
+
90
+echo
87
+#define GRAPH_RDLOCK_GUARD_MAINLOOP(x) \
91
+echo "=== -drive with read-write image: read-only/auto-read-only combinations ==="
88
+ g_autoptr(GraphLockableMainloop) \
92
+echo
89
+ glue(graph_lockable_auto, __COUNTER__) G_GNUC_UNUSED = \
90
+ graph_lockable_auto_lock_mainloop(GMLML_OBJ_())
93
+
91
+
94
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=on,auto-read-only=off
92
#endif /* GRAPH_LOCK_H */
95
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=on,auto-read-only=on
93
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
166
index XXXXXXX..XXXXXXX
167
--- /dev/null
168
+++ b/tests/qemu-iotests/232.out
169
@@ -XXX,XX +XXX,XX @@
170
+QA output created by 232
171
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
172
+
173
+=== -drive with read-write image: read-only/auto-read-only combinations ===
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
--
94
--
239
2.19.1
95
2.38.1
240
241
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
2
2
3
Just like in qemu_opts_print_help(), print the object name as a caption
3
Add/remove the AioContext in aio_context_list in graph-lock.c when it is
4
instead of on every single line, indent all options, add angle brackets
4
created/destroyed. This allows using the graph locking operations from
5
around types, and align the descriptions after 24 characters.
5
this AioContext.
6
6
7
Also, indent every object name in the list of available objects.
7
In order to allow linking util/async.c with binaries that don't include
8
the block layer, introduce stubs for (un)register_aiocontext().
8
9
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
10
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Message-Id: <20221207131838.239125-5-kwolf@redhat.com>
13
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
14
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
16
---
13
vl.c | 13 ++++++++++---
17
stubs/graph-lock.c | 10 ++++++++++
14
1 file changed, 10 insertions(+), 3 deletions(-)
18
util/async.c | 4 ++++
19
stubs/meson.build | 1 +
20
3 files changed, 15 insertions(+)
21
create mode 100644 stubs/graph-lock.c
15
22
16
diff --git a/vl.c b/vl.c
23
diff --git a/stubs/graph-lock.c b/stubs/graph-lock.c
24
new file mode 100644
25
index XXXXXXX..XXXXXXX
26
--- /dev/null
27
+++ b/stubs/graph-lock.c
28
@@ -XXX,XX +XXX,XX @@
29
+#include "qemu/osdep.h"
30
+#include "block/graph-lock.h"
31
+
32
+void register_aiocontext(AioContext *ctx)
33
+{
34
+}
35
+
36
+void unregister_aiocontext(AioContext *ctx)
37
+{
38
+}
39
diff --git a/util/async.c b/util/async.c
17
index XXXXXXX..XXXXXXX 100644
40
index XXXXXXX..XXXXXXX 100644
18
--- a/vl.c
41
--- a/util/async.c
19
+++ b/vl.c
42
+++ b/util/async.c
20
@@ -XXX,XX +XXX,XX @@ static bool object_create_initial(const char *type, QemuOpts *opts)
43
@@ -XXX,XX +XXX,XX @@
21
list = object_class_get_list_sorted(TYPE_USER_CREATABLE, false);
44
#include "qapi/error.h"
22
for (l = list; l != NULL; l = l->next) {
45
#include "block/aio.h"
23
ObjectClass *oc = OBJECT_CLASS(l->data);
46
#include "block/thread-pool.h"
24
- printf("%s\n", object_class_get_name(oc));
47
+#include "block/graph-lock.h"
25
+ printf(" %s\n", object_class_get_name(oc));
48
#include "qemu/main-loop.h"
26
}
49
#include "qemu/atomic.h"
27
g_slist_free(list);
50
#include "qemu/rcu_queue.h"
28
exit(0);
51
@@ -XXX,XX +XXX,XX @@ aio_ctx_finalize(GSource *source)
29
@@ -XXX,XX +XXX,XX @@ static bool object_create_initial(const char *type, QemuOpts *opts)
52
qemu_rec_mutex_destroy(&ctx->lock);
30
}
53
qemu_lockcnt_destroy(&ctx->list_lock);
31
54
timerlistgroup_deinit(&ctx->tlg);
32
str = g_string_new(NULL);
55
+ unregister_aiocontext(ctx);
33
- g_string_append_printf(str, "%s.%s=%s", type,
56
aio_context_destroy(ctx);
34
- prop->name, prop->type);
57
}
35
+ g_string_append_printf(str, " %s=<%s>", prop->name, prop->type);
58
36
if (prop->description) {
59
@@ -XXX,XX +XXX,XX @@ AioContext *aio_context_new(Error **errp)
37
+ if (str->len < 24) {
60
ctx->thread_pool_min = 0;
38
+ g_string_append_printf(str, "%*s", 24 - (int)str->len, "");
61
ctx->thread_pool_max = THREAD_POOL_MAX_THREADS_DEFAULT;
39
+ }
62
40
g_string_append_printf(str, " - %s", prop->description);
63
+ register_aiocontext(ctx);
41
}
64
+
42
g_ptr_array_add(array, g_string_free(str, false));
65
return ctx;
43
}
66
fail:
44
g_ptr_array_sort(array, (GCompareFunc)qemu_pstrcmp0);
67
g_source_destroy(&ctx->source);
45
+ if (array->len > 0) {
68
diff --git a/stubs/meson.build b/stubs/meson.build
46
+ printf("%s options:\n", type);
69
index XXXXXXX..XXXXXXX 100644
47
+ } else {
70
--- a/stubs/meson.build
48
+ printf("There are no options for %s.\n", type);
71
+++ b/stubs/meson.build
49
+ }
72
@@ -XXX,XX +XXX,XX @@ stub_ss.add(files('error-printf.c'))
50
for (i = 0; i < array->len; i++) {
73
stub_ss.add(files('fdset.c'))
51
printf("%s\n", (char *)array->pdata[i]);
74
stub_ss.add(files('gdbstub.c'))
52
}
75
stub_ss.add(files('get-vm-name.c'))
76
+stub_ss.add(files('graph-lock.c'))
77
if linux_io_uring.found()
78
stub_ss.add(files('io_uring.c'))
79
endif
53
--
80
--
54
2.19.1
81
2.38.1
55
56
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
This defines macros that allow clang to perform Thread Safety Analysis
2
based on function and variable annotations that specify the locking
3
rules. On non-clang compilers, the annotations are ignored.
2
4
3
Signed-off-by: Alberto Garcia <berto@igalia.com>
5
Imported tsa.h from the original repository with the pthread_mutex_t
6
wrapper removed:
7
8
https://github.com/jhi/clang-thread-safety-analysis-for-c.git
9
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Message-Id: <20221207131838.239125-6-kwolf@redhat.com>
12
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
---
14
---
6
tests/qemu-iotests/081 | 30 ++++++++++++++++++++++++++++++
15
include/qemu/clang-tsa.h | 101 +++++++++++++++++++++++++++++++++++++++
7
tests/qemu-iotests/081.out | 16 ++++++++++++++++
16
1 file changed, 101 insertions(+)
8
2 files changed, 46 insertions(+)
17
create mode 100644 include/qemu/clang-tsa.h
9
18
10
diff --git a/tests/qemu-iotests/081 b/tests/qemu-iotests/081
19
diff --git a/include/qemu/clang-tsa.h b/include/qemu/clang-tsa.h
11
index XXXXXXX..XXXXXXX 100755
20
new file mode 100644
12
--- a/tests/qemu-iotests/081
21
index XXXXXXX..XXXXXXX
13
+++ b/tests/qemu-iotests/081
22
--- /dev/null
14
@@ -XXX,XX +XXX,XX @@ echo "== checking that quorum is broken =="
23
+++ b/include/qemu/clang-tsa.h
15
24
@@ -XXX,XX +XXX,XX @@
16
$QEMU_IO -c "open -o $quorum" -c "read -P 0x32 0 $size" | _filter_qemu_io
25
+#ifndef CLANG_TSA_H
17
26
+#define CLANG_TSA_H
18
+echo
19
+echo "== checking the blkverify mode with broken content =="
20
+
27
+
21
+quorum="driver=raw,file.driver=quorum,file.vote-threshold=2,file.blkverify=on"
28
+/*
22
+quorum="$quorum,file.children.0.file.filename=$TEST_DIR/1.raw"
29
+ * Copyright 2018 Jarkko Hietaniemi <jhi@iki.fi>
23
+quorum="$quorum,file.children.1.file.filename=$TEST_DIR/2.raw"
30
+ *
24
+quorum="$quorum,file.children.0.driver=raw"
31
+ * Permission is hereby granted, free of charge, to any person obtaining
25
+quorum="$quorum,file.children.1.driver=raw"
32
+ * a copy of this software and associated documentation files (the "Software"),
33
+ * to deal in the Software without restriction, including without
34
+ * limitation the rights to use, copy, modify, merge, publish,
35
+ * distribute, sublicense, and/or sell copies of the Software, and to
36
+ * permit persons to whom the Software is furnished to do so, subject to
37
+ * the following conditions:
38
+ *
39
+ * The above copyright notice and this permission notice shall be
40
+ * included in all copies or substantial portions of the Software.
41
+ *
42
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
43
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
44
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
45
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
46
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
47
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
48
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
49
+ */
26
+
50
+
27
+$QEMU_IO -c "open -o $quorum" -c "read -P 0x32 0 $size" | _filter_qemu_io
51
+/* http://clang.llvm.org/docs/ThreadSafetyAnalysis.html
52
+ *
53
+ * TSA is available since clang 3.6-ish.
54
+ */
55
+#ifdef __clang__
56
+# define TSA(x) __attribute__((x))
57
+#else
58
+# define TSA(x) /* No TSA, make TSA attributes no-ops. */
59
+#endif
28
+
60
+
29
+echo
61
+/* TSA_CAPABILITY() is used to annotate typedefs:
30
+echo "== writing the same data to both files =="
62
+ *
63
+ * typedef pthread_mutex_t TSA_CAPABILITY("mutex") tsa_mutex;
64
+ */
65
+#define TSA_CAPABILITY(x) TSA(capability(x))
31
+
66
+
32
+$QEMU_IO -c "write -P 0x32 0 $size" "$TEST_DIR/1.raw" | _filter_qemu_io
67
+/* TSA_GUARDED_BY() is used to annotate global variables,
33
+$QEMU_IO -c "write -P 0x32 0 $size" "$TEST_DIR/2.raw" | _filter_qemu_io
68
+ * the data is guarded:
69
+ *
70
+ * Foo foo TSA_GUARDED_BY(mutex);
71
+ */
72
+#define TSA_GUARDED_BY(x) TSA(guarded_by(x))
34
+
73
+
35
+echo
74
+/* TSA_PT_GUARDED_BY() is used to annotate global pointers, the data
36
+echo "== checking the blkverify mode with valid content =="
75
+ * behind the pointer is guarded.
76
+ *
77
+ * Foo* ptr TSA_PT_GUARDED_BY(mutex);
78
+ */
79
+#define TSA_PT_GUARDED_BY(x) TSA(pt_guarded_by(x))
37
+
80
+
38
+$QEMU_IO -c "open -o $quorum" -c "read -P 0x32 0 $size" | _filter_qemu_io
81
+/* The TSA_REQUIRES() is used to annotate functions: the caller of the
82
+ * function MUST hold the resource, the function will NOT release it.
83
+ *
84
+ * More than one mutex may be specified, comma-separated.
85
+ *
86
+ * void Foo(void) TSA_REQUIRES(mutex);
87
+ */
88
+#define TSA_REQUIRES(...) TSA(requires_capability(__VA_ARGS__))
39
+
89
+
40
+echo
90
+/* TSA_EXCLUDES() is used to annotate functions: the caller of the
41
+echo "== checking the blkverify mode with invalid settings =="
91
+ * function MUST NOT hold resource, the function first acquires the
92
+ * resource, and then releases it.
93
+ *
94
+ * More than one mutex may be specified, comma-separated.
95
+ *
96
+ * void Foo(void) TSA_EXCLUDES(mutex);
97
+ */
98
+#define TSA_EXCLUDES(...) TSA(locks_excluded(__VA_ARGS__))
42
+
99
+
43
+quorum="$quorum,file.children.2.file.filename=$TEST_DIR/3.raw"
100
+/* TSA_ACQUIRE() is used to annotate functions: the caller of the
44
+quorum="$quorum,file.children.2.driver=raw"
101
+ * function MUST NOT hold the resource, the function will acquire the
102
+ * resource, but NOT release it.
103
+ *
104
+ * More than one mutex may be specified, comma-separated.
105
+ *
106
+ * void Foo(void) TSA_ACQUIRE(mutex);
107
+ */
108
+#define TSA_ACQUIRE(...) TSA(acquire_capability(__VA_ARGS__))
45
+
109
+
46
+$QEMU_IO -c "open -o $quorum" | _filter_qemu_io
110
+/* TSA_RELEASE() is used to annotate functions: the caller of the
111
+ * function MUST hold the resource, but the function will then release it.
112
+ *
113
+ * More than one mutex may be specified, comma-separated.
114
+ *
115
+ * void Foo(void) TSA_RELEASE(mutex);
116
+ */
117
+#define TSA_RELEASE(...) TSA(release_capability(__VA_ARGS__))
47
+
118
+
48
# success, all done
119
+/* TSA_NO_TSA is used to annotate functions. Use only when you need to.
49
echo "*** done"
120
+ *
50
rm -f $seq.full
121
+ * void Foo(void) TSA_NO_TSA;
51
diff --git a/tests/qemu-iotests/081.out b/tests/qemu-iotests/081.out
122
+ */
52
index XXXXXXX..XXXXXXX 100644
123
+#define TSA_NO_TSA TSA(no_thread_safety_analysis)
53
--- a/tests/qemu-iotests/081.out
54
+++ b/tests/qemu-iotests/081.out
55
@@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 0
56
57
== checking that quorum is broken ==
58
read failed: Input/output error
59
+
124
+
60
+== checking the blkverify mode with broken content ==
125
+#endif /* #ifndef CLANG_TSA_H */
61
+quorum: offset=0 bytes=10485760 contents mismatch at offset 0
62
+
63
+== writing the same data to both files ==
64
+wrote 10485760/10485760 bytes at offset 0
65
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
66
+wrote 10485760/10485760 bytes at offset 0
67
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
68
+
69
+== checking the blkverify mode with valid content ==
70
+read 10485760/10485760 bytes at offset 0
71
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
72
+
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
--
126
--
77
2.19.1
127
2.38.1
78
79
diff view generated by jsdifflib
1
From: Leonid Bloch <lbloch@janustech.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
2
Message-Id: <20221207131838.239125-7-kwolf@redhat.com>
3
The lookup table for power-of-two sizes was added in commit 540b8492618eb
3
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
4
for the purpose of having convenient shortcuts for these sizes in cases
5
when the literal number has to be present at compile time, and
6
expressions as '(1 * KiB)' can not be used. One such case is the
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
11
Despite its convenience, this table introduced 55 lines of "dumb" code,
12
the purpose and origin of which are obscure without reading the message
13
of the commit which introduced it. This patch fixes that by adding a
14
comment to the code itself with a brief explanation for the reasoning
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
20
Signed-off-by: Leonid Bloch <lbloch@janustech.com>
21
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
22
---
5
---
23
include/qemu/units.h | 18 ++++++++++++++++++
6
include/qemu/clang-tsa.h | 9 +++++++++
24
1 file changed, 18 insertions(+)
7
1 file changed, 9 insertions(+)
25
8
26
diff --git a/include/qemu/units.h b/include/qemu/units.h
9
diff --git a/include/qemu/clang-tsa.h b/include/qemu/clang-tsa.h
27
index XXXXXXX..XXXXXXX 100644
10
index XXXXXXX..XXXXXXX 100644
28
--- a/include/qemu/units.h
11
--- a/include/qemu/clang-tsa.h
29
+++ b/include/qemu/units.h
12
+++ b/include/qemu/clang-tsa.h
30
@@ -XXX,XX +XXX,XX @@
13
@@ -XXX,XX +XXX,XX @@
31
#define PiB (INT64_C(1) << 50)
14
*/
32
#define EiB (INT64_C(1) << 60)
15
#define TSA_NO_TSA TSA(no_thread_safety_analysis)
33
16
34
+/*
17
+/*
35
+ * The following lookup table is intended to be used when a literal string of
18
+ * TSA_ASSERT() is used to annotate functions: This function will assert that
36
+ * the number of bytes is required (for example if it needs to be stringified).
19
+ * the lock is held. When it returns, the caller of the function is assumed to
37
+ * It can also be used for generic shortcuts of power-of-two sizes.
20
+ * already hold the resource.
38
+ * This table is generated using the AWK script below:
39
+ *
21
+ *
40
+ * BEGIN {
22
+ * More than one mutex may be specified, comma-separated.
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
+ */
23
+ */
24
+#define TSA_ASSERT(...) TSA(assert_capability(__VA_ARGS__))
51
+
25
+
52
#define S_1KiB 1024
26
#endif /* #ifndef CLANG_TSA_H */
53
#define S_2KiB 2048
54
#define S_4KiB 4096
55
--
27
--
56
2.19.1
28
2.38.1
57
58
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
2
Message-Id: <20221207131838.239125-8-kwolf@redhat.com>
3
The blkverify mode of Quorum can only be enabled if the number of
3
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
4
children is exactly two and the value of vote-threshold is also two.
5
6
If the user tries to enable it but the other settings are incorrect
7
then QEMU simply prints an error message to stderr and carries on
8
disabling the blkverify setting.
9
10
This patch makes quorum_open() fail and return an error in this case.
11
12
Signed-off-by: Alberto Garcia <berto@igalia.com>
13
Reported-by: Markus Armbruster <armbru@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
5
---
16
block/quorum.c | 13 ++++++-------
6
include/qemu/clang-tsa.h | 4 ++++
17
1 file changed, 6 insertions(+), 7 deletions(-)
7
1 file changed, 4 insertions(+)
18
8
19
diff --git a/block/quorum.c b/block/quorum.c
9
diff --git a/include/qemu/clang-tsa.h b/include/qemu/clang-tsa.h
20
index XXXXXXX..XXXXXXX 100644
10
index XXXXXXX..XXXXXXX 100644
21
--- a/block/quorum.c
11
--- a/include/qemu/clang-tsa.h
22
+++ b/block/quorum.c
12
+++ b/include/qemu/clang-tsa.h
23
@@ -XXX,XX +XXX,XX @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags,
13
@@ -XXX,XX +XXX,XX @@
24
s->read_pattern = ret;
14
* void Foo(void) TSA_REQUIRES(mutex);
25
15
*/
26
if (s->read_pattern == QUORUM_READ_PATTERN_QUORUM) {
16
#define TSA_REQUIRES(...) TSA(requires_capability(__VA_ARGS__))
27
- /* is the driver in blkverify mode */
17
+#define TSA_REQUIRES_SHARED(...) TSA(requires_shared_capability(__VA_ARGS__))
28
- if (qemu_opt_get_bool(opts, QUORUM_OPT_BLKVERIFY, false) &&
18
29
- s->num_children == 2 && s->threshold == 2) {
19
/* TSA_EXCLUDES() is used to annotate functions: the caller of the
30
- s->is_blkverify = true;
20
* function MUST NOT hold resource, the function first acquires the
31
- } else if (qemu_opt_get_bool(opts, QUORUM_OPT_BLKVERIFY, false)) {
21
@@ -XXX,XX +XXX,XX @@
32
- fprintf(stderr, "blkverify mode is set by setting blkverify=on "
22
* void Foo(void) TSA_ACQUIRE(mutex);
33
- "and using two files with vote_threshold=2\n");
23
*/
34
+ s->is_blkverify = qemu_opt_get_bool(opts, QUORUM_OPT_BLKVERIFY, false);
24
#define TSA_ACQUIRE(...) TSA(acquire_capability(__VA_ARGS__))
35
+ if (s->is_blkverify && (s->num_children != 2 || s->threshold != 2)) {
25
+#define TSA_ACQUIRE_SHARED(...) TSA(acquire_shared_capability(__VA_ARGS__))
36
+ error_setg(&local_err, "blkverify=on can only be set if there are "
26
37
+ "exactly two files and vote-threshold is 2");
27
/* TSA_RELEASE() is used to annotate functions: the caller of the
38
+ ret = -EINVAL;
28
* function MUST hold the resource, but the function will then release it.
39
+ goto exit;
29
@@ -XXX,XX +XXX,XX @@
40
}
30
* void Foo(void) TSA_RELEASE(mutex);
41
31
*/
42
s->rewrite_corrupted = qemu_opt_get_bool(opts, QUORUM_OPT_REWRITE,
32
#define TSA_RELEASE(...) TSA(release_capability(__VA_ARGS__))
33
+#define TSA_RELEASE_SHARED(...) TSA(release_shared_capability(__VA_ARGS__))
34
35
/* TSA_NO_TSA is used to annotate functions. Use only when you need to.
36
*
37
@@ -XXX,XX +XXX,XX @@
38
* More than one mutex may be specified, comma-separated.
39
*/
40
#define TSA_ASSERT(...) TSA(assert_capability(__VA_ARGS__))
41
+#define TSA_ASSERT_SHARED(...) TSA(assert_shared_capability(__VA_ARGS__))
42
43
#endif /* #ifndef CLANG_TSA_H */
43
--
44
--
44
2.19.1
45
2.38.1
45
46
diff view generated by jsdifflib
1
Commit e2b8247a322 introduced an error path in qemu_rbd_open() after
1
This enables clang's thread safety analysis (TSA), which we'll use to
2
calling rbd_open(), but neglected to close the image again in this error
2
statically check the block graph locking.
3
path. The error path should contain everything that the regular close
4
function qemu_rbd_close() contains.
5
6
This adds the missing rbd_close() call.
7
3
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
5
Message-Id: <20221207131838.239125-9-kwolf@redhat.com>
6
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
8
---
11
block/rbd.c | 1 +
9
configure | 1 +
12
1 file changed, 1 insertion(+)
10
1 file changed, 1 insertion(+)
13
11
14
diff --git a/block/rbd.c b/block/rbd.c
12
diff --git a/configure b/configure
15
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100755
16
--- a/block/rbd.c
14
--- a/configure
17
+++ b/block/rbd.c
15
+++ b/configure
18
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
16
@@ -XXX,XX +XXX,XX @@ add_to warn_flags -Wnested-externs
19
"automatically marking the image read-only.");
17
add_to warn_flags -Wendif-labels
20
r = bdrv_set_read_only(bs, true, &local_err);
18
add_to warn_flags -Wexpansion-to-defined
21
if (r < 0) {
19
add_to warn_flags -Wimplicit-fallthrough=2
22
+ rbd_close(s->image);
20
+add_to warn_flags -Wthread-safety
23
error_propagate(errp, local_err);
21
24
goto failed_open;
22
nowarn_flags=
25
}
23
add_to nowarn_flags -Wno-initializer-overrides
26
--
24
--
27
2.19.1
25
2.38.1
28
29
diff view generated by jsdifflib
1
If read-only=off, but auto-read-only=on is given, open the file
1
The test case assumes that a drain only happens in one specific place
2
read-write if we have the permissions, but instead of erroring out for
2
where it drains explicitly. This assumption happened to hold true until
3
read-only files, just degrade to read-only.
3
now, but block layer functions may drain interally (any graph
4
modifications are going to do that through bdrv_graph_wrlock()), so this
5
is incorrect. Make sure that the test code in .drained_begin only runs
6
where we actually want it to run.
7
8
When scheduling a BH from .drained_begin, we also need to increase the
9
in_flight counter to make sure that the operation is actually completed
10
in time before the node that it works on goes away.
4
11
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Niels de Vos <ndevos@redhat.com>
13
Message-Id: <20221207131838.239125-10-kwolf@redhat.com>
14
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
16
---
8
block/gluster.c | 12 ++++++++++--
17
tests/unit/test-bdrv-drain.c | 18 ++++++++++++++++++
9
1 file changed, 10 insertions(+), 2 deletions(-)
18
1 file changed, 18 insertions(+)
10
19
11
diff --git a/block/gluster.c b/block/gluster.c
20
diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c
12
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
13
--- a/block/gluster.c
22
--- a/tests/unit/test-bdrv-drain.c
14
+++ b/block/gluster.c
23
+++ b/tests/unit/test-bdrv-drain.c
15
@@ -XXX,XX +XXX,XX @@ static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
24
@@ -XXX,XX +XXX,XX @@ struct detach_by_parent_data {
16
qemu_gluster_parse_flags(bdrv_flags, &open_flags);
25
BlockDriverState *c;
17
26
BdrvChild *child_c;
18
s->fd = glfs_open(s->glfs, gconf->path, open_flags);
27
bool by_parent_cb;
19
- if (!s->fd) {
28
+ bool detach_on_drain;
20
- ret = -errno;
29
};
21
+ ret = s->fd ? 0 : -errno;
30
static struct detach_by_parent_data detach_by_parent_data;
31
32
@@ -XXX,XX +XXX,XX @@ static void detach_indirect_bh(void *opaque)
33
{
34
struct detach_by_parent_data *data = opaque;
35
36
+ bdrv_dec_in_flight(data->child_b->bs);
37
bdrv_unref_child(data->parent_b, data->child_b);
38
39
bdrv_ref(data->c);
40
@@ -XXX,XX +XXX,XX @@ static void detach_by_parent_aio_cb(void *opaque, int ret)
41
42
g_assert_cmpint(ret, ==, 0);
43
if (data->by_parent_cb) {
44
+ bdrv_inc_in_flight(data->child_b->bs);
45
detach_indirect_bh(data);
46
}
47
}
48
49
static void detach_by_driver_cb_drained_begin(BdrvChild *child)
50
{
51
+ struct detach_by_parent_data *data = &detach_by_parent_data;
22
+
52
+
23
+ if (ret == -EACCES || ret == -EROFS) {
53
+ if (!data->detach_on_drain) {
24
+ /* Try to degrade to read-only, but if it doesn't work, still use the
54
+ return;
25
+ * normal error message. */
55
+ }
26
+ if (bdrv_apply_auto_read_only(bs, NULL, NULL) == 0) {
56
+ data->detach_on_drain = false;
27
+ open_flags = (open_flags & ~O_RDWR) | O_RDONLY;
57
+
28
+ s->fd = glfs_open(s->glfs, gconf->path, open_flags);
58
+ bdrv_inc_in_flight(data->child_b->bs);
29
+ ret = s->fd ? 0 : -errno;
59
aio_bh_schedule_oneshot(qemu_get_current_aio_context(),
30
+ }
60
detach_indirect_bh, &detach_by_parent_data);
61
child_of_bds.drained_begin(child);
62
@@ -XXX,XX +XXX,XX @@ static void test_detach_indirect(bool by_parent_cb)
63
detach_by_driver_cb_class = child_of_bds;
64
detach_by_driver_cb_class.drained_begin =
65
detach_by_driver_cb_drained_begin;
66
+ detach_by_driver_cb_class.drained_end = NULL;
67
+ detach_by_driver_cb_class.drained_poll = NULL;
31
}
68
}
32
69
33
s->supports_seek_data = qemu_gluster_test_seek(s->fd);
70
+ detach_by_parent_data = (struct detach_by_parent_data) {
71
+ .detach_on_drain = false,
72
+ };
73
+
74
/* Create all involved nodes */
75
parent_a = bdrv_new_open_driver(&bdrv_test, "parent-a", BDRV_O_RDWR,
76
&error_abort);
77
@@ -XXX,XX +XXX,XX @@ static void test_detach_indirect(bool by_parent_cb)
78
.child_b = child_b,
79
.c = c,
80
.by_parent_cb = by_parent_cb,
81
+ .detach_on_drain = true,
82
};
83
acb = blk_aio_preadv(blk, 0, &qiov, 0, detach_by_parent_aio_cb, NULL);
84
g_assert(acb != NULL);
34
--
85
--
35
2.19.1
86
2.38.1
36
37
diff view generated by jsdifflib
1
If a management application builds the block graph node by node, the
1
bdrv_img_create() polls internally (when calling bdrv_create(), which is
2
protocol layer doesn't inherit its read-only option from the format
2
a co_wrapper), so it can't be called while holding the lock of any
3
layer any more, so it must be set explicitly.
3
AioContext except the current one without causing deadlocks. Drop the
4
4
lock around the call in external_snapshot_prepare().
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: <20221207131838.239125-11-kwolf@redhat.com>
8
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
40
---
10
---
41
qapi/block-core.json | 7 +++++++
11
block.c | 4 ++++
42
include/block/block.h | 2 ++
12
blockdev.c | 4 ++++
43
block.c | 17 +++++++++++++++++
13
2 files changed, 8 insertions(+)
44
block/vvfat.c | 1 +
45
blockdev.c | 2 +-
46
5 files changed, 28 insertions(+), 1 deletion(-)
47
14
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
15
diff --git a/block.c b/block.c
94
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
95
--- a/block.c
17
--- a/block.c
96
+++ b/block.c
18
+++ b/block.c
97
@@ -XXX,XX +XXX,XX @@ static void bdrv_inherited_options(int *child_flags, QDict *child_options,
19
@@ -XXX,XX +XXX,XX @@ bool bdrv_op_blocker_is_empty(BlockDriverState *bs)
98
20
return true;
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
}
116
117
+ assert(qemu_opt_find(opts, BDRV_OPT_AUTO_READ_ONLY));
118
+ if (qemu_opt_get_bool_del(opts, BDRV_OPT_AUTO_READ_ONLY, false)) {
119
+ *flags |= BDRV_O_AUTO_RDONLY;
120
+ }
121
}
21
}
122
22
123
static void update_options_from_flags(QDict *options, int flags)
23
+/*
124
@@ -XXX,XX +XXX,XX @@ static void update_options_from_flags(QDict *options, int flags)
24
+ * Must not be called while holding the lock of an AioContext other than the
125
if (!qdict_haskey(options, BDRV_OPT_READ_ONLY)) {
25
+ * current one.
126
qdict_put_bool(options, BDRV_OPT_READ_ONLY, !(flags & BDRV_O_RDWR));
26
+ */
127
}
27
void bdrv_img_create(const char *filename, const char *fmt,
128
+ if (!qdict_haskey(options, BDRV_OPT_AUTO_READ_ONLY)) {
28
const char *base_filename, const char *base_fmt,
129
+ qdict_put_bool(options, BDRV_OPT_AUTO_READ_ONLY,
29
char *options, uint64_t img_size, int flags, bool quiet,
130
+ flags & BDRV_O_AUTO_RDONLY);
131
+ }
132
}
133
134
static void bdrv_assign_node_name(BlockDriverState *bs,
135
@@ -XXX,XX +XXX,XX @@ QemuOptsList bdrv_runtime_opts = {
136
.type = QEMU_OPT_BOOL,
137
.help = "Node is opened in read-only mode",
138
},
139
+ {
140
+ .name = BDRV_OPT_AUTO_READ_ONLY,
141
+ .type = QEMU_OPT_BOOL,
142
+ .help = "Node can become read-only if opening read-write fails",
143
+ },
144
{
145
.name = "detect-zeroes",
146
.type = QEMU_OPT_STRING,
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
+
153
}
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
30
diff --git a/blockdev.c b/blockdev.c
169
index XXXXXXX..XXXXXXX 100644
31
index XXXXXXX..XXXXXXX 100644
170
--- a/blockdev.c
32
--- a/blockdev.c
171
+++ b/blockdev.c
33
+++ b/blockdev.c
172
@@ -XXX,XX +XXX,XX @@ void qmp_blockdev_change_medium(bool has_device, const char *device,
34
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_prepare(BlkActionState *common,
173
35
goto out;
174
bdrv_flags = blk_get_open_flags_from_root_state(blk);
36
}
175
bdrv_flags &= ~(BDRV_O_TEMPORARY | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING |
37
bdrv_refresh_filename(state->old_bs);
176
- BDRV_O_PROTOCOL);
38
+
177
+ BDRV_O_PROTOCOL | BDRV_O_AUTO_RDONLY);
39
+ aio_context_release(aio_context);
178
40
bdrv_img_create(new_image_file, format,
179
if (!has_read_only) {
41
state->old_bs->filename,
180
read_only = BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN;
42
state->old_bs->drv->format_name,
43
NULL, size, flags, false, &local_err);
44
+ aio_context_acquire(aio_context);
45
+
46
if (local_err) {
47
error_propagate(errp, local_err);
48
goto out;
181
--
49
--
182
2.19.1
50
2.38.1
183
184
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
2
2
3
Signed-off-by: Alberto Garcia <berto@igalia.com>
3
Protect the main function where graph is modified.
4
5
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Message-Id: <20221207131838.239125-12-kwolf@redhat.com>
8
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
---
11
---
6
block.c | 6 +++---
12
block.c | 7 +++----
7
1 file changed, 3 insertions(+), 3 deletions(-)
13
1 file changed, 3 insertions(+), 4 deletions(-)
8
14
9
diff --git a/block.c b/block.c
15
diff --git a/block.c b/block.c
10
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
11
--- a/block.c
17
--- a/block.c
12
+++ b/block.c
18
+++ b/block.c
13
@@ -XXX,XX +XXX,XX @@ QemuOptsList bdrv_runtime_opts = {
19
@@ -XXX,XX +XXX,XX @@ uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm)
14
.help = "try to optimize zero writes (off, on, unmap)",
20
*
15
},
21
* If @new_bs is non-NULL, the parent of @child must already be drained through
16
{
22
* @child.
17
- .name = "discard",
23
- *
18
+ .name = BDRV_OPT_DISCARD,
24
- * This function does not poll.
19
.type = QEMU_OPT_STRING,
25
*/
20
.help = "discard operation (ignore/off, unmap/on)",
26
static void bdrv_replace_child_noperm(BdrvChild *child,
21
},
27
BlockDriverState *new_bs)
22
@@ -XXX,XX +XXX,XX @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file,
28
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child,
29
assert(bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs));
30
}
31
32
+ /* TODO Pull this up into the callers to avoid polling here */
33
+ bdrv_graph_wrlock();
34
if (old_bs) {
35
if (child->klass->detach) {
36
child->klass->detach(child);
37
}
38
- assert_bdrv_graph_writable(old_bs);
39
QLIST_REMOVE(child, next_parent);
40
}
41
42
child->bs = new_bs;
43
44
if (new_bs) {
45
- assert_bdrv_graph_writable(new_bs);
46
QLIST_INSERT_HEAD(&new_bs->parents, child, next_parent);
47
if (child->klass->attach) {
48
child->klass->attach(child);
23
}
49
}
24
}
50
}
25
51
+ bdrv_graph_wrunlock();
26
- discard = qemu_opt_get(opts, "discard");
52
27
+ discard = qemu_opt_get(opts, BDRV_OPT_DISCARD);
53
/*
28
if (discard != NULL) {
54
* If the parent was drained through this BdrvChild previously, but new_bs
29
if (bdrv_parse_discard_flags(discard, &bs->open_flags) != 0) {
30
error_setg(errp, "Invalid discard option");
31
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
32
33
update_flags_from_options(&reopen_state->flags, opts);
34
35
- discard = qemu_opt_get_del(opts, "discard");
36
+ discard = qemu_opt_get_del(opts, BDRV_OPT_DISCARD);
37
if (discard != NULL) {
38
if (bdrv_parse_discard_flags(discard, &reopen_state->flags) != 0) {
39
error_setg(errp, "Invalid discard option");
40
--
55
--
41
2.19.1
56
2.38.1
42
43
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
2
2
3
Following the example of qemu_opts_print_help(), indent all entries in
3
We don't protect bdrv->aio_context with the graph rwlock,
4
the list of character devices.
4
so these assertions are not needed
5
5
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
7
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Message-Id: <20221207131838.239125-13-kwolf@redhat.com>
9
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
10
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
12
---
10
chardev/char.c | 2 +-
13
block.c | 3 ---
11
1 file changed, 1 insertion(+), 1 deletion(-)
14
1 file changed, 3 deletions(-)
12
15
13
diff --git a/chardev/char.c b/chardev/char.c
16
diff --git a/block.c b/block.c
14
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
15
--- a/chardev/char.c
18
--- a/block.c
16
+++ b/chardev/char.c
19
+++ b/block.c
17
@@ -XXX,XX +XXX,XX @@ help_string_append(const char *name, void *opaque)
20
@@ -XXX,XX +XXX,XX @@ static void bdrv_detach_aio_context(BlockDriverState *bs)
18
{
21
if (bs->quiesce_counter) {
19
GString *str = opaque;
22
aio_enable_external(bs->aio_context);
20
23
}
21
- g_string_append_printf(str, "\n%s", name);
24
- assert_bdrv_graph_writable(bs);
22
+ g_string_append_printf(str, "\n %s", name);
25
bs->aio_context = NULL;
23
}
26
}
24
27
25
static const char *chardev_alias_translate(const char *name)
28
@@ -XXX,XX +XXX,XX @@ static void bdrv_attach_aio_context(BlockDriverState *bs,
29
aio_disable_external(new_context);
30
}
31
32
- assert_bdrv_graph_writable(bs);
33
bs->aio_context = new_context;
34
35
if (bs->drv && bs->drv->bdrv_attach_aio_context) {
36
@@ -XXX,XX +XXX,XX @@ static void bdrv_set_aio_context_commit(void *opaque)
37
BlockDriverState *bs = (BlockDriverState *) state->bs;
38
AioContext *new_context = state->new_ctx;
39
AioContext *old_context = bdrv_get_aio_context(bs);
40
- assert_bdrv_graph_writable(bs);
41
42
/*
43
* Take the old AioContex when detaching it from bs.
26
--
44
--
27
2.19.1
45
2.38.1
28
29
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
2
2
3
Just like in qemu_opts_print_help(), print the device name as a caption
3
Remove the old assert_bdrv_graph_writable, and replace it with
4
instead of on every single line, indent all options, add angle brackets
4
the new version using graph-lock API.
5
around types, and align the descriptions after 24 characters. Also,
6
separate the descriptions with " - " instead of putting them in
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
5
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
See the function documentation for more information.
12
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
7
8
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Message-Id: <20221207131838.239125-14-kwolf@redhat.com>
11
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
14
---
15
qdev-monitor.c | 13 +++++++++++--
15
include/block/block_int-global-state.h | 17 -----------------
16
1 file changed, 11 insertions(+), 2 deletions(-)
16
include/block/graph-lock.h | 15 +++++++++++++++
17
block.c | 4 ++--
18
block/graph-lock.c | 11 +++++++++++
19
4 files changed, 28 insertions(+), 19 deletions(-)
17
20
18
diff --git a/qdev-monitor.c b/qdev-monitor.c
21
diff --git a/include/block/block_int-global-state.h b/include/block/block_int-global-state.h
19
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
20
--- a/qdev-monitor.c
23
--- a/include/block/block_int-global-state.h
21
+++ b/qdev-monitor.c
24
+++ b/include/block/block_int-global-state.h
22
@@ -XXX,XX +XXX,XX @@ int qdev_device_help(QemuOpts *opts)
25
@@ -XXX,XX +XXX,XX @@ void bdrv_remove_aio_context_notifier(BlockDriverState *bs,
23
goto error;
26
*/
27
void bdrv_drain_all_end_quiesce(BlockDriverState *bs);
28
29
-/**
30
- * Make sure that the function is running under both drain and BQL.
31
- * The latter protects from concurrent writings
32
- * from the GS API, while the former prevents concurrent reads
33
- * from I/O.
34
- */
35
-static inline void assert_bdrv_graph_writable(BlockDriverState *bs)
36
-{
37
- /*
38
- * TODO: this function is incomplete. Because the users of this
39
- * assert lack the necessary drains, check only for BQL.
40
- * Once the necessary drains are added,
41
- * assert also for qatomic_read(&bs->quiesce_counter) > 0
42
- */
43
- assert(qemu_in_main_thread());
44
-}
45
-
46
#endif /* BLOCK_INT_GLOBAL_STATE_H */
47
diff --git a/include/block/graph-lock.h b/include/block/graph-lock.h
48
index XXXXXXX..XXXXXXX 100644
49
--- a/include/block/graph-lock.h
50
+++ b/include/block/graph-lock.h
51
@@ -XXX,XX +XXX,XX @@ void coroutine_fn bdrv_graph_co_rdunlock(void);
52
void bdrv_graph_rdlock_main_loop(void);
53
void bdrv_graph_rdunlock_main_loop(void);
54
55
+/*
56
+ * assert_bdrv_graph_readable:
57
+ * Make sure that the reader is either the main loop,
58
+ * or there is at least a reader helding the rdlock.
59
+ * In this way an incoming writer is aware of the read and waits.
60
+ */
61
+void assert_bdrv_graph_readable(void);
62
+
63
+/*
64
+ * assert_bdrv_graph_writable:
65
+ * Make sure that the writer is the main loop and has set @has_writer,
66
+ * so that incoming readers will pause.
67
+ */
68
+void assert_bdrv_graph_writable(void);
69
+
70
typedef struct GraphLockable { } GraphLockable;
71
72
/*
73
diff --git a/block.c b/block.c
74
index XXXXXXX..XXXXXXX 100644
75
--- a/block.c
76
+++ b/block.c
77
@@ -XXX,XX +XXX,XX @@ static void bdrv_child_cb_attach(BdrvChild *child)
78
{
79
BlockDriverState *bs = child->opaque;
80
81
- assert_bdrv_graph_writable(bs);
82
+ assert_bdrv_graph_writable();
83
QLIST_INSERT_HEAD(&bs->children, child, next);
84
if (bs->drv->is_filter || (child->role & BDRV_CHILD_FILTERED)) {
85
/*
86
@@ -XXX,XX +XXX,XX @@ static void bdrv_child_cb_detach(BdrvChild *child)
87
bdrv_backing_detach(child);
24
}
88
}
25
89
26
+ if (prop_list) {
90
- assert_bdrv_graph_writable(bs);
27
+ out_printf("%s options:\n", driver);
91
+ assert_bdrv_graph_writable();
28
+ } else {
92
QLIST_REMOVE(child, next);
29
+ out_printf("There are no options for %s.\n", driver);
93
if (child == bs->backing) {
30
+ }
94
assert(child != bs->file);
31
for (prop = prop_list; prop; prop = prop->next) {
95
diff --git a/block/graph-lock.c b/block/graph-lock.c
32
- out_printf("%s.%s=%s", driver, prop->value->name, prop->value->type);
96
index XXXXXXX..XXXXXXX 100644
33
+ int len;
97
--- a/block/graph-lock.c
34
+ out_printf(" %s=<%s>%n", prop->value->name, prop->value->type, &len);
98
+++ b/block/graph-lock.c
35
if (prop->value->has_description) {
99
@@ -XXX,XX +XXX,XX @@ void bdrv_graph_rdunlock_main_loop(void)
36
- out_printf(" (%s)\n", prop->value->description);
100
GLOBAL_STATE_CODE();
37
+ if (len < 24) {
101
assert(!qemu_in_coroutine());
38
+ out_printf("%*s", 24 - len, "");
102
}
39
+ }
103
+
40
+ out_printf(" - %s\n", prop->value->description);
104
+void assert_bdrv_graph_readable(void)
41
} else {
105
+{
42
out_printf("\n");
106
+ assert(qemu_in_main_thread() || reader_count());
43
}
107
+}
108
+
109
+void assert_bdrv_graph_writable(void)
110
+{
111
+ assert(qemu_in_main_thread());
112
+ assert(qatomic_read(&has_writer));
113
+}
44
--
114
--
45
2.19.1
115
2.38.1
46
47
diff view generated by jsdifflib
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Reviewed-by: Alberto Garcia <berto@igalia.com>
2
Message-Id: <20221207131838.239125-15-kwolf@redhat.com>
3
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
3
---
5
---
4
block/vpc.c | 2 ++
6
include/block/graph-lock.h | 80 +++++++++++++++++++++++++++++++++-----
5
1 file changed, 2 insertions(+)
7
block/graph-lock.c | 3 ++
8
2 files changed, 73 insertions(+), 10 deletions(-)
6
9
7
diff --git a/block/vpc.c b/block/vpc.c
10
diff --git a/include/block/graph-lock.h b/include/block/graph-lock.h
8
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
9
--- a/block/vpc.c
12
--- a/include/block/graph-lock.h
10
+++ b/block/vpc.c
13
+++ b/include/block/graph-lock.h
11
@@ -XXX,XX +XXX,XX @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
14
@@ -XXX,XX +XXX,XX @@
12
}
15
#define GRAPH_LOCK_H
13
16
14
qemu_co_mutex_init(&s->lock);
17
#include "qemu/osdep.h"
15
+ qemu_opts_del(opts);
18
+#include "qemu/clang-tsa.h"
16
19
17
return 0;
20
#include "qemu/coroutine.h"
18
21
19
fail:
22
@@ -XXX,XX +XXX,XX @@
20
+ qemu_opts_del(opts);
23
*/
21
qemu_vfree(s->pagetable);
24
typedef struct BdrvGraphRWlock BdrvGraphRWlock;
22
#ifdef CACHE
25
23
g_free(s->pageentry_u8);
26
+/* Dummy lock object to use for Thread Safety Analysis (TSA) */
27
+typedef struct TSA_CAPABILITY("graph-lock") BdrvGraphLock {
28
+} BdrvGraphLock;
29
+
30
+extern BdrvGraphLock graph_lock;
31
+
32
+/*
33
+ * clang doesn't check consistency in locking annotations between forward
34
+ * declarations and the function definition. Having the annotation on the
35
+ * definition, but not the declaration in a header file, may give the reader
36
+ * a false sense of security because the condition actually remains unchecked
37
+ * for callers in other source files.
38
+ *
39
+ * Therefore, as a convention, for public functions, GRAPH_RDLOCK and
40
+ * GRAPH_WRLOCK annotations should be present only in the header file.
41
+ */
42
+#define GRAPH_WRLOCK TSA_REQUIRES(graph_lock)
43
+#define GRAPH_RDLOCK TSA_REQUIRES_SHARED(graph_lock)
44
+
45
+/*
46
+ * TSA annotations are not part of function types, so checks are defeated when
47
+ * using a function pointer. As a workaround, annotate function pointers with
48
+ * this macro that will require that the lock is at least taken while reading
49
+ * the pointer. In most cases this is equivalent to actually protecting the
50
+ * function call.
51
+ */
52
+#define GRAPH_RDLOCK_PTR TSA_GUARDED_BY(graph_lock)
53
+#define GRAPH_WRLOCK_PTR TSA_GUARDED_BY(graph_lock)
54
+
55
/*
56
* register_aiocontext:
57
* Add AioContext @ctx to the list of AioContext.
58
@@ -XXX,XX +XXX,XX @@ void unregister_aiocontext(AioContext *ctx);
59
* This function polls. Callers must not hold the lock of any AioContext other
60
* than the current one.
61
*/
62
-void bdrv_graph_wrlock(void);
63
+void bdrv_graph_wrlock(void) TSA_ACQUIRE(graph_lock) TSA_NO_TSA;
64
65
/*
66
* bdrv_graph_wrunlock:
67
* Write finished, reset global has_writer to 0 and restart
68
* all readers that are waiting.
69
*/
70
-void bdrv_graph_wrunlock(void);
71
+void bdrv_graph_wrunlock(void) TSA_RELEASE(graph_lock) TSA_NO_TSA;
72
73
/*
74
* bdrv_graph_co_rdlock:
75
@@ -XXX,XX +XXX,XX @@ void bdrv_graph_wrunlock(void);
76
* loop) to take it and wait that the coroutine ends, so that
77
* we always signal that a reader is running.
78
*/
79
-void coroutine_fn bdrv_graph_co_rdlock(void);
80
+void coroutine_fn TSA_ACQUIRE_SHARED(graph_lock) TSA_NO_TSA
81
+bdrv_graph_co_rdlock(void);
82
83
/*
84
* bdrv_graph_rdunlock:
85
@@ -XXX,XX +XXX,XX @@ void coroutine_fn bdrv_graph_co_rdlock(void);
86
* If the writer is waiting for reads to finish (has_writer == 1), signal
87
* the writer that we are done via aio_wait_kick() to let it continue.
88
*/
89
-void coroutine_fn bdrv_graph_co_rdunlock(void);
90
+void coroutine_fn TSA_RELEASE_SHARED(graph_lock) TSA_NO_TSA
91
+bdrv_graph_co_rdunlock(void);
92
93
/*
94
* bdrv_graph_rd{un}lock_main_loop:
95
@@ -XXX,XX +XXX,XX @@ void coroutine_fn bdrv_graph_co_rdunlock(void);
96
* in the main loop. It is just asserting that we are not
97
* in a coroutine and in GLOBAL_STATE_CODE.
98
*/
99
-void bdrv_graph_rdlock_main_loop(void);
100
-void bdrv_graph_rdunlock_main_loop(void);
101
+void TSA_ACQUIRE_SHARED(graph_lock) TSA_NO_TSA
102
+bdrv_graph_rdlock_main_loop(void);
103
+
104
+void TSA_RELEASE_SHARED(graph_lock) TSA_NO_TSA
105
+bdrv_graph_rdunlock_main_loop(void);
106
107
/*
108
* assert_bdrv_graph_readable:
109
@@ -XXX,XX +XXX,XX @@ void assert_bdrv_graph_readable(void);
110
*/
111
void assert_bdrv_graph_writable(void);
112
113
+/*
114
+ * Calling this function tells TSA that we know that the lock is effectively
115
+ * taken even though we cannot prove it (yet) with GRAPH_RDLOCK. This can be
116
+ * useful in intermediate stages of a conversion to using the GRAPH_RDLOCK
117
+ * macro.
118
+ */
119
+static inline void TSA_ASSERT_SHARED(graph_lock) TSA_NO_TSA
120
+assume_graph_lock(void)
121
+{
122
+}
123
+
124
typedef struct GraphLockable { } GraphLockable;
125
126
/*
127
@@ -XXX,XX +XXX,XX @@ typedef struct GraphLockable { } GraphLockable;
128
*/
129
#define GML_OBJ_() (&(GraphLockable) { })
130
131
-static inline GraphLockable *graph_lockable_auto_lock(GraphLockable *x)
132
+/*
133
+ * This is not marked as TSA_ACQUIRE() because TSA doesn't understand the
134
+ * cleanup attribute and would therefore complain that the graph is never
135
+ * unlocked. TSA_ASSERT() makes sure that the following calls know that we
136
+ * hold the lock while unlocking is left unchecked.
137
+ */
138
+static inline GraphLockable * TSA_ASSERT(graph_lock) TSA_NO_TSA
139
+graph_lockable_auto_lock(GraphLockable *x)
140
{
141
bdrv_graph_co_rdlock();
142
return x;
143
}
144
145
-static inline void graph_lockable_auto_unlock(GraphLockable *x)
146
+static inline void TSA_NO_TSA
147
+graph_lockable_auto_unlock(GraphLockable *x)
148
{
149
bdrv_graph_co_rdunlock();
150
}
151
@@ -XXX,XX +XXX,XX @@ typedef struct GraphLockableMainloop { } GraphLockableMainloop;
152
*/
153
#define GMLML_OBJ_() (&(GraphLockableMainloop) { })
154
155
-static inline GraphLockableMainloop *
156
+/*
157
+ * This is not marked as TSA_ACQUIRE() because TSA doesn't understand the
158
+ * cleanup attribute and would therefore complain that the graph is never
159
+ * unlocked. TSA_ASSERT() makes sure that the following calls know that we
160
+ * hold the lock while unlocking is left unchecked.
161
+ */
162
+static inline GraphLockableMainloop * TSA_ASSERT(graph_lock) TSA_NO_TSA
163
graph_lockable_auto_lock_mainloop(GraphLockableMainloop *x)
164
{
165
bdrv_graph_rdlock_main_loop();
166
return x;
167
}
168
169
-static inline void
170
+static inline void TSA_NO_TSA
171
graph_lockable_auto_unlock_mainloop(GraphLockableMainloop *x)
172
{
173
bdrv_graph_rdunlock_main_loop();
174
diff --git a/block/graph-lock.c b/block/graph-lock.c
175
index XXXXXXX..XXXXXXX 100644
176
--- a/block/graph-lock.c
177
+++ b/block/graph-lock.c
178
@@ -XXX,XX +XXX,XX @@
179
#include "block/block.h"
180
#include "block/block_int.h"
181
182
+/* Dummy lock object to use for Thread Safety Analysis (TSA) */
183
+BdrvGraphLock graph_lock;
184
+
185
/* Protects the list of aiocontext and orphaned_reader_count */
186
static QemuMutex aio_context_list_lock;
187
24
--
188
--
25
2.19.1
189
2.38.1
26
27
diff view generated by jsdifflib
1
From: Cleber Rosa <crosa@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
2
Message-Id: <20221207131838.239125-16-kwolf@redhat.com>
3
While testing the Python 3 changes which touch the 083 test, I noticed
3
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
4
that it would fail with qcow2. Expanding the testing, I noticed it
5
had nothing to do with the Python 3 changes, and in fact, it would not
6
pass on anything but raw:
7
8
raw: pass
9
bochs: not generic
10
cloop: not generic
11
parallels: fail
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>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
41
---
5
---
42
tests/qemu-iotests/083 | 2 +-
6
include/block/block_int-common.h | 4 ++--
43
1 file changed, 1 insertion(+), 1 deletion(-)
7
include/block/graph-lock.h | 4 ++--
8
block.c | 4 ++--
9
3 files changed, 6 insertions(+), 6 deletions(-)
44
10
45
diff --git a/tests/qemu-iotests/083 b/tests/qemu-iotests/083
11
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
46
index XXXXXXX..XXXXXXX 100755
12
index XXXXXXX..XXXXXXX 100644
47
--- a/tests/qemu-iotests/083
13
--- a/include/block/block_int-common.h
48
+++ b/tests/qemu-iotests/083
14
+++ b/include/block/block_int-common.h
49
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
15
@@ -XXX,XX +XXX,XX @@ struct BdrvChildClass {
50
. ./common.rc
16
void (*activate)(BdrvChild *child, Error **errp);
51
. ./common.filter
17
int (*inactivate)(BdrvChild *child);
52
18
53
-_supported_fmt generic
19
- void (*attach)(BdrvChild *child);
54
+_supported_fmt raw
20
- void (*detach)(BdrvChild *child);
55
_supported_proto nbd
21
+ void GRAPH_WRLOCK_PTR (*attach)(BdrvChild *child);
56
_supported_os Linux
22
+ void GRAPH_WRLOCK_PTR (*detach)(BdrvChild *child);
23
24
/*
25
* Notifies the parent that the filename of its child has changed (e.g.
26
diff --git a/include/block/graph-lock.h b/include/block/graph-lock.h
27
index XXXXXXX..XXXXXXX 100644
28
--- a/include/block/graph-lock.h
29
+++ b/include/block/graph-lock.h
30
@@ -XXX,XX +XXX,XX @@ bdrv_graph_rdunlock_main_loop(void);
31
* or there is at least a reader helding the rdlock.
32
* In this way an incoming writer is aware of the read and waits.
33
*/
34
-void assert_bdrv_graph_readable(void);
35
+void GRAPH_RDLOCK assert_bdrv_graph_readable(void);
36
37
/*
38
* assert_bdrv_graph_writable:
39
* Make sure that the writer is the main loop and has set @has_writer,
40
* so that incoming readers will pause.
41
*/
42
-void assert_bdrv_graph_writable(void);
43
+void GRAPH_WRLOCK assert_bdrv_graph_writable(void);
44
45
/*
46
* Calling this function tells TSA that we know that the lock is effectively
47
diff --git a/block.c b/block.c
48
index XXXXXXX..XXXXXXX 100644
49
--- a/block.c
50
+++ b/block.c
51
@@ -XXX,XX +XXX,XX @@ static void bdrv_inherited_options(BdrvChildRole role, bool parent_is_format,
52
*child_flags = flags;
53
}
54
55
-static void bdrv_child_cb_attach(BdrvChild *child)
56
+static void GRAPH_WRLOCK bdrv_child_cb_attach(BdrvChild *child)
57
{
58
BlockDriverState *bs = child->opaque;
59
60
@@ -XXX,XX +XXX,XX @@ static void bdrv_child_cb_attach(BdrvChild *child)
61
}
62
}
63
64
-static void bdrv_child_cb_detach(BdrvChild *child)
65
+static void GRAPH_WRLOCK bdrv_child_cb_detach(BdrvChild *child)
66
{
67
BlockDriverState *bs = child->opaque;
57
68
58
--
69
--
59
2.19.1
70
2.38.1
60
61
diff view generated by jsdifflib
1
From: Thomas Huth <thuth@redhat.com>
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
2
2
3
When using the vvfat driver with a directory that contains too many files,
3
Add co_wrapper_bdrv_rdlock and co_wrapper_mixed_bdrv_rdlock option to
4
QEMU currently crashes. This can be triggered like this for example:
4
the block-coroutine-wrapper.py script.
5
5
6
mkdir /tmp/vvfattest
6
This "_bdrv_rdlock" option takes and releases the graph rdlock when a
7
cd /tmp/vvfattest
7
coroutine function is created.
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
8
12
Seems like read_directory() is changing the mapping->path variable. Make
9
This means that when used together with "_mixed", the function marked
13
sure we use the right pointer instead.
10
with co_wrapper_mixed_bdrv_rdlock will support both coroutine and
11
non-coroutine case, and in the latter case it will create a coroutine
12
that takes and releases the rdlock. When called from a coroutine, the
13
caller must already hold the graph lock.
14
14
15
Signed-off-by: Thomas Huth <thuth@redhat.com>
15
Example:
16
void co_wrapper_mixed_bdrv_rdlock bdrv_f1();
17
18
Becomes
19
20
static void bdrv_co_enter_f1()
21
{
22
bdrv_graph_co_rdlock();
23
bdrv_co_function();
24
bdrv_graph_co_rdunlock();
25
}
26
27
void bdrv_f1()
28
{
29
if (qemu_in_coroutine) {
30
assume_graph_lock();
31
bdrv_co_function();
32
} else {
33
qemu_co_enter(bdrv_co_enter_f1);
34
...
35
}
36
}
37
38
When used alone, the function will not work in coroutine context, and
39
when called in non-coroutine context it will create a new coroutine that
40
takes care of taking and releasing the rdlock automatically.
41
42
Example:
43
void co_wrapper_bdrv_rdlock bdrv_f1();
44
45
Becomes
46
47
static void bdrv_co_enter_f1()
48
{
49
bdrv_graph_co_rdlock();
50
bdrv_co_function();
51
bdrv_graph_co_rdunlock();
52
}
53
54
void bdrv_f1()
55
{
56
assert(!qemu_in_coroutine());
57
qemu_co_enter(bdrv_co_enter_f1);
58
...
59
}
60
61
About their usage:
62
- co_wrapper does not take the rdlock, so it can be used also outside
63
the block layer.
64
- co_wrapper_mixed will be used by many blk_* functions, since the
65
coroutine function needs to call blk_wait_while_drained() and
66
the rdlock *must* be taken afterwards, otherwise it's a deadlock.
67
In the future this annotation will go away, and blk_* will use
68
co_wrapper directly.
69
- co_wrapper_bdrv_rdlock will be used by BlockDriver callbacks, ideally
70
by all of them in the future.
71
- co_wrapper_mixed_bdrv_rdlock will be used by the remaining functions
72
that are still called by coroutine and non-coroutine context. In the
73
future this annotation will go away, as we will split such mixed
74
functions.
75
76
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
77
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
78
Message-Id: <20221207131838.239125-17-kwolf@redhat.com>
79
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
80
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
81
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
---
82
---
18
block/vvfat.c | 4 ++--
83
include/block/block-common.h | 9 ++++++++-
19
1 file changed, 2 insertions(+), 2 deletions(-)
84
scripts/block-coroutine-wrapper.py | 12 ++++++++++++
85
2 files changed, 20 insertions(+), 1 deletion(-)
20
86
21
diff --git a/block/vvfat.c b/block/vvfat.c
87
diff --git a/include/block/block-common.h b/include/block/block-common.h
22
index XXXXXXX..XXXXXXX 100644
88
index XXXXXXX..XXXXXXX 100644
23
--- a/block/vvfat.c
89
--- a/include/block/block-common.h
24
+++ b/block/vvfat.c
90
+++ b/include/block/block-common.h
25
@@ -XXX,XX +XXX,XX @@ static int init_directories(BDRVVVFATState* s,
91
@@ -XXX,XX +XXX,XX @@
26
mapping = array_get(&(s->mapping), i);
92
*
27
93
* Usage: read docs/devel/block-coroutine-wrapper.rst
28
if (mapping->mode & MODE_DIRECTORY) {
94
*
29
+ char *path = mapping->path;
95
- * There are 2 kind of specifiers:
30
mapping->begin = cluster;
96
+ * There are 4 kind of specifiers:
31
if(read_directory(s, i)) {
97
* - co_wrapper functions can be called by only non-coroutine context, because
32
- error_setg(errp, "Could not read directory %s",
98
* they always generate a new coroutine.
33
- mapping->path);
99
* - co_wrapper_mixed functions can be called by both coroutine and
34
+ error_setg(errp, "Could not read directory %s", path);
100
* non-coroutine context.
35
return -1;
101
+ * - co_wrapper_bdrv_rdlock are co_wrapper functions but automatically take and
36
}
102
+ * release the graph rdlock when creating a new coroutine
37
mapping = array_get(&(s->mapping), i);
103
+ * - co_wrapper_mixed_bdrv_rdlock are co_wrapper_mixed functions but
104
+ * automatically take and release the graph rdlock when creating a new
105
+ * coroutine.
106
*/
107
#define co_wrapper
108
#define co_wrapper_mixed
109
+#define co_wrapper_bdrv_rdlock
110
+#define co_wrapper_mixed_bdrv_rdlock
111
112
#include "block/dirty-bitmap.h"
113
#include "block/blockjob.h"
114
diff --git a/scripts/block-coroutine-wrapper.py b/scripts/block-coroutine-wrapper.py
115
index XXXXXXX..XXXXXXX 100644
116
--- a/scripts/block-coroutine-wrapper.py
117
+++ b/scripts/block-coroutine-wrapper.py
118
@@ -XXX,XX +XXX,XX @@ def __init__(self, return_type: str, name: str, args: str,
119
self.struct_name = snake_to_camel(self.name)
120
self.args = [ParamDecl(arg.strip()) for arg in args.split(',')]
121
self.create_only_co = 'mixed' not in variant
122
+ self.graph_rdlock = 'bdrv_rdlock' in variant
123
124
subsystem, subname = self.name.split('_', 1)
125
self.co_name = f'{subsystem}_co_{subname}'
126
@@ -XXX,XX +XXX,XX @@ def create_mixed_wrapper(func: FuncDecl) -> str:
127
"""
128
name = func.co_name
129
struct_name = func.struct_name
130
+ graph_assume_lock = 'assume_graph_lock();' if func.graph_rdlock else ''
131
+
132
return f"""\
133
{func.return_type} {func.name}({ func.gen_list('{decl}') })
134
{{
135
if (qemu_in_coroutine()) {{
136
+ {graph_assume_lock}
137
return {name}({ func.gen_list('{name}') });
138
}} else {{
139
{struct_name} s = {{
140
@@ -XXX,XX +XXX,XX @@ def gen_wrapper(func: FuncDecl) -> str:
141
name = func.co_name
142
struct_name = func.struct_name
143
144
+ graph_lock=''
145
+ graph_unlock=''
146
+ if func.graph_rdlock:
147
+ graph_lock=' bdrv_graph_co_rdlock();'
148
+ graph_unlock=' bdrv_graph_co_rdunlock();'
149
+
150
creation_function = create_mixed_wrapper
151
if func.create_only_co:
152
creation_function = create_co_wrapper
153
@@ -XXX,XX +XXX,XX @@ def gen_wrapper(func: FuncDecl) -> str:
154
{{
155
{struct_name} *s = opaque;
156
157
+{graph_lock}
158
s->ret = {name}({ func.gen_list('s->{name}') });
159
+{graph_unlock}
160
s->poll_state.in_progress = false;
161
162
aio_wait_kick();
38
--
163
--
39
2.19.1
164
2.38.1
40
41
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
2
2
3
This doesn't have any practical effect at the moment because the
3
Take the rdlock already, before we add the assertions.
4
values of BDRV_SECTOR_SIZE, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE and
5
QCRYPTO_BLOCK_QCOW_SECTOR_SIZE are all the same (512 bytes), but
6
future encryption methods could have different requirements.
7
4
8
Signed-off-by: Alberto Garcia <berto@igalia.com>
5
All these functions either read the graph recursively, or call
9
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
6
BlockDriver callbacks that will eventually need to be protected by the
7
graph rdlock.
8
9
Do it now to all functions together, because many of these recursively
10
call each other.
11
12
For example, bdrv_co_truncate calls BlockDriver->bdrv_co_truncate, and
13
some driver callbacks implement their own .bdrv_co_truncate by calling
14
bdrv_flush inside. So if bdrv_flush asserts but bdrv_truncate does not
15
take the rdlock yet, the assertion will always fail.
16
17
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
Message-Id: <20221207131838.239125-18-kwolf@redhat.com>
20
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
21
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
22
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
23
---
12
block/qcow2.c | 2 +-
24
block/coroutines.h | 2 +-
13
1 file changed, 1 insertion(+), 1 deletion(-)
25
include/block/block-io.h | 53 +++++++++++++++++++++++-----------------
26
2 files changed, 32 insertions(+), 23 deletions(-)
14
27
15
diff --git a/block/qcow2.c b/block/qcow2.c
28
diff --git a/block/coroutines.h b/block/coroutines.h
16
index XXXXXXX..XXXXXXX 100644
29
index XXXXXXX..XXXXXXX 100644
17
--- a/block/qcow2.c
30
--- a/block/coroutines.h
18
+++ b/block/qcow2.c
31
+++ b/block/coroutines.h
19
@@ -XXX,XX +XXX,XX @@ static void qcow2_refresh_limits(BlockDriverState *bs, Error **errp)
32
@@ -XXX,XX +XXX,XX @@ nbd_co_do_establish_connection(BlockDriverState *bs, bool blocking,
20
33
* the "I/O or GS" API.
21
if (bs->encrypted) {
34
*/
22
/* Encryption works on a sector granularity */
35
23
- bs->bl.request_alignment = BDRV_SECTOR_SIZE;
36
-int co_wrapper_mixed
24
+ bs->bl.request_alignment = qcrypto_block_get_sector_size(s->crypto);
37
+int co_wrapper_mixed_bdrv_rdlock
25
}
38
bdrv_common_block_status_above(BlockDriverState *bs,
26
bs->bl.pwrite_zeroes_alignment = s->cluster_size;
39
BlockDriverState *base,
27
bs->bl.pdiscard_alignment = s->cluster_size;
40
bool include_base,
41
diff --git a/include/block/block-io.h b/include/block/block-io.h
42
index XXXXXXX..XXXXXXX 100644
43
--- a/include/block/block-io.h
44
+++ b/include/block/block-io.h
45
@@ -XXX,XX +XXX,XX @@
46
* to catch when they are accidentally called by the wrong API.
47
*/
48
49
-int co_wrapper_mixed bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset,
50
- int64_t bytes,
51
- BdrvRequestFlags flags);
52
+int co_wrapper_mixed_bdrv_rdlock
53
+bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset, int64_t bytes,
54
+ BdrvRequestFlags flags);
55
+
56
int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags);
57
-int co_wrapper_mixed bdrv_pread(BdrvChild *child, int64_t offset,
58
- int64_t bytes, void *buf,
59
- BdrvRequestFlags flags);
60
-int co_wrapper_mixed bdrv_pwrite(BdrvChild *child, int64_t offset,
61
- int64_t bytes, const void *buf,
62
- BdrvRequestFlags flags);
63
-int co_wrapper_mixed bdrv_pwrite_sync(BdrvChild *child, int64_t offset,
64
- int64_t bytes, const void *buf,
65
- BdrvRequestFlags flags);
66
+
67
+int co_wrapper_mixed_bdrv_rdlock
68
+bdrv_pread(BdrvChild *child, int64_t offset, int64_t bytes, void *buf,
69
+ BdrvRequestFlags flags);
70
+
71
+int co_wrapper_mixed_bdrv_rdlock
72
+bdrv_pwrite(BdrvChild *child, int64_t offset,int64_t bytes,
73
+ const void *buf, BdrvRequestFlags flags);
74
+
75
+int co_wrapper_mixed_bdrv_rdlock
76
+bdrv_pwrite_sync(BdrvChild *child, int64_t offset, int64_t bytes,
77
+ const void *buf, BdrvRequestFlags flags);
78
+
79
int coroutine_fn bdrv_co_pwrite_sync(BdrvChild *child, int64_t offset,
80
int64_t bytes, const void *buf,
81
BdrvRequestFlags flags);
82
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_copy_range(BdrvChild *src, int64_t src_offset,
83
84
void bdrv_drain(BlockDriverState *bs);
85
86
-int co_wrapper_mixed
87
+int co_wrapper_mixed_bdrv_rdlock
88
bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
89
PreallocMode prealloc, BdrvRequestFlags flags, Error **errp);
90
91
-int co_wrapper_mixed bdrv_check(BlockDriverState *bs, BdrvCheckResult *res,
92
- BdrvCheckMode fix);
93
+int co_wrapper_mixed_bdrv_rdlock
94
+bdrv_check(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix);
95
96
/* Invalidate any cached metadata used by image formats */
97
-int co_wrapper_mixed bdrv_invalidate_cache(BlockDriverState *bs,
98
- Error **errp);
99
-int co_wrapper_mixed bdrv_flush(BlockDriverState *bs);
100
-int co_wrapper_mixed bdrv_pdiscard(BdrvChild *child, int64_t offset,
101
- int64_t bytes);
102
-int co_wrapper_mixed
103
+int co_wrapper_mixed_bdrv_rdlock
104
+bdrv_invalidate_cache(BlockDriverState *bs, Error **errp);
105
+
106
+int co_wrapper_mixed_bdrv_rdlock bdrv_flush(BlockDriverState *bs);
107
+
108
+int co_wrapper_mixed_bdrv_rdlock
109
+bdrv_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes);
110
+
111
+int co_wrapper_mixed_bdrv_rdlock
112
bdrv_readv_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos);
113
-int co_wrapper_mixed
114
+
115
+int co_wrapper_mixed_bdrv_rdlock
116
bdrv_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos);
117
118
/**
28
--
119
--
29
2.19.1
120
2.38.1
30
31
diff view generated by jsdifflib
1
From: Daniel P. Berrangé <berrange@redhat.com>
1
The generated coroutine wrappers already take care to take the lock in
2
the non-coroutine path, and assume that the lock is already taken in the
3
coroutine path.
2
4
3
The qcow2 block driver expects to see a valid sector size even when it
5
The only thing we need to do for the wrapped function is adding the
4
has opened the crypto layer with QCRYPTO_BLOCK_OPEN_NO_IO.
6
GRAPH_RDLOCK annotation. Doing so also allows us to mark the
7
corresponding callbacks in BlockDriver as GRAPH_RDLOCK_PTR.
5
8
6
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Reviewed-by: Alberto Garcia <berto@igalia.com>
10
Message-Id: <20221207131838.239125-19-kwolf@redhat.com>
11
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
13
---
10
crypto/block-qcow.c | 2 ++
14
block/coroutines.h | 17 ++++++++++-------
11
1 file changed, 2 insertions(+)
15
include/block/block_int-common.h | 20 +++++++++-----------
16
block.c | 2 ++
17
block/io.c | 2 ++
18
4 files changed, 23 insertions(+), 18 deletions(-)
12
19
13
diff --git a/crypto/block-qcow.c b/crypto/block-qcow.c
20
diff --git a/block/coroutines.h b/block/coroutines.h
14
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
15
--- a/crypto/block-qcow.c
22
--- a/block/coroutines.h
16
+++ b/crypto/block-qcow.c
23
+++ b/block/coroutines.h
17
@@ -XXX,XX +XXX,XX @@ qcrypto_block_qcow_open(QCryptoBlock *block,
24
@@ -XXX,XX +XXX,XX @@
18
Error **errp)
25
* the I/O API.
26
*/
27
28
-int coroutine_fn bdrv_co_check(BlockDriverState *bs,
29
- BdrvCheckResult *res, BdrvCheckMode fix);
30
-int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp);
31
+int coroutine_fn GRAPH_RDLOCK
32
+bdrv_co_check(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix);
33
+
34
+int coroutine_fn GRAPH_RDLOCK
35
+bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp);
36
37
int coroutine_fn
38
bdrv_co_common_block_status_above(BlockDriverState *bs,
39
@@ -XXX,XX +XXX,XX @@ bdrv_co_common_block_status_above(BlockDriverState *bs,
40
BlockDriverState **file,
41
int *depth);
42
43
-int coroutine_fn bdrv_co_readv_vmstate(BlockDriverState *bs,
44
- QEMUIOVector *qiov, int64_t pos);
45
-int coroutine_fn bdrv_co_writev_vmstate(BlockDriverState *bs,
46
- QEMUIOVector *qiov, int64_t pos);
47
+int coroutine_fn GRAPH_RDLOCK
48
+bdrv_co_readv_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos);
49
+
50
+int coroutine_fn GRAPH_RDLOCK
51
+bdrv_co_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos);
52
53
int coroutine_fn
54
nbd_co_do_establish_connection(BlockDriverState *bs, bool blocking,
55
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
56
index XXXXXXX..XXXXXXX 100644
57
--- a/include/block/block_int-common.h
58
+++ b/include/block/block_int-common.h
59
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
60
/*
61
* Invalidate any cached meta-data.
62
*/
63
- void coroutine_fn (*bdrv_co_invalidate_cache)(BlockDriverState *bs,
64
- Error **errp);
65
+ void coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_invalidate_cache)(
66
+ BlockDriverState *bs, Error **errp);
67
68
/*
69
* Flushes all data for all layers by calling bdrv_co_flush for underlying
70
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
71
Error **errp);
72
BlockStatsSpecific *(*bdrv_get_specific_stats)(BlockDriverState *bs);
73
74
- int coroutine_fn (*bdrv_save_vmstate)(BlockDriverState *bs,
75
- QEMUIOVector *qiov,
76
- int64_t pos);
77
- int coroutine_fn (*bdrv_load_vmstate)(BlockDriverState *bs,
78
- QEMUIOVector *qiov,
79
- int64_t pos);
80
+ int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_save_vmstate)(
81
+ BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos);
82
+
83
+ int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_load_vmstate)(
84
+ BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos);
85
86
/* removable device specific */
87
bool (*bdrv_is_inserted)(BlockDriverState *bs);
88
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
89
* Returns 0 for completed check, -errno for internal errors.
90
* The check results are stored in result.
91
*/
92
- int coroutine_fn (*bdrv_co_check)(BlockDriverState *bs,
93
- BdrvCheckResult *result,
94
- BdrvCheckMode fix);
95
+ int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_check)(
96
+ BlockDriverState *bs, BdrvCheckResult *result, BdrvCheckMode fix);
97
98
void (*bdrv_debug_event)(BlockDriverState *bs, BlkdebugEvent event);
99
100
diff --git a/block.c b/block.c
101
index XXXXXXX..XXXXXXX 100644
102
--- a/block.c
103
+++ b/block.c
104
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_check(BlockDriverState *bs,
105
BdrvCheckResult *res, BdrvCheckMode fix)
19
{
106
{
20
if (flags & QCRYPTO_BLOCK_OPEN_NO_IO) {
107
IO_CODE();
21
+ block->sector_size = QCRYPTO_BLOCK_QCOW_SECTOR_SIZE;
108
+ assert_bdrv_graph_readable();
22
+ block->payload_offset = 0;
109
if (bs->drv == NULL) {
23
return 0;
110
return -ENOMEDIUM;
24
} else {
111
}
25
if (!options->u.qcow.key_secret) {
112
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp)
113
IO_CODE();
114
115
assert(!(bs->open_flags & BDRV_O_INACTIVE));
116
+ assert_bdrv_graph_readable();
117
118
if (bs->drv->bdrv_co_invalidate_cache) {
119
bs->drv->bdrv_co_invalidate_cache(bs, &local_err);
120
diff --git a/block/io.c b/block/io.c
121
index XXXXXXX..XXXXXXX 100644
122
--- a/block/io.c
123
+++ b/block/io.c
124
@@ -XXX,XX +XXX,XX @@ bdrv_co_readv_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos)
125
BlockDriverState *child_bs = bdrv_primary_bs(bs);
126
int ret;
127
IO_CODE();
128
+ assert_bdrv_graph_readable();
129
130
ret = bdrv_check_qiov_request(pos, qiov->size, qiov, 0, NULL);
131
if (ret < 0) {
132
@@ -XXX,XX +XXX,XX @@ bdrv_co_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos)
133
BlockDriverState *child_bs = bdrv_primary_bs(bs);
134
int ret;
135
IO_CODE();
136
+ assert_bdrv_graph_readable();
137
138
ret = bdrv_check_qiov_request(pos, qiov->size, qiov, 0, NULL);
139
if (ret < 0) {
26
--
140
--
27
2.19.1
141
2.38.1
28
29
diff view generated by jsdifflib