1
The following changes since commit d9bbfea646e86426d549bd612cd9f91e49aa50c2:
1
The following changes since commit a51e5124a655b3dad80b36b18547cb1eca2c5eb2:
2
2
3
Merge remote-tracking branch 'remotes/riscv/tags/riscv-qemu-upstream-v8.2' into staging (2018-03-09 10:58:57 +0000)
3
Merge tag 'pull-omnibus-111023-1' of https://gitlab.com/stsquad/qemu into staging (2023-10-11 09:43:10 -0400)
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 a1be5921e35dcf84ce9e3c9a5c3029cea530a60b:
9
for you to fetch changes up to e6e964b8b021446c8d3d1f91c0208f653e9ec92c:
10
10
11
Merge remote-tracking branch 'mreitz/tags/pull-block-2018-03-09' into queue-block (2018-03-09 16:09:06 +0100)
11
block: Add assertion for bdrv_graph_wrlock() (2023-10-12 16:31:33 +0200)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block layer patches
14
Block layer patches
15
15
16
- Clean up coroutine versions of bdrv_{is_allocated,block_status}*
17
- Graph locking part 5 (protect children/parent links)
18
16
----------------------------------------------------------------
19
----------------------------------------------------------------
17
Alberto Garcia (8):
20
Emanuele Giuseppe Esposito (1):
18
qcow2: Generalize validate_table_offset() into qcow2_validate_table()
21
block: Mark drain related functions GRAPH_RDLOCK
19
qcow2: Check L1 table offset in qcow2_snapshot_load_tmp()
20
qcow2: Check L1 table parameters in qcow2_expand_zero_clusters()
21
qcow2: Check snapshot L1 tables in qcow2_check_metadata_overlap()
22
qcow2: Check snapshot L1 table in qcow2_snapshot_goto()
23
qcow2: Check snapshot L1 table in qcow2_snapshot_delete()
24
qcow2: Make qemu-img check detect corrupted L1 tables in snapshots
25
iotests: Tweak 030 in order to trigger a race condition with parallel jobs
26
22
27
Daniel P. Berrangé (1):
23
Kevin Wolf (21):
28
block: implement the bdrv_reopen_prepare helper for LUKS driver
24
test-bdrv-drain: Don't call bdrv_graph_wrlock() in coroutine context
25
block-coroutine-wrapper: Add no_co_wrapper_bdrv_rdlock functions
26
block: Take graph rdlock in bdrv_inactivate_all()
27
block: Mark bdrv_first_blk() and bdrv_is_root_node() GRAPH_RDLOCK
28
block: Mark bdrv_parent_cb_resize() and callers GRAPH_RDLOCK
29
block: Mark bdrv_snapshot_fallback() and callers GRAPH_RDLOCK
30
block: Take graph rdlock in parts of reopen
31
block: Mark bdrv_get_xdbg_block_graph() and callers GRAPH_RDLOCK
32
block: Mark bdrv_refresh_filename() and callers GRAPH_RDLOCK
33
block: Mark bdrv_primary_child() and callers GRAPH_RDLOCK
34
block: Mark bdrv_get_parent_name() and callers GRAPH_RDLOCK
35
block: Mark bdrv_amend_options() and callers GRAPH_RDLOCK
36
qcow2: Mark qcow2_signal_corruption() and callers GRAPH_RDLOCK
37
qcow2: Mark qcow2_inactivate() and callers GRAPH_RDLOCK
38
qcow2: Mark check_constraints_on_bitmap() GRAPH_RDLOCK
39
block: Mark bdrv_op_is_blocked() and callers GRAPH_RDLOCK
40
block: Mark bdrv_apply_auto_read_only() and callers GRAPH_RDLOCK
41
block: Mark bdrv_get_specific_info() and callers GRAPH_RDLOCK
42
block: Protect bs->parents with graph_lock
43
block: Protect bs->children with graph_lock
44
block: Add assertion for bdrv_graph_wrlock()
29
45
30
Eric Blake (1):
46
Paolo Bonzini (4):
31
iotests: Mark all tests executable
47
block: rename the bdrv_co_block_status static function
48
block: complete public block status API
49
block: switch to co_wrapper for bdrv_is_allocated_*
50
block: convert more bdrv_is_allocated* and bdrv_block_status* calls to coroutine versions
32
51
33
Fam Zheng (2):
52
block/qcow2.h | 187 ++++++++++++++++------------
34
iotests: Test creating overlay when guest running
53
block/vhdx.h | 5 +-
35
iotests: Skip test for ENOMEM error
54
include/block/block-common.h | 7 +-
36
55
include/block/block-global-state.h | 34 ++---
37
Kevin Wolf (38):
56
include/block/block-io.h | 71 +++++++----
38
block/qapi: Introduce BlockdevCreateOptions
57
include/block/block_int-common.h | 69 +++++-----
39
block/qapi: Add qcow2 create options to schema
58
include/block/block_int-io.h | 7 +-
40
qcow2: Rename qcow2_co_create2() to qcow2_co_create()
59
include/block/graph-lock.h | 3 +-
41
qcow2: Let qcow2_create() handle protocol layer
60
include/block/qapi.h | 23 ++--
42
qcow2: Pass BlockdevCreateOptions to qcow2_co_create()
61
include/block/snapshot.h | 24 ++--
43
qcow2: Use BlockdevRef in qcow2_co_create()
62
include/sysemu/block-backend-global-state.h | 4 +-
44
qcow2: Use QCryptoBlockCreateOptions in qcow2_co_create()
63
block.c | 120 ++++++++++++------
45
qcow2: Handle full/falloc preallocation in qcow2_co_create()
64
block/backup.c | 1 +
46
util: Add qemu_opts_to_qdict_filtered()
65
block/block-backend.c | 9 +-
47
test-qemu-opts: Test qemu_opts_append()
66
block/bochs.c | 2 +
48
test-qemu-opts: Test qemu_opts_to_qdict_filtered()
67
block/cloop.c | 2 +
49
qdict: Introduce qdict_rename_keys()
68
block/commit.c | 1 +
50
qcow2: Use visitor for options in qcow2_create()
69
block/copy-before-write.c | 2 +-
51
block: Make bdrv_is_whitelisted() public
70
block/copy-on-read.c | 8 +-
52
block: x-blockdev-create QMP command
71
block/crypto.c | 4 +-
53
file-posix: Support .bdrv_co_create
72
block/curl.c | 2 +
54
file-win32: Support .bdrv_co_create
73
block/dmg.c | 2 +
55
gluster: Support .bdrv_co_create
74
block/export/export.c | 4 +
56
rbd: Fix use after free in qemu_rbd_set_keypairs() error path
75
block/gluster.c | 2 +
57
rbd: Factor out qemu_rbd_connect()
76
block/graph-lock.c | 3 +-
58
rbd: Remove non-schema options from runtime_opts
77
block/io.c | 143 ++++++++++-----------
59
rbd: Pass BlockdevOptionsRbd to qemu_rbd_connect()
78
block/iscsi.c | 2 +
60
rbd: Support .bdrv_co_create
79
block/mirror.c | 10 +-
61
rbd: Assign s->snap/image_name in qemu_rbd_open()
80
block/monitor/block-hmp-cmds.c | 5 +
62
rbd: Use qemu_rbd_connect() in qemu_rbd_do_create()
81
block/nbd.c | 3 +-
63
nfs: Use QAPI options in nfs_client_open()
82
block/nfs.c | 2 +-
64
nfs: Support .bdrv_co_create
83
block/parallels.c | 3 +
65
sheepdog: QAPIfy "redundancy" create option
84
block/qapi-sysemu.c | 11 +-
66
sheepdog: Support .bdrv_co_create
85
block/qapi.c | 11 +-
67
ssh: Use QAPI BlockdevOptionsSsh object
86
block/qcow.c | 3 +
68
ssh: QAPIfy host-key-check option
87
block/qcow2-bitmap.c | 38 +++---
69
ssh: Pass BlockdevOptionsSsh to connect_to_ssh()
88
block/qcow2-cache.c | 11 +-
70
ssh: Support .bdrv_co_create
89
block/qcow2-cluster.c | 62 ++++-----
71
file-posix: Fix no-op bdrv_truncate() with falloc preallocation
90
block/qcow2-refcount.c | 80 ++++++------
72
block: Fail bdrv_truncate() with negative size
91
block/qcow2.c | 77 +++++++-----
73
qemu-iotests: Test qcow2 over file image creation with QMP
92
block/quorum.c | 4 +-
74
qemu-iotests: Test ssh image creation over QMP
93
block/raw-format.c | 2 +
75
Merge remote-tracking branch 'mreitz/tags/pull-block-2018-03-09' into queue-block
94
block/rbd.c | 4 +
76
95
block/replication.c | 29 +++--
77
Paolo Bonzini (6):
96
block/snapshot.c | 54 ++++++--
78
qcow2: introduce qcow2_write_caches and qcow2_flush_caches
97
block/stream.c | 8 +-
79
qcow2: fix flushing after dirty bitmap metadata writes
98
block/vdi.c | 3 +
80
qcow2: make qcow2_do_open a coroutine_fn
99
block/vhdx.c | 4 +
81
qed: make bdrv_qed_do_open a coroutine_fn
100
block/vmdk.c | 53 +++++---
82
block: convert bdrv_invalidate_cache callback to coroutine_fn
101
block/vpc.c | 3 +
83
block: convert bdrv_check callback to coroutine_fn
102
block/vvfat.c | 20 +--
84
103
blockdev.c | 44 +++++++
85
Stefan Hajnoczi (1):
104
blockjob.c | 1 +
86
qemu-iotests: fix 203 migration completion race
105
migration/block.c | 2 +
87
106
migration/migration-hmp-cmds.c | 2 +
88
qapi/block-core.json | 326 +++++++++++++++++++++++++-
107
qemu-img.c | 16 +++
89
block/qcow2.h | 12 +-
108
qemu-io-cmds.c | 3 +
90
include/block/block.h | 2 +
109
tests/unit/test-bdrv-drain.c | 15 ++-
91
include/block/block_int.h | 13 +-
110
tests/unit/test-block-iothread.c | 8 ++
92
include/qapi/qmp/qdict.h | 6 +
111
scripts/block-coroutine-wrapper.py | 10 +-
93
include/qemu/option.h | 2 +
112
60 files changed, 843 insertions(+), 499 deletions(-)
94
block.c | 138 +++++++++++-
95
block/create.c | 76 +++++++
96
block/crypto.c | 7 +
97
block/file-posix.c | 93 +++++---
98
block/file-win32.c | 47 +++-
99
block/gluster.c | 135 +++++++----
100
block/iscsi.c | 6 +-
101
block/nfs.c | 244 +++++++++-----------
102
block/parallels.c | 17 +-
103
block/qcow2-bitmap.c | 4 +-
104
block/qcow2-cluster.c | 24 +-
105
block/qcow2-refcount.c | 52 ++++-
106
block/qcow2-snapshot.c | 24 +-
107
block/qcow2.c | 552 ++++++++++++++++++++++++++++-----------------
108
block/qed-check.c | 1 +
109
block/qed-table.c | 26 +--
110
block/qed.c | 66 ++++--
111
block/rbd.c | 403 +++++++++++++++++----------------
112
block/sheepdog.c | 321 ++++++++++++++++++--------
113
block/ssh.c | 290 +++++++++++++-----------
114
block/vdi.c | 6 +-
115
block/vhdx.c | 7 +-
116
block/vmdk.c | 7 +-
117
qobject/qdict.c | 34 +++
118
tests/check-qdict.c | 129 +++++++++++
119
tests/test-qemu-opts.c | 253 +++++++++++++++++++++
120
util/qemu-option.c | 42 +++-
121
block/Makefile.objs | 2 +-
122
tests/qemu-iotests/030 | 52 ++++-
123
tests/qemu-iotests/030.out | 4 +-
124
tests/qemu-iotests/049.out | 8 +-
125
tests/qemu-iotests/059 | 5 +-
126
tests/qemu-iotests/080 | 22 +-
127
tests/qemu-iotests/080.out | 58 ++++-
128
tests/qemu-iotests/096 | 0
129
tests/qemu-iotests/112.out | 4 +-
130
tests/qemu-iotests/124 | 0
131
tests/qemu-iotests/129 | 0
132
tests/qemu-iotests/132 | 0
133
tests/qemu-iotests/136 | 0
134
tests/qemu-iotests/139 | 0
135
tests/qemu-iotests/148 | 0
136
tests/qemu-iotests/152 | 0
137
tests/qemu-iotests/153 | 8 +-
138
tests/qemu-iotests/153.out | 7 +-
139
tests/qemu-iotests/163 | 0
140
tests/qemu-iotests/203 | 15 +-
141
tests/qemu-iotests/203.out | 5 +
142
tests/qemu-iotests/205 | 0
143
tests/qemu-iotests/206 | 436 +++++++++++++++++++++++++++++++++++
144
tests/qemu-iotests/206.out | 209 +++++++++++++++++
145
tests/qemu-iotests/207 | 261 +++++++++++++++++++++
146
tests/qemu-iotests/207.out | 75 ++++++
147
tests/qemu-iotests/group | 2 +
148
60 files changed, 3574 insertions(+), 964 deletions(-)
149
create mode 100644 block/create.c
150
mode change 100644 => 100755 tests/qemu-iotests/096
151
mode change 100644 => 100755 tests/qemu-iotests/124
152
mode change 100644 => 100755 tests/qemu-iotests/129
153
mode change 100644 => 100755 tests/qemu-iotests/132
154
mode change 100644 => 100755 tests/qemu-iotests/136
155
mode change 100644 => 100755 tests/qemu-iotests/139
156
mode change 100644 => 100755 tests/qemu-iotests/148
157
mode change 100644 => 100755 tests/qemu-iotests/152
158
mode change 100644 => 100755 tests/qemu-iotests/163
159
mode change 100644 => 100755 tests/qemu-iotests/205
160
create mode 100755 tests/qemu-iotests/206
161
create mode 100644 tests/qemu-iotests/206.out
162
create mode 100755 tests/qemu-iotests/207
163
create mode 100644 tests/qemu-iotests/207.out
164
diff view generated by jsdifflib
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
It is called from qed_invalidate_cache in coroutine context (incoming
3
bdrv_block_status exists as a wrapper for bdrv_block_status_above, but
4
migration runs in a coroutine), so it's cleaner if metadata is always
4
the name of the (hypothetical) coroutine version, bdrv_co_block_status,
5
loaded from a coroutine.
5
is squatted by a random static function. Rename it to
6
bdrv_co_do_block_status.
6
7
7
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
8
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
8
Message-Id: <1516279431-30424-5-git-send-email-pbonzini@redhat.com>
9
Message-ID: <20230904100306.156197-2-pbonzini@redhat.com>
9
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
10
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
12
---
12
block/qed.c | 40 +++++++++++++++++++++++++++++++++++++---
13
block/io.c | 21 +++++++++++----------
13
1 file changed, 37 insertions(+), 3 deletions(-)
14
1 file changed, 11 insertions(+), 10 deletions(-)
14
15
15
diff --git a/block/qed.c b/block/qed.c
16
diff --git a/block/io.c b/block/io.c
16
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
17
--- a/block/qed.c
18
--- a/block/io.c
18
+++ b/block/qed.c
19
+++ b/block/io.c
19
@@ -XXX,XX +XXX,XX @@ static void bdrv_qed_init_state(BlockDriverState *bs)
20
@@ -XXX,XX +XXX,XX @@ int bdrv_flush_all(void)
20
qemu_co_queue_init(&s->allocating_write_reqs);
21
* set to the host mapping and BDS corresponding to the guest offset.
21
}
22
*/
22
23
static int coroutine_fn GRAPH_RDLOCK
23
-static int bdrv_qed_do_open(BlockDriverState *bs, QDict *options, int flags,
24
-bdrv_co_block_status(BlockDriverState *bs, bool want_zero,
24
- Error **errp)
25
- int64_t offset, int64_t bytes,
25
+/* Called with table_lock held. */
26
- int64_t *pnum, int64_t *map, BlockDriverState **file)
26
+static int coroutine_fn bdrv_qed_do_open(BlockDriverState *bs, QDict *options,
27
+bdrv_co_do_block_status(BlockDriverState *bs, bool want_zero,
27
+ int flags, Error **errp)
28
+ int64_t offset, int64_t bytes,
29
+ int64_t *pnum, int64_t *map, BlockDriverState **file)
28
{
30
{
29
BDRVQEDState *s = bs->opaque;
31
int64_t total_size;
30
QEDHeader le_header;
32
int64_t n; /* bytes */
31
@@ -XXX,XX +XXX,XX @@ out:
33
@@ -XXX,XX +XXX,XX @@ bdrv_co_block_status(BlockDriverState *bs, bool want_zero,
32
return ret;
34
33
}
35
if (ret & BDRV_BLOCK_RAW) {
34
36
assert(ret & BDRV_BLOCK_OFFSET_VALID && local_file);
35
+typedef struct QEDOpenCo {
37
- ret = bdrv_co_block_status(local_file, want_zero, local_map,
36
+ BlockDriverState *bs;
38
- *pnum, pnum, &local_map, &local_file);
37
+ QDict *options;
39
+ ret = bdrv_co_do_block_status(local_file, want_zero, local_map,
38
+ int flags;
40
+ *pnum, pnum, &local_map, &local_file);
39
+ Error **errp;
41
goto out;
40
+ int ret;
41
+} QEDOpenCo;
42
+
43
+static void coroutine_fn bdrv_qed_open_entry(void *opaque)
44
+{
45
+ QEDOpenCo *qoc = opaque;
46
+ BDRVQEDState *s = qoc->bs->opaque;
47
+
48
+ qemu_co_mutex_lock(&s->table_lock);
49
+ qoc->ret = bdrv_qed_do_open(qoc->bs, qoc->options, qoc->flags, qoc->errp);
50
+ qemu_co_mutex_unlock(&s->table_lock);
51
+}
52
+
53
static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
54
Error **errp)
55
{
56
+ QEDOpenCo qoc = {
57
+ .bs = bs,
58
+ .options = options,
59
+ .flags = flags,
60
+ .errp = errp,
61
+ .ret = -EINPROGRESS
62
+ };
63
+
64
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
65
false, errp);
66
if (!bs->file) {
67
@@ -XXX,XX +XXX,XX @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
68
}
42
}
69
43
70
bdrv_qed_init_state(bs);
44
@@ -XXX,XX +XXX,XX @@ bdrv_co_block_status(BlockDriverState *bs, bool want_zero,
71
- return bdrv_qed_do_open(bs, options, flags, errp);
45
int64_t file_pnum;
72
+ if (qemu_in_coroutine()) {
46
int ret2;
73
+ bdrv_qed_open_entry(&qoc);
47
74
+ } else {
48
- ret2 = bdrv_co_block_status(local_file, want_zero, local_map,
75
+ qemu_coroutine_enter(qemu_coroutine_create(bdrv_qed_open_entry, &qoc));
49
- *pnum, &file_pnum, NULL, NULL);
76
+ BDRV_POLL_WHILE(bs, qoc.ret == -EINPROGRESS);
50
+ ret2 = bdrv_co_do_block_status(local_file, want_zero, local_map,
77
+ }
51
+ *pnum, &file_pnum, NULL, NULL);
78
+ BDRV_POLL_WHILE(bs, qoc.ret == -EINPROGRESS);
52
if (ret2 >= 0) {
79
+ return qoc.ret;
53
/* Ignore errors. This is just providing extra information, it
80
}
54
* is useful but not necessary.
81
55
@@ -XXX,XX +XXX,XX @@ bdrv_co_common_block_status_above(BlockDriverState *bs,
82
static void bdrv_qed_refresh_limits(BlockDriverState *bs, Error **errp)
56
return 0;
57
}
58
59
- ret = bdrv_co_block_status(bs, want_zero, offset, bytes, pnum, map, file);
60
+ ret = bdrv_co_do_block_status(bs, want_zero, offset, bytes, pnum,
61
+ map, file);
62
++*depth;
63
if (ret < 0 || *pnum == 0 || ret & BDRV_BLOCK_ALLOCATED || bs == base) {
64
return ret;
65
@@ -XXX,XX +XXX,XX @@ bdrv_co_common_block_status_above(BlockDriverState *bs,
66
for (p = bdrv_filter_or_cow_bs(bs); include_base || p != base;
67
p = bdrv_filter_or_cow_bs(p))
68
{
69
- ret = bdrv_co_block_status(p, want_zero, offset, bytes, pnum, map,
70
- file);
71
+ ret = bdrv_co_do_block_status(p, want_zero, offset, bytes, pnum,
72
+ map, file);
73
++*depth;
74
if (ret < 0) {
75
return ret;
83
--
76
--
84
2.13.6
77
2.41.0
85
86
diff view generated by jsdifflib
1
From: "Daniel P. Berrange" <berrange@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
If the bdrv_reopen_prepare helper isn't provided, the qemu-img commit
3
Include both coroutine and non-coroutine versions, the latter being
4
command fails to re-open the base layer after committing changes into
4
co_wrapper_mixed_bdrv_rdlock of the former.
5
it. Provide a no-op implementation for the LUKS driver, since there
6
is not any custom work that needs doing to re-open it.
7
5
8
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
8
Message-ID: <20230904100306.156197-3-pbonzini@redhat.com>
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
---
11
block/crypto.c | 7 +++++++
12
include/block/block-io.h | 17 +++++++++++------
12
1 file changed, 7 insertions(+)
13
block/io.c | 18 +++++-------------
14
2 files changed, 16 insertions(+), 19 deletions(-)
13
15
14
diff --git a/block/crypto.c b/block/crypto.c
16
diff --git a/include/block/block-io.h b/include/block/block-io.h
15
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
16
--- a/block/crypto.c
18
--- a/include/block/block-io.h
17
+++ b/block/crypto.c
19
+++ b/include/block/block-io.h
18
@@ -XXX,XX +XXX,XX @@ static void block_crypto_close(BlockDriverState *bs)
20
@@ -XXX,XX +XXX,XX @@ int coroutine_fn GRAPH_RDLOCK bdrv_co_zone_append(BlockDriverState *bs,
19
qcrypto_block_free(crypto->block);
21
BdrvRequestFlags flags);
22
23
bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs);
24
-int bdrv_block_status(BlockDriverState *bs, int64_t offset,
25
- int64_t bytes, int64_t *pnum, int64_t *map,
26
- BlockDriverState **file);
27
+
28
+int coroutine_fn GRAPH_RDLOCK
29
+bdrv_co_block_status(BlockDriverState *bs, int64_t offset, int64_t bytes,
30
+ int64_t *pnum, int64_t *map, BlockDriverState **file);
31
+int co_wrapper_mixed_bdrv_rdlock
32
+bdrv_block_status(BlockDriverState *bs, int64_t offset, int64_t bytes,
33
+ int64_t *pnum, int64_t *map, BlockDriverState **file);
34
35
int coroutine_fn GRAPH_RDLOCK
36
bdrv_co_block_status_above(BlockDriverState *bs, BlockDriverState *base,
37
int64_t offset, int64_t bytes, int64_t *pnum,
38
int64_t *map, BlockDriverState **file);
39
-int bdrv_block_status_above(BlockDriverState *bs, BlockDriverState *base,
40
- int64_t offset, int64_t bytes, int64_t *pnum,
41
- int64_t *map, BlockDriverState **file);
42
+int co_wrapper_mixed_bdrv_rdlock
43
+bdrv_block_status_above(BlockDriverState *bs, BlockDriverState *base,
44
+ int64_t offset, int64_t bytes, int64_t *pnum,
45
+ int64_t *map, BlockDriverState **file);
46
47
int coroutine_fn GRAPH_RDLOCK
48
bdrv_co_is_allocated(BlockDriverState *bs, int64_t offset, int64_t bytes,
49
diff --git a/block/io.c b/block/io.c
50
index XXXXXXX..XXXXXXX 100644
51
--- a/block/io.c
52
+++ b/block/io.c
53
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_block_status_above(BlockDriverState *bs,
54
bytes, pnum, map, file, NULL);
20
}
55
}
21
56
22
+static int block_crypto_reopen_prepare(BDRVReopenState *state,
57
-int bdrv_block_status_above(BlockDriverState *bs, BlockDriverState *base,
23
+ BlockReopenQueue *queue, Error **errp)
58
- int64_t offset, int64_t bytes, int64_t *pnum,
24
+{
59
- int64_t *map, BlockDriverState **file)
25
+ /* nothing needs checking */
60
+int coroutine_fn bdrv_co_block_status(BlockDriverState *bs, int64_t offset,
26
+ return 0;
61
+ int64_t bytes, int64_t *pnum,
27
+}
62
+ int64_t *map, BlockDriverState **file)
63
{
64
IO_CODE();
65
- return bdrv_common_block_status_above(bs, base, false, true, offset, bytes,
66
- pnum, map, file, NULL);
67
-}
68
-
69
-int bdrv_block_status(BlockDriverState *bs, int64_t offset, int64_t bytes,
70
- int64_t *pnum, int64_t *map, BlockDriverState **file)
71
-{
72
- IO_CODE();
73
- return bdrv_block_status_above(bs, bdrv_filter_or_cow_bs(bs),
74
- offset, bytes, pnum, map, file);
75
+ return bdrv_co_block_status_above(bs, bdrv_filter_or_cow_bs(bs),
76
+ offset, bytes, pnum, map, file);
77
}
28
78
29
/*
79
/*
30
* 1 MB bounce buffer gives good performance / memory tradeoff
31
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_crypto_luks = {
32
.bdrv_truncate = block_crypto_truncate,
33
.create_opts = &block_crypto_create_opts_luks,
34
35
+ .bdrv_reopen_prepare = block_crypto_reopen_prepare,
36
.bdrv_refresh_limits = block_crypto_refresh_limits,
37
.bdrv_co_preadv = block_crypto_co_preadv,
38
.bdrv_co_pwritev = block_crypto_co_pwritev,
39
--
80
--
40
2.13.6
81
2.41.0
41
42
diff view generated by jsdifflib
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
They will be used to avoid recursively taking s->lock during
3
Reviewed-by: Eric Blake <eblake@redhat.com>
4
bdrv_open or bdrv_check.
5
6
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
4
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
7
Message-Id: <1516279431-30424-7-git-send-email-pbonzini@redhat.com>
5
Message-ID: <20230904100306.156197-4-pbonzini@redhat.com>
8
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
6
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
8
---
11
block/qcow2.h | 2 ++
9
include/block/block-io.h | 12 +++++----
12
block/qcow2-refcount.c | 28 ++++++++++++++++++++++++++++
10
block/io.c | 53 ++++++----------------------------------
13
block/qcow2.c | 20 ++++----------------
11
2 files changed, 14 insertions(+), 51 deletions(-)
14
3 files changed, 34 insertions(+), 16 deletions(-)
15
12
16
diff --git a/block/qcow2.h b/block/qcow2.h
13
diff --git a/include/block/block-io.h b/include/block/block-io.h
17
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
18
--- a/block/qcow2.h
15
--- a/include/block/block-io.h
19
+++ b/block/qcow2.h
16
+++ b/include/block/block-io.h
20
@@ -XXX,XX +XXX,XX @@ void qcow2_free_any_clusters(BlockDriverState *bs, uint64_t l2_entry,
17
@@ -XXX,XX +XXX,XX @@ bdrv_block_status_above(BlockDriverState *bs, BlockDriverState *base,
21
int qcow2_update_snapshot_refcount(BlockDriverState *bs,
18
int coroutine_fn GRAPH_RDLOCK
22
int64_t l1_table_offset, int l1_size, int addend);
19
bdrv_co_is_allocated(BlockDriverState *bs, int64_t offset, int64_t bytes,
23
20
int64_t *pnum);
24
+int coroutine_fn qcow2_flush_caches(BlockDriverState *bs);
21
-int bdrv_is_allocated(BlockDriverState *bs, int64_t offset, int64_t bytes,
25
+int coroutine_fn qcow2_write_caches(BlockDriverState *bs);
22
- int64_t *pnum);
26
int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
23
+int co_wrapper_mixed_bdrv_rdlock
27
BdrvCheckMode fix);
24
+bdrv_is_allocated(BlockDriverState *bs, int64_t offset,
28
25
+ int64_t bytes, int64_t *pnum);
29
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
26
27
int coroutine_fn GRAPH_RDLOCK
28
bdrv_co_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
29
bool include_base, int64_t offset, int64_t bytes,
30
int64_t *pnum);
31
-int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
32
- bool include_base, int64_t offset, int64_t bytes,
33
- int64_t *pnum);
34
+int co_wrapper_mixed_bdrv_rdlock
35
+bdrv_is_allocated_above(BlockDriverState *bs, BlockDriverState *base,
36
+ bool include_base, int64_t offset,
37
+ int64_t bytes, int64_t *pnum);
38
39
int coroutine_fn GRAPH_RDLOCK
40
bdrv_co_is_zero_fast(BlockDriverState *bs, int64_t offset, int64_t bytes);
41
diff --git a/block/io.c b/block/io.c
30
index XXXXXXX..XXXXXXX 100644
42
index XXXXXXX..XXXXXXX 100644
31
--- a/block/qcow2-refcount.c
43
--- a/block/io.c
32
+++ b/block/qcow2-refcount.c
44
+++ b/block/io.c
33
@@ -XXX,XX +XXX,XX @@ void qcow2_free_any_clusters(BlockDriverState *bs, uint64_t l2_entry,
45
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_is_allocated(BlockDriverState *bs, int64_t offset,
34
}
46
return !!(ret & BDRV_BLOCK_ALLOCATED);
35
}
47
}
36
48
37
+int coroutine_fn qcow2_write_caches(BlockDriverState *bs)
49
-int bdrv_is_allocated(BlockDriverState *bs, int64_t offset, int64_t bytes,
38
+{
50
- int64_t *pnum)
39
+ BDRVQcow2State *s = bs->opaque;
51
-{
40
+ int ret;
52
- int ret;
41
53
- int64_t dummy;
42
+ ret = qcow2_cache_write(bs, s->l2_table_cache);
54
- IO_CODE();
43
+ if (ret < 0) {
55
-
44
+ return ret;
56
- ret = bdrv_common_block_status_above(bs, bs, true, false, offset,
45
+ }
57
- bytes, pnum ? pnum : &dummy, NULL,
46
+
58
- NULL, NULL);
47
+ if (qcow2_need_accurate_refcounts(s)) {
48
+ ret = qcow2_cache_write(bs, s->refcount_block_cache);
49
+ if (ret < 0) {
50
+ return ret;
51
+ }
52
+ }
53
+
54
+ return 0;
55
+}
56
+
57
+int coroutine_fn qcow2_flush_caches(BlockDriverState *bs)
58
+{
59
+ int ret = qcow2_write_caches(bs);
60
+ if (ret < 0) {
61
+ return ret;
62
+ }
63
+
64
+ return bdrv_flush(bs->file->bs);
65
+}
66
67
/*********************************************************/
68
/* snapshots and image creation */
69
diff --git a/block/qcow2.c b/block/qcow2.c
70
index XXXXXXX..XXXXXXX 100644
71
--- a/block/qcow2.c
72
+++ b/block/qcow2.c
73
@@ -XXX,XX +XXX,XX @@ static int qcow2_mark_clean(BlockDriverState *bs)
74
75
s->incompatible_features &= ~QCOW2_INCOMPAT_DIRTY;
76
77
- ret = bdrv_flush(bs);
78
+ ret = qcow2_flush_caches(bs);
79
if (ret < 0) {
80
return ret;
81
}
82
@@ -XXX,XX +XXX,XX @@ int qcow2_mark_consistent(BlockDriverState *bs)
83
BDRVQcow2State *s = bs->opaque;
84
85
if (s->incompatible_features & QCOW2_INCOMPAT_CORRUPT) {
86
- int ret = bdrv_flush(bs);
87
+ int ret = qcow2_flush_caches(bs);
88
if (ret < 0) {
89
return ret;
90
}
91
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_flush_to_os(BlockDriverState *bs)
92
int ret;
93
94
qemu_co_mutex_lock(&s->lock);
95
- ret = qcow2_cache_write(bs, s->l2_table_cache);
96
- if (ret < 0) {
59
- if (ret < 0) {
97
- qemu_co_mutex_unlock(&s->lock);
60
- return ret;
61
- }
62
- return !!(ret & BDRV_BLOCK_ALLOCATED);
63
-}
64
-
65
-/* See bdrv_is_allocated_above for documentation */
66
-int coroutine_fn bdrv_co_is_allocated_above(BlockDriverState *top,
67
- BlockDriverState *base,
68
- bool include_base, int64_t offset,
69
- int64_t bytes, int64_t *pnum)
70
-{
71
- int depth;
72
- int ret;
73
- IO_CODE();
74
-
75
- ret = bdrv_co_common_block_status_above(top, base, include_base, false,
76
- offset, bytes, pnum, NULL, NULL,
77
- &depth);
78
- if (ret < 0) {
98
- return ret;
79
- return ret;
99
- }
80
- }
100
-
81
-
101
- if (qcow2_need_accurate_refcounts(s)) {
82
- if (ret & BDRV_BLOCK_ALLOCATED) {
102
- ret = qcow2_cache_write(bs, s->refcount_block_cache);
83
- return depth;
103
- if (ret < 0) {
104
- qemu_co_mutex_unlock(&s->lock);
105
- return ret;
106
- }
107
- }
84
- }
108
+ ret = qcow2_write_caches(bs);
109
qemu_co_mutex_unlock(&s->lock);
110
111
- return 0;
85
- return 0;
112
+ return ret;
86
-}
113
}
87
-
114
88
/*
115
static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
89
* Given an image chain: ... -> [BASE] -> [INTER1] -> [INTER2] -> [TOP]
90
*
91
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_is_allocated_above(BlockDriverState *top,
92
* words, the result is not necessarily the maximum possible range);
93
* but 'pnum' will only be 0 when end of file is reached.
94
*/
95
-int bdrv_is_allocated_above(BlockDriverState *top,
96
- BlockDriverState *base,
97
- bool include_base, int64_t offset,
98
- int64_t bytes, int64_t *pnum)
99
+int coroutine_fn bdrv_co_is_allocated_above(BlockDriverState *bs,
100
+ BlockDriverState *base,
101
+ bool include_base, int64_t offset,
102
+ int64_t bytes, int64_t *pnum)
103
{
104
int depth;
105
int ret;
106
IO_CODE();
107
108
- ret = bdrv_common_block_status_above(top, base, include_base, false,
109
- offset, bytes, pnum, NULL, NULL,
110
- &depth);
111
+ ret = bdrv_co_common_block_status_above(bs, base, include_base, false,
112
+ offset, bytes, pnum, NULL, NULL,
113
+ &depth);
114
if (ret < 0) {
115
return ret;
116
}
116
--
117
--
117
2.13.6
118
2.41.0
118
119
diff view generated by jsdifflib
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
It is called from qcow2_invalidate_cache in coroutine context (incoming
3
Reviewed-by: Eric Blake <eblake@redhat.com>
4
migration runs in a coroutine), so it's cleaner if metadata is always
5
loaded from a coroutine.
6
7
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
4
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
8
Message-Id: <1516279431-30424-4-git-send-email-pbonzini@redhat.com>
5
Message-ID: <20230904100306.156197-5-pbonzini@redhat.com>
9
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
6
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
8
---
12
block/qcow2.c | 46 +++++++++++++++++++++++++++++++++++++++++-----
9
block/copy-before-write.c | 2 +-
13
1 file changed, 41 insertions(+), 5 deletions(-)
10
block/copy-on-read.c | 8 ++++----
11
block/io.c | 6 +++---
12
block/mirror.c | 10 +++++-----
13
block/qcow2.c | 5 +++--
14
block/replication.c | 8 ++++----
15
block/stream.c | 8 ++++----
16
block/vvfat.c | 18 +++++++++---------
17
8 files changed, 33 insertions(+), 32 deletions(-)
14
18
19
diff --git a/block/copy-before-write.c b/block/copy-before-write.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/block/copy-before-write.c
22
+++ b/block/copy-before-write.c
23
@@ -XXX,XX +XXX,XX @@ cbw_co_snapshot_block_status(BlockDriverState *bs,
24
return -EACCES;
25
}
26
27
- ret = bdrv_block_status(child->bs, offset, cur_bytes, pnum, map, file);
28
+ ret = bdrv_co_block_status(child->bs, offset, cur_bytes, pnum, map, file);
29
if (child == s->target) {
30
/*
31
* We refer to s->target only for areas that we've written to it.
32
diff --git a/block/copy-on-read.c b/block/copy-on-read.c
33
index XXXXXXX..XXXXXXX 100644
34
--- a/block/copy-on-read.c
35
+++ b/block/copy-on-read.c
36
@@ -XXX,XX +XXX,XX @@ cor_co_preadv_part(BlockDriverState *bs, int64_t offset, int64_t bytes,
37
local_flags = flags;
38
39
/* In case of failure, try to copy-on-read anyway */
40
- ret = bdrv_is_allocated(bs->file->bs, offset, bytes, &n);
41
+ ret = bdrv_co_is_allocated(bs->file->bs, offset, bytes, &n);
42
if (ret <= 0) {
43
- ret = bdrv_is_allocated_above(bdrv_backing_chain_next(bs->file->bs),
44
- state->bottom_bs, true, offset,
45
- n, &n);
46
+ ret = bdrv_co_is_allocated_above(bdrv_backing_chain_next(bs->file->bs),
47
+ state->bottom_bs, true, offset,
48
+ n, &n);
49
if (ret > 0 || ret < 0) {
50
local_flags |= BDRV_REQ_COPY_ON_READ;
51
}
52
diff --git a/block/io.c b/block/io.c
53
index XXXXXXX..XXXXXXX 100644
54
--- a/block/io.c
55
+++ b/block/io.c
56
@@ -XXX,XX +XXX,XX @@ bdrv_co_do_copy_on_readv(BdrvChild *child, int64_t offset, int64_t bytes,
57
ret = 1; /* "already allocated", so nothing will be copied */
58
pnum = MIN(align_bytes, max_transfer);
59
} else {
60
- ret = bdrv_is_allocated(bs, align_offset,
61
- MIN(align_bytes, max_transfer), &pnum);
62
+ ret = bdrv_co_is_allocated(bs, align_offset,
63
+ MIN(align_bytes, max_transfer), &pnum);
64
if (ret < 0) {
65
/*
66
* Safe to treat errors in querying allocation as if
67
@@ -XXX,XX +XXX,XX @@ bdrv_aligned_preadv(BdrvChild *child, BdrvTrackedRequest *req,
68
/* The flag BDRV_REQ_COPY_ON_READ has reached its addressee */
69
flags &= ~BDRV_REQ_COPY_ON_READ;
70
71
- ret = bdrv_is_allocated(bs, offset, bytes, &pnum);
72
+ ret = bdrv_co_is_allocated(bs, offset, bytes, &pnum);
73
if (ret < 0) {
74
goto out;
75
}
76
diff --git a/block/mirror.c b/block/mirror.c
77
index XXXXXXX..XXXXXXX 100644
78
--- a/block/mirror.c
79
+++ b/block/mirror.c
80
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn mirror_iteration(MirrorBlockJob *s)
81
82
assert(!(offset % s->granularity));
83
WITH_GRAPH_RDLOCK_GUARD() {
84
- ret = bdrv_block_status_above(source, NULL, offset,
85
- nb_chunks * s->granularity,
86
- &io_bytes, NULL, NULL);
87
+ ret = bdrv_co_block_status_above(source, NULL, offset,
88
+ nb_chunks * s->granularity,
89
+ &io_bytes, NULL, NULL);
90
}
91
if (ret < 0) {
92
io_bytes = MIN(nb_chunks * s->granularity, max_io_bytes);
93
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s)
94
}
95
96
WITH_GRAPH_RDLOCK_GUARD() {
97
- ret = bdrv_is_allocated_above(bs, s->base_overlay, true, offset,
98
- bytes, &count);
99
+ ret = bdrv_co_is_allocated_above(bs, s->base_overlay, true, offset,
100
+ bytes, &count);
101
}
102
if (ret < 0) {
103
return ret;
15
diff --git a/block/qcow2.c b/block/qcow2.c
104
diff --git a/block/qcow2.c b/block/qcow2.c
16
index XXXXXXX..XXXXXXX 100644
105
index XXXXXXX..XXXXXXX 100644
17
--- a/block/qcow2.c
106
--- a/block/qcow2.c
18
+++ b/block/qcow2.c
107
+++ b/block/qcow2.c
19
@@ -XXX,XX +XXX,XX @@ static int qcow2_update_options(BlockDriverState *bs, QDict *options,
108
@@ -XXX,XX +XXX,XX @@ finish:
20
return ret;
21
}
109
}
22
110
23
-static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
111
24
- Error **errp)
112
-static bool is_zero(BlockDriverState *bs, int64_t offset, int64_t bytes)
25
+/* Called with s->lock held. */
113
+static bool coroutine_fn GRAPH_RDLOCK
26
+static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
114
+is_zero(BlockDriverState *bs, int64_t offset, int64_t bytes)
27
+ int flags, Error **errp)
28
{
115
{
29
BDRVQcow2State *s = bs->opaque;
116
int64_t nr;
30
unsigned int len, i;
117
int res;
31
@@ -XXX,XX +XXX,XX @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
118
@@ -XXX,XX +XXX,XX @@ static bool is_zero(BlockDriverState *bs, int64_t offset, int64_t bytes)
32
}
119
* backing file. So, we need a loop.
120
*/
121
do {
122
- res = bdrv_block_status_above(bs, NULL, offset, bytes, &nr, NULL, NULL);
123
+ res = bdrv_co_block_status_above(bs, NULL, offset, bytes, &nr, NULL, NULL);
124
offset += nr;
125
bytes -= nr;
126
} while (res >= 0 && (res & BDRV_BLOCK_ZERO) && nr && bytes);
127
diff --git a/block/replication.c b/block/replication.c
128
index XXXXXXX..XXXXXXX 100644
129
--- a/block/replication.c
130
+++ b/block/replication.c
131
@@ -XXX,XX +XXX,XX @@ replication_co_writev(BlockDriverState *bs, int64_t sector_num,
132
while (remaining_sectors > 0) {
133
int64_t count;
134
135
- ret = bdrv_is_allocated_above(top->bs, base->bs, false,
136
- sector_num * BDRV_SECTOR_SIZE,
137
- remaining_sectors * BDRV_SECTOR_SIZE,
138
- &count);
139
+ ret = bdrv_co_is_allocated_above(top->bs, base->bs, false,
140
+ sector_num * BDRV_SECTOR_SIZE,
141
+ remaining_sectors * BDRV_SECTOR_SIZE,
142
+ &count);
143
if (ret < 0) {
144
goto out1;
145
}
146
diff --git a/block/stream.c b/block/stream.c
147
index XXXXXXX..XXXXXXX 100644
148
--- a/block/stream.c
149
+++ b/block/stream.c
150
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn stream_run(Job *job, Error **errp)
151
copy = false;
152
153
WITH_GRAPH_RDLOCK_GUARD() {
154
- ret = bdrv_is_allocated(unfiltered_bs, offset, STREAM_CHUNK, &n);
155
+ ret = bdrv_co_is_allocated(unfiltered_bs, offset, STREAM_CHUNK, &n);
156
if (ret == 1) {
157
/* Allocated in the top, no need to copy. */
158
} else if (ret >= 0) {
159
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn stream_run(Job *job, Error **errp)
160
* Copy if allocated in the intermediate images. Limit to the
161
* known-unallocated area [offset, offset+n*BDRV_SECTOR_SIZE).
162
*/
163
- ret = bdrv_is_allocated_above(bdrv_cow_bs(unfiltered_bs),
164
- s->base_overlay, true,
165
- offset, n, &n);
166
+ ret = bdrv_co_is_allocated_above(bdrv_cow_bs(unfiltered_bs),
167
+ s->base_overlay, true,
168
+ offset, n, &n);
169
/* Finish early if end of backing file has been reached */
170
if (ret == 0 && n == 0) {
171
n = len - offset;
172
diff --git a/block/vvfat.c b/block/vvfat.c
173
index XXXXXXX..XXXXXXX 100644
174
--- a/block/vvfat.c
175
+++ b/block/vvfat.c
176
@@ -XXX,XX +XXX,XX @@ vvfat_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sector
177
if (s->qcow) {
178
int64_t n;
179
int ret;
180
- ret = bdrv_is_allocated(s->qcow->bs, sector_num * BDRV_SECTOR_SIZE,
181
- (nb_sectors - i) * BDRV_SECTOR_SIZE, &n);
182
+ ret = bdrv_co_is_allocated(s->qcow->bs, sector_num * BDRV_SECTOR_SIZE,
183
+ (nb_sectors - i) * BDRV_SECTOR_SIZE, &n);
184
if (ret < 0) {
185
return ret;
186
}
187
@@ -XXX,XX +XXX,XX @@ cluster_was_modified(BDRVVVFATState *s, uint32_t cluster_num)
33
}
188
}
34
189
35
- /* Initialise locks */
190
for (i = 0; !was_modified && i < s->sectors_per_cluster; i++) {
36
- qemu_co_mutex_init(&s->lock);
191
- was_modified = bdrv_is_allocated(s->qcow->bs,
37
bs->supported_zero_flags = header.version >= 3 ? BDRV_REQ_MAY_UNMAP : 0;
192
- (cluster2sector(s, cluster_num) +
38
193
- i) * BDRV_SECTOR_SIZE,
39
/* Repair image if dirty */
194
- BDRV_SECTOR_SIZE, NULL);
40
@@ -XXX,XX +XXX,XX @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
195
+ was_modified = bdrv_co_is_allocated(s->qcow->bs,
41
return ret;
196
+ (cluster2sector(s, cluster_num) +
42
}
197
+ i) * BDRV_SECTOR_SIZE,
43
198
+ BDRV_SECTOR_SIZE, NULL);
44
+typedef struct QCow2OpenCo {
45
+ BlockDriverState *bs;
46
+ QDict *options;
47
+ int flags;
48
+ Error **errp;
49
+ int ret;
50
+} QCow2OpenCo;
51
+
52
+static void coroutine_fn qcow2_open_entry(void *opaque)
53
+{
54
+ QCow2OpenCo *qoc = opaque;
55
+ BDRVQcow2State *s = qoc->bs->opaque;
56
+
57
+ qemu_co_mutex_lock(&s->lock);
58
+ qoc->ret = qcow2_do_open(qoc->bs, qoc->options, qoc->flags, qoc->errp);
59
+ qemu_co_mutex_unlock(&s->lock);
60
+}
61
+
62
static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
63
Error **errp)
64
{
65
+ BDRVQcow2State *s = bs->opaque;
66
+ QCow2OpenCo qoc = {
67
+ .bs = bs,
68
+ .options = options,
69
+ .flags = flags,
70
+ .errp = errp,
71
+ .ret = -EINPROGRESS
72
+ };
73
+
74
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
75
false, errp);
76
if (!bs->file) {
77
return -EINVAL;
78
}
199
}
79
200
80
- return qcow2_do_open(bs, options, flags, errp);
201
/*
81
+ /* Initialise locks */
202
@@ -XXX,XX +XXX,XX @@ get_cluster_count_for_direntry(BDRVVVFATState* s, direntry_t* direntry, const ch
82
+ qemu_co_mutex_init(&s->lock);
203
for (i = 0; i < s->sectors_per_cluster; i++) {
83
+
204
int res;
84
+ if (qemu_in_coroutine()) {
205
85
+ /* From bdrv_co_create. */
206
- res = bdrv_is_allocated(s->qcow->bs,
86
+ qcow2_open_entry(&qoc);
207
- (offs + i) * BDRV_SECTOR_SIZE,
87
+ } else {
208
- BDRV_SECTOR_SIZE, NULL);
88
+ qemu_coroutine_enter(qemu_coroutine_create(qcow2_open_entry, &qoc));
209
+ res = bdrv_co_is_allocated(s->qcow->bs,
89
+ BDRV_POLL_WHILE(bs, qoc.ret == -EINPROGRESS);
210
+ (offs + i) * BDRV_SECTOR_SIZE,
90
+ }
211
+ BDRV_SECTOR_SIZE, NULL);
91
+ return qoc.ret;
212
if (res < 0) {
92
}
213
return -1;
93
214
}
94
static void qcow2_refresh_limits(BlockDriverState *bs, Error **errp)
95
--
215
--
96
2.13.6
216
2.41.0
97
98
diff view generated by jsdifflib
1
The code to establish an RBD connection is duplicated between open and
1
AIO callbacks are effectively coroutine_mixed_fn. If AIO requests don't
2
create. In order to be able to share the code, factor out the code from
2
return immediately, their callback is called from the request coroutine.
3
qemu_rbd_open() as a first step.
3
This means that in AIO callbacks, we can't call no_coroutine_fns such as
4
bdrv_graph_wrlock(). Unfortunately test-bdrv-drain does so.
5
6
Change the test to use a BH to drop out of coroutine context, and add
7
coroutine_mixed_fn and no_coroutine_fn markers to clarify the context
8
each function runs in.
4
9
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
11
Message-ID: <20230929145157.45443-2-kwolf@redhat.com>
12
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
14
---
8
block/rbd.c | 100 ++++++++++++++++++++++++++++++++++++------------------------
15
tests/unit/test-bdrv-drain.c | 7 ++++---
9
1 file changed, 60 insertions(+), 40 deletions(-)
16
1 file changed, 4 insertions(+), 3 deletions(-)
10
17
11
diff --git a/block/rbd.c b/block/rbd.c
18
diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c
12
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
13
--- a/block/rbd.c
20
--- a/tests/unit/test-bdrv-drain.c
14
+++ b/block/rbd.c
21
+++ b/tests/unit/test-bdrv-drain.c
15
@@ -XXX,XX +XXX,XX @@ out:
22
@@ -XXX,XX +XXX,XX @@ struct detach_by_parent_data {
16
return rados_str;
23
};
24
static struct detach_by_parent_data detach_by_parent_data;
25
26
-static void detach_indirect_bh(void *opaque)
27
+static void no_coroutine_fn detach_indirect_bh(void *opaque)
28
{
29
struct detach_by_parent_data *data = opaque;
30
31
@@ -XXX,XX +XXX,XX @@ static void detach_indirect_bh(void *opaque)
32
bdrv_graph_wrunlock();
17
}
33
}
18
34
19
-static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
35
-static void detach_by_parent_aio_cb(void *opaque, int ret)
20
- Error **errp)
36
+static void coroutine_mixed_fn detach_by_parent_aio_cb(void *opaque, int ret)
21
+static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
22
+ char **s_snap, char **s_image_name,
23
+ QDict *options, bool cache, Error **errp)
24
{
37
{
25
- BDRVRBDState *s = bs->opaque;
38
struct detach_by_parent_data *data = &detach_by_parent_data;
26
- const char *pool, *snap, *conf, *user, *image_name, *keypairs;
39
27
- const char *secretid, *filename;
40
g_assert_cmpint(ret, ==, 0);
28
QemuOpts *opts;
41
if (data->by_parent_cb) {
29
- Error *local_err = NULL;
42
bdrv_inc_in_flight(data->child_b->bs);
30
char *mon_host = NULL;
43
- detach_indirect_bh(data);
31
+ const char *pool, *snap, *conf, *user, *image_name, *keypairs;
44
+ aio_bh_schedule_oneshot(qemu_get_current_aio_context(),
32
+ const char *secretid;
45
+ detach_indirect_bh, &detach_by_parent_data);
33
+ Error *local_err = NULL;
34
int r;
35
36
- /* If we are given a filename, parse the filename, with precedence given to
37
- * filename encoded options */
38
- filename = qdict_get_try_str(options, "filename");
39
- if (filename) {
40
- warn_report("'filename' option specified. "
41
- "This is an unsupported option, and may be deprecated "
42
- "in the future");
43
- qemu_rbd_parse_filename(filename, options, &local_err);
44
- if (local_err) {
45
- r = -EINVAL;
46
- error_propagate(errp, local_err);
47
- goto exit;
48
- }
49
- }
50
-
51
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
52
qemu_opts_absorb_qdict(opts, options, &local_err);
53
if (local_err) {
54
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
55
goto failed_opts;
56
}
46
}
57
58
- r = rados_create(&s->cluster, user);
59
+ r = rados_create(cluster, user);
60
if (r < 0) {
61
error_setg_errno(errp, -r, "error initializing");
62
goto failed_opts;
63
}
64
65
- s->snap = g_strdup(snap);
66
- s->image_name = g_strdup(image_name);
67
+ *s_snap = g_strdup(snap);
68
+ *s_image_name = g_strdup(image_name);
69
70
/* try default location when conf=NULL, but ignore failure */
71
- r = rados_conf_read_file(s->cluster, conf);
72
+ r = rados_conf_read_file(*cluster, conf);
73
if (conf && r < 0) {
74
error_setg_errno(errp, -r, "error reading conf file %s", conf);
75
goto failed_shutdown;
76
}
77
78
- r = qemu_rbd_set_keypairs(s->cluster, keypairs, errp);
79
+ r = qemu_rbd_set_keypairs(*cluster, keypairs, errp);
80
if (r < 0) {
81
goto failed_shutdown;
82
}
83
84
if (mon_host) {
85
- r = rados_conf_set(s->cluster, "mon_host", mon_host);
86
+ r = rados_conf_set(*cluster, "mon_host", mon_host);
87
if (r < 0) {
88
goto failed_shutdown;
89
}
90
}
91
92
- if (qemu_rbd_set_auth(s->cluster, secretid, errp) < 0) {
93
+ if (qemu_rbd_set_auth(*cluster, secretid, errp) < 0) {
94
r = -EIO;
95
goto failed_shutdown;
96
}
97
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
98
* librbd defaults to no caching. If write through caching cannot
99
* be set up, fall back to no caching.
100
*/
101
- if (flags & BDRV_O_NOCACHE) {
102
- rados_conf_set(s->cluster, "rbd_cache", "false");
103
+ if (cache) {
104
+ rados_conf_set(*cluster, "rbd_cache", "true");
105
} else {
106
- rados_conf_set(s->cluster, "rbd_cache", "true");
107
+ rados_conf_set(*cluster, "rbd_cache", "false");
108
}
109
110
- r = rados_connect(s->cluster);
111
+ r = rados_connect(*cluster);
112
if (r < 0) {
113
error_setg_errno(errp, -r, "error connecting");
114
goto failed_shutdown;
115
}
116
117
- r = rados_ioctx_create(s->cluster, pool, &s->io_ctx);
118
+ r = rados_ioctx_create(*cluster, pool, io_ctx);
119
if (r < 0) {
120
error_setg_errno(errp, -r, "error opening pool %s", pool);
121
goto failed_shutdown;
122
}
123
124
+ qemu_opts_del(opts);
125
+ return 0;
126
+
127
+failed_shutdown:
128
+ rados_shutdown(*cluster);
129
+ g_free(*s_snap);
130
+ g_free(*s_image_name);
131
+failed_opts:
132
+ qemu_opts_del(opts);
133
+ g_free(mon_host);
134
+ return r;
135
+}
136
+
137
+static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
138
+ Error **errp)
139
+{
140
+ BDRVRBDState *s = bs->opaque;
141
+ Error *local_err = NULL;
142
+ const char *filename;
143
+ int r;
144
+
145
+ /* If we are given a filename, parse the filename, with precedence given to
146
+ * filename encoded options */
147
+ filename = qdict_get_try_str(options, "filename");
148
+ if (filename) {
149
+ warn_report("'filename' option specified. "
150
+ "This is an unsupported option, and may be deprecated "
151
+ "in the future");
152
+ qemu_rbd_parse_filename(filename, options, &local_err);
153
+ if (local_err) {
154
+ error_propagate(errp, local_err);
155
+ return -EINVAL;
156
+ }
157
+ }
158
+
159
+ r = qemu_rbd_connect(&s->cluster, &s->io_ctx, &s->snap, &s->image_name,
160
+ options, !(flags & BDRV_O_NOCACHE), errp);
161
+ if (r < 0) {
162
+ return r;
163
+ }
164
+
165
/* rbd_open is always r/w */
166
r = rbd_open(s->io_ctx, s->image_name, &s->image, s->snap);
167
if (r < 0) {
168
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
169
}
170
}
171
172
- qemu_opts_del(opts);
173
return 0;
174
175
failed_open:
176
rados_ioctx_destroy(s->io_ctx);
177
-failed_shutdown:
178
- rados_shutdown(s->cluster);
179
g_free(s->snap);
180
g_free(s->image_name);
181
-failed_opts:
182
- qemu_opts_del(opts);
183
- g_free(mon_host);
184
-exit:
185
+ rados_shutdown(s->cluster);
186
return r;
187
}
47
}
188
48
189
--
49
--
190
2.13.6
50
2.41.0
191
192
diff view generated by jsdifflib
1
Move the parsing of the QDict options up to the callers, in preparation
1
Add a new wrapper type for GRAPH_RDLOCK functions that should be called
2
for the .bdrv_co_create implementation that directly gets a QAPI type.
2
from coroutine context.
3
3
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
5
Message-ID: <20230929145157.45443-3-kwolf@redhat.com>
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
8
---
7
block/ssh.c | 34 +++++++++++++++++++++-------------
9
include/block/block-common.h | 7 +++++--
8
1 file changed, 21 insertions(+), 13 deletions(-)
10
scripts/block-coroutine-wrapper.py | 10 +++++++---
11
2 files changed, 12 insertions(+), 5 deletions(-)
9
12
10
diff --git a/block/ssh.c b/block/ssh.c
13
diff --git a/include/block/block-common.h b/include/block/block-common.h
11
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
12
--- a/block/ssh.c
15
--- a/include/block/block-common.h
13
+++ b/block/ssh.c
16
+++ b/include/block/block-common.h
14
@@ -XXX,XX +XXX,XX @@ fail:
17
@@ -XXX,XX +XXX,XX @@
15
return result;
18
* function. The coroutine yields after scheduling the BH and is reentered when
16
}
19
* the wrapped function returns.
17
20
*
18
-static int connect_to_ssh(BDRVSSHState *s, QDict *options,
21
- * A no_co_wrapper_bdrv_wrlock function is a no_co_wrapper function that
19
+static int connect_to_ssh(BDRVSSHState *s, BlockdevOptionsSsh *opts,
22
- * automatically takes the graph wrlock when calling the wrapped function.
20
int ssh_flags, int creat_mode, Error **errp)
23
+ * A no_co_wrapper_bdrv_rdlock function is a no_co_wrapper function that
21
{
24
+ * automatically takes the graph rdlock when calling the wrapped function. In
22
- BlockdevOptionsSsh *opts;
25
+ * the same way, no_co_wrapper_bdrv_wrlock functions automatically take the
23
int r, ret;
26
+ * graph wrlock.
24
const char *user;
27
*
25
long port = 0;
28
* If the first parameter of the function is a BlockDriverState, BdrvChild or
26
29
* BlockBackend pointer, the AioContext lock for it is taken in the wrapper.
27
- opts = ssh_parse_options(options, errp);
30
*/
28
- if (opts == NULL) {
31
#define no_co_wrapper
29
- return -EINVAL;
32
+#define no_co_wrapper_bdrv_rdlock
30
- }
33
#define no_co_wrapper_bdrv_wrlock
31
-
34
32
if (opts->has_user) {
35
#include "block/blockjob.h"
33
user = opts->user;
36
diff --git a/scripts/block-coroutine-wrapper.py b/scripts/block-coroutine-wrapper.py
34
} else {
37
index XXXXXXX..XXXXXXX 100644
35
@@ -XXX,XX +XXX,XX @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
38
--- a/scripts/block-coroutine-wrapper.py
36
goto err;
39
+++ b/scripts/block-coroutine-wrapper.py
37
}
40
@@ -XXX,XX +XXX,XX @@ def __init__(self, wrapper_type: str, return_type: str, name: str,
38
41
raise ValueError(f"Invalid no_co function name: {self.name}")
39
- qapi_free_BlockdevOptionsSsh(opts);
42
if not self.create_only_co:
40
-
43
raise ValueError(f"no_co function can't be mixed: {self.name}")
41
r = libssh2_sftp_fstat(s->sftp_handle, &s->attrs);
44
- if self.graph_rdlock:
42
if (r < 0) {
45
- raise ValueError(f"no_co function can't be rdlock: {self.name}")
43
sftp_error_setg(errp, s, "failed to read file attributes");
46
+ if self.graph_rdlock and self.graph_wrlock:
44
@@ -XXX,XX +XXX,XX @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
47
+ raise ValueError("function can't be both rdlock and wrlock: "
45
}
48
+ f"{self.name}")
46
s->session = NULL;
49
self.target_name = f'{subsystem}_{subname}'
47
50
48
- qapi_free_BlockdevOptionsSsh(opts);
51
self.ctx = self.gen_ctx()
49
-
52
@@ -XXX,XX +XXX,XX @@ def gen_no_co_wrapper(func: FuncDecl) -> str:
50
return ret;
53
51
}
54
graph_lock=''
52
55
graph_unlock=''
53
@@ -XXX,XX +XXX,XX @@ static int ssh_file_open(BlockDriverState *bs, QDict *options, int bdrv_flags,
56
- if func.graph_wrlock:
54
Error **errp)
57
+ if func.graph_rdlock:
55
{
58
+ graph_lock=' bdrv_graph_rdlock_main_loop();'
56
BDRVSSHState *s = bs->opaque;
59
+ graph_unlock=' bdrv_graph_rdunlock_main_loop();'
57
+ BlockdevOptionsSsh *opts;
60
+ elif func.graph_wrlock:
58
int ret;
61
graph_lock=' bdrv_graph_wrlock(NULL);'
59
int ssh_flags;
62
graph_unlock=' bdrv_graph_wrunlock();'
60
61
@@ -XXX,XX +XXX,XX @@ static int ssh_file_open(BlockDriverState *bs, QDict *options, int bdrv_flags,
62
ssh_flags |= LIBSSH2_FXF_WRITE;
63
}
64
65
+ opts = ssh_parse_options(options, errp);
66
+ if (opts == NULL) {
67
+ return -EINVAL;
68
+ }
69
+
70
/* Start up SSH. */
71
- ret = connect_to_ssh(s, options, ssh_flags, 0, errp);
72
+ ret = connect_to_ssh(s, opts, ssh_flags, 0, errp);
73
if (ret < 0) {
74
goto err;
75
}
76
@@ -XXX,XX +XXX,XX @@ static int ssh_file_open(BlockDriverState *bs, QDict *options, int bdrv_flags,
77
/* Go non-blocking. */
78
libssh2_session_set_blocking(s->session, 0);
79
80
+ qapi_free_BlockdevOptionsSsh(opts);
81
+
82
return 0;
83
84
err:
85
@@ -XXX,XX +XXX,XX @@ static int ssh_file_open(BlockDriverState *bs, QDict *options, int bdrv_flags,
86
}
87
s->sock = -1;
88
89
+ qapi_free_BlockdevOptionsSsh(opts);
90
+
91
return ret;
92
}
93
94
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn ssh_co_create_opts(const char *filename, QemuOpts *opts,
95
int r, ret;
96
int64_t total_size = 0;
97
QDict *uri_options = NULL;
98
+ BlockdevOptionsSsh *ssh_opts = NULL;
99
BDRVSSHState s;
100
101
ssh_state_init(&s);
102
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn ssh_co_create_opts(const char *filename, QemuOpts *opts,
103
goto out;
104
}
105
106
- r = connect_to_ssh(&s, uri_options,
107
+ ssh_opts = ssh_parse_options(uri_options, errp);
108
+ if (ssh_opts == NULL) {
109
+ ret = -EINVAL;
110
+ goto out;
111
+ }
112
+
113
+ r = connect_to_ssh(&s, ssh_opts,
114
LIBSSH2_FXF_READ|LIBSSH2_FXF_WRITE|
115
LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC,
116
0644, errp);
117
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn ssh_co_create_opts(const char *filename, QemuOpts *opts,
118
if (uri_options != NULL) {
119
QDECREF(uri_options);
120
}
121
+ qapi_free_BlockdevOptionsSsh(ssh_opts);
122
return ret;
123
}
124
63
125
--
64
--
126
2.13.6
65
2.41.0
127
128
diff view generated by jsdifflib
1
This makes the host-key-check option available in blockdev-add.
1
The function reads the parents list, so it needs to hold the graph lock.
2
2
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Reviewed-by: Max Reitz <mreitz@redhat.com>
4
Message-ID: <20230929145157.45443-4-kwolf@redhat.com>
5
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
---
7
---
6
qapi/block-core.json | 63 +++++++++++++++++++++++++++++++++++--
8
block.c | 7 ++++---
7
block/ssh.c | 88 +++++++++++++++++++++++++++++++++-------------------
9
1 file changed, 4 insertions(+), 3 deletions(-)
8
2 files changed, 117 insertions(+), 34 deletions(-)
9
10
10
diff --git a/qapi/block-core.json b/qapi/block-core.json
11
diff --git a/block.c b/block.c
11
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
12
--- a/qapi/block-core.json
13
--- a/block.c
13
+++ b/qapi/block-core.json
14
+++ b/block.c
14
@@ -XXX,XX +XXX,XX @@
15
@@ -XXX,XX +XXX,XX @@ void bdrv_activate_all(Error **errp)
15
'*encrypt': 'BlockdevQcow2Encryption' } }
16
}
16
17
##
18
+# @SshHostKeyCheckMode:
19
+#
20
+# @none Don't check the host key at all
21
+# @hash Compare the host key with a given hash
22
+# @known_hosts Check the host key against the known_hosts file
23
+#
24
+# Since: 2.12
25
+##
26
+{ 'enum': 'SshHostKeyCheckMode',
27
+ 'data': [ 'none', 'hash', 'known_hosts' ] }
28
+
29
+##
30
+# @SshHostKeyCheckHashType:
31
+#
32
+# @md5 The given hash is an md5 hash
33
+# @sha1 The given hash is an sha1 hash
34
+#
35
+# Since: 2.12
36
+##
37
+{ 'enum': 'SshHostKeyCheckHashType',
38
+ 'data': [ 'md5', 'sha1' ] }
39
+
40
+##
41
+# @SshHostKeyHash:
42
+#
43
+# @type The hash algorithm used for the hash
44
+# @hash The expected hash value
45
+#
46
+# Since: 2.12
47
+##
48
+{ 'struct': 'SshHostKeyHash',
49
+ 'data': { 'type': 'SshHostKeyCheckHashType',
50
+ 'hash': 'str' }}
51
+
52
+##
53
+# @SshHostKeyDummy:
54
+#
55
+# For those union branches that don't need additional fields.
56
+#
57
+# Since: 2.12
58
+##
59
+{ 'struct': 'SshHostKeyDummy',
60
+ 'data': {} }
61
+
62
+##
63
+# @SshHostKeyCheck:
64
+#
65
+# Since: 2.12
66
+##
67
+{ 'union': 'SshHostKeyCheck',
68
+ 'base': { 'mode': 'SshHostKeyCheckMode' },
69
+ 'discriminator': 'mode',
70
+ 'data': { 'none': 'SshHostKeyDummy',
71
+ 'hash': 'SshHostKeyHash',
72
+ 'known_hosts': 'SshHostKeyDummy' } }
73
+
74
+##
75
# @BlockdevOptionsSsh:
76
#
77
# @server: host address
78
@@ -XXX,XX +XXX,XX @@
79
# @user: user as which to connect, defaults to current
80
# local user name
81
#
82
-# TODO: Expose the host_key_check option in QMP
83
+# @host-key-check: Defines how and what to check the host key against
84
+# (default: known_hosts)
85
#
86
# Since: 2.9
87
##
88
{ 'struct': 'BlockdevOptionsSsh',
89
'data': { 'server': 'InetSocketAddress',
90
'path': 'str',
91
- '*user': 'str' } }
92
+ '*user': 'str',
93
+ '*host-key-check': 'SshHostKeyCheck' } }
94
95
96
##
97
diff --git a/block/ssh.c b/block/ssh.c
98
index XXXXXXX..XXXXXXX 100644
99
--- a/block/ssh.c
100
+++ b/block/ssh.c
101
@@ -XXX,XX +XXX,XX @@ check_host_key_hash(BDRVSSHState *s, const char *hash,
102
}
17
}
103
18
104
static int check_host_key(BDRVSSHState *s, const char *host, int port,
19
-static bool bdrv_has_bds_parent(BlockDriverState *bs, bool only_active)
105
- const char *host_key_check, Error **errp)
20
+static bool GRAPH_RDLOCK
106
+ SshHostKeyCheck *hkc, Error **errp)
21
+bdrv_has_bds_parent(BlockDriverState *bs, bool only_active)
107
{
22
{
108
- /* host_key_check=no */
23
BdrvChild *parent;
109
- if (strcmp(host_key_check, "no") == 0) {
24
GLOBAL_STATE_CODE();
110
- return 0;
25
@@ -XXX,XX +XXX,XX @@ static bool bdrv_has_bds_parent(BlockDriverState *bs, bool only_active)
111
- }
26
return false;
112
+ SshHostKeyCheckMode mode;
113
114
- /* host_key_check=md5:xx:yy:zz:... */
115
- if (strncmp(host_key_check, "md5:", 4) == 0) {
116
- return check_host_key_hash(s, &host_key_check[4],
117
- LIBSSH2_HOSTKEY_HASH_MD5, 16, errp);
118
- }
119
-
120
- /* host_key_check=sha1:xx:yy:zz:... */
121
- if (strncmp(host_key_check, "sha1:", 5) == 0) {
122
- return check_host_key_hash(s, &host_key_check[5],
123
- LIBSSH2_HOSTKEY_HASH_SHA1, 20, errp);
124
+ if (hkc) {
125
+ mode = hkc->mode;
126
+ } else {
127
+ mode = SSH_HOST_KEY_CHECK_MODE_KNOWN_HOSTS;
128
}
129
130
- /* host_key_check=yes */
131
- if (strcmp(host_key_check, "yes") == 0) {
132
+ switch (mode) {
133
+ case SSH_HOST_KEY_CHECK_MODE_NONE:
134
+ return 0;
135
+ case SSH_HOST_KEY_CHECK_MODE_HASH:
136
+ if (hkc->u.hash.type == SSH_HOST_KEY_CHECK_HASH_TYPE_MD5) {
137
+ return check_host_key_hash(s, hkc->u.hash.hash,
138
+ LIBSSH2_HOSTKEY_HASH_MD5, 16, errp);
139
+ } else if (hkc->u.hash.type == SSH_HOST_KEY_CHECK_HASH_TYPE_SHA1) {
140
+ return check_host_key_hash(s, hkc->u.hash.hash,
141
+ LIBSSH2_HOSTKEY_HASH_SHA1, 20, errp);
142
+ }
143
+ g_assert_not_reached();
144
+ break;
145
+ case SSH_HOST_KEY_CHECK_MODE_KNOWN_HOSTS:
146
return check_host_key_knownhosts(s, host, port, errp);
147
+ default:
148
+ g_assert_not_reached();
149
}
150
151
- error_setg(errp, "unknown host_key_check setting (%s)", host_key_check);
152
return -EINVAL;
153
}
27
}
154
28
155
@@ -XXX,XX +XXX,XX @@ static QemuOptsList ssh_runtime_opts = {
29
-static int bdrv_inactivate_recurse(BlockDriverState *bs)
156
.type = QEMU_OPT_NUMBER,
30
+static int GRAPH_RDLOCK bdrv_inactivate_recurse(BlockDriverState *bs)
157
.help = "Port to connect to",
158
},
159
+ {
160
+ .name = "host_key_check",
161
+ .type = QEMU_OPT_STRING,
162
+ .help = "Defines how and what to check the host key against",
163
+ },
164
{ /* end of list */ }
165
},
166
};
167
168
-static bool ssh_process_legacy_socket_options(QDict *output_opts,
169
- QemuOpts *legacy_opts,
170
- Error **errp)
171
+static bool ssh_process_legacy_options(QDict *output_opts,
172
+ QemuOpts *legacy_opts,
173
+ Error **errp)
174
{
31
{
175
const char *host = qemu_opt_get(legacy_opts, "host");
32
BdrvChild *child, *parent;
176
const char *port = qemu_opt_get(legacy_opts, "port");
33
int ret;
177
+ const char *host_key_check = qemu_opt_get(legacy_opts, "host_key_check");
34
uint64_t cumulative_perms, cumulative_shared_perms;
178
35
179
if (!host && port) {
36
GLOBAL_STATE_CODE();
180
error_setg(errp, "port may not be used without host");
37
- GRAPH_RDLOCK_GUARD_MAINLOOP();
181
@@ -XXX,XX +XXX,XX @@ static bool ssh_process_legacy_socket_options(QDict *output_opts,
38
182
qdict_put_str(output_opts, "server.port", port ?: stringify(22));
39
if (!bs->drv) {
183
}
40
return -ENOMEDIUM;
184
41
@@ -XXX,XX +XXX,XX @@ int bdrv_inactivate_all(void)
185
+ if (host_key_check) {
42
GSList *aio_ctxs = NULL, *ctx;
186
+ if (strcmp(host_key_check, "no") == 0) {
43
187
+ qdict_put_str(output_opts, "host-key-check.mode", "none");
44
GLOBAL_STATE_CODE();
188
+ } else if (strncmp(host_key_check, "md5:", 4) == 0) {
45
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
189
+ qdict_put_str(output_opts, "host-key-check.mode", "hash");
46
190
+ qdict_put_str(output_opts, "host-key-check.type", "md5");
47
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
191
+ qdict_put_str(output_opts, "host-key-check.hash",
48
AioContext *aio_context = bdrv_get_aio_context(bs);
192
+ &host_key_check[4]);
193
+ } else if (strncmp(host_key_check, "sha1:", 5) == 0) {
194
+ qdict_put_str(output_opts, "host-key-check.mode", "hash");
195
+ qdict_put_str(output_opts, "host-key-check.type", "sha1");
196
+ qdict_put_str(output_opts, "host-key-check.hash",
197
+ &host_key_check[5]);
198
+ } else if (strcmp(host_key_check, "yes") == 0) {
199
+ qdict_put_str(output_opts, "host-key-check.mode", "known_hosts");
200
+ } else {
201
+ error_setg(errp, "unknown host_key_check setting (%s)",
202
+ host_key_check);
203
+ return false;
204
+ }
205
+ }
206
+
207
return true;
208
}
209
210
@@ -XXX,XX +XXX,XX @@ static BlockdevOptionsSsh *ssh_parse_options(QDict *options, Error **errp)
211
goto fail;
212
}
213
214
- if (!ssh_process_legacy_socket_options(options, opts, errp)) {
215
+ if (!ssh_process_legacy_options(options, opts, errp)) {
216
goto fail;
217
}
218
219
@@ -XXX,XX +XXX,XX @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
220
{
221
BlockdevOptionsSsh *opts;
222
int r, ret;
223
- const char *user, *host_key_check;
224
+ const char *user;
225
long port = 0;
226
227
- host_key_check = qdict_get_try_str(options, "host_key_check");
228
- if (!host_key_check) {
229
- host_key_check = "yes";
230
- } else {
231
- qdict_del(options, "host_key_check");
232
- }
233
-
234
opts = ssh_parse_options(options, errp);
235
if (opts == NULL) {
236
return -EINVAL;
237
@@ -XXX,XX +XXX,XX @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
238
}
239
240
/* Check the remote host's key against known_hosts. */
241
- ret = check_host_key(s, s->inet->host, port, host_key_check,
242
- errp);
243
+ ret = check_host_key(s, s->inet->host, port, opts->host_key_check, errp);
244
if (ret < 0) {
245
goto err;
246
}
247
--
49
--
248
2.13.6
50
2.41.0
249
250
diff view generated by jsdifflib
1
Instead of passing a separate BlockDriverState* into qcow2_co_create(),
1
This adds GRAPH_RDLOCK annotations to declare that callers of
2
make use of the BlockdevRef that is included in BlockdevCreateOptions.
2
bdrv_first_blk() and bdrv_is_root_node() need to hold a reader lock
3
for the graph. These functions are the only functions in block-backend.c
4
that access the parent list of a node.
3
5
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Message-ID: <20230929145157.45443-5-kwolf@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
10
---
8
include/block/block.h | 1 +
11
include/block/block-global-state.h | 9 +++++----
9
block.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
12
include/sysemu/block-backend-global-state.h | 4 ++--
10
block/qcow2.c | 39 +++++++++++++++++++++++++--------------
13
block.c | 1 +
11
3 files changed, 73 insertions(+), 14 deletions(-)
14
block/block-backend.c | 6 +++++-
15
block/export/export.c | 4 ++++
16
block/io.c | 1 +
17
block/monitor/block-hmp-cmds.c | 2 ++
18
block/qapi-sysemu.c | 2 ++
19
block/replication.c | 10 ++++++++--
20
block/snapshot.c | 15 +++++++++++----
21
blockdev.c | 5 +++++
22
migration/block.c | 2 ++
23
migration/migration-hmp-cmds.c | 2 ++
24
tests/unit/test-block-iothread.c | 3 +++
25
14 files changed, 53 insertions(+), 13 deletions(-)
12
26
13
diff --git a/include/block/block.h b/include/block/block.h
27
diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h
14
index XXXXXXX..XXXXXXX 100644
28
index XXXXXXX..XXXXXXX 100644
15
--- a/include/block/block.h
29
--- a/include/block/block-global-state.h
16
+++ b/include/block/block.h
30
+++ b/include/block/block-global-state.h
17
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_open_child(const char *filename,
31
@@ -XXX,XX +XXX,XX @@ BlockDriverState * GRAPH_RDLOCK
18
BlockDriverState* parent,
32
check_to_replace_node(BlockDriverState *parent_bs, const char *node_name,
19
const BdrvChildRole *child_role,
33
Error **errp);
20
bool allow_none, Error **errp);
34
21
+BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp);
35
-int no_coroutine_fn bdrv_activate(BlockDriverState *bs, Error **errp);
22
void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
36
+int no_coroutine_fn GRAPH_RDLOCK
23
Error **errp);
37
+bdrv_activate(BlockDriverState *bs, Error **errp);
24
int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
38
39
-int coroutine_fn no_co_wrapper
40
+int coroutine_fn no_co_wrapper_bdrv_rdlock
41
bdrv_co_activate(BlockDriverState *bs, Error **errp);
42
43
void bdrv_activate_all(Error **errp);
44
@@ -XXX,XX +XXX,XX @@ typedef struct BdrvNextIterator {
45
BlockDriverState *bs;
46
} BdrvNextIterator;
47
48
-BlockDriverState *bdrv_first(BdrvNextIterator *it);
49
-BlockDriverState *bdrv_next(BdrvNextIterator *it);
50
+BlockDriverState * GRAPH_RDLOCK bdrv_first(BdrvNextIterator *it);
51
+BlockDriverState * GRAPH_RDLOCK bdrv_next(BdrvNextIterator *it);
52
void bdrv_next_cleanup(BdrvNextIterator *it);
53
54
BlockDriverState *bdrv_next_monitor_owned(BlockDriverState *bs);
55
diff --git a/include/sysemu/block-backend-global-state.h b/include/sysemu/block-backend-global-state.h
56
index XXXXXXX..XXXXXXX 100644
57
--- a/include/sysemu/block-backend-global-state.h
58
+++ b/include/sysemu/block-backend-global-state.h
59
@@ -XXX,XX +XXX,XX @@ BlockBackend *blk_by_public(BlockBackendPublic *public);
60
void blk_remove_bs(BlockBackend *blk);
61
int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp);
62
int blk_replace_bs(BlockBackend *blk, BlockDriverState *new_bs, Error **errp);
63
-bool bdrv_has_blk(BlockDriverState *bs);
64
-bool bdrv_is_root_node(BlockDriverState *bs);
65
+bool GRAPH_RDLOCK bdrv_has_blk(BlockDriverState *bs);
66
+bool GRAPH_RDLOCK bdrv_is_root_node(BlockDriverState *bs);
67
int GRAPH_UNLOCKED blk_set_perm(BlockBackend *blk, uint64_t perm,
68
uint64_t shared_perm, Error **errp);
69
void blk_get_perm(BlockBackend *blk, uint64_t *perm, uint64_t *shared_perm);
25
diff --git a/block.c b/block.c
70
diff --git a/block.c b/block.c
26
index XXXXXXX..XXXXXXX 100644
71
index XXXXXXX..XXXXXXX 100644
27
--- a/block.c
72
--- a/block.c
28
+++ b/block.c
73
+++ b/block.c
29
@@ -XXX,XX +XXX,XX @@
74
@@ -XXX,XX +XXX,XX @@ void bdrv_activate_all(Error **errp)
30
#include "qapi/qmp/qdict.h"
75
BdrvNextIterator it;
31
#include "qapi/qmp/qjson.h"
76
32
#include "qapi/qmp/qstring.h"
77
GLOBAL_STATE_CODE();
33
+#include "qapi/qobject-output-visitor.h"
78
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
34
+#include "qapi/qapi-visit-block-core.h"
79
35
#include "sysemu/block-backend.h"
80
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
36
#include "sysemu/sysemu.h"
81
AioContext *aio_context = bdrv_get_aio_context(bs);
37
#include "qemu/notify.h"
82
diff --git a/block/block-backend.c b/block/block-backend.c
38
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_open_child(const char *filename,
83
index XXXXXXX..XXXXXXX 100644
39
return c;
84
--- a/block/block-backend.c
40
}
85
+++ b/block/block-backend.c
41
86
@@ -XXX,XX +XXX,XX @@ BlockDriverState *blk_bs(BlockBackend *blk)
42
+/* TODO Future callers may need to specify parent/child_role in order for
87
return blk->root ? blk->root->bs : NULL;
43
+ * option inheritance to work. Existing callers use it for the root node. */
88
}
44
+BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp)
89
45
+{
90
-static BlockBackend *bdrv_first_blk(BlockDriverState *bs)
46
+ BlockDriverState *bs = NULL;
91
+static BlockBackend * GRAPH_RDLOCK bdrv_first_blk(BlockDriverState *bs)
47
+ Error *local_err = NULL;
92
{
48
+ QObject *obj = NULL;
93
BdrvChild *child;
49
+ QDict *qdict = NULL;
94
50
+ const char *reference = NULL;
95
GLOBAL_STATE_CODE();
51
+ Visitor *v = NULL;
96
+ assert_bdrv_graph_readable();
52
+
97
53
+ if (ref->type == QTYPE_QSTRING) {
98
QLIST_FOREACH(child, &bs->parents, next_parent) {
54
+ reference = ref->u.reference;
99
if (child->klass == &child_root) {
55
+ } else {
100
@@ -XXX,XX +XXX,XX @@ bool bdrv_is_root_node(BlockDriverState *bs)
56
+ BlockdevOptions *options = &ref->u.definition;
101
BdrvChild *c;
57
+ assert(ref->type == QTYPE_QDICT);
102
58
+
103
GLOBAL_STATE_CODE();
59
+ v = qobject_output_visitor_new(&obj);
104
+ assert_bdrv_graph_readable();
60
+ visit_type_BlockdevOptions(v, NULL, &options, &local_err);
105
+
61
+ if (local_err) {
106
QLIST_FOREACH(c, &bs->parents, next_parent) {
62
+ error_propagate(errp, local_err);
107
if (c->klass != &child_root) {
63
+ goto fail;
108
return false;
64
+ }
109
@@ -XXX,XX +XXX,XX @@ void blk_activate(BlockBackend *blk, Error **errp)
65
+ visit_complete(v, &obj);
110
if (qemu_in_coroutine()) {
66
+
111
bdrv_co_activate(bs, errp);
67
+ qdict = qobject_to_qdict(obj);
112
} else {
68
+ qdict_flatten(qdict);
113
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
69
+
114
bdrv_activate(bs, errp);
70
+ /* bdrv_open_inherit() defaults to the values in bdrv_flags (for
115
}
71
+ * compatibility with other callers) rather than what we want as the
116
}
72
+ * real defaults. Apply the defaults here instead. */
117
diff --git a/block/export/export.c b/block/export/export.c
73
+ qdict_set_default_str(qdict, BDRV_OPT_CACHE_DIRECT, "off");
118
index XXXXXXX..XXXXXXX 100644
74
+ qdict_set_default_str(qdict, BDRV_OPT_CACHE_NO_FLUSH, "off");
119
--- a/block/export/export.c
75
+ qdict_set_default_str(qdict, BDRV_OPT_READ_ONLY, "off");
120
+++ b/block/export/export.c
76
+ }
121
@@ -XXX,XX +XXX,XX @@ BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp)
77
+
122
uint64_t perm;
78
+ bs = bdrv_open_inherit(NULL, reference, qdict, 0, NULL, NULL, errp);
123
int ret;
79
+ obj = NULL;
124
80
+
125
+ GLOBAL_STATE_CODE();
81
+fail:
126
+
82
+ qobject_decref(obj);
127
if (!id_wellformed(export->id)) {
83
+ visit_free(v);
128
error_setg(errp, "Invalid block export id");
84
+ return bs;
129
return NULL;
85
+}
130
@@ -XXX,XX +XXX,XX @@ BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp)
86
+
131
* access since the export could be available before migration handover.
87
static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs,
132
* ctx was acquired in the caller.
88
int flags,
89
QDict *snapshot_options,
90
diff --git a/block/qcow2.c b/block/qcow2.c
91
index XXXXXXX..XXXXXXX 100644
92
--- a/block/qcow2.c
93
+++ b/block/qcow2.c
94
@@ -XXX,XX +XXX,XX @@ static uint64_t qcow2_opt_get_refcount_bits_del(QemuOpts *opts, int version,
95
}
96
97
static int coroutine_fn
98
-qcow2_co_create(BlockDriverState *bs, BlockdevCreateOptions *create_options,
99
- QemuOpts *opts, const char *encryptfmt, Error **errp)
100
+qcow2_co_create(BlockdevCreateOptions *create_options, QemuOpts *opts,
101
+ const char *encryptfmt, Error **errp)
102
{
103
BlockdevCreateOptionsQcow2 *qcow2_opts;
104
QDict *options;
105
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockDriverState *bs, BlockdevCreateOptions *create_options,
106
* 2 GB for 64k clusters, and we don't want to have a 2 GB initial file
107
* size for any qcow2 image.
108
*/
133
*/
109
- BlockBackend *blk;
134
+ bdrv_graph_rdlock_main_loop();
110
+ BlockBackend *blk = NULL;
135
bdrv_activate(bs, NULL);
111
+ BlockDriverState *bs = NULL;
136
+ bdrv_graph_rdunlock_main_loop();
112
QCowHeader *header;
137
113
size_t cluster_size;
138
perm = BLK_PERM_CONSISTENT_READ;
114
int version;
139
if (export->writable) {
115
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockDriverState *bs, BlockdevCreateOptions *create_options,
140
diff --git a/block/io.c b/block/io.c
141
index XXXXXXX..XXXXXXX 100644
142
--- a/block/io.c
143
+++ b/block/io.c
144
@@ -XXX,XX +XXX,XX @@ int bdrv_flush_all(void)
145
int result = 0;
146
147
GLOBAL_STATE_CODE();
148
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
149
150
/*
151
* bdrv queue is managed by record/replay,
152
diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c
153
index XXXXXXX..XXXXXXX 100644
154
--- a/block/monitor/block-hmp-cmds.c
155
+++ b/block/monitor/block-hmp-cmds.c
156
@@ -XXX,XX +XXX,XX @@ void hmp_info_snapshots(Monitor *mon, const QDict *qdict)
157
SnapshotEntry *snapshot_entry;
158
Error *err = NULL;
159
160
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
161
+
162
bs = bdrv_all_find_vmstate_bs(NULL, false, NULL, &err);
163
if (!bs) {
164
error_report_err(err);
165
diff --git a/block/qapi-sysemu.c b/block/qapi-sysemu.c
166
index XXXXXXX..XXXXXXX 100644
167
--- a/block/qapi-sysemu.c
168
+++ b/block/qapi-sysemu.c
169
@@ -XXX,XX +XXX,XX @@ static void blockdev_insert_medium(const char *device, const char *id,
170
BlockBackend *blk;
171
BlockDriverState *bs;
172
173
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
174
+
175
blk = qmp_get_blk(device, id, errp);
176
if (!blk) {
177
return;
178
diff --git a/block/replication.c b/block/replication.c
179
index XXXXXXX..XXXXXXX 100644
180
--- a/block/replication.c
181
+++ b/block/replication.c
182
@@ -XXX,XX +XXX,XX @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
183
Error *local_err = NULL;
184
BackupPerf perf = { .use_copy_range = true, .max_workers = 1 };
185
186
+ GLOBAL_STATE_CODE();
187
+
188
aio_context = bdrv_get_aio_context(bs);
189
aio_context_acquire(aio_context);
190
s = bs->opaque;
191
@@ -XXX,XX +XXX,XX @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
192
return;
193
}
194
195
+ bdrv_graph_rdlock_main_loop();
196
secondary_disk = hidden_disk->bs->backing;
197
if (!secondary_disk->bs || !bdrv_has_blk(secondary_disk->bs)) {
198
error_setg(errp, "The secondary disk doesn't have block backend");
199
+ bdrv_graph_rdunlock_main_loop();
200
aio_context_release(aio_context);
201
return;
202
}
203
+ bdrv_graph_rdunlock_main_loop();
204
205
/* verify the length */
206
active_length = bdrv_getlength(active_disk->bs);
207
@@ -XXX,XX +XXX,XX @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
208
return;
209
}
210
211
- bdrv_graph_wrunlock();
212
-
213
/* start backup job now */
214
error_setg(&s->blocker,
215
"Block device is in use by internal backup job");
216
@@ -XXX,XX +XXX,XX @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
217
if (!top_bs || !bdrv_is_root_node(top_bs) ||
218
!check_top_bs(top_bs, bs)) {
219
error_setg(errp, "No top_bs or it is invalid");
220
+ bdrv_graph_wrunlock();
221
reopen_backing_file(bs, false, NULL);
222
aio_context_release(aio_context);
223
return;
224
@@ -XXX,XX +XXX,XX @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
225
bdrv_op_block_all(top_bs, s->blocker);
226
bdrv_op_unblock(top_bs, BLOCK_OP_TYPE_DATAPLANE, s->blocker);
227
228
+ bdrv_graph_wrunlock();
229
+
230
s->backup_job = backup_job_create(
231
NULL, s->secondary_disk->bs, s->hidden_disk->bs,
232
0, MIRROR_SYNC_MODE_NONE, NULL, 0, false, NULL,
233
diff --git a/block/snapshot.c b/block/snapshot.c
234
index XXXXXXX..XXXXXXX 100644
235
--- a/block/snapshot.c
236
+++ b/block/snapshot.c
237
@@ -XXX,XX +XXX,XX @@ int bdrv_snapshot_load_tmp_by_id_or_name(BlockDriverState *bs,
238
}
239
240
241
-static int bdrv_all_get_snapshot_devices(bool has_devices, strList *devices,
242
- GList **all_bdrvs,
243
- Error **errp)
244
+static int GRAPH_RDLOCK
245
+bdrv_all_get_snapshot_devices(bool has_devices, strList *devices,
246
+ GList **all_bdrvs, Error **errp)
247
{
248
g_autoptr(GList) bdrvs = NULL;
249
250
@@ -XXX,XX +XXX,XX @@ static int bdrv_all_get_snapshot_devices(bool has_devices, strList *devices,
251
}
252
253
254
-static bool bdrv_all_snapshots_includes_bs(BlockDriverState *bs)
255
+static bool GRAPH_RDLOCK bdrv_all_snapshots_includes_bs(BlockDriverState *bs)
256
{
257
if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) {
258
return false;
259
@@ -XXX,XX +XXX,XX @@ bool bdrv_all_can_snapshot(bool has_devices, strList *devices,
260
GList *iterbdrvs;
261
262
GLOBAL_STATE_CODE();
263
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
264
265
if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) {
266
return false;
267
@@ -XXX,XX +XXX,XX @@ int bdrv_all_delete_snapshot(const char *name,
268
GList *iterbdrvs;
269
270
GLOBAL_STATE_CODE();
271
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
272
273
if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) {
274
return -1;
275
@@ -XXX,XX +XXX,XX @@ int bdrv_all_goto_snapshot(const char *name,
276
GList *iterbdrvs;
277
278
GLOBAL_STATE_CODE();
279
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
280
281
if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) {
282
return -1;
283
@@ -XXX,XX +XXX,XX @@ int bdrv_all_has_snapshot(const char *name,
284
GList *iterbdrvs;
285
286
GLOBAL_STATE_CODE();
287
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
288
289
if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) {
290
return -1;
291
@@ -XXX,XX +XXX,XX @@ int bdrv_all_create_snapshot(QEMUSnapshotInfo *sn,
292
{
293
g_autoptr(GList) bdrvs = NULL;
294
GList *iterbdrvs;
295
+
296
GLOBAL_STATE_CODE();
297
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
298
299
if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) {
300
return -1;
301
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_all_find_vmstate_bs(const char *vmstate_bs,
302
GList *iterbdrvs;
303
304
GLOBAL_STATE_CODE();
305
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
306
307
if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) {
308
return NULL;
309
diff --git a/blockdev.c b/blockdev.c
310
index XXXXXXX..XXXXXXX 100644
311
--- a/blockdev.c
312
+++ b/blockdev.c
313
@@ -XXX,XX +XXX,XX @@ static BlockDriverState *qmp_get_root_bs(const char *name, Error **errp)
314
BlockDriverState *bs;
315
AioContext *aio_context;
316
317
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
318
+
319
bs = bdrv_lookup_bs(name, name, errp);
320
if (bs == NULL) {
321
return NULL;
322
@@ -XXX,XX +XXX,XX @@ void qmp_blockdev_del(const char *node_name, Error **errp)
323
BlockDriverState *bs;
324
325
GLOBAL_STATE_CODE();
326
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
327
328
bs = bdrv_find_node(node_name);
329
if (!bs) {
330
@@ -XXX,XX +XXX,XX @@ void qmp_x_blockdev_set_iothread(const char *node_name, StrOrNull *iothread,
331
AioContext *new_context;
332
BlockDriverState *bs;
333
334
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
335
+
336
bs = bdrv_find_node(node_name);
337
if (!bs) {
338
error_setg(errp, "Failed to find node with node-name='%s'", node_name);
339
diff --git a/migration/block.c b/migration/block.c
340
index XXXXXXX..XXXXXXX 100644
341
--- a/migration/block.c
342
+++ b/migration/block.c
343
@@ -XXX,XX +XXX,XX @@ static int init_blk_migration(QEMUFile *f)
116
Error *local_err = NULL;
344
Error *local_err = NULL;
117
int ret;
345
int ret;
118
346
119
- /* Validate options and set default values */
347
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
120
assert(create_options->driver == BLOCKDEV_DRIVER_QCOW2);
348
+
121
qcow2_opts = &create_options->u.qcow2;
349
block_mig_state.submitted = 0;
122
350
block_mig_state.read_done = 0;
123
+ bs = bdrv_open_blockdev_ref(qcow2_opts->file, errp);
351
block_mig_state.transferred = 0;
124
+ if (bs == NULL) {
352
diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c
125
+ return -EIO;
353
index XXXXXXX..XXXXXXX 100644
126
+ }
354
--- a/migration/migration-hmp-cmds.c
127
+
355
+++ b/migration/migration-hmp-cmds.c
128
+ /* Validate options and set default values */
356
@@ -XXX,XX +XXX,XX @@ static void vm_completion(ReadLineState *rs, const char *str)
129
if (!QEMU_IS_ALIGNED(qcow2_opts->size, BDRV_SECTOR_SIZE)) {
357
BlockDriverState *bs;
130
error_setg(errp, "Image size must be a multiple of 512 bytes");
358
BdrvNextIterator it;
131
ret = -EINVAL;
359
132
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockDriverState *bs, BlockdevCreateOptions *create_options,
360
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
133
}
361
+
134
362
len = strlen(str);
135
if (!validate_cluster_size(cluster_size, errp)) {
363
readline_set_completion_index(rs, len);
136
- return -EINVAL;
364
137
+ ret = -EINVAL;
365
diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c
138
+ goto out;
366
index XXXXXXX..XXXXXXX 100644
139
}
367
--- a/tests/unit/test-block-iothread.c
140
368
+++ b/tests/unit/test-block-iothread.c
141
if (!qcow2_opts->has_preallocation) {
369
@@ -XXX,XX +XXX,XX @@ static void test_sync_op_check(BdrvChild *c)
142
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockDriverState *bs, BlockdevCreateOptions *create_options,
370
143
{
371
static void test_sync_op_activate(BdrvChild *c)
144
error_setg(errp, "Backing file and preallocation cannot be used at "
372
{
145
"the same time");
373
+ GLOBAL_STATE_CODE();
146
- return -EINVAL;
374
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
147
+ ret = -EINVAL;
375
+
148
+ goto out;
376
/* Early success: Image is not inactive */
149
}
377
bdrv_activate(c->bs, NULL);
150
if (qcow2_opts->has_backing_fmt && !qcow2_opts->has_backing_file) {
378
}
151
error_setg(errp, "Backing format cannot be used without backing file");
152
- return -EINVAL;
153
+ ret = -EINVAL;
154
+ goto out;
155
}
156
157
if (!qcow2_opts->has_lazy_refcounts) {
158
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockDriverState *bs, BlockdevCreateOptions *create_options,
159
if (version < 3 && qcow2_opts->lazy_refcounts) {
160
error_setg(errp, "Lazy refcounts only supported with compatibility "
161
"level 1.1 and above (use compat=1.1 or greater)");
162
- return -EINVAL;
163
+ ret = -EINVAL;
164
+ goto out;
165
}
166
167
if (!qcow2_opts->has_refcount_bits) {
168
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockDriverState *bs, BlockdevCreateOptions *create_options,
169
{
170
error_setg(errp, "Refcount width must be a power of two and may not "
171
"exceed 64 bits");
172
- return -EINVAL;
173
+ ret = -EINVAL;
174
+ goto out;
175
}
176
if (version < 3 && qcow2_opts->refcount_bits != 16) {
177
error_setg(errp, "Different refcount widths than 16 bits require "
178
"compatibility level 1.1 or above (use compat=1.1 or "
179
"greater)");
180
- return -EINVAL;
181
+ ret = -EINVAL;
182
+ goto out;
183
}
184
refcount_order = ctz32(qcow2_opts->refcount_bits);
185
186
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockDriverState *bs, BlockdevCreateOptions *create_options,
187
188
ret = 0;
189
out:
190
- if (blk) {
191
- blk_unref(blk);
192
- }
193
+ blk_unref(blk);
194
+ bdrv_unref(bs);
195
return ret;
196
}
197
198
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
199
.refcount_bits = refcount_bits,
200
},
201
};
202
- ret = qcow2_co_create(bs, &create_options, opts, encryptfmt, errp);
203
+ ret = qcow2_co_create(&create_options, opts, encryptfmt, errp);
204
if (ret < 0) {
205
goto finish;
206
}
207
--
379
--
208
2.13.6
380
2.41.0
209
210
diff view generated by jsdifflib
1
Most callers have their own checks, but something like this should also
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
2
be checked centrally. As it happens, x-blockdev-create can pass negative
2
3
image sizes to format drivers (because there is no QAPI type that would
3
Draining recursively traverses the graph, therefore we need to make sure
4
reject negative numbers) and triggers the check added by this patch.
4
that also such accesses to the graph are protected by the graph rdlock.
5
5
6
There are 3 different drain callers to consider:
7
1. drain in the main loop: no issue at all, rdlock is nop.
8
2. drain in an iothread: rdlock only works in main loop or coroutines,
9
so disallow it.
10
3. drain in a coroutine (regardless of AioContext): the drain mechanism
11
takes care of scheduling a BH in the bs->aio_context that will
12
then take care of perform the actual draining. This is wrong,
13
because as pointed in (2) if bs->aio_context is an iothread then
14
rdlock won't work. Therefore change bdrv_co_yield_to_drain to
15
schedule the BH in the main loop.
16
17
Caller (2) also implies that we need to modify test-bdrv-drain.c to
18
disallow draining in the iothreads.
19
20
For some places, we know that they will hold the lock, but we don't have
21
the GRAPH_RDLOCK annotations yet. In this case, add assume_graph_lock()
22
with a FIXME comment. These places will be removed once everything is
23
properly annotated.
24
25
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
26
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
27
Message-ID: <20230929145157.45443-6-kwolf@redhat.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
28
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
29
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
30
---
10
block.c | 5 +++++
31
include/block/block-io.h | 23 ++++++++++++++++++-----
11
1 file changed, 5 insertions(+)
32
include/block/block_int-common.h | 6 +++---
12
33
block.c | 6 +++---
34
block/io.c | 32 ++++++++++++++++++++++++++++----
35
tests/unit/test-bdrv-drain.c | 4 ++--
36
5 files changed, 54 insertions(+), 17 deletions(-)
37
38
diff --git a/include/block/block-io.h b/include/block/block-io.h
39
index XXXXXXX..XXXXXXX 100644
40
--- a/include/block/block-io.h
41
+++ b/include/block/block-io.h
42
@@ -XXX,XX +XXX,XX @@ bdrv_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos);
43
*
44
* Begin a quiesced section for the parent of @c.
45
*/
46
-void bdrv_parent_drained_begin_single(BdrvChild *c);
47
+void GRAPH_RDLOCK bdrv_parent_drained_begin_single(BdrvChild *c);
48
49
/**
50
* bdrv_parent_drained_poll_single:
51
@@ -XXX,XX +XXX,XX @@ void bdrv_parent_drained_begin_single(BdrvChild *c);
52
* Returns true if there is any pending activity to cease before @c can be
53
* called quiesced, false otherwise.
54
*/
55
-bool bdrv_parent_drained_poll_single(BdrvChild *c);
56
+bool GRAPH_RDLOCK bdrv_parent_drained_poll_single(BdrvChild *c);
57
58
/**
59
* bdrv_parent_drained_end_single:
60
*
61
* End a quiesced section for the parent of @c.
62
*/
63
-void bdrv_parent_drained_end_single(BdrvChild *c);
64
+void GRAPH_RDLOCK bdrv_parent_drained_end_single(BdrvChild *c);
65
66
/**
67
* bdrv_drain_poll:
68
@@ -XXX,XX +XXX,XX @@ void bdrv_parent_drained_end_single(BdrvChild *c);
69
*
70
* This is part of bdrv_drained_begin.
71
*/
72
-bool bdrv_drain_poll(BlockDriverState *bs, BdrvChild *ignore_parent,
73
- bool ignore_bds_parents);
74
+bool GRAPH_RDLOCK
75
+bdrv_drain_poll(BlockDriverState *bs, BdrvChild *ignore_parent,
76
+ bool ignore_bds_parents);
77
78
/**
79
* bdrv_drained_begin:
80
@@ -XXX,XX +XXX,XX @@ bool bdrv_drain_poll(BlockDriverState *bs, BdrvChild *ignore_parent,
81
* Begin a quiesced section for exclusive access to the BDS, by disabling
82
* external request sources including NBD server, block jobs, and device model.
83
*
84
+ * This function can only be invoked by the main loop or a coroutine
85
+ * (regardless of the AioContext where it is running).
86
+ * If the coroutine is running in an Iothread AioContext, this function will
87
+ * just schedule a BH to run in the main loop.
88
+ * However, it cannot be directly called by an Iothread.
89
+ *
90
* This function can be recursive.
91
*/
92
void bdrv_drained_begin(BlockDriverState *bs);
93
@@ -XXX,XX +XXX,XX @@ void bdrv_do_drained_begin_quiesce(BlockDriverState *bs, BdrvChild *parent);
94
* bdrv_drained_end:
95
*
96
* End a quiescent section started by bdrv_drained_begin().
97
+ *
98
+ * This function can only be invoked by the main loop or a coroutine
99
+ * (regardless of the AioContext where it is running).
100
+ * If the coroutine is running in an Iothread AioContext, this function will
101
+ * just schedule a BH to run in the main loop.
102
+ * However, it cannot be directly called by an Iothread.
103
*/
104
void bdrv_drained_end(BlockDriverState *bs);
105
106
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
107
index XXXXXXX..XXXXXXX 100644
108
--- a/include/block/block_int-common.h
109
+++ b/include/block/block_int-common.h
110
@@ -XXX,XX +XXX,XX @@ struct BdrvChildClass {
111
* Note that this can be nested. If drained_begin() was called twice, new
112
* I/O is allowed only after drained_end() was called twice, too.
113
*/
114
- void (*drained_begin)(BdrvChild *child);
115
- void (*drained_end)(BdrvChild *child);
116
+ void GRAPH_RDLOCK_PTR (*drained_begin)(BdrvChild *child);
117
+ void GRAPH_RDLOCK_PTR (*drained_end)(BdrvChild *child);
118
119
/*
120
* Returns whether the parent has pending requests for the child. This
121
* callback is polled after .drained_begin() has been called until all
122
* activity on the child has stopped.
123
*/
124
- bool (*drained_poll)(BdrvChild *child);
125
+ bool GRAPH_RDLOCK_PTR (*drained_poll)(BdrvChild *child);
126
127
/*
128
* Notifies the parent that the filename of its child has changed (e.g.
13
diff --git a/block.c b/block.c
129
diff --git a/block.c b/block.c
14
index XXXXXXX..XXXXXXX 100644
130
index XXXXXXX..XXXXXXX 100644
15
--- a/block.c
131
--- a/block.c
16
+++ b/block.c
132
+++ b/block.c
17
@@ -XXX,XX +XXX,XX @@ int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc,
133
@@ -XXX,XX +XXX,XX @@ static char *bdrv_child_get_parent_desc(BdrvChild *c)
18
error_setg(errp, "No medium inserted");
134
return g_strdup_printf("node '%s'", bdrv_get_node_name(parent));
19
return -ENOMEDIUM;
135
}
20
}
136
21
+ if (offset < 0) {
137
-static void bdrv_child_cb_drained_begin(BdrvChild *child)
22
+ error_setg(errp, "Image size cannot be negative");
138
+static void GRAPH_RDLOCK bdrv_child_cb_drained_begin(BdrvChild *child)
23
+ return -EINVAL;
139
{
24
+ }
140
BlockDriverState *bs = child->opaque;
25
+
141
bdrv_do_drained_begin_quiesce(bs, NULL);
26
if (!drv->bdrv_truncate) {
142
}
27
if (bs->file && drv->is_filter) {
143
28
return bdrv_truncate(bs->file, offset, prealloc, errp);
144
-static bool bdrv_child_cb_drained_poll(BdrvChild *child)
145
+static bool GRAPH_RDLOCK bdrv_child_cb_drained_poll(BdrvChild *child)
146
{
147
BlockDriverState *bs = child->opaque;
148
return bdrv_drain_poll(bs, NULL, false);
149
}
150
151
-static void bdrv_child_cb_drained_end(BdrvChild *child)
152
+static void GRAPH_RDLOCK bdrv_child_cb_drained_end(BdrvChild *child)
153
{
154
BlockDriverState *bs = child->opaque;
155
bdrv_drained_end(bs);
156
diff --git a/block/io.c b/block/io.c
157
index XXXXXXX..XXXXXXX 100644
158
--- a/block/io.c
159
+++ b/block/io.c
160
@@ -XXX,XX +XXX,XX @@ static void bdrv_parent_cb_resize(BlockDriverState *bs);
161
static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
162
int64_t offset, int64_t bytes, BdrvRequestFlags flags);
163
164
-static void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore)
165
+static void GRAPH_RDLOCK
166
+bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore)
167
{
168
BdrvChild *c, *next;
169
+ IO_OR_GS_CODE();
170
+ assert_bdrv_graph_readable();
171
172
QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) {
173
if (c == ignore) {
174
@@ -XXX,XX +XXX,XX @@ void bdrv_parent_drained_end_single(BdrvChild *c)
175
}
176
}
177
178
-static void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore)
179
+static void GRAPH_RDLOCK
180
+bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore)
181
{
182
BdrvChild *c;
183
+ IO_OR_GS_CODE();
184
+ assert_bdrv_graph_readable();
185
186
QLIST_FOREACH(c, &bs->parents, next_parent) {
187
if (c == ignore) {
188
@@ -XXX,XX +XXX,XX @@ static void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore)
189
190
bool bdrv_parent_drained_poll_single(BdrvChild *c)
191
{
192
+ IO_OR_GS_CODE();
193
+
194
if (c->klass->drained_poll) {
195
return c->klass->drained_poll(c);
196
}
197
return false;
198
}
199
200
-static bool bdrv_parent_drained_poll(BlockDriverState *bs, BdrvChild *ignore,
201
- bool ignore_bds_parents)
202
+static bool GRAPH_RDLOCK
203
+bdrv_parent_drained_poll(BlockDriverState *bs, BdrvChild *ignore,
204
+ bool ignore_bds_parents)
205
{
206
BdrvChild *c, *next;
207
bool busy = false;
208
+ IO_OR_GS_CODE();
209
+ assert_bdrv_graph_readable();
210
211
QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) {
212
if (c == ignore || (ignore_bds_parents && c->klass->parent_is_bds)) {
213
@@ -XXX,XX +XXX,XX @@ void bdrv_parent_drained_begin_single(BdrvChild *c)
214
c->quiesced_parent = true;
215
216
if (c->klass->drained_begin) {
217
+ /* called with rdlock taken, but it doesn't really need it. */
218
c->klass->drained_begin(c);
219
}
220
}
221
@@ -XXX,XX +XXX,XX @@ bool bdrv_drain_poll(BlockDriverState *bs, BdrvChild *ignore_parent,
222
static bool bdrv_drain_poll_top_level(BlockDriverState *bs,
223
BdrvChild *ignore_parent)
224
{
225
+ GLOBAL_STATE_CODE();
226
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
227
+
228
return bdrv_drain_poll(bs, ignore_parent, false);
229
}
230
231
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent,
232
233
/* Stop things in parent-to-child order */
234
if (qatomic_fetch_inc(&bs->quiesce_counter) == 0) {
235
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
236
bdrv_parent_drained_begin(bs, parent);
237
if (bs->drv && bs->drv->bdrv_drain_begin) {
238
bs->drv->bdrv_drain_begin(bs);
239
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent)
240
bdrv_co_yield_to_drain(bs, false, parent, false);
241
return;
242
}
243
+
244
+ /* At this point, we should be always running in the main loop. */
245
+ GLOBAL_STATE_CODE();
246
assert(bs->quiesce_counter > 0);
247
GLOBAL_STATE_CODE();
248
249
/* Re-enable things in child-to-parent order */
250
old_quiesce_counter = qatomic_fetch_dec(&bs->quiesce_counter);
251
if (old_quiesce_counter == 1) {
252
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
253
if (bs->drv && bs->drv->bdrv_drain_end) {
254
bs->drv->bdrv_drain_end(bs);
255
}
256
@@ -XXX,XX +XXX,XX @@ void bdrv_drain(BlockDriverState *bs)
257
static void bdrv_drain_assert_idle(BlockDriverState *bs)
258
{
259
BdrvChild *child, *next;
260
+ GLOBAL_STATE_CODE();
261
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
262
263
assert(qatomic_read(&bs->in_flight) == 0);
264
QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
265
@@ -XXX,XX +XXX,XX @@ static bool bdrv_drain_all_poll(void)
266
{
267
BlockDriverState *bs = NULL;
268
bool result = false;
269
+
270
GLOBAL_STATE_CODE();
271
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
272
273
/* bdrv_drain_poll() can't make changes to the graph and we are holding the
274
* main AioContext lock, so iterating bdrv_next_all_states() is safe. */
275
diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c
276
index XXXXXXX..XXXXXXX 100644
277
--- a/tests/unit/test-bdrv-drain.c
278
+++ b/tests/unit/test-bdrv-drain.c
279
@@ -XXX,XX +XXX,XX @@ static void coroutine_mixed_fn detach_by_parent_aio_cb(void *opaque, int ret)
280
}
281
}
282
283
-static void detach_by_driver_cb_drained_begin(BdrvChild *child)
284
+static void GRAPH_RDLOCK detach_by_driver_cb_drained_begin(BdrvChild *child)
285
{
286
struct detach_by_parent_data *data = &detach_by_parent_data;
287
288
@@ -XXX,XX +XXX,XX @@ static BdrvChildClass detach_by_driver_cb_class;
289
* state is messed up, but if it is only polled in the single
290
* BDRV_POLL_WHILE() at the end of the drain, this should work fine.
291
*/
292
-static void test_detach_indirect(bool by_parent_cb)
293
+static void TSA_NO_TSA test_detach_indirect(bool by_parent_cb)
294
{
295
BlockBackend *blk;
296
BlockDriverState *parent_a, *parent_b, *a, *b, *c;
29
--
297
--
30
2.13.6
298
2.41.0
31
32
diff view generated by jsdifflib
1
This adds the .bdrv_co_create driver callback to file, which enables
1
This adds GRAPH_RDLOCK annotations to declare that callers of
2
image creation over QMP.
2
bdrv_parent_cb_resize() need to hold a reader lock for the graph.
3
3
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
5
Message-ID: <20230929145157.45443-7-kwolf@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
8
---
8
qapi/block-core.json | 20 ++++++++++++-
9
block/io.c | 12 +++++++++---
9
block/file-posix.c | 79 +++++++++++++++++++++++++++++++++++++---------------
10
1 file changed, 9 insertions(+), 3 deletions(-)
10
2 files changed, 75 insertions(+), 24 deletions(-)
11
11
12
diff --git a/qapi/block-core.json b/qapi/block-core.json
12
diff --git a/block/io.c b/block/io.c
13
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
14
--- a/qapi/block-core.json
14
--- a/block/io.c
15
+++ b/qapi/block-core.json
15
+++ b/block/io.c
16
@@ -XXX,XX +XXX,XX @@
16
@@ -XXX,XX +XXX,XX @@
17
{ 'command': 'blockdev-del', 'data': { 'node-name': 'str' } }
17
/* Maximum bounce buffer for copy-on-read and write zeroes, in bytes */
18
18
#define MAX_BOUNCE_BUFFER (32768 << BDRV_SECTOR_BITS)
19
##
19
20
+# @BlockdevCreateOptionsFile:
20
-static void bdrv_parent_cb_resize(BlockDriverState *bs);
21
+#
21
+static void coroutine_fn GRAPH_RDLOCK
22
+# Driver specific image creation options for file.
22
+bdrv_parent_cb_resize(BlockDriverState *bs);
23
+#
24
+# @filename Filename for the new image file
25
+# @size Size of the virtual disk in bytes
26
+# @preallocation Preallocation mode for the new image (default: off)
27
+# @nocow Turn off copy-on-write (valid only on btrfs; default: off)
28
+#
29
+# Since: 2.12
30
+##
31
+{ 'struct': 'BlockdevCreateOptionsFile',
32
+ 'data': { 'filename': 'str',
33
+ 'size': 'size',
34
+ '*preallocation': 'PreallocMode',
35
+ '*nocow': 'bool' } }
36
+
23
+
37
+##
24
static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
38
# @BlockdevQcow2Version:
25
int64_t offset, int64_t bytes, BdrvRequestFlags flags);
39
#
26
40
# @v2: The original QCOW2 format as introduced in qemu 0.10 (version 2)
27
@@ -XXX,XX +XXX,XX @@ bdrv_co_write_req_prepare(BdrvChild *child, int64_t offset, int64_t bytes,
41
@@ -XXX,XX +XXX,XX @@
28
}
42
'bochs': 'BlockdevCreateNotSupported',
43
'cloop': 'BlockdevCreateNotSupported',
44
'dmg': 'BlockdevCreateNotSupported',
45
- 'file': 'BlockdevCreateNotSupported',
46
+ 'file': 'BlockdevCreateOptionsFile',
47
'ftp': 'BlockdevCreateNotSupported',
48
'ftps': 'BlockdevCreateNotSupported',
49
'gluster': 'BlockdevCreateNotSupported',
50
diff --git a/block/file-posix.c b/block/file-posix.c
51
index XXXXXXX..XXXXXXX 100644
52
--- a/block/file-posix.c
53
+++ b/block/file-posix.c
54
@@ -XXX,XX +XXX,XX @@ static int64_t raw_get_allocated_file_size(BlockDriverState *bs)
55
return (int64_t)st.st_blocks * 512;
56
}
29
}
57
30
58
-static int coroutine_fn raw_co_create_opts(const char *filename, QemuOpts *opts,
31
-static inline void coroutine_fn
59
- Error **errp)
32
+static inline void coroutine_fn GRAPH_RDLOCK
60
+static int raw_co_create(BlockdevCreateOptions *options, Error **errp)
33
bdrv_co_write_req_finish(BdrvChild *child, int64_t offset, int64_t bytes,
34
BdrvTrackedRequest *req, int ret)
61
{
35
{
62
+ BlockdevCreateOptionsFile *file_opts;
36
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_copy_range(BdrvChild *src, int64_t src_offset,
63
int fd;
37
bytes, read_flags, write_flags);
64
int result = 0;
65
- int64_t total_size = 0;
66
- bool nocow = false;
67
- PreallocMode prealloc;
68
- char *buf = NULL;
69
- Error *local_err = NULL;
70
71
- strstart(filename, "file:", &filename);
72
+ /* Validate options and set default values */
73
+ assert(options->driver == BLOCKDEV_DRIVER_FILE);
74
+ file_opts = &options->u.file;
75
76
- /* Read out options */
77
- total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
78
- BDRV_SECTOR_SIZE);
79
- nocow = qemu_opt_get_bool(opts, BLOCK_OPT_NOCOW, false);
80
- buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
81
- prealloc = qapi_enum_parse(&PreallocMode_lookup, buf,
82
- PREALLOC_MODE_OFF, &local_err);
83
- g_free(buf);
84
- if (local_err) {
85
- error_propagate(errp, local_err);
86
- result = -EINVAL;
87
- goto out;
88
+ if (!file_opts->has_nocow) {
89
+ file_opts->nocow = false;
90
+ }
91
+ if (!file_opts->has_preallocation) {
92
+ file_opts->preallocation = PREALLOC_MODE_OFF;
93
}
94
95
- fd = qemu_open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
96
+ /* Create file */
97
+ fd = qemu_open(file_opts->filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
98
0644);
99
if (fd < 0) {
100
result = -errno;
101
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_create_opts(const char *filename, QemuOpts *opts,
102
goto out;
103
}
104
105
- if (nocow) {
106
+ if (file_opts->nocow) {
107
#ifdef __linux__
108
/* Set NOCOW flag to solve performance issue on fs like btrfs.
109
* This is an optimisation. The FS_IOC_SETFLAGS ioctl return value
110
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_create_opts(const char *filename, QemuOpts *opts,
111
#endif
112
}
113
114
- result = raw_regular_truncate(fd, total_size, prealloc, errp);
115
+ result = raw_regular_truncate(fd, file_opts->size, file_opts->preallocation,
116
+ errp);
117
if (result < 0) {
118
goto out_close;
119
}
120
@@ -XXX,XX +XXX,XX @@ out:
121
return result;
122
}
38
}
123
39
124
+static int coroutine_fn raw_co_create_opts(const char *filename, QemuOpts *opts,
40
-static void bdrv_parent_cb_resize(BlockDriverState *bs)
125
+ Error **errp)
41
+static void coroutine_fn GRAPH_RDLOCK
126
+{
42
+bdrv_parent_cb_resize(BlockDriverState *bs)
127
+ BlockdevCreateOptions options;
43
{
128
+ int64_t total_size = 0;
44
BdrvChild *c;
129
+ bool nocow = false;
130
+ PreallocMode prealloc;
131
+ char *buf = NULL;
132
+ Error *local_err = NULL;
133
+
45
+
134
+ /* Skip file: protocol prefix */
46
+ assert_bdrv_graph_readable();
135
+ strstart(filename, "file:", &filename);
136
+
47
+
137
+ /* Read out options */
48
QLIST_FOREACH(c, &bs->parents, next_parent) {
138
+ total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
49
if (c->klass->resize) {
139
+ BDRV_SECTOR_SIZE);
50
c->klass->resize(c);
140
+ nocow = qemu_opt_get_bool(opts, BLOCK_OPT_NOCOW, false);
141
+ buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
142
+ prealloc = qapi_enum_parse(&PreallocMode_lookup, buf,
143
+ PREALLOC_MODE_OFF, &local_err);
144
+ g_free(buf);
145
+ if (local_err) {
146
+ error_propagate(errp, local_err);
147
+ return -EINVAL;
148
+ }
149
+
150
+ options = (BlockdevCreateOptions) {
151
+ .driver = BLOCKDEV_DRIVER_FILE,
152
+ .u.file = {
153
+ .filename = (char *) filename,
154
+ .size = total_size,
155
+ .has_preallocation = true,
156
+ .preallocation = prealloc,
157
+ .has_nocow = true,
158
+ .nocow = nocow,
159
+ },
160
+ };
161
+ return raw_co_create(&options, errp);
162
+}
163
+
164
/*
165
* Find allocation range in @bs around offset @start.
166
* May change underlying file descriptor's file offset.
167
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_file = {
168
.bdrv_reopen_commit = raw_reopen_commit,
169
.bdrv_reopen_abort = raw_reopen_abort,
170
.bdrv_close = raw_close,
171
+ .bdrv_co_create = raw_co_create,
172
.bdrv_co_create_opts = raw_co_create_opts,
173
.bdrv_has_zero_init = bdrv_has_zero_init_1,
174
.bdrv_co_block_status = raw_co_block_status,
175
--
51
--
176
2.13.6
52
2.41.0
177
178
diff view generated by jsdifflib
1
All of the simple options are now passed to qcow2_co_create() in a
1
This adds GRAPH_RDLOCK annotations to declare that callers of
2
BlockdevCreateOptions object. Still missing: node-name and the
2
bdrv_snapshot_fallback() need to hold a reader lock for the graph
3
encryption options.
3
because it accesses the children list of a node.
4
4
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Message-ID: <20230929145157.45443-8-kwolf@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
9
---
9
block/qcow2.c | 189 ++++++++++++++++++++++++++++++++++++++++++++++------------
10
include/block/block_int-common.h | 18 ++++++++--------
10
1 file changed, 151 insertions(+), 38 deletions(-)
11
include/block/snapshot.h | 24 +++++++++++++---------
12
block/snapshot.c | 35 ++++++++++++++++++++++++++------
13
blockdev.c | 9 ++++++++
14
qemu-img.c | 5 +++++
15
5 files changed, 67 insertions(+), 24 deletions(-)
11
16
12
diff --git a/block/qcow2.c b/block/qcow2.c
17
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
13
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
14
--- a/block/qcow2.c
19
--- a/include/block/block_int-common.h
15
+++ b/block/qcow2.c
20
+++ b/include/block/block_int-common.h
16
@@ -XXX,XX +XXX,XX @@ static int64_t qcow2_calc_prealloc_size(int64_t total_size,
21
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
17
return meta_size + aligned_total_size;
22
23
int GRAPH_RDLOCK_PTR (*bdrv_inactivate)(BlockDriverState *bs);
24
25
- int (*bdrv_snapshot_create)(BlockDriverState *bs,
26
- QEMUSnapshotInfo *sn_info);
27
- int (*bdrv_snapshot_goto)(BlockDriverState *bs,
28
- const char *snapshot_id);
29
- int (*bdrv_snapshot_delete)(BlockDriverState *bs,
30
- const char *snapshot_id,
31
- const char *name,
32
- Error **errp);
33
+ int GRAPH_RDLOCK_PTR (*bdrv_snapshot_create)(
34
+ BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
35
+
36
+ int GRAPH_UNLOCKED_PTR (*bdrv_snapshot_goto)(
37
+ BlockDriverState *bs, const char *snapshot_id);
38
+
39
+ int GRAPH_RDLOCK_PTR (*bdrv_snapshot_delete)(
40
+ BlockDriverState *bs, const char *snapshot_id, const char *name,
41
+ Error **errp);
42
+
43
int (*bdrv_snapshot_list)(BlockDriverState *bs,
44
QEMUSnapshotInfo **psn_info);
45
int (*bdrv_snapshot_load_tmp)(BlockDriverState *bs,
46
diff --git a/include/block/snapshot.h b/include/block/snapshot.h
47
index XXXXXXX..XXXXXXX 100644
48
--- a/include/block/snapshot.h
49
+++ b/include/block/snapshot.h
50
@@ -XXX,XX +XXX,XX @@
51
#ifndef SNAPSHOT_H
52
#define SNAPSHOT_H
53
54
+#include "block/graph-lock.h"
55
#include "qapi/qapi-builtin-types.h"
56
57
#define SNAPSHOT_OPT_BASE "snapshot."
58
@@ -XXX,XX +XXX,XX @@ bool bdrv_snapshot_find_by_id_and_name(BlockDriverState *bs,
59
const char *name,
60
QEMUSnapshotInfo *sn_info,
61
Error **errp);
62
-int bdrv_can_snapshot(BlockDriverState *bs);
63
-int bdrv_snapshot_create(BlockDriverState *bs,
64
- QEMUSnapshotInfo *sn_info);
65
-int bdrv_snapshot_goto(BlockDriverState *bs,
66
- const char *snapshot_id,
67
- Error **errp);
68
-int bdrv_snapshot_delete(BlockDriverState *bs,
69
- const char *snapshot_id,
70
- const char *name,
71
- Error **errp);
72
+
73
+int GRAPH_RDLOCK bdrv_can_snapshot(BlockDriverState *bs);
74
+
75
+int GRAPH_RDLOCK
76
+bdrv_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
77
+
78
+int GRAPH_UNLOCKED
79
+bdrv_snapshot_goto(BlockDriverState *bs, const char *snapshot_id, Error **errp);
80
+
81
+int GRAPH_RDLOCK
82
+bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id,
83
+ const char *name, Error **errp);
84
+
85
int bdrv_snapshot_list(BlockDriverState *bs,
86
QEMUSnapshotInfo **psn_info);
87
int bdrv_snapshot_load_tmp(BlockDriverState *bs,
88
diff --git a/block/snapshot.c b/block/snapshot.c
89
index XXXXXXX..XXXXXXX 100644
90
--- a/block/snapshot.c
91
+++ b/block/snapshot.c
92
@@ -XXX,XX +XXX,XX @@ bool bdrv_snapshot_find_by_id_and_name(BlockDriverState *bs,
93
* back if the given BDS does not support snapshots.
94
* Return NULL if there is no BDS to (safely) fall back to.
95
*/
96
-static BdrvChild *bdrv_snapshot_fallback_child(BlockDriverState *bs)
97
+static BdrvChild * GRAPH_RDLOCK
98
+bdrv_snapshot_fallback_child(BlockDriverState *bs)
99
{
100
BdrvChild *fallback = bdrv_primary_child(bs);
101
BdrvChild *child;
102
103
+ GLOBAL_STATE_CODE();
104
+ assert_bdrv_graph_readable();
105
+
106
/* We allow fallback only to primary child */
107
if (!fallback) {
108
return NULL;
109
@@ -XXX,XX +XXX,XX @@ static BdrvChild *bdrv_snapshot_fallback_child(BlockDriverState *bs)
110
return fallback;
18
}
111
}
19
112
20
-static size_t qcow2_opt_get_cluster_size_del(QemuOpts *opts, Error **errp)
113
-static BlockDriverState *bdrv_snapshot_fallback(BlockDriverState *bs)
21
+static bool validate_cluster_size(size_t cluster_size, Error **errp)
114
+static BlockDriverState * GRAPH_RDLOCK
22
{
115
+bdrv_snapshot_fallback(BlockDriverState *bs)
23
- size_t cluster_size;
116
{
24
- int cluster_bits;
117
+ GLOBAL_STATE_CODE();
25
-
118
return child_bs(bdrv_snapshot_fallback_child(bs));
26
- cluster_size = qemu_opt_get_size_del(opts, BLOCK_OPT_CLUSTER_SIZE,
27
- DEFAULT_CLUSTER_SIZE);
28
- cluster_bits = ctz32(cluster_size);
29
+ int cluster_bits = ctz32(cluster_size);
30
if (cluster_bits < MIN_CLUSTER_BITS || cluster_bits > MAX_CLUSTER_BITS ||
31
(1 << cluster_bits) != cluster_size)
32
{
33
error_setg(errp, "Cluster size must be a power of two between %d and "
34
"%dk", 1 << MIN_CLUSTER_BITS, 1 << (MAX_CLUSTER_BITS - 10));
35
+ return false;
36
+ }
37
+ return true;
38
+}
39
+
40
+static size_t qcow2_opt_get_cluster_size_del(QemuOpts *opts, Error **errp)
41
+{
42
+ size_t cluster_size;
43
+
44
+ cluster_size = qemu_opt_get_size_del(opts, BLOCK_OPT_CLUSTER_SIZE,
45
+ DEFAULT_CLUSTER_SIZE);
46
+ if (!validate_cluster_size(cluster_size, errp)) {
47
return 0;
48
}
49
return cluster_size;
50
@@ -XXX,XX +XXX,XX @@ static uint64_t qcow2_opt_get_refcount_bits_del(QemuOpts *opts, int version,
51
}
119
}
52
120
53
static int coroutine_fn
121
@@ -XXX,XX +XXX,XX @@ int bdrv_snapshot_goto(BlockDriverState *bs,
54
-qcow2_co_create(BlockDriverState *bs, int64_t total_size,
122
return ret;
55
- const char *backing_file, const char *backing_format,
123
}
56
- int flags, size_t cluster_size, PreallocMode prealloc,
124
57
- QemuOpts *opts, int version, int refcount_order,
125
+ bdrv_graph_rdlock_main_loop();
58
- const char *encryptfmt, Error **errp)
126
fallback = bdrv_snapshot_fallback_child(bs);
59
+qcow2_co_create(BlockDriverState *bs, BlockdevCreateOptions *create_options,
127
+ bdrv_graph_rdunlock_main_loop();
60
+ QemuOpts *opts, const char *encryptfmt, Error **errp)
128
+
61
{
129
if (fallback) {
62
+ BlockdevCreateOptionsQcow2 *qcow2_opts;
130
QDict *options;
63
QDict *options;
131
QDict *file_options;
64
132
@@ -XXX,XX +XXX,XX @@ int bdrv_snapshot_delete(BlockDriverState *bs,
65
/*
133
int bdrv_snapshot_list(BlockDriverState *bs,
66
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockDriverState *bs, int64_t total_size,
134
QEMUSnapshotInfo **psn_info)
67
*/
135
{
68
BlockBackend *blk;
136
+ GLOBAL_STATE_CODE();
69
QCowHeader *header;
137
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
70
+ size_t cluster_size;
138
+
71
+ int version;
139
BlockDriver *drv = bs->drv;
72
+ int refcount_order;
140
BlockDriverState *fallback_bs = bdrv_snapshot_fallback(bs);
73
uint64_t* refcount_table;
141
74
Error *local_err = NULL;
142
- GLOBAL_STATE_CODE();
143
if (!drv) {
144
return -ENOMEDIUM;
145
}
146
@@ -XXX,XX +XXX,XX @@ bdrv_all_get_snapshot_devices(bool has_devices, strList *devices,
147
148
static bool GRAPH_RDLOCK bdrv_all_snapshots_includes_bs(BlockDriverState *bs)
149
{
150
+ GLOBAL_STATE_CODE();
151
+ assert_bdrv_graph_readable();
152
+
153
if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) {
154
return false;
155
}
156
@@ -XXX,XX +XXX,XX @@ int bdrv_all_goto_snapshot(const char *name,
157
{
158
g_autoptr(GList) bdrvs = NULL;
159
GList *iterbdrvs;
160
+ int ret;
161
162
GLOBAL_STATE_CODE();
163
- GRAPH_RDLOCK_GUARD_MAINLOOP();
164
165
- if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) {
166
+ bdrv_graph_rdlock_main_loop();
167
+ ret = bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp);
168
+ bdrv_graph_rdunlock_main_loop();
169
+
170
+ if (ret < 0) {
171
return -1;
172
}
173
174
@@ -XXX,XX +XXX,XX @@ int bdrv_all_goto_snapshot(const char *name,
175
BlockDriverState *bs = iterbdrvs->data;
176
AioContext *ctx = bdrv_get_aio_context(bs);
177
int ret = 0;
178
+ bool all_snapshots_includes_bs;
179
180
aio_context_acquire(ctx);
181
- if (devices || bdrv_all_snapshots_includes_bs(bs)) {
182
+ bdrv_graph_rdlock_main_loop();
183
+ all_snapshots_includes_bs = bdrv_all_snapshots_includes_bs(bs);
184
+ bdrv_graph_rdunlock_main_loop();
185
+
186
+ if (devices || all_snapshots_includes_bs) {
187
ret = bdrv_snapshot_goto(bs, name, errp);
188
}
189
aio_context_release(ctx);
190
diff --git a/blockdev.c b/blockdev.c
191
index XXXXXXX..XXXXXXX 100644
192
--- a/blockdev.c
193
+++ b/blockdev.c
194
@@ -XXX,XX +XXX,XX @@ SnapshotInfo *qmp_blockdev_snapshot_delete_internal_sync(const char *device,
195
SnapshotInfo *info = NULL;
75
int ret;
196
int ret;
76
197
77
+ /* Validate options and set default values */
198
+ GLOBAL_STATE_CODE();
78
+ assert(create_options->driver == BLOCKDEV_DRIVER_QCOW2);
199
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
79
+ qcow2_opts = &create_options->u.qcow2;
200
+
80
+
201
bs = qmp_get_root_bs(device, errp);
81
+ if (!QEMU_IS_ALIGNED(qcow2_opts->size, BDRV_SECTOR_SIZE)) {
202
if (!bs) {
82
+ error_setg(errp, "Image size must be a multiple of 512 bytes");
203
return NULL;
83
+ ret = -EINVAL;
204
@@ -XXX,XX +XXX,XX @@ static void internal_snapshot_action(BlockdevSnapshotInternal *internal,
84
+ goto out;
205
AioContext *aio_context;
85
+ }
206
int ret1;
86
+
207
87
+ if (qcow2_opts->has_version) {
208
+ GLOBAL_STATE_CODE();
88
+ switch (qcow2_opts->version) {
209
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
89
+ case BLOCKDEV_QCOW2_VERSION_V2:
210
+
90
+ version = 2;
211
tran_add(tran, &internal_snapshot_drv, state);
91
+ break;
212
92
+ case BLOCKDEV_QCOW2_VERSION_V3:
213
device = internal->device;
93
+ version = 3;
214
@@ -XXX,XX +XXX,XX @@ static void internal_snapshot_abort(void *opaque)
94
+ break;
215
AioContext *aio_context;
95
+ default:
216
Error *local_error = NULL;
96
+ g_assert_not_reached();
217
97
+ }
218
+ GLOBAL_STATE_CODE();
98
+ } else {
219
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
99
+ version = 3;
220
+
100
+ }
221
if (!state->created) {
101
+
222
return;
102
+ if (qcow2_opts->has_cluster_size) {
223
}
103
+ cluster_size = qcow2_opts->cluster_size;
224
diff --git a/qemu-img.c b/qemu-img.c
104
+ } else {
225
index XXXXXXX..XXXXXXX 100644
105
+ cluster_size = DEFAULT_CLUSTER_SIZE;
226
--- a/qemu-img.c
106
+ }
227
+++ b/qemu-img.c
107
+
228
@@ -XXX,XX +XXX,XX @@ static int img_snapshot(int argc, char **argv)
108
+ if (!validate_cluster_size(cluster_size, errp)) {
229
sn.date_sec = rt / G_USEC_PER_SEC;
109
+ return -EINVAL;
230
sn.date_nsec = (rt % G_USEC_PER_SEC) * 1000;
110
+ }
231
111
+
232
+ bdrv_graph_rdlock_main_loop();
112
+ if (!qcow2_opts->has_preallocation) {
233
ret = bdrv_snapshot_create(bs, &sn);
113
+ qcow2_opts->preallocation = PREALLOC_MODE_OFF;
234
+ bdrv_graph_rdunlock_main_loop();
114
+ }
235
+
115
+ if (qcow2_opts->has_backing_file &&
236
if (ret) {
116
+ qcow2_opts->preallocation != PREALLOC_MODE_OFF)
237
error_report("Could not create snapshot '%s': %s",
117
+ {
238
snapshot_name, strerror(-ret));
118
+ error_setg(errp, "Backing file and preallocation cannot be used at "
239
@@ -XXX,XX +XXX,XX @@ static int img_snapshot(int argc, char **argv)
119
+ "the same time");
240
break;
120
+ return -EINVAL;
241
121
+ }
242
case SNAPSHOT_DELETE:
122
+ if (qcow2_opts->has_backing_fmt && !qcow2_opts->has_backing_file) {
243
+ bdrv_graph_rdlock_main_loop();
123
+ error_setg(errp, "Backing format cannot be used without backing file");
244
ret = bdrv_snapshot_find(bs, &sn, snapshot_name);
124
+ return -EINVAL;
125
+ }
126
+
127
+ if (!qcow2_opts->has_lazy_refcounts) {
128
+ qcow2_opts->lazy_refcounts = false;
129
+ }
130
+ if (version < 3 && qcow2_opts->lazy_refcounts) {
131
+ error_setg(errp, "Lazy refcounts only supported with compatibility "
132
+ "level 1.1 and above (use compat=1.1 or greater)");
133
+ return -EINVAL;
134
+ }
135
+
136
+ if (!qcow2_opts->has_refcount_bits) {
137
+ qcow2_opts->refcount_bits = 16;
138
+ }
139
+ if (qcow2_opts->refcount_bits > 64 ||
140
+ !is_power_of_2(qcow2_opts->refcount_bits))
141
+ {
142
+ error_setg(errp, "Refcount width must be a power of two and may not "
143
+ "exceed 64 bits");
144
+ return -EINVAL;
145
+ }
146
+ if (version < 3 && qcow2_opts->refcount_bits != 16) {
147
+ error_setg(errp, "Different refcount widths than 16 bits require "
148
+ "compatibility level 1.1 or above (use compat=1.1 or "
149
+ "greater)");
150
+ return -EINVAL;
151
+ }
152
+ refcount_order = ctz32(qcow2_opts->refcount_bits);
153
+
154
+
155
+ /* Create BlockBackend to write to the image */
156
blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
157
ret = blk_insert_bs(blk, bs, errp);
158
if (ret < 0) {
159
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockDriverState *bs, int64_t total_size,
160
/* We'll update this to correct value later */
161
header->crypt_method = cpu_to_be32(QCOW_CRYPT_NONE);
162
163
- if (flags & BLOCK_FLAG_LAZY_REFCOUNTS) {
164
+ if (qcow2_opts->lazy_refcounts) {
165
header->compatible_features |=
166
cpu_to_be64(QCOW2_COMPAT_LAZY_REFCOUNTS);
167
}
168
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockDriverState *bs, int64_t total_size,
169
}
170
171
/* Okay, now that we have a valid image, let's give it the right size */
172
- ret = blk_truncate(blk, total_size, PREALLOC_MODE_OFF, errp);
173
+ ret = blk_truncate(blk, qcow2_opts->size, PREALLOC_MODE_OFF, errp);
174
if (ret < 0) {
175
error_prepend(errp, "Could not resize image: ");
176
goto out;
177
}
178
179
/* Want a backing file? There you go.*/
180
- if (backing_file) {
181
- ret = bdrv_change_backing_file(blk_bs(blk), backing_file, backing_format);
182
+ if (qcow2_opts->has_backing_file) {
183
+ const char *backing_format = NULL;
184
+
185
+ if (qcow2_opts->has_backing_fmt) {
186
+ backing_format = BlockdevDriver_str(qcow2_opts->backing_fmt);
187
+ }
188
+
189
+ ret = bdrv_change_backing_file(blk_bs(blk), qcow2_opts->backing_file,
190
+ backing_format);
191
if (ret < 0) {
245
if (ret < 0) {
192
error_setg_errno(errp, -ret, "Could not assign backing file '%s' "
246
error_report("Could not delete snapshot '%s': snapshot not "
193
- "with format '%s'", backing_file, backing_format);
247
@@ -XXX,XX +XXX,XX @@ static int img_snapshot(int argc, char **argv)
194
+ "with format '%s'", qcow2_opts->backing_file,
248
ret = 1;
195
+ backing_format);
249
}
196
goto out;
197
}
250
}
198
}
251
+ bdrv_graph_rdunlock_main_loop();
199
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockDriverState *bs, int64_t total_size,
252
break;
200
}
253
}
201
254
202
/* And if we're supposed to preallocate metadata, do that now */
203
- if (prealloc != PREALLOC_MODE_OFF) {
204
- ret = preallocate(blk_bs(blk), 0, total_size);
205
+ if (qcow2_opts->preallocation != PREALLOC_MODE_OFF) {
206
+ ret = preallocate(blk_bs(blk), 0, qcow2_opts->size);
207
if (ret < 0) {
208
error_setg_errno(errp, -ret, "Could not preallocate metadata");
209
goto out;
210
@@ -XXX,XX +XXX,XX @@ out:
211
static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opts,
212
Error **errp)
213
{
214
+ BlockdevCreateOptions create_options;
215
char *backing_file = NULL;
216
char *backing_fmt = NULL;
217
+ BlockdevDriver backing_drv;
218
char *buf = NULL;
219
uint64_t size = 0;
220
int flags = 0;
221
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
222
PreallocMode prealloc;
223
int version;
224
uint64_t refcount_bits;
225
- int refcount_order;
226
char *encryptfmt = NULL;
227
BlockDriverState *bs = NULL;
228
Error *local_err = NULL;
229
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
230
BDRV_SECTOR_SIZE);
231
backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
232
backing_fmt = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FMT);
233
+ backing_drv = qapi_enum_parse(&BlockdevDriver_lookup, backing_fmt,
234
+ 0, &local_err);
235
+ if (local_err) {
236
+ error_propagate(errp, local_err);
237
+ ret = -EINVAL;
238
+ goto finish;
239
+ }
240
encryptfmt = qemu_opt_get_del(opts, BLOCK_OPT_ENCRYPT_FORMAT);
241
if (encryptfmt) {
242
if (qemu_opt_get(opts, BLOCK_OPT_ENCRYPT)) {
243
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
244
flags |= BLOCK_FLAG_LAZY_REFCOUNTS;
245
}
246
247
- if (backing_file && prealloc != PREALLOC_MODE_OFF) {
248
- error_setg(errp, "Backing file and preallocation cannot be used at "
249
- "the same time");
250
- ret = -EINVAL;
251
- goto finish;
252
- }
253
-
254
- if (version < 3 && (flags & BLOCK_FLAG_LAZY_REFCOUNTS)) {
255
- error_setg(errp, "Lazy refcounts only supported with compatibility "
256
- "level 1.1 and above (use compat=1.1 or greater)");
257
- ret = -EINVAL;
258
- goto finish;
259
- }
260
-
261
refcount_bits = qcow2_opt_get_refcount_bits_del(opts, version, &local_err);
262
if (local_err) {
263
error_propagate(errp, local_err);
264
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
265
goto finish;
266
}
267
268
- refcount_order = ctz32(refcount_bits);
269
270
/* Create and open the file (protocol layer) */
271
if (prealloc == PREALLOC_MODE_FULL || prealloc == PREALLOC_MODE_FALLOC) {
272
+ int refcount_order = ctz32(refcount_bits);
273
int64_t prealloc_size =
274
qcow2_calc_prealloc_size(size, cluster_size, refcount_order);
275
qemu_opt_set_number(opts, BLOCK_OPT_SIZE, prealloc_size, &error_abort);
276
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
277
}
278
279
/* Create the qcow2 image (format layer) */
280
- ret = qcow2_co_create(bs, size, backing_file, backing_fmt, flags,
281
- cluster_size, prealloc, opts, version, refcount_order,
282
- encryptfmt, errp);
283
+ create_options = (BlockdevCreateOptions) {
284
+ .driver = BLOCKDEV_DRIVER_QCOW2,
285
+ .u.qcow2 = {
286
+ .file = &(BlockdevRef) {
287
+ .type = QTYPE_QSTRING,
288
+ .u.reference = bs->node_name,
289
+ },
290
+ .size = size,
291
+ .has_version = true,
292
+ .version = version == 2
293
+ ? BLOCKDEV_QCOW2_VERSION_V2
294
+ : BLOCKDEV_QCOW2_VERSION_V3,
295
+ .has_backing_file = (backing_file != NULL),
296
+ .backing_file = backing_file,
297
+ .has_backing_fmt = (backing_fmt != NULL),
298
+ .backing_fmt = backing_drv,
299
+ .has_cluster_size = true,
300
+ .cluster_size = cluster_size,
301
+ .has_preallocation = true,
302
+ .preallocation = prealloc,
303
+ .has_lazy_refcounts = true,
304
+ .lazy_refcounts = (flags & BLOCK_FLAG_LAZY_REFCOUNTS),
305
+ .has_refcount_bits = true,
306
+ .refcount_bits = refcount_bits,
307
+ },
308
+ };
309
+ ret = qcow2_co_create(bs, &create_options, opts, encryptfmt, errp);
310
if (ret < 0) {
311
goto finish;
312
}
313
--
255
--
314
2.13.6
256
2.41.0
315
316
diff view generated by jsdifflib
1
We'll use a separate source file for image creation, and we need to
1
Reopen isn't easy with respect to locking because many of its functions
2
check there whether the requested driver is whitelisted.
2
need to iterate the graph, some change it, and then you get some drains
3
in the middle where you can't hold any locks.
4
5
Therefore just documents most of the functions to be unlocked, and take
6
locks internally before accessing the graph.
3
7
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Message-ID: <20230929145157.45443-9-kwolf@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
12
---
8
include/block/block.h | 1 +
13
include/block/block_int-common.h | 13 +++++---
9
block.c | 2 +-
14
block.c | 57 ++++++++++++++++++++------------
10
2 files changed, 2 insertions(+), 1 deletion(-)
15
2 files changed, 43 insertions(+), 27 deletions(-)
11
16
12
diff --git a/include/block/block.h b/include/block/block.h
17
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
13
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
14
--- a/include/block/block.h
19
--- a/include/block/block_int-common.h
15
+++ b/include/block/block.h
20
+++ b/include/block/block_int-common.h
16
@@ -XXX,XX +XXX,XX @@ char *bdrv_perm_names(uint64_t perm);
21
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
17
void bdrv_init(void);
18
void bdrv_init_with_whitelist(void);
19
bool bdrv_uses_whitelist(void);
20
+int bdrv_is_whitelisted(BlockDriver *drv, bool read_only);
21
BlockDriver *bdrv_find_protocol(const char *filename,
22
bool allow_protocol_prefix,
23
Error **errp);
22
Error **errp);
23
24
/* For handling image reopen for split or non-split files. */
25
- int (*bdrv_reopen_prepare)(BDRVReopenState *reopen_state,
26
- BlockReopenQueue *queue, Error **errp);
27
- void (*bdrv_reopen_commit)(BDRVReopenState *reopen_state);
28
- void (*bdrv_reopen_commit_post)(BDRVReopenState *reopen_state);
29
- void (*bdrv_reopen_abort)(BDRVReopenState *reopen_state);
30
+ int GRAPH_UNLOCKED_PTR (*bdrv_reopen_prepare)(
31
+ BDRVReopenState *reopen_state, BlockReopenQueue *queue, Error **errp);
32
+ void GRAPH_UNLOCKED_PTR (*bdrv_reopen_commit)(
33
+ BDRVReopenState *reopen_state);
34
+ void GRAPH_UNLOCKED_PTR (*bdrv_reopen_commit_post)(
35
+ BDRVReopenState *reopen_state);
36
+ void GRAPH_UNLOCKED_PTR (*bdrv_reopen_abort)(
37
+ BDRVReopenState *reopen_state);
38
void (*bdrv_join_options)(QDict *options, QDict *old_options);
39
40
int GRAPH_UNLOCKED_PTR (*bdrv_open)(
24
diff --git a/block.c b/block.c
41
diff --git a/block.c b/block.c
25
index XXXXXXX..XXXXXXX 100644
42
index XXXXXXX..XXXXXXX 100644
26
--- a/block.c
43
--- a/block.c
27
+++ b/block.c
44
+++ b/block.c
28
@@ -XXX,XX +XXX,XX @@ BlockDriver *bdrv_find_format(const char *format_name)
45
@@ -XXX,XX +XXX,XX @@ static int bdrv_reset_options_allowed(BlockDriverState *bs,
29
return bdrv_do_find_format(format_name);
46
/*
47
* Returns true if @child can be reached recursively from @bs
48
*/
49
-static bool bdrv_recurse_has_child(BlockDriverState *bs,
50
- BlockDriverState *child)
51
+static bool GRAPH_RDLOCK
52
+bdrv_recurse_has_child(BlockDriverState *bs, BlockDriverState *child)
53
{
54
BdrvChild *c;
55
56
@@ -XXX,XX +XXX,XX @@ static bool bdrv_recurse_has_child(BlockDriverState *bs,
57
*
58
* To be called with bs->aio_context locked.
59
*/
60
-static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
61
- BlockDriverState *bs,
62
- QDict *options,
63
- const BdrvChildClass *klass,
64
- BdrvChildRole role,
65
- bool parent_is_format,
66
- QDict *parent_options,
67
- int parent_flags,
68
- bool keep_old_opts)
69
+static BlockReopenQueue * GRAPH_RDLOCK
70
+bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, BlockDriverState *bs,
71
+ QDict *options, const BdrvChildClass *klass,
72
+ BdrvChildRole role, bool parent_is_format,
73
+ QDict *parent_options, int parent_flags,
74
+ bool keep_old_opts)
75
{
76
assert(bs != NULL);
77
78
@@ -XXX,XX +XXX,XX @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
79
80
GLOBAL_STATE_CODE();
81
82
+ /*
83
+ * Strictly speaking, draining is illegal under GRAPH_RDLOCK. We know that
84
+ * we've been called with bdrv_graph_rdlock_main_loop(), though, so it's ok
85
+ * in practice.
86
+ */
87
bdrv_drained_begin(bs);
88
89
if (bs_queue == NULL) {
90
@@ -XXX,XX +XXX,XX @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
91
QDict *options, bool keep_old_opts)
92
{
93
GLOBAL_STATE_CODE();
94
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
95
96
return bdrv_reopen_queue_child(bs_queue, bs, options, NULL, 0, false,
97
NULL, 0, keep_old_opts);
98
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only,
99
* Callers must make sure that their AioContext locking is still correct after
100
* this.
101
*/
102
-static int bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
103
- bool is_backing, Transaction *tran,
104
- Error **errp)
105
+static int GRAPH_UNLOCKED
106
+bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
107
+ bool is_backing, Transaction *tran,
108
+ Error **errp)
109
{
110
BlockDriverState *bs = reopen_state->bs;
111
BlockDriverState *new_child_bs;
112
@@ -XXX,XX +XXX,XX @@ static int bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
113
QObject *value;
114
const char *str;
115
AioContext *ctx, *old_ctx;
116
+ bool has_child;
117
int ret;
118
119
GLOBAL_STATE_CODE();
120
@@ -XXX,XX +XXX,XX @@ static int bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
121
new_child_bs = bdrv_lookup_bs(NULL, str, errp);
122
if (new_child_bs == NULL) {
123
return -EINVAL;
124
- } else if (bdrv_recurse_has_child(new_child_bs, bs)) {
125
+ }
126
+
127
+ bdrv_graph_rdlock_main_loop();
128
+ has_child = bdrv_recurse_has_child(new_child_bs, bs);
129
+ bdrv_graph_rdunlock_main_loop();
130
+
131
+ if (has_child) {
132
error_setg(errp, "Making '%s' a %s child of '%s' would create a "
133
"cycle", str, child_name, bs->node_name);
134
return -EINVAL;
135
@@ -XXX,XX +XXX,XX @@ static int bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
136
* After calling this function, the transaction @change_child_tran may only be
137
* completed while holding a writer lock for the graph.
138
*/
139
-static int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
140
- BlockReopenQueue *queue,
141
- Transaction *change_child_tran, Error **errp)
142
+static int GRAPH_UNLOCKED
143
+bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
144
+ Transaction *change_child_tran, Error **errp)
145
{
146
int ret = -1;
147
int old_flags;
148
@@ -XXX,XX +XXX,XX @@ static int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
149
if (qdict_size(reopen_state->options)) {
150
const QDictEntry *entry = qdict_first(reopen_state->options);
151
152
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
153
+
154
do {
155
QObject *new = entry->value;
156
QObject *old = qdict_get(reopen_state->bs->options, entry->key);
157
@@ -XXX,XX +XXX,XX @@ error:
158
* makes them final by swapping the staging BlockDriverState contents into
159
* the active BlockDriverState contents.
160
*/
161
-static void bdrv_reopen_commit(BDRVReopenState *reopen_state)
162
+static void GRAPH_UNLOCKED bdrv_reopen_commit(BDRVReopenState *reopen_state)
163
{
164
BlockDriver *drv;
165
BlockDriverState *bs;
166
@@ -XXX,XX +XXX,XX @@ static void bdrv_reopen_commit(BDRVReopenState *reopen_state)
167
drv->bdrv_reopen_commit(reopen_state);
168
}
169
170
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
171
+
172
/* set BDS specific flags now */
173
qobject_unref(bs->explicit_options);
174
qobject_unref(bs->options);
175
@@ -XXX,XX +XXX,XX @@ static void bdrv_reopen_commit(BDRVReopenState *reopen_state)
176
qdict_del(bs->explicit_options, "backing");
177
qdict_del(bs->options, "backing");
178
179
- bdrv_graph_rdlock_main_loop();
180
bdrv_refresh_limits(bs, NULL, NULL);
181
- bdrv_graph_rdunlock_main_loop();
182
bdrv_refresh_total_sectors(bs, bs->total_sectors);
30
}
183
}
31
184
32
-static int bdrv_is_whitelisted(BlockDriver *drv, bool read_only)
185
@@ -XXX,XX +XXX,XX @@ static void bdrv_reopen_commit(BDRVReopenState *reopen_state)
33
+int bdrv_is_whitelisted(BlockDriver *drv, bool read_only)
186
* Abort the reopen, and delete and free the staged changes in
187
* reopen_state
188
*/
189
-static void bdrv_reopen_abort(BDRVReopenState *reopen_state)
190
+static void GRAPH_UNLOCKED bdrv_reopen_abort(BDRVReopenState *reopen_state)
34
{
191
{
35
static const char *whitelist_rw[] = {
192
BlockDriver *drv;
36
CONFIG_BDRV_RW_WHITELIST
193
37
--
194
--
38
2.13.6
195
2.41.0
39
40
diff view generated by jsdifflib
1
Instead of the QemuOpts in qemu_rbd_connect(), we want to use QAPI
1
This adds GRAPH_RDLOCK annotations to declare that callers of
2
objects. As a preparation, fetch those options directly from the QDict
2
bdrv_get_xdbg_block_graph() need to hold a reader lock for the graph
3
that .bdrv_open() supports in the rbd driver and that are not in the
3
because it accesses the children list of a node.
4
schema.
5
4
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Message-ID: <20230929145157.45443-10-kwolf@redhat.com>
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
9
---
9
block/rbd.c | 55 ++++++++++++++++++++++++-------------------------------
10
include/block/block-global-state.h | 2 +-
10
1 file changed, 24 insertions(+), 31 deletions(-)
11
blockdev.c | 2 ++
12
2 files changed, 3 insertions(+), 1 deletion(-)
11
13
12
diff --git a/block/rbd.c b/block/rbd.c
14
diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h
13
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
14
--- a/block/rbd.c
16
--- a/include/block/block-global-state.h
15
+++ b/block/rbd.c
17
+++ b/include/block/block-global-state.h
16
@@ -XXX,XX +XXX,XX @@ static QemuOptsList runtime_opts = {
18
@@ -XXX,XX +XXX,XX @@ int bdrv_has_zero_init_1(BlockDriverState *bs);
17
/*
19
int bdrv_has_zero_init(BlockDriverState *bs);
18
* server.* extracted manually, see qemu_rbd_mon_host()
20
BlockDriverState *bdrv_find_node(const char *node_name);
19
*/
21
BlockDeviceInfoList *bdrv_named_nodes_list(bool flat, Error **errp);
20
- {
22
-XDbgBlockGraph *bdrv_get_xdbg_block_graph(Error **errp);
21
- .name = "password-secret",
23
+XDbgBlockGraph * GRAPH_RDLOCK bdrv_get_xdbg_block_graph(Error **errp);
22
- .type = QEMU_OPT_STRING,
24
BlockDriverState *bdrv_lookup_bs(const char *device,
23
- .help = "ID of secret providing the password",
25
const char *node_name,
24
- },
26
Error **errp);
25
-
27
diff --git a/blockdev.c b/blockdev.c
26
- /*
28
index XXXXXXX..XXXXXXX 100644
27
- * Keys for qemu_rbd_parse_filename(), not in the QAPI schema
29
--- a/blockdev.c
28
- */
30
+++ b/blockdev.c
29
- {
31
@@ -XXX,XX +XXX,XX @@ BlockDeviceInfoList *qmp_query_named_block_nodes(bool has_flat,
30
- /*
32
31
- * HACK: name starts with '=' so that qemu_opts_parse()
33
XDbgBlockGraph *qmp_x_debug_query_block_graph(Error **errp)
32
- * can't set it
33
- */
34
- .name = "=keyvalue-pairs",
35
- .type = QEMU_OPT_STRING,
36
- .help = "Legacy rados key/value option parameters",
37
- },
38
- {
39
- .name = "filename",
40
- .type = QEMU_OPT_STRING,
41
- },
42
{ /* end of list */ }
43
},
44
};
45
@@ -XXX,XX +XXX,XX @@ out:
46
47
static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
48
char **s_snap, char **s_image_name,
49
- QDict *options, bool cache, Error **errp)
50
+ QDict *options, bool cache,
51
+ const char *keypairs, const char *secretid,
52
+ Error **errp)
53
{
34
{
54
QemuOpts *opts;
35
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
55
char *mon_host = NULL;
56
- const char *pool, *snap, *conf, *user, *image_name, *keypairs;
57
- const char *secretid;
58
+ const char *pool, *snap, *conf, *user, *image_name;
59
Error *local_err = NULL;
60
int r;
61
62
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
63
goto failed_opts;
64
}
65
66
- secretid = qemu_opt_get(opts, "password-secret");
67
-
68
pool = qemu_opt_get(opts, "pool");
69
conf = qemu_opt_get(opts, "conf");
70
snap = qemu_opt_get(opts, "snapshot");
71
user = qemu_opt_get(opts, "user");
72
image_name = qemu_opt_get(opts, "image");
73
- keypairs = qemu_opt_get(opts, "=keyvalue-pairs");
74
75
if (!pool || !image_name) {
76
error_setg(errp, "Parameters 'pool' and 'image' are required");
77
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
78
BDRVRBDState *s = bs->opaque;
79
Error *local_err = NULL;
80
const char *filename;
81
+ char *keypairs, *secretid;
82
int r;
83
84
/* If we are given a filename, parse the filename, with precedence given to
85
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
86
"This is an unsupported option, and may be deprecated "
87
"in the future");
88
qemu_rbd_parse_filename(filename, options, &local_err);
89
+ qdict_del(options, "filename");
90
if (local_err) {
91
error_propagate(errp, local_err);
92
return -EINVAL;
93
}
94
}
95
96
+ keypairs = g_strdup(qdict_get_try_str(options, "=keyvalue-pairs"));
97
+ if (keypairs) {
98
+ qdict_del(options, "=keyvalue-pairs");
99
+ }
100
+
36
+
101
+ secretid = g_strdup(qdict_get_try_str(options, "password-secret"));
37
return bdrv_get_xdbg_block_graph(errp);
102
+ if (secretid) {
103
+ qdict_del(options, "password-secret");
104
+ }
105
+
106
r = qemu_rbd_connect(&s->cluster, &s->io_ctx, &s->snap, &s->image_name,
107
- options, !(flags & BDRV_O_NOCACHE), errp);
108
+ options, !(flags & BDRV_O_NOCACHE), keypairs, secretid,
109
+ errp);
110
if (r < 0) {
111
- return r;
112
+ goto out;
113
}
114
115
/* rbd_open is always r/w */
116
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
117
}
118
}
119
120
- return 0;
121
+ r = 0;
122
+ goto out;
123
124
failed_open:
125
rados_ioctx_destroy(s->io_ctx);
126
g_free(s->snap);
127
g_free(s->image_name);
128
rados_shutdown(s->cluster);
129
+out:
130
+ g_free(keypairs);
131
+ g_free(secretid);
132
return r;
133
}
38
}
134
39
135
--
40
--
136
2.13.6
41
2.41.0
137
138
diff view generated by jsdifflib
1
This adds the .bdrv_co_create driver callback to nfs, which enables
1
This adds GRAPH_RDLOCK annotations to declare that callers of
2
image creation over QMP.
2
bdrv_refresh_filename() need to hold a reader lock for the graph
3
because it accesses the children list of a node.
3
4
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Message-ID: <20230929145157.45443-11-kwolf@redhat.com>
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
9
---
7
qapi/block-core.json | 16 ++++++++++-
10
block/vhdx.h | 5 +--
8
block/nfs.c | 76 +++++++++++++++++++++++++++++++++++++++++-----------
11
include/block/block-global-state.h | 9 ++++--
9
2 files changed, 75 insertions(+), 17 deletions(-)
12
include/block/block_int-common.h | 8 ++---
13
include/block/qapi.h | 16 ++++------
14
block.c | 23 +++++++++++---
15
block/nfs.c | 2 +-
16
block/qapi.c | 11 ++++---
17
block/raw-format.c | 2 ++
18
block/vhdx.c | 4 +++
19
block/vmdk.c | 51 +++++++++++++++++++-----------
20
blockdev.c | 13 ++++++++
21
qemu-img.c | 4 +++
22
12 files changed, 101 insertions(+), 47 deletions(-)
10
23
11
diff --git a/qapi/block-core.json b/qapi/block-core.json
24
diff --git a/block/vhdx.h b/block/vhdx.h
12
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
13
--- a/qapi/block-core.json
26
--- a/block/vhdx.h
14
+++ b/qapi/block-core.json
27
+++ b/block/vhdx.h
28
@@ -XXX,XX +XXX,XX @@ uint32_t vhdx_checksum_calc(uint32_t crc, uint8_t *buf, size_t size,
29
30
bool vhdx_checksum_is_valid(uint8_t *buf, size_t size, int crc_offset);
31
32
-int vhdx_parse_log(BlockDriverState *bs, BDRVVHDXState *s, bool *flushed,
33
- Error **errp);
34
+int GRAPH_RDLOCK
35
+vhdx_parse_log(BlockDriverState *bs, BDRVVHDXState *s, bool *flushed,
36
+ Error **errp);
37
38
int coroutine_fn GRAPH_RDLOCK
39
vhdx_log_write_and_flush(BlockDriverState *bs, BDRVVHDXState *s,
40
diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h
41
index XXXXXXX..XXXXXXX 100644
42
--- a/include/block/block-global-state.h
43
+++ b/include/block/block-global-state.h
44
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only,
45
Error **errp);
46
BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
47
const char *backing_file);
48
-void bdrv_refresh_filename(BlockDriverState *bs);
49
+void GRAPH_RDLOCK bdrv_refresh_filename(BlockDriverState *bs);
50
51
void GRAPH_RDLOCK
52
bdrv_refresh_limits(BlockDriverState *bs, Transaction *tran, Error **errp);
53
@@ -XXX,XX +XXX,XX @@ void bdrv_next_cleanup(BdrvNextIterator *it);
54
BlockDriverState *bdrv_next_monitor_owned(BlockDriverState *bs);
55
void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
56
void *opaque, bool read_only);
57
-char *bdrv_get_full_backing_filename(BlockDriverState *bs, Error **errp);
58
-char *bdrv_dirname(BlockDriverState *bs, Error **errp);
59
+
60
+char * GRAPH_RDLOCK
61
+bdrv_get_full_backing_filename(BlockDriverState *bs, Error **errp);
62
+
63
+char * GRAPH_RDLOCK bdrv_dirname(BlockDriverState *bs, Error **errp);
64
65
void bdrv_img_create(const char *filename, const char *fmt,
66
const char *base_filename, const char *base_fmt,
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 BlockDriver {
72
* Refreshes the bs->exact_filename field. If that is impossible,
73
* bs->exact_filename has to be left empty.
74
*/
75
- void (*bdrv_refresh_filename)(BlockDriverState *bs);
76
+ void GRAPH_RDLOCK_PTR (*bdrv_refresh_filename)(BlockDriverState *bs);
77
78
/*
79
* Gathers the open options for all children into @target.
80
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
81
* block driver which implements it is probably doing something
82
* shady regarding its runtime option structure.
83
*/
84
- void (*bdrv_gather_child_options)(BlockDriverState *bs, QDict *target,
85
- bool backing_overridden);
86
+ void GRAPH_RDLOCK_PTR (*bdrv_gather_child_options)(
87
+ BlockDriverState *bs, QDict *target, bool backing_overridden);
88
89
/*
90
* Returns an allocated string which is the directory name of this BDS: It
91
* will be used to make relative filenames absolute by prepending this
92
* function's return value to them.
93
*/
94
- char *(*bdrv_dirname)(BlockDriverState *bs, Error **errp);
95
+ char * GRAPH_RDLOCK_PTR (*bdrv_dirname)(BlockDriverState *bs, Error **errp);
96
97
/*
98
* This informs the driver that we are no longer interested in the result
99
diff --git a/include/block/qapi.h b/include/block/qapi.h
100
index XXXXXXX..XXXXXXX 100644
101
--- a/include/block/qapi.h
102
+++ b/include/block/qapi.h
15
@@ -XXX,XX +XXX,XX @@
103
@@ -XXX,XX +XXX,XX @@
16
'*preallocation': 'PreallocMode' } }
104
#include "block/snapshot.h"
17
105
#include "qapi/qapi-types-block-core.h"
18
##
106
19
+# @BlockdevCreateOptionsNfs:
107
-BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
20
+#
108
- BlockDriverState *bs,
21
+# Driver specific image creation options for NFS.
109
- bool flat,
22
+#
110
- Error **errp);
23
+# @location Where to store the new image file
111
+BlockDeviceInfo * GRAPH_RDLOCK
24
+# @size Size of the virtual disk in bytes
112
+bdrv_block_device_info(BlockBackend *blk, BlockDriverState *bs,
25
+#
113
+ bool flat, Error **errp);
26
+# Since: 2.12
114
+
27
+##
115
int bdrv_query_snapshot_info_list(BlockDriverState *bs,
28
+{ 'struct': 'BlockdevCreateOptionsNfs',
116
SnapshotInfoList **p_list,
29
+ 'data': { 'location': 'BlockdevOptionsNfs',
117
Error **errp);
30
+ 'size': 'size' } }
118
-void bdrv_query_image_info(BlockDriverState *bs,
31
+
119
- ImageInfo **p_info,
32
+##
120
- bool flat,
33
# @BlockdevQcow2Version:
121
- bool skip_implicit_filters,
34
#
122
- Error **errp);
35
# @v2: The original QCOW2 format as introduced in qemu 0.10 (version 2)
123
+void GRAPH_RDLOCK
36
@@ -XXX,XX +XXX,XX @@
124
+bdrv_query_image_info(BlockDriverState *bs, ImageInfo **p_info, bool flat,
37
'iscsi': 'BlockdevCreateNotSupported',
125
+ bool skip_implicit_filters, Error **errp);
38
'luks': 'BlockdevCreateNotSupported',
126
void GRAPH_RDLOCK
39
'nbd': 'BlockdevCreateNotSupported',
127
bdrv_query_block_graph_info(BlockDriverState *bs, BlockGraphInfo **p_info,
40
- 'nfs': 'BlockdevCreateNotSupported',
128
Error **errp);
41
+ 'nfs': 'BlockdevCreateOptionsNfs',
129
diff --git a/block.c b/block.c
42
'null-aio': 'BlockdevCreateNotSupported',
130
index XXXXXXX..XXXXXXX 100644
43
'null-co': 'BlockdevCreateNotSupported',
131
--- a/block.c
44
'nvme': 'BlockdevCreateNotSupported',
132
+++ b/block.c
133
@@ -XXX,XX +XXX,XX @@ char *bdrv_get_full_backing_filename_from_filename(const char *backed,
134
* setting @errp. In all other cases, NULL will only be returned with
135
* @errp set.
136
*/
137
-static char *bdrv_make_absolute_filename(BlockDriverState *relative_to,
138
- const char *filename, Error **errp)
139
+static char * GRAPH_RDLOCK
140
+bdrv_make_absolute_filename(BlockDriverState *relative_to,
141
+ const char *filename, Error **errp)
142
{
143
char *dir, *full_name;
144
145
@@ -XXX,XX +XXX,XX @@ static void bdrv_temp_snapshot_options(int *child_flags, QDict *child_options,
146
*child_flags &= ~BDRV_O_NATIVE_AIO;
147
}
148
149
-static void bdrv_backing_attach(BdrvChild *c)
150
+static void GRAPH_WRLOCK bdrv_backing_attach(BdrvChild *c)
151
{
152
BlockDriverState *parent = c->opaque;
153
BlockDriverState *backing_hd = c->bs;
154
@@ -XXX,XX +XXX,XX @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file,
155
}
156
157
if (file != NULL) {
158
+ bdrv_graph_rdlock_main_loop();
159
bdrv_refresh_filename(blk_bs(file));
160
+ bdrv_graph_rdunlock_main_loop();
161
+
162
filename = blk_bs(file)->filename;
163
} else {
164
/*
165
@@ -XXX,XX +XXX,XX @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
166
implicit_backing = !strcmp(bs->auto_backing_file, bs->backing_file);
167
}
168
169
+ bdrv_graph_rdlock_main_loop();
170
backing_filename = bdrv_get_full_backing_filename(bs, &local_err);
171
+ bdrv_graph_rdunlock_main_loop();
172
+
173
if (local_err) {
174
ret = -EINVAL;
175
error_propagate(errp, local_err);
176
@@ -XXX,XX +XXX,XX @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
177
}
178
179
if (implicit_backing) {
180
+ bdrv_graph_rdlock_main_loop();
181
bdrv_refresh_filename(backing_hd);
182
+ bdrv_graph_rdunlock_main_loop();
183
pstrcpy(bs->auto_backing_file, sizeof(bs->auto_backing_file),
184
backing_hd->filename);
185
}
186
@@ -XXX,XX +XXX,XX @@ bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
187
if (local_err != NULL) {
188
error_propagate(errp, local_err);
189
} else {
190
+ bdrv_graph_rdlock_main_loop();
191
bdrv_refresh_filename(reopen_state->bs);
192
+ bdrv_graph_rdunlock_main_loop();
193
error_setg(errp, "failed while preparing to reopen image '%s'",
194
reopen_state->bs->filename);
195
}
196
@@ -XXX,XX +XXX,XX @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
197
198
bdrv_ref(top);
199
bdrv_drained_begin(base);
200
+ bdrv_graph_rdlock_main_loop();
201
202
if (!top->drv || !base->drv) {
203
goto exit;
204
@@ -XXX,XX +XXX,XX @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
205
backing_file_str = base->filename;
206
}
207
208
- bdrv_graph_rdlock_main_loop();
209
QLIST_FOREACH(c, &top->parents, next_parent) {
210
updated_children = g_slist_prepend(updated_children, c);
211
}
212
- bdrv_graph_rdunlock_main_loop();
213
214
/*
215
* It seems correct to pass detach_subchain=true here, but it triggers
216
@@ -XXX,XX +XXX,XX @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
217
218
ret = 0;
219
exit:
220
+ bdrv_graph_rdunlock_main_loop();
221
bdrv_drained_end(base);
222
bdrv_unref(top);
223
return ret;
224
@@ -XXX,XX +XXX,XX @@ BlockDeviceInfoList *bdrv_named_nodes_list(bool flat,
225
BlockDriverState *bs;
226
227
GLOBAL_STATE_CODE();
228
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
229
230
list = NULL;
231
QTAILQ_FOREACH(bs, &graph_bdrv_states, node_list) {
232
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
233
BlockDriverState *bs_below;
234
235
GLOBAL_STATE_CODE();
236
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
237
238
if (!bs || !bs->drv || !backing_file) {
239
return NULL;
45
diff --git a/block/nfs.c b/block/nfs.c
240
diff --git a/block/nfs.c b/block/nfs.c
46
index XXXXXXX..XXXXXXX 100644
241
index XXXXXXX..XXXXXXX 100644
47
--- a/block/nfs.c
242
--- a/block/nfs.c
48
+++ b/block/nfs.c
243
+++ b/block/nfs.c
244
@@ -XXX,XX +XXX,XX @@ static void nfs_refresh_filename(BlockDriverState *bs)
245
}
246
}
247
248
-static char *nfs_dirname(BlockDriverState *bs, Error **errp)
249
+static char * GRAPH_RDLOCK nfs_dirname(BlockDriverState *bs, Error **errp)
250
{
251
NFSClient *client = bs->opaque;
252
253
diff --git a/block/qapi.c b/block/qapi.c
254
index XXXXXXX..XXXXXXX 100644
255
--- a/block/qapi.c
256
+++ b/block/qapi.c
257
@@ -XXX,XX +XXX,XX @@ int bdrv_query_snapshot_info_list(BlockDriverState *bs,
258
* Helper function for other query info functions. Store information about @bs
259
* in @info, setting @errp on error.
260
*/
261
-static void bdrv_do_query_node_info(BlockDriverState *bs,
262
- BlockNodeInfo *info,
263
- Error **errp)
264
+static void GRAPH_RDLOCK
265
+bdrv_do_query_node_info(BlockDriverState *bs, BlockNodeInfo *info, Error **errp)
266
{
267
int64_t size;
268
const char *backing_filename;
269
@@ -XXX,XX +XXX,XX @@ fail:
270
}
271
272
/* @p_info will be set only on success. */
273
-static void bdrv_query_info(BlockBackend *blk, BlockInfo **p_info,
274
- Error **errp)
275
+static void GRAPH_RDLOCK
276
+bdrv_query_info(BlockBackend *blk, BlockInfo **p_info, Error **errp)
277
{
278
BlockInfo *info = g_malloc0(sizeof(*info));
279
BlockDriverState *bs = blk_bs(blk);
280
@@ -XXX,XX +XXX,XX @@ BlockInfoList *qmp_query_block(Error **errp)
281
BlockBackend *blk;
282
Error *local_err = NULL;
283
284
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
285
+
286
for (blk = blk_all_next(NULL); blk; blk = blk_all_next(blk)) {
287
BlockInfoList *info;
288
289
diff --git a/block/raw-format.c b/block/raw-format.c
290
index XXXXXXX..XXXXXXX 100644
291
--- a/block/raw-format.c
292
+++ b/block/raw-format.c
293
@@ -XXX,XX +XXX,XX @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
294
BDRV_REQ_ZERO_WRITE;
295
296
if (bs->probed && !bdrv_is_read_only(bs)) {
297
+ bdrv_graph_rdlock_main_loop();
298
bdrv_refresh_filename(bs->file->bs);
299
+ bdrv_graph_rdunlock_main_loop();
300
fprintf(stderr,
301
"WARNING: Image format was not specified for '%s' and probing "
302
"guessed raw.\n"
303
diff --git a/block/vhdx.c b/block/vhdx.c
304
index XXXXXXX..XXXXXXX 100644
305
--- a/block/vhdx.c
306
+++ b/block/vhdx.c
307
@@ -XXX,XX +XXX,XX @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags,
308
uint64_t signature;
309
Error *local_err = NULL;
310
311
+ GLOBAL_STATE_CODE();
312
+
313
ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
314
if (ret < 0) {
315
return ret;
316
}
317
318
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
319
+
320
s->bat = NULL;
321
s->first_visible_write = true;
322
323
diff --git a/block/vmdk.c b/block/vmdk.c
324
index XXXXXXX..XXXXXXX 100644
325
--- a/block/vmdk.c
326
+++ b/block/vmdk.c
327
@@ -XXX,XX +XXX,XX @@ static int vmdk_add_extent(BlockDriverState *bs,
328
return 0;
329
}
330
331
-static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent,
332
- Error **errp)
333
+static int GRAPH_RDLOCK
334
+vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent, Error **errp)
335
{
336
int ret;
337
size_t l1_size;
338
@@ -XXX,XX +XXX,XX @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent,
339
return ret;
340
}
341
342
-static int vmdk_open_vmfs_sparse(BlockDriverState *bs,
343
- BdrvChild *file,
344
- int flags, Error **errp)
345
+static int GRAPH_RDLOCK
346
+vmdk_open_vmfs_sparse(BlockDriverState *bs, BdrvChild *file, int flags,
347
+ Error **errp)
348
{
349
int ret;
350
uint32_t magic;
351
@@ -XXX,XX +XXX,XX @@ static int check_se_sparse_volatile_header(VMDKSESparseVolatileHeader *header,
352
return 0;
353
}
354
355
-static int vmdk_open_se_sparse(BlockDriverState *bs,
356
- BdrvChild *file,
357
- int flags, Error **errp)
358
+static int GRAPH_RDLOCK
359
+vmdk_open_se_sparse(BlockDriverState *bs, BdrvChild *file, int flags,
360
+ Error **errp)
361
{
362
int ret;
363
VMDKSESparseConstHeader const_header;
364
@@ -XXX,XX +XXX,XX @@ static char *vmdk_read_desc(BdrvChild *file, uint64_t desc_offset, Error **errp)
365
return buf;
366
}
367
368
-static int vmdk_open_vmdk4(BlockDriverState *bs,
369
- BdrvChild *file,
370
- int flags, QDict *options, Error **errp)
371
+static int GRAPH_RDLOCK
372
+vmdk_open_vmdk4(BlockDriverState *bs, BdrvChild *file, int flags,
373
+ QDict *options, Error **errp)
374
{
375
int ret;
376
uint32_t magic;
377
@@ -XXX,XX +XXX,XX @@ static int vmdk_parse_description(const char *desc, const char *opt_name,
378
}
379
380
/* Open an extent file and append to bs array */
381
-static int vmdk_open_sparse(BlockDriverState *bs, BdrvChild *file, int flags,
382
- char *buf, QDict *options, Error **errp)
383
+static int GRAPH_RDLOCK
384
+vmdk_open_sparse(BlockDriverState *bs, BdrvChild *file, int flags,
385
+ char *buf, QDict *options, Error **errp)
386
{
387
uint32_t magic;
388
389
@@ -XXX,XX +XXX,XX @@ static const char *next_line(const char *s)
390
return s;
391
}
392
393
-static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
394
- QDict *options, Error **errp)
395
+static int GRAPH_RDLOCK
396
+vmdk_parse_extents(const char *desc, BlockDriverState *bs, QDict *options,
397
+ Error **errp)
398
{
399
int ret;
400
int matches;
401
@@ -XXX,XX +XXX,XX @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
402
char extent_opt_prefix[32];
403
Error *local_err = NULL;
404
405
+ GLOBAL_STATE_CODE();
406
+
407
for (p = desc; *p; p = next_line(p)) {
408
/* parse extent line in one of below formats:
409
*
410
@@ -XXX,XX +XXX,XX @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
411
ret = vmdk_add_extent(bs, extent_file, true, sectors,
412
0, 0, 0, 0, 0, &extent, errp);
413
if (ret < 0) {
414
+ bdrv_graph_rdunlock_main_loop();
415
bdrv_graph_wrlock(NULL);
416
bdrv_unref_child(bs, extent_file);
417
bdrv_graph_wrunlock();
418
+ bdrv_graph_rdlock_main_loop();
419
goto out;
420
}
421
extent->flat_start_offset = flat_offset << 9;
422
@@ -XXX,XX +XXX,XX @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
423
}
424
g_free(buf);
425
if (ret) {
426
+ bdrv_graph_rdunlock_main_loop();
427
bdrv_graph_wrlock(NULL);
428
bdrv_unref_child(bs, extent_file);
429
bdrv_graph_wrunlock();
430
+ bdrv_graph_rdlock_main_loop();
431
goto out;
432
}
433
extent = &s->extents[s->num_extents - 1];
434
} else if (!strcmp(type, "SESPARSE")) {
435
ret = vmdk_open_se_sparse(bs, extent_file, bs->open_flags, errp);
436
if (ret) {
437
+ bdrv_graph_rdunlock_main_loop();
438
bdrv_graph_wrlock(NULL);
439
bdrv_unref_child(bs, extent_file);
440
bdrv_graph_wrunlock();
441
+ bdrv_graph_rdlock_main_loop();
442
goto out;
443
}
444
extent = &s->extents[s->num_extents - 1];
445
} else {
446
error_setg(errp, "Unsupported extent type '%s'", type);
447
+ bdrv_graph_rdunlock_main_loop();
448
bdrv_graph_wrlock(NULL);
449
bdrv_unref_child(bs, extent_file);
450
bdrv_graph_wrunlock();
451
+ bdrv_graph_rdlock_main_loop();
452
ret = -ENOTSUP;
453
goto out;
454
}
49
@@ -XXX,XX +XXX,XX @@ out:
455
@@ -XXX,XX +XXX,XX @@ out:
50
return ret;
456
return ret;
51
}
457
}
52
458
53
-static int64_t nfs_client_open_qdict(NFSClient *client, QDict *options,
459
-static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf,
54
- int flags, int open_flags, Error **errp)
460
- QDict *options, Error **errp)
55
+static BlockdevOptionsNfs *nfs_options_qdict_to_qapi(QDict *options,
461
+static int GRAPH_RDLOCK
56
+ Error **errp)
462
+vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf, QDict *options,
57
{
463
+ Error **errp)
58
BlockdevOptionsNfs *opts = NULL;
464
{
59
QObject *crumpled = NULL;
465
int ret;
60
Visitor *v;
466
char ct[128];
467
@@ -XXX,XX +XXX,XX @@ static int vmdk_has_zero_init(BlockDriverState *bs)
468
return 1;
469
}
470
471
-static VmdkExtentInfo *vmdk_get_extent_info(VmdkExtent *extent)
472
+static VmdkExtentInfo * GRAPH_RDLOCK vmdk_get_extent_info(VmdkExtent *extent)
473
{
474
VmdkExtentInfo *info = g_new0(VmdkExtentInfo, 1);
475
476
@@ -XXX,XX +XXX,XX @@ static ImageInfoSpecific *vmdk_get_specific_info(BlockDriverState *bs,
477
ImageInfoSpecific *spec_info = g_new0(ImageInfoSpecific, 1);
478
VmdkExtentInfoList **tail;
479
480
+ assume_graph_lock(); /* FIXME */
481
+
482
*spec_info = (ImageInfoSpecific){
483
.type = IMAGE_INFO_SPECIFIC_KIND_VMDK,
484
.u = {
485
diff --git a/blockdev.c b/blockdev.c
486
index XXXXXXX..XXXXXXX 100644
487
--- a/blockdev.c
488
+++ b/blockdev.c
489
@@ -XXX,XX +XXX,XX @@ static void drive_backup_action(DriveBackup *backup,
490
bool set_backing_hd = false;
491
int ret;
492
493
+ GLOBAL_STATE_CODE();
494
+
495
tran_add(tran, &drive_backup_drv, state);
496
497
if (!backup->has_mode) {
498
@@ -XXX,XX +XXX,XX @@ static void drive_backup_action(DriveBackup *backup,
499
BlockDriverState *explicit_backing =
500
bdrv_skip_implicit_filters(source);
501
502
+ bdrv_graph_rdlock_main_loop();
503
bdrv_refresh_filename(explicit_backing);
504
+ bdrv_graph_rdunlock_main_loop();
505
+
506
bdrv_img_create(backup->target, format,
507
explicit_backing->filename,
508
explicit_backing->drv->format_name, NULL,
509
@@ -XXX,XX +XXX,XX @@ void qmp_block_stream(const char *job_id, const char *device,
61
Error *local_err = NULL;
510
Error *local_err = NULL;
62
- int ret;
511
int job_flags = JOB_DEFAULT;
63
512
64
crumpled = qdict_crumple(options, errp);
513
+ GLOBAL_STATE_CODE();
65
if (crumpled == NULL) {
514
+
66
- return -EINVAL;
515
if (base && base_node) {
67
+ return NULL;
516
error_setg(errp, "'base' and 'base-node' cannot be specified "
68
}
517
"at the same time");
69
518
@@ -XXX,XX +XXX,XX @@ void qmp_block_stream(const char *job_id, const char *device,
70
v = qobject_input_visitor_new_keyval(crumpled);
519
goto out;
71
visit_type_BlockdevOptionsNfs(v, NULL, &opts, &local_err);
520
}
72
visit_free(v);
521
assert(bdrv_get_aio_context(base_bs) == aio_context);
73
+ qobject_decref(crumpled);
522
+
74
523
+ bdrv_graph_rdlock_main_loop();
75
if (local_err) {
524
bdrv_refresh_filename(base_bs);
76
- error_propagate(errp, local_err);
525
+ bdrv_graph_rdunlock_main_loop();
77
+ return NULL;
526
}
78
+ }
527
79
+
528
if (bottom) {
80
+ return opts;
529
@@ -XXX,XX +XXX,XX @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
81
+}
530
break;
82
+
531
case NEW_IMAGE_MODE_ABSOLUTE_PATHS:
83
+static int64_t nfs_client_open_qdict(NFSClient *client, QDict *options,
532
/* create new image with backing file */
84
+ int flags, int open_flags, Error **errp)
533
+ bdrv_graph_rdlock_main_loop();
85
+{
534
bdrv_refresh_filename(explicit_backing);
86
+ BlockdevOptionsNfs *opts;
535
+ bdrv_graph_rdunlock_main_loop();
87
+ int ret;
536
+
88
+
537
bdrv_img_create(arg->target, format,
89
+ opts = nfs_options_qdict_to_qapi(options, errp);
538
explicit_backing->filename,
90
+ if (opts == NULL) {
539
explicit_backing->drv->format_name,
91
ret = -EINVAL;
540
diff --git a/qemu-img.c b/qemu-img.c
92
goto fail;
541
index XXXXXXX..XXXXXXX 100644
93
}
542
--- a/qemu-img.c
94
543
+++ b/qemu-img.c
95
ret = nfs_client_open(client, opts, flags, open_flags, errp);
544
@@ -XXX,XX +XXX,XX @@ static int get_block_status(BlockDriverState *bs, int64_t offset,
96
fail:
545
has_offset = !!(ret & BDRV_BLOCK_OFFSET_VALID);
97
- qobject_decref(crumpled);
546
98
qapi_free_BlockdevOptionsNfs(opts);
547
if (file && has_offset) {
99
return ret;
548
+ bdrv_graph_rdlock_main_loop();
100
}
549
bdrv_refresh_filename(file);
101
@@ -XXX,XX +XXX,XX @@ static QemuOptsList nfs_create_opts = {
550
+ bdrv_graph_rdunlock_main_loop();
102
}
551
filename = file->filename;
103
};
552
}
104
553
105
-static int coroutine_fn nfs_file_co_create_opts(const char *url, QemuOpts *opts,
554
@@ -XXX,XX +XXX,XX @@ static int img_rebase(int argc, char **argv)
106
- Error **errp)
555
qdict_put_bool(options, BDRV_OPT_FORCE_SHARE, true);
107
+static int nfs_file_co_create(BlockdevCreateOptions *options, Error **errp)
556
}
108
{
557
109
- int64_t ret, total_size;
558
+ bdrv_graph_rdlock_main_loop();
110
+ BlockdevCreateOptionsNfs *opts = &options->u.nfs;
559
bdrv_refresh_filename(bs);
111
NFSClient *client = g_new0(NFSClient, 1);
560
+ bdrv_graph_rdunlock_main_loop();
112
- QDict *options = NULL;
561
overlay_filename = bs->exact_filename[0] ? bs->exact_filename
113
+ int ret;
562
: bs->filename;
114
+
563
out_real_path =
115
+ assert(options->driver == BLOCKDEV_DRIVER_NFS);
116
117
client->aio_context = qemu_get_aio_context();
118
119
+ ret = nfs_client_open(client, opts->location, O_CREAT, 0, errp);
120
+ if (ret < 0) {
121
+ goto out;
122
+ }
123
+ ret = nfs_ftruncate(client->context, client->fh, opts->size);
124
+ nfs_client_close(client);
125
+
126
+out:
127
+ g_free(client);
128
+ return ret;
129
+}
130
+
131
+static int coroutine_fn nfs_file_co_create_opts(const char *url, QemuOpts *opts,
132
+ Error **errp)
133
+{
134
+ BlockdevCreateOptions *create_options;
135
+ BlockdevCreateOptionsNfs *nfs_opts;
136
+ QDict *options;
137
+ int ret;
138
+
139
+ create_options = g_new0(BlockdevCreateOptions, 1);
140
+ create_options->driver = BLOCKDEV_DRIVER_NFS;
141
+ nfs_opts = &create_options->u.nfs;
142
+
143
/* Read out options */
144
- total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
145
- BDRV_SECTOR_SIZE);
146
+ nfs_opts->size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
147
+ BDRV_SECTOR_SIZE);
148
149
options = qdict_new();
150
ret = nfs_parse_uri(url, options, errp);
151
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn nfs_file_co_create_opts(const char *url, QemuOpts *opts,
152
goto out;
153
}
154
155
- ret = nfs_client_open_qdict(client, options, O_CREAT, 0, errp);
156
+ nfs_opts->location = nfs_options_qdict_to_qapi(options, errp);
157
+ if (nfs_opts->location == NULL) {
158
+ ret = -EINVAL;
159
+ goto out;
160
+ }
161
+
162
+ ret = nfs_file_co_create(create_options, errp);
163
if (ret < 0) {
164
goto out;
165
}
166
- ret = nfs_ftruncate(client->context, client->fh, total_size);
167
- nfs_client_close(client);
168
+
169
+ ret = 0;
170
out:
171
QDECREF(options);
172
- g_free(client);
173
+ qapi_free_BlockdevCreateOptions(create_options);
174
return ret;
175
}
176
177
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_nfs = {
178
179
.bdrv_file_open = nfs_file_open,
180
.bdrv_close = nfs_file_close,
181
+ .bdrv_co_create = nfs_file_co_create,
182
.bdrv_co_create_opts = nfs_file_co_create_opts,
183
.bdrv_reopen_prepare = nfs_reopen_prepare,
184
185
--
564
--
186
2.13.6
565
2.41.0
187
188
diff view generated by jsdifflib
1
Using the QAPI visitor to turn all options into QAPI BlockdevOptionsNfs
1
This adds GRAPH_RDLOCK annotations to declare that callers of
2
simplifies the code a lot. It will also be useful for implementing the
2
bdrv_primary_child() need to hold a reader lock for the graph
3
QAPI based .bdrv_co_create callback.
3
because it accesses the children list of a node.
4
4
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Message-ID: <20230929145157.45443-12-kwolf@redhat.com>
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
9
---
8
block/nfs.c | 176 ++++++++++++++++++------------------------------------------
10
include/block/block_int-io.h | 5 +++--
9
1 file changed, 53 insertions(+), 123 deletions(-)
11
block.c | 11 ++++++++++-
12
block/snapshot.c | 3 +++
13
3 files changed, 16 insertions(+), 3 deletions(-)
10
14
11
diff --git a/block/nfs.c b/block/nfs.c
15
diff --git a/include/block/block_int-io.h b/include/block/block_int-io.h
12
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
13
--- a/block/nfs.c
17
--- a/include/block/block_int-io.h
14
+++ b/block/nfs.c
18
+++ b/include/block/block_int-io.h
15
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn nfs_co_flush(BlockDriverState *bs)
19
@@ -XXX,XX +XXX,XX @@ bdrv_refresh_total_sectors(BlockDriverState *bs, int64_t hint);
16
return task.ret;
20
BdrvChild *bdrv_cow_child(BlockDriverState *bs);
21
BdrvChild *bdrv_filter_child(BlockDriverState *bs);
22
BdrvChild *bdrv_filter_or_cow_child(BlockDriverState *bs);
23
-BdrvChild *bdrv_primary_child(BlockDriverState *bs);
24
+BdrvChild * GRAPH_RDLOCK bdrv_primary_child(BlockDriverState *bs);
25
BlockDriverState *bdrv_skip_filters(BlockDriverState *bs);
26
BlockDriverState *bdrv_backing_chain_next(BlockDriverState *bs);
27
28
@@ -XXX,XX +XXX,XX @@ static inline BlockDriverState *bdrv_filter_or_cow_bs(BlockDriverState *bs)
29
return child_bs(bdrv_filter_or_cow_child(bs));
17
}
30
}
18
31
19
-static QemuOptsList runtime_opts = {
32
-static inline BlockDriverState *bdrv_primary_bs(BlockDriverState *bs)
20
- .name = "nfs",
33
+static inline BlockDriverState * GRAPH_RDLOCK
21
- .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
34
+bdrv_primary_bs(BlockDriverState *bs)
22
- .desc = {
23
- {
24
- .name = "path",
25
- .type = QEMU_OPT_STRING,
26
- .help = "Path of the image on the host",
27
- },
28
- {
29
- .name = "user",
30
- .type = QEMU_OPT_NUMBER,
31
- .help = "UID value to use when talking to the server",
32
- },
33
- {
34
- .name = "group",
35
- .type = QEMU_OPT_NUMBER,
36
- .help = "GID value to use when talking to the server",
37
- },
38
- {
39
- .name = "tcp-syn-count",
40
- .type = QEMU_OPT_NUMBER,
41
- .help = "Number of SYNs to send during the session establish",
42
- },
43
- {
44
- .name = "readahead-size",
45
- .type = QEMU_OPT_NUMBER,
46
- .help = "Set the readahead size in bytes",
47
- },
48
- {
49
- .name = "page-cache-size",
50
- .type = QEMU_OPT_NUMBER,
51
- .help = "Set the pagecache size in bytes",
52
- },
53
- {
54
- .name = "debug",
55
- .type = QEMU_OPT_NUMBER,
56
- .help = "Set the NFS debug level (max 2)",
57
- },
58
- { /* end of list */ }
59
- },
60
-};
61
-
62
static void nfs_detach_aio_context(BlockDriverState *bs)
63
{
35
{
64
NFSClient *client = bs->opaque;
36
IO_CODE();
65
@@ -XXX,XX +XXX,XX @@ static void nfs_file_close(BlockDriverState *bs)
37
return child_bs(bdrv_primary_child(bs));
66
nfs_client_close(client);
38
diff --git a/block.c b/block.c
39
index XXXXXXX..XXXXXXX 100644
40
--- a/block.c
41
+++ b/block.c
42
@@ -XXX,XX +XXX,XX @@ void coroutine_fn bdrv_co_debug_event(BlockDriverState *bs, BlkdebugEvent event)
43
bs->drv->bdrv_co_debug_event(bs, event);
67
}
44
}
68
45
69
-static NFSServer *nfs_config(QDict *options, Error **errp)
46
-static BlockDriverState *bdrv_find_debug_node(BlockDriverState *bs)
70
-{
47
+static BlockDriverState * GRAPH_RDLOCK
71
- NFSServer *server = NULL;
48
+bdrv_find_debug_node(BlockDriverState *bs)
72
- QDict *addr = NULL;
73
- QObject *crumpled_addr = NULL;
74
- Visitor *iv = NULL;
75
- Error *local_error = NULL;
76
-
77
- qdict_extract_subqdict(options, &addr, "server.");
78
- if (!qdict_size(addr)) {
79
- error_setg(errp, "NFS server address missing");
80
- goto out;
81
- }
82
-
83
- crumpled_addr = qdict_crumple(addr, errp);
84
- if (!crumpled_addr) {
85
- goto out;
86
- }
87
-
88
- /*
89
- * Caution: this works only because all scalar members of
90
- * NFSServer are QString in @crumpled_addr. The visitor expects
91
- * @crumpled_addr to be typed according to the QAPI schema. It
92
- * is when @options come from -blockdev or blockdev_add. But when
93
- * they come from -drive, they're all QString.
94
- */
95
- iv = qobject_input_visitor_new(crumpled_addr);
96
- visit_type_NFSServer(iv, NULL, &server, &local_error);
97
- if (local_error) {
98
- error_propagate(errp, local_error);
99
- goto out;
100
- }
101
-
102
-out:
103
- QDECREF(addr);
104
- qobject_decref(crumpled_addr);
105
- visit_free(iv);
106
- return server;
107
-}
108
-
109
-
110
-static int64_t nfs_client_open(NFSClient *client, QDict *options,
111
+static int64_t nfs_client_open(NFSClient *client, BlockdevOptionsNfs *opts,
112
int flags, int open_flags, Error **errp)
113
{
49
{
114
int64_t ret = -EINVAL;
50
GLOBAL_STATE_CODE();
115
- QemuOpts *opts = NULL;
51
while (bs && bs->drv && !bs->drv->bdrv_debug_breakpoint) {
116
- Error *local_err = NULL;
52
@@ -XXX,XX +XXX,XX @@ int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event,
117
struct stat st;
53
const char *tag)
118
char *file = NULL, *strp = NULL;
54
{
119
55
GLOBAL_STATE_CODE();
120
qemu_mutex_init(&client->mutex);
56
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
121
- opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
57
+
122
- qemu_opts_absorb_qdict(opts, options, &local_err);
58
bs = bdrv_find_debug_node(bs);
123
- if (local_err) {
59
if (bs) {
124
- error_propagate(errp, local_err);
60
return bs->drv->bdrv_debug_breakpoint(bs, event, tag);
125
- ret = -EINVAL;
61
@@ -XXX,XX +XXX,XX @@ int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event,
126
- goto fail;
62
int bdrv_debug_remove_breakpoint(BlockDriverState *bs, const char *tag)
127
- }
63
{
128
64
GLOBAL_STATE_CODE();
129
- client->path = g_strdup(qemu_opt_get(opts, "path"));
65
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
130
- if (!client->path) {
66
+
131
- ret = -EINVAL;
67
bs = bdrv_find_debug_node(bs);
132
- error_setg(errp, "No path was specified");
68
if (bs) {
133
- goto fail;
69
return bs->drv->bdrv_debug_remove_breakpoint(bs, tag);
134
- }
70
@@ -XXX,XX +XXX,XX @@ int bdrv_debug_remove_breakpoint(BlockDriverState *bs, const char *tag)
135
+ client->path = g_strdup(opts->path);
71
int bdrv_debug_resume(BlockDriverState *bs, const char *tag)
136
72
{
137
strp = strrchr(client->path, '/');
73
GLOBAL_STATE_CODE();
138
if (strp == NULL) {
74
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
139
@@ -XXX,XX +XXX,XX @@ static int64_t nfs_client_open(NFSClient *client, QDict *options,
75
+
140
file = g_strdup(strp);
76
while (bs && (!bs->drv || !bs->drv->bdrv_debug_resume)) {
141
*strp = 0;
77
bs = bdrv_primary_bs(bs);
142
143
- /* Pop the config into our state object, Exit if invalid */
144
- client->server = nfs_config(options, errp);
145
- if (!client->server) {
146
- ret = -EINVAL;
147
- goto fail;
148
- }
149
+ /* Steal the NFSServer object from opts; set the original pointer to NULL
150
+ * to avoid use after free and double free. */
151
+ client->server = opts->server;
152
+ opts->server = NULL;
153
154
client->context = nfs_init_context();
155
if (client->context == NULL) {
156
@@ -XXX,XX +XXX,XX @@ static int64_t nfs_client_open(NFSClient *client, QDict *options,
157
goto fail;
158
}
78
}
159
79
@@ -XXX,XX +XXX,XX @@ int bdrv_debug_resume(BlockDriverState *bs, const char *tag)
160
- if (qemu_opt_get(opts, "user")) {
80
bool bdrv_debug_is_suspended(BlockDriverState *bs, const char *tag)
161
- client->uid = qemu_opt_get_number(opts, "user", 0);
81
{
162
+ if (opts->has_user) {
82
GLOBAL_STATE_CODE();
163
+ client->uid = opts->user;
83
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
164
nfs_set_uid(client->context, client->uid);
84
+
85
while (bs && bs->drv && !bs->drv->bdrv_debug_is_suspended) {
86
bs = bdrv_primary_bs(bs);
165
}
87
}
166
88
diff --git a/block/snapshot.c b/block/snapshot.c
167
- if (qemu_opt_get(opts, "group")) {
89
index XXXXXXX..XXXXXXX 100644
168
- client->gid = qemu_opt_get_number(opts, "group", 0);
90
--- a/block/snapshot.c
169
+ if (opts->has_group) {
91
+++ b/block/snapshot.c
170
+ client->gid = opts->group;
92
@@ -XXX,XX +XXX,XX @@ int bdrv_snapshot_goto(BlockDriverState *bs,
171
nfs_set_gid(client->context, client->gid);
93
* respective option (with the qdict_put_str() call above).
172
}
94
* Assert that .bdrv_open() has attached the right BDS as primary child.
173
95
*/
174
- if (qemu_opt_get(opts, "tcp-syn-count")) {
96
+ bdrv_graph_rdlock_main_loop();
175
- client->tcp_syncnt = qemu_opt_get_number(opts, "tcp-syn-count", 0);
97
assert(bdrv_primary_bs(bs) == fallback_bs);
176
+ if (opts->has_tcp_syn_count) {
98
+ bdrv_graph_rdunlock_main_loop();
177
+ client->tcp_syncnt = opts->tcp_syn_count;
178
nfs_set_tcp_syncnt(client->context, client->tcp_syncnt);
179
}
180
181
#ifdef LIBNFS_FEATURE_READAHEAD
182
- if (qemu_opt_get(opts, "readahead-size")) {
183
+ if (opts->has_readahead_size) {
184
if (open_flags & BDRV_O_NOCACHE) {
185
error_setg(errp, "Cannot enable NFS readahead "
186
"if cache.direct = on");
187
goto fail;
188
}
189
- client->readahead = qemu_opt_get_number(opts, "readahead-size", 0);
190
+ client->readahead = opts->readahead_size;
191
if (client->readahead > QEMU_NFS_MAX_READAHEAD_SIZE) {
192
warn_report("Truncating NFS readahead size to %d",
193
QEMU_NFS_MAX_READAHEAD_SIZE);
194
@@ -XXX,XX +XXX,XX @@ static int64_t nfs_client_open(NFSClient *client, QDict *options,
195
#endif
196
197
#ifdef LIBNFS_FEATURE_PAGECACHE
198
- if (qemu_opt_get(opts, "page-cache-size")) {
199
+ if (opts->has_page_cache_size) {
200
if (open_flags & BDRV_O_NOCACHE) {
201
error_setg(errp, "Cannot enable NFS pagecache "
202
"if cache.direct = on");
203
goto fail;
204
}
205
- client->pagecache = qemu_opt_get_number(opts, "page-cache-size", 0);
206
+ client->pagecache = opts->page_cache_size;
207
if (client->pagecache > QEMU_NFS_MAX_PAGECACHE_SIZE) {
208
warn_report("Truncating NFS pagecache size to %d pages",
209
QEMU_NFS_MAX_PAGECACHE_SIZE);
210
@@ -XXX,XX +XXX,XX @@ static int64_t nfs_client_open(NFSClient *client, QDict *options,
211
#endif
212
213
#ifdef LIBNFS_FEATURE_DEBUG
214
- if (qemu_opt_get(opts, "debug")) {
215
- client->debug = qemu_opt_get_number(opts, "debug", 0);
216
+ if (opts->has_debug) {
217
+ client->debug = opts->debug;
218
/* limit the maximum debug level to avoid potential flooding
219
* of our log files. */
220
if (client->debug > QEMU_NFS_MAX_DEBUG_LEVEL) {
221
@@ -XXX,XX +XXX,XX @@ static int64_t nfs_client_open(NFSClient *client, QDict *options,
222
fail:
223
nfs_client_close(client);
224
out:
225
- qemu_opts_del(opts);
226
g_free(file);
227
return ret;
228
}
229
230
+static int64_t nfs_client_open_qdict(NFSClient *client, QDict *options,
231
+ int flags, int open_flags, Error **errp)
232
+{
233
+ BlockdevOptionsNfs *opts = NULL;
234
+ QObject *crumpled = NULL;
235
+ Visitor *v;
236
+ Error *local_err = NULL;
237
+ int ret;
238
+
99
+
239
+ crumpled = qdict_crumple(options, errp);
100
bdrv_unref(fallback_bs);
240
+ if (crumpled == NULL) {
241
+ return -EINVAL;
242
+ }
243
+
244
+ v = qobject_input_visitor_new_keyval(crumpled);
245
+ visit_type_BlockdevOptionsNfs(v, NULL, &opts, &local_err);
246
+ visit_free(v);
247
+
248
+ if (local_err) {
249
+ error_propagate(errp, local_err);
250
+ ret = -EINVAL;
251
+ goto fail;
252
+ }
253
+
254
+ ret = nfs_client_open(client, opts, flags, open_flags, errp);
255
+fail:
256
+ qobject_decref(crumpled);
257
+ qapi_free_BlockdevOptionsNfs(opts);
258
+ return ret;
259
+}
260
+
261
static int nfs_file_open(BlockDriverState *bs, QDict *options, int flags,
262
Error **errp) {
263
NFSClient *client = bs->opaque;
264
@@ -XXX,XX +XXX,XX @@ static int nfs_file_open(BlockDriverState *bs, QDict *options, int flags,
265
266
client->aio_context = bdrv_get_aio_context(bs);
267
268
- ret = nfs_client_open(client, options,
269
- (flags & BDRV_O_RDWR) ? O_RDWR : O_RDONLY,
270
- bs->open_flags, errp);
271
+ ret = nfs_client_open_qdict(client, options,
272
+ (flags & BDRV_O_RDWR) ? O_RDWR : O_RDONLY,
273
+ bs->open_flags, errp);
274
if (ret < 0) {
275
return ret;
101
return ret;
276
}
102
}
277
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn nfs_file_co_create_opts(const char *url, QemuOpts *opts,
278
goto out;
279
}
280
281
- ret = nfs_client_open(client, options, O_CREAT, 0, errp);
282
+ ret = nfs_client_open_qdict(client, options, O_CREAT, 0, errp);
283
if (ret < 0) {
284
goto out;
285
}
286
--
103
--
287
2.13.6
104
2.41.0
288
289
diff view generated by jsdifflib
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
This adds GRAPH_RDLOCK annotations to declare that callers of
2
bdrv_get_parent_name() need to hold a reader lock for the graph
3
because it accesses the parents list of a node.
2
4
3
Suggested-by: Kevin Wolf <kwolf@redhat.com>
5
For some places, we know that they will hold the lock, but we don't have
4
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
6
the GRAPH_RDLOCK annotations yet. In this case, add assume_graph_lock()
5
Message-Id: <1516279431-30424-8-git-send-email-pbonzini@redhat.com>
7
with a FIXME comment. These places will be removed once everything is
6
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
8
properly annotated.
9
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Message-ID: <20230929145157.45443-13-kwolf@redhat.com>
12
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
14
---
9
include/block/block_int.h | 5 +++--
15
block/qcow2.h | 7 +++----
10
block.c | 43 ++++++++++++++++++++++++++++++++++++++++---
16
include/block/block-io.h | 8 ++++++--
11
block/parallels.c | 17 +++++++++++------
17
include/block/block_int-io.h | 2 +-
12
block/qcow2.c | 23 +++++++++++++++++++----
18
include/block/qapi.h | 7 ++++---
13
block/qed-check.c | 1 +
19
block.c | 14 ++++++++++++--
14
block/qed-table.c | 26 +++++++++-----------------
20
block/backup.c | 1 +
15
block/qed.c | 13 +++++++++----
21
block/parallels.c | 3 +++
16
block/vdi.c | 6 +++---
22
block/qcow.c | 3 +++
17
block/vhdx.c | 7 ++++---
23
block/qcow2-bitmap.c | 2 ++
18
block/vmdk.c | 7 ++++---
24
block/qcow2.c | 4 ++++
19
10 files changed, 103 insertions(+), 45 deletions(-)
25
block/quorum.c | 4 ++--
26
block/rbd.c | 2 ++
27
block/snapshot.c | 3 +++
28
block/vdi.c | 3 +++
29
block/vpc.c | 3 +++
30
block/vvfat.c | 2 ++
31
blockjob.c | 1 +
32
17 files changed, 55 insertions(+), 14 deletions(-)
20
33
21
diff --git a/include/block/block_int.h b/include/block/block_int.h
34
diff --git a/block/qcow2.h b/block/qcow2.h
22
index XXXXXXX..XXXXXXX 100644
35
index XXXXXXX..XXXXXXX 100644
23
--- a/include/block/block_int.h
36
--- a/block/qcow2.h
24
+++ b/include/block/block_int.h
37
+++ b/block/qcow2.h
25
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
38
@@ -XXX,XX +XXX,XX @@ int coroutine_fn qcow2_truncate_bitmaps_check(BlockDriverState *bs, Error **errp
26
* Returns 0 for completed check, -errno for internal errors.
39
bool qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs,
27
* The check results are stored in result.
40
bool release_stored, Error **errp);
28
*/
41
int qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp);
29
- int (*bdrv_check)(BlockDriverState *bs, BdrvCheckResult *result,
42
-bool coroutine_fn qcow2_co_can_store_new_dirty_bitmap(BlockDriverState *bs,
30
- BdrvCheckMode fix);
43
- const char *name,
31
+ int coroutine_fn (*bdrv_co_check)(BlockDriverState *bs,
44
- uint32_t granularity,
32
+ BdrvCheckResult *result,
45
- Error **errp);
33
+ BdrvCheckMode fix);
46
+bool coroutine_fn GRAPH_RDLOCK
34
47
+qcow2_co_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name,
35
int (*bdrv_amend_options)(BlockDriverState *bs, QemuOpts *opts,
48
+ uint32_t granularity, Error **errp);
36
BlockDriverAmendStatusCB *status_cb,
49
int coroutine_fn qcow2_co_remove_persistent_dirty_bitmap(BlockDriverState *bs,
50
const char *name,
51
Error **errp);
52
diff --git a/include/block/block-io.h b/include/block/block-io.h
53
index XXXXXXX..XXXXXXX 100644
54
--- a/include/block/block-io.h
55
+++ b/include/block/block-io.h
56
@@ -XXX,XX +XXX,XX @@ const char *bdrv_get_format_name(BlockDriverState *bs);
57
58
bool bdrv_supports_compressed_writes(BlockDriverState *bs);
59
const char *bdrv_get_node_name(const BlockDriverState *bs);
60
-const char *bdrv_get_device_name(const BlockDriverState *bs);
61
-const char *bdrv_get_device_or_node_name(const BlockDriverState *bs);
62
+
63
+const char * GRAPH_RDLOCK
64
+bdrv_get_device_name(const BlockDriverState *bs);
65
+
66
+const char * GRAPH_RDLOCK
67
+bdrv_get_device_or_node_name(const BlockDriverState *bs);
68
69
int coroutine_fn GRAPH_RDLOCK
70
bdrv_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi);
71
diff --git a/include/block/block_int-io.h b/include/block/block_int-io.h
72
index XXXXXXX..XXXXXXX 100644
73
--- a/include/block/block_int-io.h
74
+++ b/include/block/block_int-io.h
75
@@ -XXX,XX +XXX,XX @@ BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size,
76
*/
77
void bdrv_wakeup(BlockDriverState *bs);
78
79
-const char *bdrv_get_parent_name(const BlockDriverState *bs);
80
+const char * GRAPH_RDLOCK bdrv_get_parent_name(const BlockDriverState *bs);
81
bool blk_dev_has_tray(BlockBackend *blk);
82
bool blk_dev_is_tray_open(BlockBackend *blk);
83
84
diff --git a/include/block/qapi.h b/include/block/qapi.h
85
index XXXXXXX..XXXXXXX 100644
86
--- a/include/block/qapi.h
87
+++ b/include/block/qapi.h
88
@@ -XXX,XX +XXX,XX @@ BlockDeviceInfo * GRAPH_RDLOCK
89
bdrv_block_device_info(BlockBackend *blk, BlockDriverState *bs,
90
bool flat, Error **errp);
91
92
-int bdrv_query_snapshot_info_list(BlockDriverState *bs,
93
- SnapshotInfoList **p_list,
94
- Error **errp);
95
+int GRAPH_RDLOCK
96
+bdrv_query_snapshot_info_list(BlockDriverState *bs,
97
+ SnapshotInfoList **p_list,
98
+ Error **errp);
99
void GRAPH_RDLOCK
100
bdrv_query_image_info(BlockDriverState *bs, ImageInfo **p_info, bool flat,
101
bool skip_implicit_filters, Error **errp);
37
diff --git a/block.c b/block.c
102
diff --git a/block.c b/block.c
38
index XXXXXXX..XXXXXXX 100644
103
index XXXXXXX..XXXXXXX 100644
39
--- a/block.c
104
--- a/block.c
40
+++ b/block.c
105
+++ b/block.c
41
@@ -XXX,XX +XXX,XX @@ static void bdrv_delete(BlockDriverState *bs)
106
@@ -XXX,XX +XXX,XX @@ bool bdrv_is_read_only(BlockDriverState *bs)
42
* free of errors) or -errno when an internal error occurred. The results of the
107
return !(bs->open_flags & BDRV_O_RDWR);
43
* check are stored in res.
108
}
44
*/
109
45
-int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix)
110
-static int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only,
46
+static int coroutine_fn bdrv_co_check(BlockDriverState *bs,
111
- bool ignore_allow_rdw, Error **errp)
47
+ BdrvCheckResult *res, BdrvCheckMode fix)
112
+static int GRAPH_RDLOCK
113
+bdrv_can_set_read_only(BlockDriverState *bs, bool read_only,
114
+ bool ignore_allow_rdw, Error **errp)
48
{
115
{
49
if (bs->drv == NULL) {
116
IO_CODE();
50
return -ENOMEDIUM;
117
51
}
118
@@ -XXX,XX +XXX,XX @@ int bdrv_apply_auto_read_only(BlockDriverState *bs, const char *errmsg,
52
- if (bs->drv->bdrv_check == NULL) {
119
int ret = 0;
53
+ if (bs->drv->bdrv_co_check == NULL) {
120
IO_CODE();
54
return -ENOTSUP;
121
55
}
122
+ assume_graph_lock(); /* FIXME */
56
123
+
57
memset(res, 0, sizeof(*res));
124
if (!(bs->open_flags & BDRV_O_RDWR)) {
58
- return bs->drv->bdrv_check(bs, res, fix);
125
return 0;
59
+ return bs->drv->bdrv_co_check(bs, res, fix);
126
}
60
+}
127
@@ -XXX,XX +XXX,XX @@ bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
61
+
128
* to r/w. Attempting to set to r/w may fail if either BDRV_O_ALLOW_RDWR is
62
+typedef struct CheckCo {
129
* not set, or if the BDS still has copy_on_read enabled */
63
+ BlockDriverState *bs;
130
read_only = !(reopen_state->flags & BDRV_O_RDWR);
64
+ BdrvCheckResult *res;
131
+
65
+ BdrvCheckMode fix;
132
+ bdrv_graph_rdlock_main_loop();
66
+ int ret;
133
ret = bdrv_can_set_read_only(reopen_state->bs, read_only, true, &local_err);
67
+} CheckCo;
134
+ bdrv_graph_rdunlock_main_loop();
68
+
135
if (local_err) {
69
+static void bdrv_check_co_entry(void *opaque)
136
error_propagate(errp, local_err);
70
+{
137
goto error;
71
+ CheckCo *cco = opaque;
138
@@ -XXX,XX +XXX,XX @@ bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
72
+ cco->ret = bdrv_co_check(cco->bs, cco->res, cco->fix);
139
} else {
73
+}
140
/* It is currently mandatory to have a bdrv_reopen_prepare()
74
+
141
* handler for each supported drv. */
75
+int bdrv_check(BlockDriverState *bs,
142
+ bdrv_graph_rdlock_main_loop();
76
+ BdrvCheckResult *res, BdrvCheckMode fix)
143
error_setg(errp, "Block format '%s' used by node '%s' "
77
+{
144
"does not support reopening files", drv->format_name,
78
+ Coroutine *co;
145
bdrv_get_device_or_node_name(reopen_state->bs));
79
+ CheckCo cco = {
146
+ bdrv_graph_rdunlock_main_loop();
80
+ .bs = bs,
147
ret = -1;
81
+ .res = res,
148
goto error;
82
+ .ret = -EINPROGRESS,
149
}
83
+ .fix = fix,
150
@@ -XXX,XX +XXX,XX @@ bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp)
84
+ };
151
{
85
+
152
BdrvOpBlocker *blocker;
86
+ if (qemu_in_coroutine()) {
153
GLOBAL_STATE_CODE();
87
+ /* Fast-path if already in coroutine context */
154
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
88
+ bdrv_check_co_entry(&cco);
155
+
89
+ } else {
156
assert((int) op >= 0 && op < BLOCK_OP_TYPE_MAX);
90
+ co = qemu_coroutine_create(bdrv_check_co_entry, &cco);
157
if (!QLIST_EMPTY(&bs->op_blockers[op])) {
91
+ qemu_coroutine_enter(co);
158
blocker = QLIST_FIRST(&bs->op_blockers[op]);
92
+ BDRV_POLL_WHILE(bs, cco.ret == -EINPROGRESS);
159
diff --git a/block/backup.c b/block/backup.c
93
+ }
160
index XXXXXXX..XXXXXXX 100644
94
+
161
--- a/block/backup.c
95
+ return cco.ret;
162
+++ b/block/backup.c
96
}
163
@@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
97
164
assert(bs);
98
/*
165
assert(target);
166
GLOBAL_STATE_CODE();
167
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
168
169
/* QMP interface protects us from these cases */
170
assert(sync_mode != MIRROR_SYNC_MODE_INCREMENTAL);
99
diff --git a/block/parallels.c b/block/parallels.c
171
diff --git a/block/parallels.c b/block/parallels.c
100
index XXXXXXX..XXXXXXX 100644
172
index XXXXXXX..XXXXXXX 100644
101
--- a/block/parallels.c
173
--- a/block/parallels.c
102
+++ b/block/parallels.c
174
+++ b/block/parallels.c
103
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int parallels_co_readv(BlockDriverState *bs,
175
@@ -XXX,XX +XXX,XX @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
104
}
176
bitmap_new(DIV_ROUND_UP(s->header_size, s->bat_dirty_block));
105
177
106
178
/* Disable migration until bdrv_activate method is added */
107
-static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
179
+ bdrv_graph_rdlock_main_loop();
108
- BdrvCheckMode fix)
180
error_setg(&s->migration_blocker, "The Parallels format used by node '%s' "
109
+static int coroutine_fn parallels_co_check(BlockDriverState *bs,
181
"does not support live migration",
110
+ BdrvCheckResult *res,
182
bdrv_get_device_or_node_name(bs));
111
+ BdrvCheckMode fix)
183
+ bdrv_graph_rdunlock_main_loop();
112
{
184
+
113
BDRVParallelsState *s = bs->opaque;
185
ret = migrate_add_blocker(s->migration_blocker, errp);
114
int64_t size, prev_off, high_off;
186
if (ret < 0) {
115
@@ -XXX,XX +XXX,XX @@ static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
187
error_setg(errp, "Migration blocker error");
116
return size;
188
diff --git a/block/qcow.c b/block/qcow.c
117
}
189
index XXXXXXX..XXXXXXX 100644
118
190
--- a/block/qcow.c
119
+ qemu_co_mutex_lock(&s->lock);
191
+++ b/block/qcow.c
120
if (s->header_unclean) {
192
@@ -XXX,XX +XXX,XX @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
121
fprintf(stderr, "%s image was not closed correctly\n",
193
}
122
fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR");
194
123
@@ -XXX,XX +XXX,XX @@ static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
195
/* Disable migration when qcow images are used */
124
prev_off = off;
196
+ bdrv_graph_rdlock_main_loop();
125
}
197
error_setg(&s->migration_blocker, "The qcow format used by node '%s' "
126
198
"does not support live migration",
127
+ ret = 0;
199
bdrv_get_device_or_node_name(bs));
128
if (flush_bat) {
200
+ bdrv_graph_rdunlock_main_loop();
129
ret = bdrv_pwrite_sync(bs->file, 0, s->header, s->header_size);
201
+
130
if (ret < 0) {
202
ret = migrate_add_blocker(s->migration_blocker, errp);
131
res->check_errors++;
203
if (ret < 0) {
132
- return ret;
204
error_free(s->migration_blocker);
133
+ goto out;
205
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
134
}
206
index XXXXXXX..XXXXXXX 100644
135
}
207
--- a/block/qcow2-bitmap.c
136
208
+++ b/block/qcow2-bitmap.c
137
@@ -XXX,XX +XXX,XX @@ static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
209
@@ -XXX,XX +XXX,XX @@ static int check_constraints_on_bitmap(BlockDriverState *bs,
138
if (ret < 0) {
210
int64_t len = bdrv_getlength(bs);
139
error_report_err(local_err);
211
int64_t bitmap_bytes;
140
res->check_errors++;
212
141
- return ret;
213
+ assume_graph_lock(); /* FIXME */
142
+ goto out;
214
+
143
}
215
assert(granularity > 0);
144
res->leaks_fixed += count;
216
assert((granularity & (granularity - 1)) == 0);
145
}
146
}
147
148
- return 0;
149
+out:
150
+ qemu_co_mutex_unlock(&s->lock);
151
+ return ret;
152
}
153
154
155
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_parallels = {
156
.bdrv_co_writev = parallels_co_writev,
157
.supports_backing = true,
158
.bdrv_co_create_opts = parallels_co_create_opts,
159
- .bdrv_check = parallels_check,
160
+ .bdrv_co_check = parallels_co_check,
161
.create_opts = &parallels_create_opts,
162
};
163
217
164
diff --git a/block/qcow2.c b/block/qcow2.c
218
diff --git a/block/qcow2.c b/block/qcow2.c
165
index XXXXXXX..XXXXXXX 100644
219
index XXXXXXX..XXXXXXX 100644
166
--- a/block/qcow2.c
220
--- a/block/qcow2.c
167
+++ b/block/qcow2.c
221
+++ b/block/qcow2.c
168
@@ -XXX,XX +XXX,XX @@ int qcow2_mark_consistent(BlockDriverState *bs)
222
@@ -XXX,XX +XXX,XX @@ static int qcow2_inactivate(BlockDriverState *bs)
169
return 0;
223
int ret, result = 0;
224
Error *local_err = NULL;
225
226
+ assume_graph_lock(); /* FIXME */
227
+
228
qcow2_store_persistent_dirty_bitmaps(bs, true, &local_err);
229
if (local_err != NULL) {
230
result = -EINVAL;
231
@@ -XXX,XX +XXX,XX @@ void qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset,
232
char *message;
233
va_list ap;
234
235
+ assume_graph_lock(); /* FIXME */
236
+
237
fatal = fatal && bdrv_is_writable(bs);
238
239
if (s->signaled_corruption &&
240
diff --git a/block/quorum.c b/block/quorum.c
241
index XXXXXXX..XXXXXXX 100644
242
--- a/block/quorum.c
243
+++ b/block/quorum.c
244
@@ -XXX,XX +XXX,XX @@ static void quorum_report_bad(QuorumOpType type, uint64_t offset,
245
end_sector - start_sector);
170
}
246
}
171
247
172
-static int qcow2_check(BlockDriverState *bs, BdrvCheckResult *result,
248
-static void quorum_report_failure(QuorumAIOCB *acb)
173
- BdrvCheckMode fix)
249
+static void GRAPH_RDLOCK quorum_report_failure(QuorumAIOCB *acb)
174
+static int coroutine_fn qcow2_co_check_locked(BlockDriverState *bs,
175
+ BdrvCheckResult *result,
176
+ BdrvCheckMode fix)
177
{
250
{
178
int ret = qcow2_check_refcounts(bs, result, fix);
251
const char *reference = bdrv_get_device_or_node_name(acb->bs);
179
if (ret < 0) {
252
int64_t start_sector = acb->offset / BDRV_SECTOR_SIZE;
180
@@ -XXX,XX +XXX,XX @@ static int qcow2_check(BlockDriverState *bs, BdrvCheckResult *result,
253
@@ -XXX,XX +XXX,XX @@ static void quorum_report_failure(QuorumAIOCB *acb)
181
return ret;
254
182
}
255
static int quorum_vote_error(QuorumAIOCB *acb);
183
256
184
+static int coroutine_fn qcow2_co_check(BlockDriverState *bs,
257
-static bool quorum_has_too_much_io_failed(QuorumAIOCB *acb)
185
+ BdrvCheckResult *result,
258
+static bool GRAPH_RDLOCK quorum_has_too_much_io_failed(QuorumAIOCB *acb)
186
+ BdrvCheckMode fix)
187
+{
188
+ BDRVQcow2State *s = bs->opaque;
189
+ int ret;
190
+
191
+ qemu_co_mutex_lock(&s->lock);
192
+ ret = qcow2_co_check_locked(bs, result, fix);
193
+ qemu_co_mutex_unlock(&s->lock);
194
+ return ret;
195
+}
196
+
197
static int validate_table_offset(BlockDriverState *bs, uint64_t offset,
198
uint64_t entries, size_t entry_len)
199
{
259
{
200
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
260
BDRVQuorumState *s = acb->bs->opaque;
201
(s->incompatible_features & QCOW2_INCOMPAT_DIRTY)) {
261
202
BdrvCheckResult result = {0};
262
diff --git a/block/rbd.c b/block/rbd.c
203
263
index XXXXXXX..XXXXXXX 100644
204
- ret = qcow2_check(bs, &result, BDRV_FIX_ERRORS | BDRV_FIX_LEAKS);
264
--- a/block/rbd.c
205
+ ret = qcow2_co_check_locked(bs, &result,
265
+++ b/block/rbd.c
206
+ BDRV_FIX_ERRORS | BDRV_FIX_LEAKS);
266
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_reopen_prepare(BDRVReopenState *state,
207
if (ret < 0 || result.check_errors) {
267
BDRVRBDState *s = state->bs->opaque;
208
if (ret >= 0) {
268
int ret = 0;
209
ret = -EIO;
269
210
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_qcow2 = {
270
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
211
.bdrv_inactivate = qcow2_inactivate,
271
+
212
272
if (s->snap && state->flags & BDRV_O_RDWR) {
213
.create_opts = &qcow2_create_opts,
273
error_setg(errp,
214
- .bdrv_check = qcow2_check,
274
"Cannot change node '%s' to r/w when using RBD snapshot",
215
+ .bdrv_co_check = qcow2_co_check,
275
diff --git a/block/snapshot.c b/block/snapshot.c
216
.bdrv_amend_options = qcow2_amend_options,
276
index XXXXXXX..XXXXXXX 100644
217
277
--- a/block/snapshot.c
218
.bdrv_detach_aio_context = qcow2_detach_aio_context,
278
+++ b/block/snapshot.c
219
diff --git a/block/qed-check.c b/block/qed-check.c
279
@@ -XXX,XX +XXX,XX @@ int bdrv_snapshot_load_tmp(BlockDriverState *bs,
220
index XXXXXXX..XXXXXXX 100644
280
BlockDriver *drv = bs->drv;
221
--- a/block/qed-check.c
281
222
+++ b/block/qed-check.c
282
GLOBAL_STATE_CODE();
223
@@ -XXX,XX +XXX,XX @@ static void qed_check_mark_clean(BDRVQEDState *s, BdrvCheckResult *result)
283
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
224
qed_write_header_sync(s);
284
225
}
285
if (!drv) {
226
286
error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, bdrv_get_device_name(bs));
227
+/* Called with table_lock held. */
287
@@ -XXX,XX +XXX,XX @@ int bdrv_all_goto_snapshot(const char *name,
228
int qed_check(BDRVQEDState *s, BdrvCheckResult *result, bool fix)
288
}
229
{
289
aio_context_release(ctx);
230
QEDCheck check = {
290
if (ret < 0) {
231
diff --git a/block/qed-table.c b/block/qed-table.c
291
+ bdrv_graph_rdlock_main_loop();
232
index XXXXXXX..XXXXXXX 100644
292
error_prepend(errp, "Could not load snapshot '%s' on '%s': ",
233
--- a/block/qed-table.c
293
name, bdrv_get_device_or_node_name(bs));
234
+++ b/block/qed-table.c
294
+ bdrv_graph_rdunlock_main_loop();
235
@@ -XXX,XX +XXX,XX @@
295
return -1;
236
#include "qed.h"
296
}
237
#include "qemu/bswap.h"
297
238
239
-/* Called either from qed_check or with table_lock held. */
240
+/* Called with table_lock held. */
241
static int qed_read_table(BDRVQEDState *s, uint64_t offset, QEDTable *table)
242
{
243
QEMUIOVector qiov;
244
@@ -XXX,XX +XXX,XX @@ static int qed_read_table(BDRVQEDState *s, uint64_t offset, QEDTable *table)
245
246
trace_qed_read_table(s, offset, table);
247
248
- if (qemu_in_coroutine()) {
249
- qemu_co_mutex_unlock(&s->table_lock);
250
- }
251
+ qemu_co_mutex_unlock(&s->table_lock);
252
ret = bdrv_preadv(s->bs->file, offset, &qiov);
253
- if (qemu_in_coroutine()) {
254
- qemu_co_mutex_lock(&s->table_lock);
255
- }
256
+ qemu_co_mutex_lock(&s->table_lock);
257
if (ret < 0) {
258
goto out;
259
}
260
@@ -XXX,XX +XXX,XX @@ out:
261
* @n: Number of elements
262
* @flush: Whether or not to sync to disk
263
*
264
- * Called either from qed_check or with table_lock held.
265
+ * Called with table_lock held.
266
*/
267
static int qed_write_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
268
unsigned int index, unsigned int n, bool flush)
269
@@ -XXX,XX +XXX,XX @@ static int qed_write_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
270
/* Adjust for offset into table */
271
offset += start * sizeof(uint64_t);
272
273
- if (qemu_in_coroutine()) {
274
- qemu_co_mutex_unlock(&s->table_lock);
275
- }
276
+ qemu_co_mutex_unlock(&s->table_lock);
277
ret = bdrv_pwritev(s->bs->file, offset, &qiov);
278
- if (qemu_in_coroutine()) {
279
- qemu_co_mutex_lock(&s->table_lock);
280
- }
281
+ qemu_co_mutex_lock(&s->table_lock);
282
trace_qed_write_table_cb(s, table, flush, ret);
283
if (ret < 0) {
284
goto out;
285
@@ -XXX,XX +XXX,XX @@ int qed_read_l1_table_sync(BDRVQEDState *s)
286
return qed_read_table(s, s->header.l1_table_offset, s->l1_table);
287
}
288
289
-/* Called either from qed_check or with table_lock held. */
290
+/* Called with table_lock held. */
291
int qed_write_l1_table(BDRVQEDState *s, unsigned int index, unsigned int n)
292
{
293
BLKDBG_EVENT(s->bs->file, BLKDBG_L1_UPDATE);
294
@@ -XXX,XX +XXX,XX @@ int qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index,
295
return qed_write_l1_table(s, index, n);
296
}
297
298
-/* Called either from qed_check or with table_lock held. */
299
+/* Called with table_lock held. */
300
int qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset)
301
{
302
int ret;
303
@@ -XXX,XX +XXX,XX @@ int qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request, uint64_t offset
304
return qed_read_l2_table(s, request, offset);
305
}
306
307
-/* Called either from qed_check or with table_lock held. */
308
+/* Called with table_lock held. */
309
int qed_write_l2_table(BDRVQEDState *s, QEDRequest *request,
310
unsigned int index, unsigned int n, bool flush)
311
{
312
diff --git a/block/qed.c b/block/qed.c
313
index XXXXXXX..XXXXXXX 100644
314
--- a/block/qed.c
315
+++ b/block/qed.c
316
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_qed_co_invalidate_cache(BlockDriverState *bs,
317
}
318
}
319
320
-static int bdrv_qed_check(BlockDriverState *bs, BdrvCheckResult *result,
321
- BdrvCheckMode fix)
322
+static int bdrv_qed_co_check(BlockDriverState *bs, BdrvCheckResult *result,
323
+ BdrvCheckMode fix)
324
{
325
BDRVQEDState *s = bs->opaque;
326
+ int ret;
327
328
- return qed_check(s, result, !!fix);
329
+ qemu_co_mutex_lock(&s->table_lock);
330
+ ret = qed_check(s, result, !!fix);
331
+ qemu_co_mutex_unlock(&s->table_lock);
332
+
333
+ return ret;
334
}
335
336
static QemuOptsList qed_create_opts = {
337
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_qed = {
338
.bdrv_refresh_limits = bdrv_qed_refresh_limits,
339
.bdrv_change_backing_file = bdrv_qed_change_backing_file,
340
.bdrv_co_invalidate_cache = bdrv_qed_co_invalidate_cache,
341
- .bdrv_check = bdrv_qed_check,
342
+ .bdrv_co_check = bdrv_qed_co_check,
343
.bdrv_detach_aio_context = bdrv_qed_detach_aio_context,
344
.bdrv_attach_aio_context = bdrv_qed_attach_aio_context,
345
.bdrv_co_drain_begin = bdrv_qed_co_drain_begin,
346
diff --git a/block/vdi.c b/block/vdi.c
298
diff --git a/block/vdi.c b/block/vdi.c
347
index XXXXXXX..XXXXXXX 100644
299
index XXXXXXX..XXXXXXX 100644
348
--- a/block/vdi.c
300
--- a/block/vdi.c
349
+++ b/block/vdi.c
301
+++ b/block/vdi.c
350
@@ -XXX,XX +XXX,XX @@ static void vdi_header_print(VdiHeader *header)
302
@@ -XXX,XX +XXX,XX @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
351
}
303
}
304
305
/* Disable migration when vdi images are used */
306
+ bdrv_graph_rdlock_main_loop();
307
error_setg(&s->migration_blocker, "The vdi format used by node '%s' "
308
"does not support live migration",
309
bdrv_get_device_or_node_name(bs));
310
+ bdrv_graph_rdunlock_main_loop();
311
+
312
ret = migrate_add_blocker(s->migration_blocker, errp);
313
if (ret < 0) {
314
error_free(s->migration_blocker);
315
diff --git a/block/vpc.c b/block/vpc.c
316
index XXXXXXX..XXXXXXX 100644
317
--- a/block/vpc.c
318
+++ b/block/vpc.c
319
@@ -XXX,XX +XXX,XX @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
320
}
321
322
/* Disable migration when VHD images are used */
323
+ bdrv_graph_rdlock_main_loop();
324
error_setg(&s->migration_blocker, "The vpc format used by node '%s' "
325
"does not support live migration",
326
bdrv_get_device_or_node_name(bs));
327
+ bdrv_graph_rdunlock_main_loop();
328
+
329
ret = migrate_add_blocker(s->migration_blocker, errp);
330
if (ret < 0) {
331
error_free(s->migration_blocker);
332
diff --git a/block/vvfat.c b/block/vvfat.c
333
index XXXXXXX..XXXXXXX 100644
334
--- a/block/vvfat.c
335
+++ b/block/vvfat.c
336
@@ -XXX,XX +XXX,XX @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
337
QemuOpts *opts;
338
int ret;
339
340
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
341
+
342
#ifdef DEBUG
343
vvv = s;
352
#endif
344
#endif
353
345
diff --git a/blockjob.c b/blockjob.c
354
-static int vdi_check(BlockDriverState *bs, BdrvCheckResult *res,
346
index XXXXXXX..XXXXXXX 100644
355
- BdrvCheckMode fix)
347
--- a/blockjob.c
356
+static int coroutine_fn vdi_co_check(BlockDriverState *bs, BdrvCheckResult *res,
348
+++ b/blockjob.c
357
+ BdrvCheckMode fix)
349
@@ -XXX,XX +XXX,XX @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
358
{
350
BlockJob *job;
359
/* TODO: additional checks possible. */
351
int ret;
360
BDRVVdiState *s = (BDRVVdiState *)bs->opaque;
352
GLOBAL_STATE_CODE();
361
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_vdi = {
353
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
362
.bdrv_get_info = vdi_get_info,
354
363
355
if (job_id == NULL && !(flags & JOB_INTERNAL)) {
364
.create_opts = &vdi_create_opts,
356
job_id = bdrv_get_device_name(bs);
365
- .bdrv_check = vdi_check,
366
+ .bdrv_co_check = vdi_co_check,
367
};
368
369
static void bdrv_vdi_init(void)
370
diff --git a/block/vhdx.c b/block/vhdx.c
371
index XXXXXXX..XXXXXXX 100644
372
--- a/block/vhdx.c
373
+++ b/block/vhdx.c
374
@@ -XXX,XX +XXX,XX @@ exit:
375
* r/w and any log has already been replayed, so there is nothing (currently)
376
* for us to do here
377
*/
378
-static int vhdx_check(BlockDriverState *bs, BdrvCheckResult *result,
379
- BdrvCheckMode fix)
380
+static int coroutine_fn vhdx_co_check(BlockDriverState *bs,
381
+ BdrvCheckResult *result,
382
+ BdrvCheckMode fix)
383
{
384
BDRVVHDXState *s = bs->opaque;
385
386
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_vhdx = {
387
.bdrv_co_writev = vhdx_co_writev,
388
.bdrv_co_create_opts = vhdx_co_create_opts,
389
.bdrv_get_info = vhdx_get_info,
390
- .bdrv_check = vhdx_check,
391
+ .bdrv_co_check = vhdx_co_check,
392
.bdrv_has_zero_init = bdrv_has_zero_init_1,
393
394
.create_opts = &vhdx_create_opts,
395
diff --git a/block/vmdk.c b/block/vmdk.c
396
index XXXXXXX..XXXXXXX 100644
397
--- a/block/vmdk.c
398
+++ b/block/vmdk.c
399
@@ -XXX,XX +XXX,XX @@ static ImageInfo *vmdk_get_extent_info(VmdkExtent *extent)
400
return info;
401
}
402
403
-static int vmdk_check(BlockDriverState *bs, BdrvCheckResult *result,
404
- BdrvCheckMode fix)
405
+static int coroutine_fn vmdk_co_check(BlockDriverState *bs,
406
+ BdrvCheckResult *result,
407
+ BdrvCheckMode fix)
408
{
409
BDRVVmdkState *s = bs->opaque;
410
VmdkExtent *extent = NULL;
411
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_vmdk = {
412
.instance_size = sizeof(BDRVVmdkState),
413
.bdrv_probe = vmdk_probe,
414
.bdrv_open = vmdk_open,
415
- .bdrv_check = vmdk_check,
416
+ .bdrv_co_check = vmdk_co_check,
417
.bdrv_reopen_prepare = vmdk_reopen_prepare,
418
.bdrv_child_perm = bdrv_format_default_perms,
419
.bdrv_co_preadv = vmdk_co_preadv,
420
--
357
--
421
2.13.6
358
2.41.0
422
423
diff view generated by jsdifflib
1
Now that the options are already available in qemu_rbd_open() and not
1
This adds GRAPH_RDLOCK annotations to declare that callers of
2
only parsed in qemu_rbd_connect(), we can assign s->snap and
2
bdrv_amend_options() need to hold a reader lock for the graph. This
3
s->image_name there instead of passing the fields by reference to
3
removes an assume_graph_lock() call in crypto's implementation.
4
qemu_rbd_connect().
5
4
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Message-ID: <20230929145157.45443-14-kwolf@redhat.com>
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
9
---
9
block/rbd.c | 14 +++++---------
10
include/block/block-global-state.h | 8 ++++----
10
1 file changed, 5 insertions(+), 9 deletions(-)
11
include/block/block_int-common.h | 10 ++++------
12
block/crypto.c | 4 +---
13
qemu-img.c | 7 +++++++
14
4 files changed, 16 insertions(+), 13 deletions(-)
11
15
12
diff --git a/block/rbd.c b/block/rbd.c
16
diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h
13
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
14
--- a/block/rbd.c
18
--- a/include/block/block-global-state.h
15
+++ b/block/rbd.c
19
+++ b/include/block/block-global-state.h
16
@@ -XXX,XX +XXX,XX @@ static char *qemu_rbd_mon_host(BlockdevOptionsRbd *opts, Error **errp)
20
@@ -XXX,XX +XXX,XX @@ void bdrv_unfreeze_backing_chain(BlockDriverState *bs, BlockDriverState *base);
21
*/
22
typedef void BlockDriverAmendStatusCB(BlockDriverState *bs, int64_t offset,
23
int64_t total_work_size, void *opaque);
24
-int bdrv_amend_options(BlockDriverState *bs_new, QemuOpts *opts,
25
- BlockDriverAmendStatusCB *status_cb, void *cb_opaque,
26
- bool force,
27
- Error **errp);
28
+int GRAPH_RDLOCK
29
+bdrv_amend_options(BlockDriverState *bs_new, QemuOpts *opts,
30
+ BlockDriverAmendStatusCB *status_cb, void *cb_opaque,
31
+ bool force, Error **errp);
32
33
/* check if a named node can be replaced when doing drive-mirror */
34
BlockDriverState * GRAPH_RDLOCK
35
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
36
index XXXXXXX..XXXXXXX 100644
37
--- a/include/block/block_int-common.h
38
+++ b/include/block/block_int-common.h
39
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
40
int coroutine_fn GRAPH_UNLOCKED_PTR (*bdrv_co_create_opts)(
41
BlockDriver *drv, const char *filename, QemuOpts *opts, Error **errp);
42
43
- int (*bdrv_amend_options)(BlockDriverState *bs,
44
- QemuOpts *opts,
45
- BlockDriverAmendStatusCB *status_cb,
46
- void *cb_opaque,
47
- bool force,
48
- Error **errp);
49
+ int GRAPH_RDLOCK_PTR (*bdrv_amend_options)(
50
+ BlockDriverState *bs, QemuOpts *opts,
51
+ BlockDriverAmendStatusCB *status_cb, void *cb_opaque,
52
+ bool force, Error **errp);
53
54
int (*bdrv_make_empty)(BlockDriverState *bs);
55
56
diff --git a/block/crypto.c b/block/crypto.c
57
index XXXXXXX..XXXXXXX 100644
58
--- a/block/crypto.c
59
+++ b/block/crypto.c
60
@@ -XXX,XX +XXX,XX @@ block_crypto_amend_options_generic_luks(BlockDriverState *bs,
61
errp);
17
}
62
}
18
63
19
static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
64
-static int
20
- char **s_snap, char **s_image_name,
65
+static int GRAPH_RDLOCK
21
BlockdevOptionsRbd *opts, bool cache,
66
block_crypto_amend_options_luks(BlockDriverState *bs,
22
const char *keypairs, const char *secretid,
67
QemuOpts *opts,
23
Error **errp)
68
BlockDriverAmendStatusCB *status_cb,
24
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
69
@@ -XXX,XX +XXX,XX @@ block_crypto_amend_options_luks(BlockDriverState *bs,
25
goto failed_opts;
70
QCryptoBlockAmendOptions *amend_options = NULL;
26
}
71
int ret = -EINVAL;
27
72
28
- *s_snap = g_strdup(opts->snapshot);
73
- assume_graph_lock(); /* FIXME */
29
- *s_image_name = g_strdup(opts->image);
30
-
74
-
31
/* try default location when conf=NULL, but ignore failure */
75
assert(crypto);
32
r = rados_conf_read_file(*cluster, opts->conf);
76
assert(crypto->block);
33
if (opts->has_conf && r < 0) {
77
34
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
78
diff --git a/qemu-img.c b/qemu-img.c
35
79
index XXXXXXX..XXXXXXX 100644
36
failed_shutdown:
80
--- a/qemu-img.c
37
rados_shutdown(*cluster);
81
+++ b/qemu-img.c
38
- g_free(*s_snap);
82
@@ -XXX,XX +XXX,XX @@ static int print_amend_option_help(const char *format)
39
- g_free(*s_image_name);
83
{
40
failed_opts:
84
BlockDriver *drv;
41
g_free(mon_host);
85
42
return r;
86
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
43
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
87
+
88
/* Find driver and parse its options */
89
drv = bdrv_find_format(format);
90
if (!drv) {
91
@@ -XXX,XX +XXX,XX @@ static int img_amend(int argc, char **argv)
44
goto out;
92
goto out;
45
}
93
}
46
94
47
- r = qemu_rbd_connect(&s->cluster, &s->io_ctx, &s->snap, &s->image_name,
95
+ bdrv_graph_rdlock_main_loop();
48
- opts, !(flags & BDRV_O_NOCACHE), keypairs, secretid,
96
if (!bs->drv->bdrv_amend_options) {
49
- errp);
97
error_report("Format driver '%s' does not support option amendment",
50
+ r = qemu_rbd_connect(&s->cluster, &s->io_ctx, opts,
98
fmt);
51
+ !(flags & BDRV_O_NOCACHE), keypairs, secretid, errp);
99
+ bdrv_graph_rdunlock_main_loop();
52
if (r < 0) {
100
ret = -1;
53
goto out;
101
goto out;
54
}
102
}
55
103
@@ -XXX,XX +XXX,XX @@ static int img_amend(int argc, char **argv)
56
+ s->snap = g_strdup(opts->snapshot);
104
"This option is only supported for image creation\n");
57
+ s->image_name = g_strdup(opts->image);
105
}
106
107
+ bdrv_graph_rdunlock_main_loop();
108
error_report_err(err);
109
ret = -1;
110
goto out;
111
@@ -XXX,XX +XXX,XX @@ static int img_amend(int argc, char **argv)
112
qemu_progress_print(0.f, 0);
113
ret = bdrv_amend_options(bs, opts, &amend_status_cb, NULL, force, &err);
114
qemu_progress_print(100.f, 0);
115
+ bdrv_graph_rdunlock_main_loop();
58
+
116
+
59
/* rbd_open is always r/w */
117
if (ret < 0) {
60
r = rbd_open(s->io_ctx, s->image_name, &s->image, s->snap);
118
error_report_err(err);
61
if (r < 0) {
119
goto out;
62
--
120
--
63
2.13.6
121
2.41.0
64
65
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
This adds GRAPH_RDLOCK annotations to declare that callers of
2
qcow2_signal_corruption() need to hold a reader lock for the graph
3
because it calls bdrv_get_node_name(), which accesses the parents list
4
of a node.
2
5
3
This function checks that the offset and size of a table are valid.
6
For some places, we know that they will hold the lock, but we don't have
7
the GRAPH_RDLOCK annotations yet. In this case, add assume_graph_lock()
8
with a FIXME comment. These places will be removed once everything is
9
properly annotated.
4
10
5
While the offset checks are fine, the size check is too generic, since
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
it only verifies that the total size in bytes fits in a 64-bit
12
Message-ID: <20230929145157.45443-15-kwolf@redhat.com>
7
integer. In practice all tables used in qcow2 have much smaller size
13
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
limits, so the size needs to be checked again for each table using its
9
actual limit.
10
11
This patch generalizes this function by allowing the caller to specify
12
the maximum size for that table. In addition to that it allows passing
13
an Error variable.
14
15
The function is also renamed and made public since we're going to use
16
it in other parts of the code.
17
18
Signed-off-by: Alberto Garcia <berto@igalia.com>
19
Reviewed-by: Eric Blake <eblake@redhat.com>
20
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
21
---
15
---
22
block/qcow2.h | 10 +++---
16
block/qcow2.h | 180 +++++++++++++++++------------
23
block/qcow2.c | 77 ++++++++++++++++++----------------------------
17
include/block/block-global-state.h | 2 +-
24
tests/qemu-iotests/080.out | 16 +++++-----
18
include/block/block_int-common.h | 2 +-
25
3 files changed, 43 insertions(+), 60 deletions(-)
19
block.c | 3 +-
20
block/block-backend.c | 2 +
21
block/qcow2-bitmap.c | 31 ++---
22
block/qcow2-cache.c | 11 +-
23
block/qcow2-cluster.c | 62 +++++-----
24
block/qcow2-refcount.c | 80 ++++++-------
25
block/qcow2.c | 61 +++++-----
26
block/replication.c | 8 +-
27
11 files changed, 250 insertions(+), 192 deletions(-)
26
28
27
diff --git a/block/qcow2.h b/block/qcow2.h
29
diff --git a/block/qcow2.h b/block/qcow2.h
28
index XXXXXXX..XXXXXXX 100644
30
index XXXXXXX..XXXXXXX 100644
29
--- a/block/qcow2.h
31
--- a/block/qcow2.h
30
+++ b/block/qcow2.h
32
+++ b/block/qcow2.h
31
@@ -XXX,XX +XXX,XX @@ static inline int64_t qcow2_vm_state_offset(BDRVQcow2State *s)
33
@@ -XXX,XX +XXX,XX @@ int qcow2_mark_dirty(BlockDriverState *bs);
32
return (int64_t)s->l1_vm_state_index << (s->cluster_bits + s->l2_bits);
34
int qcow2_mark_corrupt(BlockDriverState *bs);
33
}
35
int qcow2_update_header(BlockDriverState *bs);
34
36
35
-static inline uint64_t qcow2_max_refcount_clusters(BDRVQcow2State *s)
37
-void qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset,
36
-{
38
- int64_t size, const char *message_format, ...)
37
- return QCOW_MAX_REFTABLE_SIZE >> s->cluster_bits;
39
- G_GNUC_PRINTF(5, 6);
38
-}
40
+void GRAPH_RDLOCK
39
-
41
+qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset,
40
static inline QCow2ClusterType qcow2_get_cluster_type(uint64_t l2_entry)
42
+ int64_t size, const char *message_format, ...)
41
{
43
+ G_GNUC_PRINTF(5, 6);
42
if (l2_entry & QCOW_OFLAG_COMPRESSED) {
44
43
@@ -XXX,XX +XXX,XX @@ void qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset,
45
int qcow2_validate_table(BlockDriverState *bs, uint64_t offset,
44
int64_t size, const char *message_format, ...)
46
uint64_t entries, size_t entry_len,
45
GCC_FMT_ATTR(5, 6);
47
@@ -XXX,XX +XXX,XX @@ int qcow2_validate_table(BlockDriverState *bs, uint64_t offset,
46
48
int coroutine_fn GRAPH_RDLOCK qcow2_refcount_init(BlockDriverState *bs);
47
+int qcow2_validate_table(BlockDriverState *bs, uint64_t offset,
48
+ uint64_t entries, size_t entry_len,
49
+ int64_t max_size_bytes, const char *table_name,
50
+ Error **errp);
51
+
52
/* qcow2-refcount.c functions */
53
int qcow2_refcount_init(BlockDriverState *bs);
54
void qcow2_refcount_close(BlockDriverState *bs);
49
void qcow2_refcount_close(BlockDriverState *bs);
50
51
-int qcow2_get_refcount(BlockDriverState *bs, int64_t cluster_index,
52
- uint64_t *refcount);
53
+int GRAPH_RDLOCK qcow2_get_refcount(BlockDriverState *bs, int64_t cluster_index,
54
+ uint64_t *refcount);
55
56
-int qcow2_update_cluster_refcount(BlockDriverState *bs, int64_t cluster_index,
57
- uint64_t addend, bool decrease,
58
- enum qcow2_discard_type type);
59
+int GRAPH_RDLOCK
60
+qcow2_update_cluster_refcount(BlockDriverState *bs, int64_t cluster_index,
61
+ uint64_t addend, bool decrease,
62
+ enum qcow2_discard_type type);
63
64
-int64_t qcow2_refcount_area(BlockDriverState *bs, uint64_t offset,
65
- uint64_t additional_clusters, bool exact_size,
66
- int new_refblock_index,
67
- uint64_t new_refblock_offset);
68
+int64_t GRAPH_RDLOCK
69
+qcow2_refcount_area(BlockDriverState *bs, uint64_t offset,
70
+ uint64_t additional_clusters, bool exact_size,
71
+ int new_refblock_index,
72
+ uint64_t new_refblock_offset);
73
74
-int64_t qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size);
75
-int64_t coroutine_fn qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
76
- int64_t nb_clusters);
77
-int64_t coroutine_fn GRAPH_RDLOCK qcow2_alloc_bytes(BlockDriverState *bs, int size);
78
-void qcow2_free_clusters(BlockDriverState *bs,
79
- int64_t offset, int64_t size,
80
- enum qcow2_discard_type type);
81
-void qcow2_free_any_cluster(BlockDriverState *bs, uint64_t l2_entry,
82
- enum qcow2_discard_type type);
83
+int64_t GRAPH_RDLOCK
84
+qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size);
85
86
-int qcow2_update_snapshot_refcount(BlockDriverState *bs,
87
- int64_t l1_table_offset, int l1_size, int addend);
88
+int64_t GRAPH_RDLOCK coroutine_fn
89
+qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
90
+ int64_t nb_clusters);
91
92
-int qcow2_flush_caches(BlockDriverState *bs);
93
-int qcow2_write_caches(BlockDriverState *bs);
94
+int64_t coroutine_fn GRAPH_RDLOCK qcow2_alloc_bytes(BlockDriverState *bs, int size);
95
+void GRAPH_RDLOCK qcow2_free_clusters(BlockDriverState *bs,
96
+ int64_t offset, int64_t size,
97
+ enum qcow2_discard_type type);
98
+void GRAPH_RDLOCK
99
+qcow2_free_any_cluster(BlockDriverState *bs, uint64_t l2_entry,
100
+ enum qcow2_discard_type type);
101
+
102
+int GRAPH_RDLOCK
103
+qcow2_update_snapshot_refcount(BlockDriverState *bs, int64_t l1_table_offset,
104
+ int l1_size, int addend);
105
+
106
+int GRAPH_RDLOCK qcow2_flush_caches(BlockDriverState *bs);
107
+int GRAPH_RDLOCK qcow2_write_caches(BlockDriverState *bs);
108
int coroutine_fn qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
109
BdrvCheckMode fix);
110
111
@@ -XXX,XX +XXX,XX @@ void qcow2_process_discards(BlockDriverState *bs, int ret);
112
113
int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset,
114
int64_t size);
115
-int qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset,
116
- int64_t size, bool data_file);
117
+int GRAPH_RDLOCK
118
+qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset,
119
+ int64_t size, bool data_file);
120
+
121
int coroutine_fn qcow2_inc_refcounts_imrt(BlockDriverState *bs, BdrvCheckResult *res,
122
void **refcount_table,
123
int64_t *refcount_table_size,
124
int64_t offset, int64_t size);
125
126
-int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order,
127
- BlockDriverAmendStatusCB *status_cb,
128
- void *cb_opaque, Error **errp);
129
+int GRAPH_RDLOCK
130
+qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order,
131
+ BlockDriverAmendStatusCB *status_cb,
132
+ void *cb_opaque, Error **errp);
133
int coroutine_fn GRAPH_RDLOCK qcow2_shrink_reftable(BlockDriverState *bs);
134
-int64_t coroutine_fn qcow2_get_last_cluster(BlockDriverState *bs, int64_t size);
135
+
136
+int64_t coroutine_fn GRAPH_RDLOCK
137
+qcow2_get_last_cluster(BlockDriverState *bs, int64_t size);
138
139
int coroutine_fn GRAPH_RDLOCK
140
qcow2_detect_metadata_preallocation(BlockDriverState *bs);
141
142
/* qcow2-cluster.c functions */
143
-int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
144
- bool exact_size);
145
+int GRAPH_RDLOCK
146
+qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, bool exact_size);
147
148
int coroutine_fn GRAPH_RDLOCK
149
qcow2_shrink_l1_table(BlockDriverState *bs, uint64_t max_size);
150
151
-int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index);
152
+int GRAPH_RDLOCK qcow2_write_l1_entry(BlockDriverState *bs, int l1_index);
153
int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num,
154
uint8_t *buf, int nb_sectors, bool enc, Error **errp);
155
156
-int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,
157
- unsigned int *bytes, uint64_t *host_offset,
158
- QCow2SubclusterType *subcluster_type);
159
-int coroutine_fn qcow2_alloc_host_offset(BlockDriverState *bs, uint64_t offset,
160
- unsigned int *bytes,
161
- uint64_t *host_offset, QCowL2Meta **m);
162
+int GRAPH_RDLOCK
163
+qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,
164
+ unsigned int *bytes, uint64_t *host_offset,
165
+ QCow2SubclusterType *subcluster_type);
166
+
167
+int coroutine_fn GRAPH_RDLOCK
168
+qcow2_alloc_host_offset(BlockDriverState *bs, uint64_t offset,
169
+ unsigned int *bytes, uint64_t *host_offset,
170
+ QCowL2Meta **m);
171
+
172
int coroutine_fn GRAPH_RDLOCK
173
qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, uint64_t offset,
174
int compressed_size, uint64_t *host_offset);
175
@@ -XXX,XX +XXX,XX @@ void qcow2_parse_compressed_l2_entry(BlockDriverState *bs, uint64_t l2_entry,
176
int coroutine_fn GRAPH_RDLOCK
177
qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m);
178
179
-void coroutine_fn qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m);
180
-int qcow2_cluster_discard(BlockDriverState *bs, uint64_t offset,
181
- uint64_t bytes, enum qcow2_discard_type type,
182
- bool full_discard);
183
+void coroutine_fn GRAPH_RDLOCK
184
+qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m);
185
+
186
+int GRAPH_RDLOCK
187
+qcow2_cluster_discard(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
188
+ enum qcow2_discard_type type, bool full_discard);
189
190
int coroutine_fn GRAPH_RDLOCK
191
qcow2_subcluster_zeroize(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
192
int flags);
193
194
-int qcow2_expand_zero_clusters(BlockDriverState *bs,
195
- BlockDriverAmendStatusCB *status_cb,
196
- void *cb_opaque);
197
+int GRAPH_RDLOCK
198
+qcow2_expand_zero_clusters(BlockDriverState *bs,
199
+ BlockDriverAmendStatusCB *status_cb,
200
+ void *cb_opaque);
201
202
/* qcow2-snapshot.c functions */
203
-int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
204
-int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id);
205
-int qcow2_snapshot_delete(BlockDriverState *bs,
206
- const char *snapshot_id,
207
- const char *name,
208
- Error **errp);
209
+int GRAPH_RDLOCK
210
+qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
211
+
212
+int GRAPH_RDLOCK
213
+qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id);
214
+
215
+int GRAPH_RDLOCK
216
+qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id,
217
+ const char *name, Error **errp);
218
+
219
int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab);
220
int qcow2_snapshot_load_tmp(BlockDriverState *bs,
221
const char *snapshot_id,
222
@@ -XXX,XX +XXX,XX @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs,
223
void qcow2_free_snapshots(BlockDriverState *bs);
224
int coroutine_fn GRAPH_RDLOCK
225
qcow2_read_snapshots(BlockDriverState *bs, Error **errp);
226
-int qcow2_write_snapshots(BlockDriverState *bs);
227
+int GRAPH_RDLOCK qcow2_write_snapshots(BlockDriverState *bs);
228
229
int coroutine_fn GRAPH_RDLOCK
230
qcow2_check_read_snapshot_table(BlockDriverState *bs, BdrvCheckResult *result,
231
BdrvCheckMode fix);
232
233
-int coroutine_fn qcow2_check_fix_snapshot_table(BlockDriverState *bs,
234
- BdrvCheckResult *result,
235
- BdrvCheckMode fix);
236
+int coroutine_fn GRAPH_RDLOCK
237
+qcow2_check_fix_snapshot_table(BlockDriverState *bs, BdrvCheckResult *result,
238
+ BdrvCheckMode fix);
239
240
/* qcow2-cache.c functions */
241
Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables,
242
@@ -XXX,XX +XXX,XX @@ Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables,
243
int qcow2_cache_destroy(Qcow2Cache *c);
244
245
void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table);
246
-int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c);
247
-int qcow2_cache_write(BlockDriverState *bs, Qcow2Cache *c);
248
-int qcow2_cache_set_dependency(BlockDriverState *bs, Qcow2Cache *c,
249
- Qcow2Cache *dependency);
250
+int GRAPH_RDLOCK qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c);
251
+int GRAPH_RDLOCK qcow2_cache_write(BlockDriverState *bs, Qcow2Cache *c);
252
+int GRAPH_RDLOCK qcow2_cache_set_dependency(BlockDriverState *bs, Qcow2Cache *c,
253
+ Qcow2Cache *dependency);
254
void qcow2_cache_depends_on_flush(Qcow2Cache *c);
255
256
void qcow2_cache_clean_unused(Qcow2Cache *c);
257
-int qcow2_cache_empty(BlockDriverState *bs, Qcow2Cache *c);
258
+int GRAPH_RDLOCK qcow2_cache_empty(BlockDriverState *bs, Qcow2Cache *c);
259
+
260
+int GRAPH_RDLOCK
261
+qcow2_cache_get(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
262
+ void **table);
263
+
264
+int GRAPH_RDLOCK
265
+qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
266
+ void **table);
267
268
-int qcow2_cache_get(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
269
- void **table);
270
-int qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
271
- void **table);
272
void qcow2_cache_put(Qcow2Cache *c, void **table);
273
void *qcow2_cache_is_table_offset(Qcow2Cache *c, uint64_t offset);
274
void qcow2_cache_discard(Qcow2Cache *c, void *table);
275
@@ -XXX,XX +XXX,XX @@ bool coroutine_fn GRAPH_RDLOCK
276
qcow2_load_dirty_bitmaps(BlockDriverState *bs, bool *header_updated, Error **errp);
277
bool qcow2_get_bitmap_info_list(BlockDriverState *bs,
278
Qcow2BitmapInfoList **info_list, Error **errp);
279
-int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp);
280
+int GRAPH_RDLOCK qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp);
281
+int GRAPH_RDLOCK qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp);
282
int coroutine_fn qcow2_truncate_bitmaps_check(BlockDriverState *bs, Error **errp);
283
-bool qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs,
284
- bool release_stored, Error **errp);
285
-int qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp);
286
+
287
+bool GRAPH_RDLOCK
288
+qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, bool release_stored,
289
+ Error **errp);
290
+
291
bool coroutine_fn GRAPH_RDLOCK
292
qcow2_co_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name,
293
uint32_t granularity, Error **errp);
294
-int coroutine_fn qcow2_co_remove_persistent_dirty_bitmap(BlockDriverState *bs,
295
- const char *name,
296
- Error **errp);
297
+
298
+int coroutine_fn GRAPH_RDLOCK
299
+qcow2_co_remove_persistent_dirty_bitmap(BlockDriverState *bs, const char *name,
300
+ Error **errp);
301
+
302
bool qcow2_supports_persistent_dirty_bitmap(BlockDriverState *bs);
303
uint64_t qcow2_get_persistent_dirty_bitmap_size(BlockDriverState *bs,
304
uint32_t cluster_size);
305
diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h
306
index XXXXXXX..XXXXXXX 100644
307
--- a/include/block/block-global-state.h
308
+++ b/include/block/block-global-state.h
309
@@ -XXX,XX +XXX,XX @@ void GRAPH_RDLOCK
310
bdrv_refresh_limits(BlockDriverState *bs, Transaction *tran, Error **errp);
311
312
int bdrv_commit(BlockDriverState *bs);
313
-int bdrv_make_empty(BdrvChild *c, Error **errp);
314
+int GRAPH_RDLOCK bdrv_make_empty(BdrvChild *c, Error **errp);
315
int bdrv_change_backing_file(BlockDriverState *bs, const char *backing_file,
316
const char *backing_fmt, bool warn);
317
void bdrv_register(BlockDriver *bdrv);
318
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
319
index XXXXXXX..XXXXXXX 100644
320
--- a/include/block/block_int-common.h
321
+++ b/include/block/block_int-common.h
322
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
323
BlockDriverAmendStatusCB *status_cb, void *cb_opaque,
324
bool force, Error **errp);
325
326
- int (*bdrv_make_empty)(BlockDriverState *bs);
327
+ int GRAPH_RDLOCK_PTR (*bdrv_make_empty)(BlockDriverState *bs);
328
329
/*
330
* Refreshes the bs->exact_filename field. If that is impossible,
331
diff --git a/block.c b/block.c
332
index XXXXXXX..XXXXXXX 100644
333
--- a/block.c
334
+++ b/block.c
335
@@ -XXX,XX +XXX,XX @@ bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp)
336
{
337
BdrvOpBlocker *blocker;
338
GLOBAL_STATE_CODE();
339
- GRAPH_RDLOCK_GUARD_MAINLOOP();
340
+
341
+ assume_graph_lock(); /* FIXME */
342
343
assert((int) op >= 0 && op < BLOCK_OP_TYPE_MAX);
344
if (!QLIST_EMPTY(&bs->op_blockers[op])) {
345
diff --git a/block/block-backend.c b/block/block-backend.c
346
index XXXXXXX..XXXXXXX 100644
347
--- a/block/block-backend.c
348
+++ b/block/block-backend.c
349
@@ -XXX,XX +XXX,XX @@ const BdrvChild *blk_root(BlockBackend *blk)
350
int blk_make_empty(BlockBackend *blk, Error **errp)
351
{
352
GLOBAL_STATE_CODE();
353
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
354
+
355
if (!blk_is_available(blk)) {
356
error_setg(errp, "No medium inserted");
357
return -ENOMEDIUM;
358
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
359
index XXXXXXX..XXXXXXX 100644
360
--- a/block/qcow2-bitmap.c
361
+++ b/block/qcow2-bitmap.c
362
@@ -XXX,XX +XXX,XX @@ static int check_constraints_on_bitmap(BlockDriverState *bs,
363
return 0;
364
}
365
366
-static void clear_bitmap_table(BlockDriverState *bs, uint64_t *bitmap_table,
367
- uint32_t bitmap_table_size)
368
+static void GRAPH_RDLOCK
369
+clear_bitmap_table(BlockDriverState *bs, uint64_t *bitmap_table,
370
+ uint32_t bitmap_table_size)
371
{
372
BDRVQcow2State *s = bs->opaque;
373
int i;
374
@@ -XXX,XX +XXX,XX @@ fail:
375
return ret;
376
}
377
378
-static int free_bitmap_clusters(BlockDriverState *bs, Qcow2BitmapTable *tb)
379
+static int GRAPH_RDLOCK
380
+free_bitmap_clusters(BlockDriverState *bs, Qcow2BitmapTable *tb)
381
{
382
int ret;
383
uint64_t *bitmap_table;
384
@@ -XXX,XX +XXX,XX @@ out:
385
* Store bitmap list to qcow2 image as a bitmap directory.
386
* Everything is checked.
387
*/
388
-static int bitmap_list_store(BlockDriverState *bs, Qcow2BitmapList *bm_list,
389
- uint64_t *offset, uint64_t *size, bool in_place)
390
+static int GRAPH_RDLOCK
391
+bitmap_list_store(BlockDriverState *bs, Qcow2BitmapList *bm_list,
392
+ uint64_t *offset, uint64_t *size, bool in_place)
393
{
394
int ret;
395
uint8_t *dir;
396
@@ -XXX,XX +XXX,XX @@ fail:
397
* Bitmap List end
398
*/
399
400
-static int update_ext_header_and_dir_in_place(BlockDriverState *bs,
401
- Qcow2BitmapList *bm_list)
402
+static int GRAPH_RDLOCK
403
+update_ext_header_and_dir_in_place(BlockDriverState *bs,
404
+ Qcow2BitmapList *bm_list)
405
{
406
BDRVQcow2State *s = bs->opaque;
407
int ret;
408
@@ -XXX,XX +XXX,XX @@ static int update_ext_header_and_dir_in_place(BlockDriverState *bs,
409
*/
410
}
411
412
-static int update_ext_header_and_dir(BlockDriverState *bs,
413
- Qcow2BitmapList *bm_list)
414
+static int GRAPH_RDLOCK
415
+update_ext_header_and_dir(BlockDriverState *bs, Qcow2BitmapList *bm_list)
416
{
417
BDRVQcow2State *s = bs->opaque;
418
int ret;
419
@@ -XXX,XX +XXX,XX @@ out:
420
/* store_bitmap_data()
421
* Store bitmap to image, filling bitmap table accordingly.
422
*/
423
-static uint64_t *store_bitmap_data(BlockDriverState *bs,
424
- BdrvDirtyBitmap *bitmap,
425
- uint32_t *bitmap_table_size, Error **errp)
426
+static uint64_t * GRAPH_RDLOCK
427
+store_bitmap_data(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
428
+ uint32_t *bitmap_table_size, Error **errp)
429
{
430
int ret;
431
BDRVQcow2State *s = bs->opaque;
432
@@ -XXX,XX +XXX,XX @@ fail:
433
* Store bm->dirty_bitmap to qcow2.
434
* Set bm->table_offset and bm->table_size accordingly.
435
*/
436
-static int store_bitmap(BlockDriverState *bs, Qcow2Bitmap *bm, Error **errp)
437
+static int GRAPH_RDLOCK
438
+store_bitmap(BlockDriverState *bs, Qcow2Bitmap *bm, Error **errp)
439
{
440
int ret;
441
uint64_t *tb;
442
diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c
443
index XXXXXXX..XXXXXXX 100644
444
--- a/block/qcow2-cache.c
445
+++ b/block/qcow2-cache.c
446
@@ -XXX,XX +XXX,XX @@ int qcow2_cache_destroy(Qcow2Cache *c)
447
return 0;
448
}
449
450
-static int qcow2_cache_flush_dependency(BlockDriverState *bs, Qcow2Cache *c)
451
+static int GRAPH_RDLOCK
452
+qcow2_cache_flush_dependency(BlockDriverState *bs, Qcow2Cache *c)
453
{
454
int ret;
455
456
@@ -XXX,XX +XXX,XX @@ static int qcow2_cache_flush_dependency(BlockDriverState *bs, Qcow2Cache *c)
457
return 0;
458
}
459
460
-static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i)
461
+static int GRAPH_RDLOCK
462
+qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i)
463
{
464
BDRVQcow2State *s = bs->opaque;
465
int ret = 0;
466
@@ -XXX,XX +XXX,XX @@ int qcow2_cache_empty(BlockDriverState *bs, Qcow2Cache *c)
467
return 0;
468
}
469
470
-static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
471
- uint64_t offset, void **table, bool read_from_disk)
472
+static int GRAPH_RDLOCK
473
+qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
474
+ void **table, bool read_from_disk)
475
{
476
BDRVQcow2State *s = bs->opaque;
477
int i;
478
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
479
index XXXXXXX..XXXXXXX 100644
480
--- a/block/qcow2-cluster.c
481
+++ b/block/qcow2-cluster.c
482
@@ -XXX,XX +XXX,XX @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
483
* the cache is used; otherwise the L2 slice is loaded from the image
484
* file.
485
*/
486
-static int l2_load(BlockDriverState *bs, uint64_t offset,
487
- uint64_t l2_offset, uint64_t **l2_slice)
488
+static int GRAPH_RDLOCK
489
+l2_load(BlockDriverState *bs, uint64_t offset,
490
+ uint64_t l2_offset, uint64_t **l2_slice)
491
{
492
BDRVQcow2State *s = bs->opaque;
493
int start_of_slice = l2_entry_size(s) *
494
@@ -XXX,XX +XXX,XX @@ int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index)
495
*
496
*/
497
498
-static int l2_allocate(BlockDriverState *bs, int l1_index)
499
+static int GRAPH_RDLOCK l2_allocate(BlockDriverState *bs, int l1_index)
500
{
501
BDRVQcow2State *s = bs->opaque;
502
uint64_t old_l2_offset;
503
@@ -XXX,XX +XXX,XX @@ fail:
504
*
505
* Returns 0 on success, -errno in failure case
506
*/
507
-static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
508
- uint64_t **new_l2_slice,
509
- int *new_l2_index)
510
+static int GRAPH_RDLOCK
511
+get_cluster_table(BlockDriverState *bs, uint64_t offset,
512
+ uint64_t **new_l2_slice, int *new_l2_index)
513
{
514
BDRVQcow2State *s = bs->opaque;
515
unsigned int l2_index;
516
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m)
517
*
518
* Returns 0 on success, -errno on failure.
519
*/
520
-static int coroutine_fn calculate_l2_meta(BlockDriverState *bs,
521
- uint64_t host_cluster_offset,
522
- uint64_t guest_offset, unsigned bytes,
523
- uint64_t *l2_slice, QCowL2Meta **m,
524
- bool keep_old)
525
+static int coroutine_fn GRAPH_RDLOCK
526
+calculate_l2_meta(BlockDriverState *bs, uint64_t host_cluster_offset,
527
+ uint64_t guest_offset, unsigned bytes, uint64_t *l2_slice,
528
+ QCowL2Meta **m, bool keep_old)
529
{
530
BDRVQcow2State *s = bs->opaque;
531
int sc_index, l2_index = offset_to_l2_slice_index(s, guest_offset);
532
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn handle_dependencies(BlockDriverState *bs,
533
*
534
* -errno: in error cases
535
*/
536
-static int coroutine_fn handle_copied(BlockDriverState *bs,
537
- uint64_t guest_offset, uint64_t *host_offset, uint64_t *bytes,
538
- QCowL2Meta **m)
539
+static int coroutine_fn GRAPH_RDLOCK
540
+handle_copied(BlockDriverState *bs, uint64_t guest_offset,
541
+ uint64_t *host_offset, uint64_t *bytes, QCowL2Meta **m)
542
{
543
BDRVQcow2State *s = bs->opaque;
544
int l2_index;
545
@@ -XXX,XX +XXX,XX @@ out:
546
* function has been waiting for another request and the allocation must be
547
* restarted, but the whole request should not be failed.
548
*/
549
-static int coroutine_fn do_alloc_cluster_offset(BlockDriverState *bs,
550
- uint64_t guest_offset,
551
- uint64_t *host_offset,
552
- uint64_t *nb_clusters)
553
+static int coroutine_fn GRAPH_RDLOCK
554
+do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset,
555
+ uint64_t *host_offset, uint64_t *nb_clusters)
556
{
557
BDRVQcow2State *s = bs->opaque;
558
559
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn do_alloc_cluster_offset(BlockDriverState *bs,
560
*
561
* -errno: in error cases
562
*/
563
-static int coroutine_fn handle_alloc(BlockDriverState *bs,
564
- uint64_t guest_offset, uint64_t *host_offset, uint64_t *bytes,
565
- QCowL2Meta **m)
566
+static int coroutine_fn GRAPH_RDLOCK
567
+handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
568
+ uint64_t *host_offset, uint64_t *bytes, QCowL2Meta **m)
569
{
570
BDRVQcow2State *s = bs->opaque;
571
int l2_index;
572
@@ -XXX,XX +XXX,XX @@ again:
573
* all clusters in the same L2 slice) and returns the number of discarded
574
* clusters.
575
*/
576
-static int discard_in_l2_slice(BlockDriverState *bs, uint64_t offset,
577
- uint64_t nb_clusters,
578
- enum qcow2_discard_type type, bool full_discard)
579
+static int GRAPH_RDLOCK
580
+discard_in_l2_slice(BlockDriverState *bs, uint64_t offset, uint64_t nb_clusters,
581
+ enum qcow2_discard_type type, bool full_discard)
582
{
583
BDRVQcow2State *s = bs->opaque;
584
uint64_t *l2_slice;
585
@@ -XXX,XX +XXX,XX @@ fail:
586
* all clusters in the same L2 slice) and returns the number of zeroed
587
* clusters.
588
*/
589
-static int coroutine_fn
590
+static int coroutine_fn GRAPH_RDLOCK
591
zero_in_l2_slice(BlockDriverState *bs, uint64_t offset,
592
uint64_t nb_clusters, int flags)
593
{
594
@@ -XXX,XX +XXX,XX @@ zero_in_l2_slice(BlockDriverState *bs, uint64_t offset,
595
return nb_clusters;
596
}
597
598
-static int coroutine_fn
599
+static int coroutine_fn GRAPH_RDLOCK
600
zero_l2_subclusters(BlockDriverState *bs, uint64_t offset,
601
unsigned nb_subclusters)
602
{
603
@@ -XXX,XX +XXX,XX @@ fail:
604
* status_cb(). l1_entries contains the total number of L1 entries and
605
* *visited_l1_entries counts all visited L1 entries.
606
*/
607
-static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
608
- int l1_size, int64_t *visited_l1_entries,
609
- int64_t l1_entries,
610
- BlockDriverAmendStatusCB *status_cb,
611
- void *cb_opaque)
612
+static int GRAPH_RDLOCK
613
+expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
614
+ int l1_size, int64_t *visited_l1_entries,
615
+ int64_t l1_entries,
616
+ BlockDriverAmendStatusCB *status_cb,
617
+ void *cb_opaque)
618
{
619
BDRVQcow2State *s = bs->opaque;
620
bool is_active_l1 = (l1_table == s->l1_table);
621
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
622
index XXXXXXX..XXXXXXX 100644
623
--- a/block/qcow2-refcount.c
624
+++ b/block/qcow2-refcount.c
625
@@ -XXX,XX +XXX,XX @@ static void set_refcount_ro6(void *refcount_array, uint64_t index,
626
}
627
628
629
-static int load_refcount_block(BlockDriverState *bs,
630
- int64_t refcount_block_offset,
631
- void **refcount_block)
632
+static int GRAPH_RDLOCK
633
+load_refcount_block(BlockDriverState *bs, int64_t refcount_block_offset,
634
+ void **refcount_block)
635
{
636
BDRVQcow2State *s = bs->opaque;
637
638
@@ -XXX,XX +XXX,XX @@ static int in_same_refcount_block(BDRVQcow2State *s, uint64_t offset_a,
639
*
640
* Returns 0 on success or -errno in error case
641
*/
642
-static int alloc_refcount_block(BlockDriverState *bs,
643
- int64_t cluster_index, void **refcount_block)
644
+static int GRAPH_RDLOCK
645
+alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index,
646
+ void **refcount_block)
647
{
648
BDRVQcow2State *s = bs->opaque;
649
unsigned int refcount_table_index;
650
@@ -XXX,XX +XXX,XX @@ found:
651
/* XXX: cache several refcount block clusters ? */
652
/* @addend is the absolute value of the addend; if @decrease is set, @addend
653
* will be subtracted from the current refcount, otherwise it will be added */
654
-static int update_refcount(BlockDriverState *bs,
655
- int64_t offset,
656
- int64_t length,
657
- uint64_t addend,
658
- bool decrease,
659
- enum qcow2_discard_type type)
660
+static int GRAPH_RDLOCK
661
+update_refcount(BlockDriverState *bs, int64_t offset, int64_t length,
662
+ uint64_t addend, bool decrease, enum qcow2_discard_type type)
663
{
664
BDRVQcow2State *s = bs->opaque;
665
int64_t start, last, cluster_offset;
666
@@ -XXX,XX +XXX,XX @@ int qcow2_update_cluster_refcount(BlockDriverState *bs,
667
668
669
/* return < 0 if error */
670
-static int64_t alloc_clusters_noref(BlockDriverState *bs, uint64_t size,
671
- uint64_t max)
672
+static int64_t GRAPH_RDLOCK
673
+alloc_clusters_noref(BlockDriverState *bs, uint64_t size, uint64_t max)
674
{
675
BDRVQcow2State *s = bs->opaque;
676
uint64_t i, nb_clusters, refcount;
677
@@ -XXX,XX +XXX,XX @@ calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
678
* Compares the actual reference count for each cluster in the image against the
679
* refcount as reported by the refcount structures on-disk.
680
*/
681
-static void coroutine_fn
682
+static void coroutine_fn GRAPH_RDLOCK
683
compare_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
684
BdrvCheckMode fix, bool *rebuild,
685
int64_t *highest_cluster,
686
@@ -XXX,XX +XXX,XX @@ int qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset,
687
*
688
* @allocated should be set to true if a new cluster has been allocated.
689
*/
690
-typedef int (RefblockFinishOp)(BlockDriverState *bs, uint64_t **reftable,
691
- uint64_t reftable_index, uint64_t *reftable_size,
692
- void *refblock, bool refblock_empty,
693
- bool *allocated, Error **errp);
694
+typedef int /* GRAPH_RDLOCK_PTR */
695
+ (RefblockFinishOp)(BlockDriverState *bs, uint64_t **reftable,
696
+ uint64_t reftable_index, uint64_t *reftable_size,
697
+ void *refblock, bool refblock_empty,
698
+ bool *allocated, Error **errp);
699
700
/**
701
* This "operation" for walk_over_reftable() allocates the refblock on disk (if
702
* it is not empty) and inserts its offset into the new reftable. The size of
703
* this new reftable is increased as required.
704
*/
705
-static int alloc_refblock(BlockDriverState *bs, uint64_t **reftable,
706
- uint64_t reftable_index, uint64_t *reftable_size,
707
- void *refblock, bool refblock_empty, bool *allocated,
708
- Error **errp)
709
+static int GRAPH_RDLOCK
710
+alloc_refblock(BlockDriverState *bs, uint64_t **reftable,
711
+ uint64_t reftable_index, uint64_t *reftable_size,
712
+ void *refblock, bool refblock_empty, bool *allocated,
713
+ Error **errp)
714
{
715
BDRVQcow2State *s = bs->opaque;
716
int64_t offset;
717
@@ -XXX,XX +XXX,XX @@ static int alloc_refblock(BlockDriverState *bs, uint64_t **reftable,
718
* offset specified by the new reftable's entry. It does not modify the new
719
* reftable or change any refcounts.
720
*/
721
-static int flush_refblock(BlockDriverState *bs, uint64_t **reftable,
722
- uint64_t reftable_index, uint64_t *reftable_size,
723
- void *refblock, bool refblock_empty, bool *allocated,
724
- Error **errp)
725
+static int GRAPH_RDLOCK
726
+flush_refblock(BlockDriverState *bs, uint64_t **reftable,
727
+ uint64_t reftable_index, uint64_t *reftable_size,
728
+ void *refblock, bool refblock_empty, bool *allocated,
729
+ Error **errp)
730
{
731
BDRVQcow2State *s = bs->opaque;
732
int64_t offset;
733
@@ -XXX,XX +XXX,XX @@ static int flush_refblock(BlockDriverState *bs, uint64_t **reftable,
734
*
735
* @allocated is set to true if a new cluster has been allocated.
736
*/
737
-static int walk_over_reftable(BlockDriverState *bs, uint64_t **new_reftable,
738
- uint64_t *new_reftable_index,
739
- uint64_t *new_reftable_size,
740
- void *new_refblock, int new_refblock_size,
741
- int new_refcount_bits,
742
- RefblockFinishOp *operation, bool *allocated,
743
- Qcow2SetRefcountFunc *new_set_refcount,
744
- BlockDriverAmendStatusCB *status_cb,
745
- void *cb_opaque, int index, int total,
746
- Error **errp)
747
+static int GRAPH_RDLOCK
748
+walk_over_reftable(BlockDriverState *bs, uint64_t **new_reftable,
749
+ uint64_t *new_reftable_index,
750
+ uint64_t *new_reftable_size,
751
+ void *new_refblock, int new_refblock_size,
752
+ int new_refcount_bits,
753
+ RefblockFinishOp *operation, bool *allocated,
754
+ Qcow2SetRefcountFunc *new_set_refcount,
755
+ BlockDriverAmendStatusCB *status_cb,
756
+ void *cb_opaque, int index, int total,
757
+ Error **errp)
758
{
759
BDRVQcow2State *s = bs->opaque;
760
uint64_t reftable_index;
761
@@ -XXX,XX +XXX,XX @@ done:
762
return ret;
763
}
764
765
-static int64_t coroutine_fn get_refblock_offset(BlockDriverState *bs,
766
- uint64_t offset)
767
+static int64_t coroutine_fn GRAPH_RDLOCK
768
+get_refblock_offset(BlockDriverState *bs, uint64_t offset)
769
{
770
BDRVQcow2State *s = bs->opaque;
771
uint32_t index = offset_to_reftable_index(s, offset);
772
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn get_refblock_offset(BlockDriverState *bs,
773
return covering_refblock_offset;
774
}
775
776
-static int coroutine_fn
777
+static int coroutine_fn GRAPH_RDLOCK
778
qcow2_discard_refcount_block(BlockDriverState *bs, uint64_t discard_block_offs)
779
{
780
BDRVQcow2State *s = bs->opaque;
55
diff --git a/block/qcow2.c b/block/qcow2.c
781
diff --git a/block/qcow2.c b/block/qcow2.c
56
index XXXXXXX..XXXXXXX 100644
782
index XXXXXXX..XXXXXXX 100644
57
--- a/block/qcow2.c
783
--- a/block/qcow2.c
58
+++ b/block/qcow2.c
784
+++ b/block/qcow2.c
59
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_check(BlockDriverState *bs,
785
@@ -XXX,XX +XXX,XX @@ int qcow2_mark_dirty(BlockDriverState *bs)
786
* function when there are no pending requests, it does not guard against
787
* concurrent requests dirtying the image.
788
*/
789
-static int qcow2_mark_clean(BlockDriverState *bs)
790
+static int GRAPH_RDLOCK qcow2_mark_clean(BlockDriverState *bs)
791
{
792
BDRVQcow2State *s = bs->opaque;
793
794
@@ -XXX,XX +XXX,XX @@ int qcow2_mark_corrupt(BlockDriverState *bs)
795
* Marks the image as consistent, i.e., unsets the corrupt bit, and flushes
796
* before if necessary.
797
*/
798
-static int coroutine_fn qcow2_mark_consistent(BlockDriverState *bs)
799
+static int coroutine_fn GRAPH_RDLOCK
800
+qcow2_mark_consistent(BlockDriverState *bs)
801
{
802
BDRVQcow2State *s = bs->opaque;
803
804
@@ -XXX,XX +XXX,XX @@ typedef struct Qcow2ReopenState {
805
QCryptoBlockOpenOptions *crypto_opts; /* Disk encryption runtime options */
806
} Qcow2ReopenState;
807
808
-static int qcow2_update_options_prepare(BlockDriverState *bs,
809
- Qcow2ReopenState *r,
810
- QDict *options, int flags,
811
- Error **errp)
812
+static int GRAPH_RDLOCK
813
+qcow2_update_options_prepare(BlockDriverState *bs, Qcow2ReopenState *r,
814
+ QDict *options, int flags, Error **errp)
815
{
816
BDRVQcow2State *s = bs->opaque;
817
QemuOpts *opts = NULL;
818
@@ -XXX,XX +XXX,XX @@ static void qcow2_update_options_abort(BlockDriverState *bs,
819
qapi_free_QCryptoBlockOpenOptions(r->crypto_opts);
820
}
821
822
-static int coroutine_fn
823
+static int coroutine_fn GRAPH_RDLOCK
824
qcow2_update_options(BlockDriverState *bs, QDict *options, int flags,
825
Error **errp)
826
{
827
@@ -XXX,XX +XXX,XX @@ static void qcow2_refresh_limits(BlockDriverState *bs, Error **errp)
828
bs->bl.pdiscard_alignment = s->cluster_size;
829
}
830
831
-static int qcow2_reopen_prepare(BDRVReopenState *state,
832
- BlockReopenQueue *queue, Error **errp)
833
+static int GRAPH_UNLOCKED
834
+qcow2_reopen_prepare(BDRVReopenState *state,BlockReopenQueue *queue,
835
+ Error **errp)
836
{
837
BDRVQcow2State *s = state->bs->opaque;
838
Qcow2ReopenState *r;
839
int ret;
840
841
+ GLOBAL_STATE_CODE();
842
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
843
+
844
r = g_new0(Qcow2ReopenState, 1);
845
state->opaque = r;
846
847
@@ -XXX,XX +XXX,XX @@ static void qcow2_reopen_commit(BDRVReopenState *state)
848
849
static void qcow2_reopen_commit_post(BDRVReopenState *state)
850
{
851
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
852
+
853
if (state->flags & BDRV_O_RDWR) {
854
Error *local_err = NULL;
855
856
@@ -XXX,XX +XXX,XX @@ qcow2_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes,
60
return ret;
857
return ret;
61
}
858
}
62
859
63
-static int validate_table_offset(BlockDriverState *bs, uint64_t offset,
860
-static coroutine_fn int qcow2_co_pdiscard(BlockDriverState *bs,
64
- uint64_t entries, size_t entry_len)
861
- int64_t offset, int64_t bytes)
65
+int qcow2_validate_table(BlockDriverState *bs, uint64_t offset,
862
+static int coroutine_fn GRAPH_RDLOCK
66
+ uint64_t entries, size_t entry_len,
863
+qcow2_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
67
+ int64_t max_size_bytes, const char *table_name,
864
{
68
+ Error **errp)
865
int ret;
69
{
866
BDRVQcow2State *s = bs->opaque;
70
BDRVQcow2State *s = bs->opaque;
867
@@ -XXX,XX +XXX,XX @@ fail:
71
- uint64_t size;
868
return ret;
72
869
}
73
- /* Use signed INT64_MAX as the maximum even for uint64_t header fields,
870
74
- * because values will be passed to qemu functions taking int64_t. */
871
-static int make_completely_empty(BlockDriverState *bs)
75
- if (entries > INT64_MAX / entry_len) {
872
+static int GRAPH_RDLOCK make_completely_empty(BlockDriverState *bs)
76
- return -EINVAL;
873
{
77
- }
874
BDRVQcow2State *s = bs->opaque;
875
Error *local_err = NULL;
876
@@ -XXX,XX +XXX,XX @@ fail:
877
return ret;
878
}
879
880
-static int qcow2_make_empty(BlockDriverState *bs)
881
+static int GRAPH_RDLOCK qcow2_make_empty(BlockDriverState *bs)
882
{
883
BDRVQcow2State *s = bs->opaque;
884
uint64_t offset, end_offset;
885
@@ -XXX,XX +XXX,XX @@ static int qcow2_make_empty(BlockDriverState *bs)
886
return ret;
887
}
888
889
-static coroutine_fn int qcow2_co_flush_to_os(BlockDriverState *bs)
890
+static coroutine_fn GRAPH_RDLOCK int qcow2_co_flush_to_os(BlockDriverState *bs)
891
{
892
BDRVQcow2State *s = bs->opaque;
893
int ret;
894
@@ -XXX,XX +XXX,XX @@ qcow2_co_load_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos)
895
return bs->drv->bdrv_co_preadv_part(bs, offset, qiov->size, qiov, 0, 0);
896
}
897
898
-static int qcow2_has_compressed_clusters(BlockDriverState *bs)
899
+static int GRAPH_RDLOCK qcow2_has_compressed_clusters(BlockDriverState *bs)
900
{
901
int64_t offset = 0;
902
int64_t bytes = bdrv_getlength(bs);
903
@@ -XXX,XX +XXX,XX @@ static int qcow2_has_compressed_clusters(BlockDriverState *bs)
904
* Downgrades an image's version. To achieve this, any incompatible features
905
* have to be removed.
906
*/
907
-static int qcow2_downgrade(BlockDriverState *bs, int target_version,
908
- BlockDriverAmendStatusCB *status_cb, void *cb_opaque,
909
- Error **errp)
910
+static int GRAPH_RDLOCK
911
+qcow2_downgrade(BlockDriverState *bs, int target_version,
912
+ BlockDriverAmendStatusCB *status_cb, void *cb_opaque,
913
+ Error **errp)
914
{
915
BDRVQcow2State *s = bs->opaque;
916
int current_version = s->qcow_version;
917
@@ -XXX,XX +XXX,XX @@ static int qcow2_downgrade(BlockDriverState *bs, int target_version,
918
* features of older versions, some things may have to be presented
919
* differently.
920
*/
921
-static int qcow2_upgrade(BlockDriverState *bs, int target_version,
922
- BlockDriverAmendStatusCB *status_cb, void *cb_opaque,
923
- Error **errp)
924
+static int GRAPH_RDLOCK
925
+qcow2_upgrade(BlockDriverState *bs, int target_version,
926
+ BlockDriverAmendStatusCB *status_cb, void *cb_opaque,
927
+ Error **errp)
928
{
929
BDRVQcow2State *s = bs->opaque;
930
bool need_snapshot_update;
931
@@ -XXX,XX +XXX,XX @@ static void qcow2_amend_helper_cb(BlockDriverState *bs,
932
info->original_cb_opaque);
933
}
934
935
-static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
936
- BlockDriverAmendStatusCB *status_cb,
937
- void *cb_opaque,
938
- bool force,
939
- Error **errp)
940
+static int GRAPH_RDLOCK
941
+qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
942
+ BlockDriverAmendStatusCB *status_cb, void *cb_opaque,
943
+ bool force, Error **errp)
944
{
945
BDRVQcow2State *s = bs->opaque;
946
int old_version = s->qcow_version, new_version = old_version;
947
@@ -XXX,XX +XXX,XX @@ void qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset,
948
char *message;
949
va_list ap;
950
951
- assume_graph_lock(); /* FIXME */
78
-
952
-
79
- size = entries * entry_len;
953
fatal = fatal && bdrv_is_writable(bs);
80
-
954
81
- if (INT64_MAX - size < offset) {
955
if (s->signaled_corruption &&
82
- return -EINVAL;
956
diff --git a/block/replication.c b/block/replication.c
83
+ if (entries > max_size_bytes / entry_len) {
957
index XXXXXXX..XXXXXXX 100644
84
+ error_setg(errp, "%s too large", table_name);
958
--- a/block/replication.c
85
+ return -EFBIG;
959
+++ b/block/replication.c
86
}
960
@@ -XXX,XX +XXX,XX @@ out:
87
961
return ret;
88
- /* Tables must be cluster aligned */
962
}
89
- if (offset_into_cluster(s, offset) != 0) {
963
90
+ /* Use signed INT64_MAX as the maximum even for uint64_t header fields,
964
-static void secondary_do_checkpoint(BlockDriverState *bs, Error **errp)
91
+ * because values will be passed to qemu functions taking int64_t. */
965
+static void GRAPH_UNLOCKED
92
+ if ((INT64_MAX - entries * entry_len < offset) ||
966
+secondary_do_checkpoint(BlockDriverState *bs, Error **errp)
93
+ (offset_into_cluster(s, offset) != 0)) {
967
{
94
+ error_setg(errp, "%s offset invalid", table_name);
968
BDRVReplicationState *s = bs->opaque;
95
return -EINVAL;
969
BdrvChild *active_disk = bs->file;
96
}
970
Error *local_err = NULL;
97
971
int ret;
98
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
972
99
s->refcount_table_size =
973
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
100
header.refcount_table_clusters << (s->cluster_bits - 3);
974
+
101
975
if (!s->backup_job) {
102
- if (header.refcount_table_clusters > qcow2_max_refcount_clusters(s)) {
976
error_setg(errp, "Backup job was cancelled unexpectedly");
103
- error_setg(errp, "Reference count table too large");
977
return;
104
- ret = -EINVAL;
978
@@ -XXX,XX +XXX,XX @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
105
- goto fail;
979
/* Must be true, or the bdrv_getlength() calls would have failed */
106
- }
980
assert(active_disk->bs->drv && hidden_disk->bs->drv);
107
-
981
108
if (header.refcount_table_clusters == 0 && !(flags & BDRV_O_CHECK)) {
982
+ bdrv_graph_rdlock_main_loop();
109
error_setg(errp, "Image does not contain a reference count table");
983
if (!active_disk->bs->drv->bdrv_make_empty ||
110
ret = -EINVAL;
984
!hidden_disk->bs->drv->bdrv_make_empty) {
111
goto fail;
985
error_setg(errp,
112
}
986
"Active disk or hidden disk doesn't support make_empty");
113
987
aio_context_release(aio_context);
114
- ret = validate_table_offset(bs, s->refcount_table_offset,
988
+ bdrv_graph_rdunlock_main_loop();
115
- s->refcount_table_size, sizeof(uint64_t));
989
return;
116
+ ret = qcow2_validate_table(bs, s->refcount_table_offset,
990
}
117
+ header.refcount_table_clusters,
991
+ bdrv_graph_rdunlock_main_loop();
118
+ s->cluster_size, QCOW_MAX_REFTABLE_SIZE,
992
119
+ "Reference count table", errp);
993
/* reopen the backing file in r/w mode */
120
if (ret < 0) {
994
reopen_backing_file(bs, true, &local_err);
121
- error_setg(errp, "Invalid reference count table offset");
122
goto fail;
123
}
124
125
- /* Snapshot table offset/length */
126
- if (header.nb_snapshots > QCOW_MAX_SNAPSHOTS) {
127
- error_setg(errp, "Too many snapshots");
128
- ret = -EINVAL;
129
- goto fail;
130
- }
131
-
132
- ret = validate_table_offset(bs, header.snapshots_offset,
133
- header.nb_snapshots,
134
- sizeof(QCowSnapshotHeader));
135
+ /* The total size in bytes of the snapshot table is checked in
136
+ * qcow2_read_snapshots() because the size of each snapshot is
137
+ * variable and we don't know it yet.
138
+ * Here we only check the offset and number of snapshots. */
139
+ ret = qcow2_validate_table(bs, header.snapshots_offset,
140
+ header.nb_snapshots,
141
+ sizeof(QCowSnapshotHeader),
142
+ sizeof(QCowSnapshotHeader) * QCOW_MAX_SNAPSHOTS,
143
+ "Snapshot table", errp);
144
if (ret < 0) {
145
- error_setg(errp, "Invalid snapshot table offset");
146
goto fail;
147
}
148
149
/* read the level 1 table */
150
- if (header.l1_size > QCOW_MAX_L1_SIZE / sizeof(uint64_t)) {
151
- error_setg(errp, "Active L1 table too large");
152
- ret = -EFBIG;
153
+ ret = qcow2_validate_table(bs, header.l1_table_offset,
154
+ header.l1_size, sizeof(uint64_t),
155
+ QCOW_MAX_L1_SIZE, "Active L1 table", errp);
156
+ if (ret < 0) {
157
goto fail;
158
}
159
s->l1_size = header.l1_size;
160
+ s->l1_table_offset = header.l1_table_offset;
161
162
l1_vm_state_index = size_to_l1(s, header.size);
163
if (l1_vm_state_index > INT_MAX) {
164
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
165
goto fail;
166
}
167
168
- ret = validate_table_offset(bs, header.l1_table_offset,
169
- header.l1_size, sizeof(uint64_t));
170
- if (ret < 0) {
171
- error_setg(errp, "Invalid L1 table offset");
172
- goto fail;
173
- }
174
- s->l1_table_offset = header.l1_table_offset;
175
-
176
-
177
if (s->l1_size > 0) {
178
s->l1_table = qemu_try_blockalign(bs->file->bs,
179
ROUND_UP(s->l1_size * sizeof(uint64_t), 512));
180
diff --git a/tests/qemu-iotests/080.out b/tests/qemu-iotests/080.out
181
index XXXXXXX..XXXXXXX 100644
182
--- a/tests/qemu-iotests/080.out
183
+++ b/tests/qemu-iotests/080.out
184
@@ -XXX,XX +XXX,XX @@ can't open device TEST_DIR/t.qcow2: Reference count table too large
185
186
== Misaligned refcount table ==
187
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
188
-can't open device TEST_DIR/t.qcow2: Invalid reference count table offset
189
+can't open device TEST_DIR/t.qcow2: Reference count table offset invalid
190
191
== Huge refcount offset ==
192
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
193
-can't open device TEST_DIR/t.qcow2: Invalid reference count table offset
194
+can't open device TEST_DIR/t.qcow2: Reference count table offset invalid
195
196
== Invalid snapshot table ==
197
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
198
-can't open device TEST_DIR/t.qcow2: Too many snapshots
199
-can't open device TEST_DIR/t.qcow2: Too many snapshots
200
-can't open device TEST_DIR/t.qcow2: Invalid snapshot table offset
201
-can't open device TEST_DIR/t.qcow2: Invalid snapshot table offset
202
+can't open device TEST_DIR/t.qcow2: Snapshot table too large
203
+can't open device TEST_DIR/t.qcow2: Snapshot table too large
204
+can't open device TEST_DIR/t.qcow2: Snapshot table offset invalid
205
+can't open device TEST_DIR/t.qcow2: Snapshot table offset invalid
206
207
== Hitting snapshot table size limit ==
208
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
209
@@ -XXX,XX +XXX,XX @@ read 512/512 bytes at offset 0
210
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
211
can't open device TEST_DIR/t.qcow2: Active L1 table too large
212
can't open device TEST_DIR/t.qcow2: Active L1 table too large
213
-can't open device TEST_DIR/t.qcow2: Invalid L1 table offset
214
-can't open device TEST_DIR/t.qcow2: Invalid L1 table offset
215
+can't open device TEST_DIR/t.qcow2: Active L1 table offset invalid
216
+can't open device TEST_DIR/t.qcow2: Active L1 table offset invalid
217
218
== Invalid L1 table (with internal snapshot in the image) ==
219
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
220
--
995
--
221
2.13.6
996
2.41.0
222
223
diff view generated by jsdifflib
1
Instead of passing the encryption format name and the QemuOpts down, use
1
This adds GRAPH_RDLOCK annotations to declare that callers of
2
the QCryptoBlockCreateOptions contained in BlockdevCreateOptions.
2
qcow2_inactivate() need to hold a reader lock for the graph because it
3
calls bdrv_get_device_or_node_name(), which accesses the parents list of
4
a node.
5
6
qcow2_do_close() is a bit strange because it is called from different
7
contexts. If close_data_file = true, we know that we were called from
8
non-coroutine main loop context (more specifically, we're coming from
9
qcow2_close()) and can safely drop the reader lock temporarily with
10
bdrv_graph_rdunlock_main_loop() and acquire the writer lock.
3
11
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Eric Blake <eblake@redhat.com>
13
Message-ID: <20230929145157.45443-16-kwolf@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
14
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
16
---
8
block/qcow2.c | 62 +++++++++++++++++++++++++++++++++++++++++++----------------
17
block/qcow2.c | 15 ++++++++++-----
9
1 file changed, 45 insertions(+), 17 deletions(-)
18
1 file changed, 10 insertions(+), 5 deletions(-)
10
19
11
diff --git a/block/qcow2.c b/block/qcow2.c
20
diff --git a/block/qcow2.c b/block/qcow2.c
12
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
13
--- a/block/qcow2.c
22
--- a/block/qcow2.c
14
+++ b/block/qcow2.c
23
+++ b/block/qcow2.c
15
@@ -XXX,XX +XXX,XX @@ static int qcow2_crypt_method_from_format(const char *encryptfmt)
24
@@ -XXX,XX +XXX,XX @@ fail_nometa:
16
}
17
}
18
19
-static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt,
20
- QemuOpts *opts, Error **errp)
21
+static QCryptoBlockCreateOptions *
22
+qcow2_parse_encryption(const char *encryptfmt, QemuOpts *opts, Error **errp)
23
{
24
- BDRVQcow2State *s = bs->opaque;
25
QCryptoBlockCreateOptions *cryptoopts = NULL;
26
- QCryptoBlock *crypto = NULL;
27
- int ret = -EINVAL;
28
QDict *options, *encryptopts;
29
int fmt;
30
31
@@ -XXX,XX +XXX,XX @@ static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt,
32
error_setg(errp, "Unknown encryption format '%s'", encryptfmt);
33
break;
34
}
35
- if (!cryptoopts) {
36
- ret = -EINVAL;
37
- goto out;
38
+
39
+ QDECREF(encryptopts);
40
+ return cryptoopts;
41
+}
42
+
43
+static int qcow2_set_up_encryption(BlockDriverState *bs,
44
+ QCryptoBlockCreateOptions *cryptoopts,
45
+ Error **errp)
46
+{
47
+ BDRVQcow2State *s = bs->opaque;
48
+ QCryptoBlock *crypto = NULL;
49
+ int fmt, ret;
50
+
51
+ switch (cryptoopts->format) {
52
+ case Q_CRYPTO_BLOCK_FORMAT_LUKS:
53
+ fmt = QCOW_CRYPT_LUKS;
54
+ break;
55
+ case Q_CRYPTO_BLOCK_FORMAT_QCOW:
56
+ fmt = QCOW_CRYPT_AES;
57
+ break;
58
+ default:
59
+ error_setg(errp, "Crypto format not supported in qcow2");
60
+ return -EINVAL;
61
}
62
+
63
s->crypt_method_header = fmt;
64
65
crypto = qcrypto_block_create(cryptoopts, "encrypt.",
66
@@ -XXX,XX +XXX,XX @@ static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt,
67
qcow2_crypto_hdr_write_func,
68
bs, errp);
69
if (!crypto) {
70
- ret = -EINVAL;
71
- goto out;
72
+ return -EINVAL;
73
}
74
75
ret = qcow2_update_header(bs);
76
@@ -XXX,XX +XXX,XX @@ static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt,
77
goto out;
78
}
79
80
+ ret = 0;
81
out:
82
- QDECREF(encryptopts);
83
qcrypto_block_free(crypto);
84
- qapi_free_QCryptoBlockCreateOptions(cryptoopts);
85
return ret;
25
return ret;
86
}
26
}
87
27
88
@@ -XXX,XX +XXX,XX @@ static uint64_t qcow2_opt_get_refcount_bits_del(QemuOpts *opts, int version,
28
-static int qcow2_inactivate(BlockDriverState *bs)
29
+static int GRAPH_RDLOCK qcow2_inactivate(BlockDriverState *bs)
30
{
31
BDRVQcow2State *s = bs->opaque;
32
int ret, result = 0;
33
Error *local_err = NULL;
34
35
- assume_graph_lock(); /* FIXME */
36
-
37
qcow2_store_persistent_dirty_bitmaps(bs, true, &local_err);
38
if (local_err != NULL) {
39
result = -EINVAL;
40
@@ -XXX,XX +XXX,XX @@ static int qcow2_inactivate(BlockDriverState *bs)
41
return result;
89
}
42
}
90
43
91
static int coroutine_fn
44
-static void qcow2_do_close(BlockDriverState *bs, bool close_data_file)
92
-qcow2_co_create(BlockdevCreateOptions *create_options, QemuOpts *opts,
45
+static void coroutine_mixed_fn GRAPH_RDLOCK
93
- const char *encryptfmt, Error **errp)
46
+qcow2_do_close(BlockDriverState *bs, bool close_data_file)
94
+qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
95
{
47
{
96
BlockdevCreateOptionsQcow2 *qcow2_opts;
48
BDRVQcow2State *s = bs->opaque;
97
QDict *options;
49
qemu_vfree(s->l1_table);
98
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, QemuOpts *opts,
50
@@ -XXX,XX +XXX,XX @@ static void qcow2_do_close(BlockDriverState *bs, bool close_data_file)
51
g_free(s->image_backing_format);
52
53
if (close_data_file && has_data_file(bs)) {
54
+ GLOBAL_STATE_CODE();
55
+ bdrv_graph_rdunlock_main_loop();
56
bdrv_graph_wrlock(NULL);
57
bdrv_unref_child(bs, s->data_file);
58
bdrv_graph_wrunlock();
59
s->data_file = NULL;
60
+ bdrv_graph_rdlock_main_loop();
99
}
61
}
100
62
101
/* Want encryption? There you go. */
63
qcow2_refcount_close(bs);
102
- if (encryptfmt) {
64
qcow2_free_snapshots(bs);
103
- ret = qcow2_set_up_encryption(blk_bs(blk), encryptfmt, opts, errp);
65
}
104
+ if (qcow2_opts->has_encrypt) {
66
105
+ ret = qcow2_set_up_encryption(blk_bs(blk), qcow2_opts->encrypt, errp);
67
-static void qcow2_close(BlockDriverState *bs)
106
if (ret < 0) {
68
+static void GRAPH_UNLOCKED qcow2_close(BlockDriverState *bs)
107
goto out;
69
{
108
}
70
+ GLOBAL_STATE_CODE();
109
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
71
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
110
int version;
111
uint64_t refcount_bits;
112
char *encryptfmt = NULL;
113
+ QCryptoBlockCreateOptions *cryptoopts = NULL;
114
BlockDriverState *bs = NULL;
115
Error *local_err = NULL;
116
int ret;
117
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
118
ret = -EINVAL;
119
goto finish;
120
}
121
+
72
+
122
encryptfmt = qemu_opt_get_del(opts, BLOCK_OPT_ENCRYPT_FORMAT);
73
qcow2_do_close(bs, true);
123
if (encryptfmt) {
74
}
124
if (qemu_opt_get(opts, BLOCK_OPT_ENCRYPT)) {
75
125
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
126
} else if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ENCRYPT, false)) {
127
encryptfmt = g_strdup("aes");
128
}
129
+ if (encryptfmt) {
130
+ cryptoopts = qcow2_parse_encryption(encryptfmt, opts, errp);
131
+ if (cryptoopts == NULL) {
132
+ ret = -EINVAL;
133
+ goto finish;
134
+ }
135
+ }
136
+
137
cluster_size = qcow2_opt_get_cluster_size_del(opts, &local_err);
138
if (local_err) {
139
error_propagate(errp, local_err);
140
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
141
.backing_file = backing_file,
142
.has_backing_fmt = (backing_fmt != NULL),
143
.backing_fmt = backing_drv,
144
+ .has_encrypt = (encryptfmt != NULL),
145
+ .encrypt = cryptoopts,
146
.has_cluster_size = true,
147
.cluster_size = cluster_size,
148
.has_preallocation = true,
149
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
150
.refcount_bits = refcount_bits,
151
},
152
};
153
- ret = qcow2_co_create(&create_options, opts, encryptfmt, errp);
154
+ ret = qcow2_co_create(&create_options, errp);
155
if (ret < 0) {
156
goto finish;
157
}
158
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
159
finish:
160
bdrv_unref(bs);
161
162
+ qapi_free_QCryptoBlockCreateOptions(cryptoopts);
163
g_free(backing_file);
164
g_free(backing_fmt);
165
g_free(encryptfmt);
166
--
76
--
167
2.13.6
77
2.41.0
168
169
diff view generated by jsdifflib
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
It still has an assume_graph_lock() call, but all of its callers are now
2
properly annotated to hold the graph lock. Update the function to be
3
GRAPH_RDLOCK as well and remove the assume_graph_lock().
2
4
3
update_header_sync itself does not need to flush the caches to disk.
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
The only paths that allocate clusters are:
6
Message-ID: <20230929145157.45443-17-kwolf@redhat.com>
5
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
6
- bitmap_list_store with in_place=false, called by update_ext_header_and_dir
7
8
- store_bitmap_data, called by store_bitmap
9
10
- store_bitmap, called by qcow2_store_persistent_dirty_bitmaps and
11
followed by update_ext_header_and_dir
12
13
So in the end the central place where we need to flush the caches
14
is update_ext_header_and_dir.
15
16
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
---
9
---
19
block/qcow2-bitmap.c | 4 ++--
10
block/qcow2-bitmap.c | 9 +++------
20
1 file changed, 2 insertions(+), 2 deletions(-)
11
1 file changed, 3 insertions(+), 6 deletions(-)
21
12
22
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
13
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
23
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
24
--- a/block/qcow2-bitmap.c
15
--- a/block/qcow2-bitmap.c
25
+++ b/block/qcow2-bitmap.c
16
+++ b/block/qcow2-bitmap.c
26
@@ -XXX,XX +XXX,XX @@ static int update_header_sync(BlockDriverState *bs)
17
@@ -XXX,XX +XXX,XX @@ static int64_t get_bitmap_bytes_needed(int64_t len, uint32_t granularity)
27
return ret;
18
return DIV_ROUND_UP(num_bits, 8);
28
}
29
30
- return bdrv_flush(bs);
31
+ return bdrv_flush(bs->file->bs);
32
}
19
}
33
20
34
static inline void bitmap_table_to_be(uint64_t *bitmap_table, size_t size)
21
-static int check_constraints_on_bitmap(BlockDriverState *bs,
35
@@ -XXX,XX +XXX,XX @@ static int update_ext_header_and_dir(BlockDriverState *bs,
22
- const char *name,
36
return ret;
23
- uint32_t granularity,
37
}
24
- Error **errp)
38
25
+static int GRAPH_RDLOCK
39
- ret = bdrv_flush(bs->file->bs);
26
+check_constraints_on_bitmap(BlockDriverState *bs, const char *name,
40
+ ret = qcow2_flush_caches(bs);
27
+ uint32_t granularity, Error **errp)
41
if (ret < 0) {
28
{
42
goto fail;
29
BDRVQcow2State *s = bs->opaque;
43
}
30
int granularity_bits = ctz32(granularity);
31
int64_t len = bdrv_getlength(bs);
32
int64_t bitmap_bytes;
33
34
- assume_graph_lock(); /* FIXME */
35
-
36
assert(granularity > 0);
37
assert((granularity & (granularity - 1)) == 0);
38
44
--
39
--
45
2.13.6
40
2.41.0
46
47
diff view generated by jsdifflib
1
This adds the .bdrv_co_create driver callback to sheepdog, which enables
1
This adds GRAPH_RDLOCK annotations to declare that callers of
2
image creation over QMP.
2
bdrv_op_is_blocked() need to hold a reader lock for the graph
3
because it calls bdrv_get_device_or_node_name(), which accesses the
4
parents list of a node.
3
5
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
Message-ID: <20230929145157.45443-18-kwolf@redhat.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
10
---
7
qapi/block-core.json | 24 ++++-
11
include/block/block-global-state.h | 4 +++-
8
block/sheepdog.c | 243 +++++++++++++++++++++++++++++++++++----------------
12
block.c | 2 --
9
2 files changed, 192 insertions(+), 75 deletions(-)
13
block/block-backend.c | 1 +
14
block/commit.c | 1 +
15
block/monitor/block-hmp-cmds.c | 3 +++
16
block/qapi-sysemu.c | 9 +++++++--
17
blockdev.c | 15 +++++++++++++++
18
7 files changed, 30 insertions(+), 5 deletions(-)
10
19
11
diff --git a/qapi/block-core.json b/qapi/block-core.json
20
diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h
12
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
13
--- a/qapi/block-core.json
22
--- a/include/block/block-global-state.h
14
+++ b/qapi/block-core.json
23
+++ b/include/block/block-global-state.h
15
@@ -XXX,XX +XXX,XX @@
24
@@ -XXX,XX +XXX,XX @@ bdrv_attach_child(BlockDriverState *parent_bs,
16
'erasure-coded': 'SheepdogRedundancyErasureCoded' } }
25
BdrvChildRole child_role,
17
26
Error **errp);
18
##
27
19
+# @BlockdevCreateOptionsSheepdog:
28
-bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp);
20
+#
29
+bool GRAPH_RDLOCK
21
+# Driver specific image creation options for Sheepdog.
30
+bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp);
22
+#
23
+# @location Where to store the new image file
24
+# @size Size of the virtual disk in bytes
25
+# @backing-file File name of a base image
26
+# @preallocation Preallocation mode (allowed values: off, full)
27
+# @redundancy Redundancy of the image
28
+# @object-size Object size of the image
29
+#
30
+# Since: 2.12
31
+##
32
+{ 'struct': 'BlockdevCreateOptionsSheepdog',
33
+ 'data': { 'location': 'BlockdevOptionsSheepdog',
34
+ 'size': 'size',
35
+ '*backing-file': 'str',
36
+ '*preallocation': 'PreallocMode',
37
+ '*redundancy': 'SheepdogRedundancy',
38
+ '*object-size': 'size' } }
39
+
31
+
40
+##
32
void bdrv_op_block(BlockDriverState *bs, BlockOpType op, Error *reason);
41
# @BlockdevCreateNotSupported:
33
void bdrv_op_unblock(BlockDriverState *bs, BlockOpType op, Error *reason);
42
#
34
void bdrv_op_block_all(BlockDriverState *bs, Error *reason);
43
# This is used for all drivers that don't support creating images.
35
diff --git a/block.c b/block.c
44
@@ -XXX,XX +XXX,XX @@
45
'raw': 'BlockdevCreateNotSupported',
46
'rbd': 'BlockdevCreateOptionsRbd',
47
'replication': 'BlockdevCreateNotSupported',
48
- 'sheepdog': 'BlockdevCreateNotSupported',
49
+ 'sheepdog': 'BlockdevCreateOptionsSheepdog',
50
'ssh': 'BlockdevCreateNotSupported',
51
'throttle': 'BlockdevCreateNotSupported',
52
'vdi': 'BlockdevCreateNotSupported',
53
diff --git a/block/sheepdog.c b/block/sheepdog.c
54
index XXXXXXX..XXXXXXX 100644
36
index XXXXXXX..XXXXXXX 100644
55
--- a/block/sheepdog.c
37
--- a/block.c
56
+++ b/block/sheepdog.c
38
+++ b/block.c
57
@@ -XXX,XX +XXX,XX @@
39
@@ -XXX,XX +XXX,XX @@ bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp)
58
#include "qemu/osdep.h"
40
BdrvOpBlocker *blocker;
59
#include "qapi/error.h"
41
GLOBAL_STATE_CODE();
60
#include "qapi/qapi-visit-sockets.h"
42
61
+#include "qapi/qapi-visit-block-core.h"
43
- assume_graph_lock(); /* FIXME */
62
#include "qapi/qmp/qdict.h"
44
-
63
#include "qapi/qobject-input-visitor.h"
45
assert((int) op >= 0 && op < BLOCK_OP_TYPE_MAX);
64
+#include "qapi/qobject-output-visitor.h"
46
if (!QLIST_EMPTY(&bs->op_blockers[op])) {
65
#include "qemu/uri.h"
47
blocker = QLIST_FIRST(&bs->op_blockers[op]);
66
#include "qemu/error-report.h"
48
diff --git a/block/block-backend.c b/block/block-backend.c
67
#include "qemu/option.h"
49
index XXXXXXX..XXXXXXX 100644
68
@@ -XXX,XX +XXX,XX @@ static void sd_aio_setup(SheepdogAIOCB *acb, BDRVSheepdogState *s,
50
--- a/block/block-backend.c
69
qemu_co_mutex_unlock(&s->queue_lock);
51
+++ b/block/block-backend.c
52
@@ -XXX,XX +XXX,XX @@ bool blk_op_is_blocked(BlockBackend *blk, BlockOpType op, Error **errp)
53
{
54
BlockDriverState *bs = blk_bs(blk);
55
GLOBAL_STATE_CODE();
56
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
57
58
if (!bs) {
59
return false;
60
diff --git a/block/commit.c b/block/commit.c
61
index XXXXXXX..XXXXXXX 100644
62
--- a/block/commit.c
63
+++ b/block/commit.c
64
@@ -XXX,XX +XXX,XX @@ int bdrv_commit(BlockDriverState *bs)
65
Error *local_err = NULL;
66
67
GLOBAL_STATE_CODE();
68
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
69
70
if (!drv)
71
return -ENOMEDIUM;
72
diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c
73
index XXXXXXX..XXXXXXX 100644
74
--- a/block/monitor/block-hmp-cmds.c
75
+++ b/block/monitor/block-hmp-cmds.c
76
@@ -XXX,XX +XXX,XX @@ void hmp_drive_del(Monitor *mon, const QDict *qdict)
77
AioContext *aio_context;
78
Error *local_err = NULL;
79
80
+ GLOBAL_STATE_CODE();
81
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
82
+
83
bs = bdrv_find_node(id);
84
if (bs) {
85
qmp_blockdev_del(id, &local_err);
86
diff --git a/block/qapi-sysemu.c b/block/qapi-sysemu.c
87
index XXXXXXX..XXXXXXX 100644
88
--- a/block/qapi-sysemu.c
89
+++ b/block/qapi-sysemu.c
90
@@ -XXX,XX +XXX,XX @@ void qmp_blockdev_close_tray(const char *device,
91
}
70
}
92
}
71
93
72
-static SocketAddress *sd_socket_address(const char *path,
94
-static void blockdev_remove_medium(const char *device, const char *id,
73
- const char *host, const char *port)
95
- Error **errp)
74
-{
96
+static void GRAPH_UNLOCKED
75
- SocketAddress *addr = g_new0(SocketAddress, 1);
97
+blockdev_remove_medium(const char *device, const char *id, Error **errp)
76
-
77
- if (path) {
78
- addr->type = SOCKET_ADDRESS_TYPE_UNIX;
79
- addr->u.q_unix.path = g_strdup(path);
80
- } else {
81
- addr->type = SOCKET_ADDRESS_TYPE_INET;
82
- addr->u.inet.host = g_strdup(host ?: SD_DEFAULT_ADDR);
83
- addr->u.inet.port = g_strdup(port ?: stringify(SD_DEFAULT_PORT));
84
- }
85
-
86
- return addr;
87
-}
88
-
89
static SocketAddress *sd_server_config(QDict *options, Error **errp)
90
{
98
{
91
QDict *server = NULL;
99
BlockBackend *blk;
92
@@ -XXX,XX +XXX,XX @@ out_with_err_set:
100
BlockDriverState *bs;
93
return ret;
101
AioContext *aio_context;
94
}
102
bool has_attached_device;
95
103
96
+static int sd_create_prealloc(BlockdevOptionsSheepdog *location, int64_t size,
104
+ GLOBAL_STATE_CODE();
97
+ Error **errp)
98
+{
99
+ BlockDriverState *bs;
100
+ Visitor *v;
101
+ QObject *obj = NULL;
102
+ QDict *qdict;
103
+ Error *local_err = NULL;
104
+ int ret;
105
+
105
+
106
+ v = qobject_output_visitor_new(&obj);
106
blk = qmp_get_blk(device, id, errp);
107
+ visit_type_BlockdevOptionsSheepdog(v, NULL, &location, &local_err);
107
if (!blk) {
108
+ visit_free(v);
108
return;
109
+
109
@@ -XXX,XX +XXX,XX @@ static void blockdev_remove_medium(const char *device, const char *id,
110
+ if (local_err) {
110
aio_context = bdrv_get_aio_context(bs);
111
+ error_propagate(errp, local_err);
111
aio_context_acquire(aio_context);
112
+ qobject_decref(obj);
112
113
+ return -EINVAL;
113
+ bdrv_graph_rdlock_main_loop();
114
+ }
114
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) {
115
+
115
+ bdrv_graph_rdunlock_main_loop();
116
+ qdict = qobject_to_qdict(obj);
117
+ qdict_flatten(qdict);
118
+
119
+ qdict_put_str(qdict, "driver", "sheepdog");
120
+
121
+ bs = bdrv_open(NULL, NULL, qdict, BDRV_O_PROTOCOL | BDRV_O_RDWR, errp);
122
+ if (bs == NULL) {
123
+ ret = -EIO;
124
+ goto fail;
125
+ }
126
+
127
+ ret = sd_prealloc(bs, 0, size, errp);
128
+fail:
129
+ bdrv_unref(bs);
130
+ QDECREF(qdict);
131
+ return ret;
132
+}
133
+
134
static int parse_redundancy(BDRVSheepdogState *s, SheepdogRedundancy *opt)
135
{
136
struct SheepdogInode *inode = &s->inode;
137
@@ -XXX,XX +XXX,XX @@ static int parse_redundancy(BDRVSheepdogState *s, SheepdogRedundancy *opt)
138
* # create a erasure coded vdi with x data strips and y parity strips
139
* -o redundancy=x:y (x must be one of {2,4,8,16} and 1 <= y < SD_EC_MAX_STRIP)
140
*/
141
-static int parse_redundancy_str(BDRVSheepdogState *s, const char *opt)
142
+static SheepdogRedundancy *parse_redundancy_str(const char *opt)
143
{
144
- struct SheepdogRedundancy redundancy;
145
+ SheepdogRedundancy *redundancy;
146
const char *n1, *n2;
147
long copy, parity;
148
char p[10];
149
@@ -XXX,XX +XXX,XX @@ static int parse_redundancy_str(BDRVSheepdogState *s, const char *opt)
150
n2 = strtok(NULL, ":");
151
152
if (!n1) {
153
- return -EINVAL;
154
+ return NULL;
155
}
156
157
ret = qemu_strtol(n1, NULL, 10, &copy);
158
if (ret < 0) {
159
- return ret;
160
+ return NULL;
161
}
162
163
+ redundancy = g_new0(SheepdogRedundancy, 1);
164
if (!n2) {
165
- redundancy = (SheepdogRedundancy) {
166
+ *redundancy = (SheepdogRedundancy) {
167
.type = SHEEPDOG_REDUNDANCY_TYPE_FULL,
168
.u.full.copies = copy,
169
};
170
} else {
171
ret = qemu_strtol(n2, NULL, 10, &parity);
172
if (ret < 0) {
173
- return ret;
174
+ return NULL;
175
}
176
177
- redundancy = (SheepdogRedundancy) {
178
+ *redundancy = (SheepdogRedundancy) {
179
.type = SHEEPDOG_REDUNDANCY_TYPE_ERASURE_CODED,
180
.u.erasure_coded = {
181
.data_strips = copy,
182
@@ -XXX,XX +XXX,XX @@ static int parse_redundancy_str(BDRVSheepdogState *s, const char *opt)
183
};
184
}
185
186
- return parse_redundancy(s, &redundancy);
187
+ return redundancy;
188
}
189
190
-static int parse_block_size_shift(BDRVSheepdogState *s, QemuOpts *opt)
191
+static int parse_block_size_shift(BDRVSheepdogState *s,
192
+ BlockdevCreateOptionsSheepdog *opts)
193
{
194
struct SheepdogInode *inode = &s->inode;
195
uint64_t object_size;
196
int obj_order;
197
198
- object_size = qemu_opt_get_size_del(opt, BLOCK_OPT_OBJECT_SIZE, 0);
199
- if (object_size) {
200
+ if (opts->has_object_size) {
201
+ object_size = opts->object_size;
202
+
203
if ((object_size - 1) & object_size) { /* not a power of 2? */
204
return -EINVAL;
205
}
206
@@ -XXX,XX +XXX,XX @@ static int parse_block_size_shift(BDRVSheepdogState *s, QemuOpts *opt)
207
return 0;
208
}
209
210
-static int coroutine_fn sd_co_create_opts(const char *filename, QemuOpts *opts,
211
- Error **errp)
212
+static int sd_co_create(BlockdevCreateOptions *options, Error **errp)
213
{
214
- Error *err = NULL;
215
+ BlockdevCreateOptionsSheepdog *opts = &options->u.sheepdog;
216
int ret = 0;
217
uint32_t vid = 0;
218
char *backing_file = NULL;
219
char *buf = NULL;
220
BDRVSheepdogState *s;
221
- SheepdogConfig cfg;
222
uint64_t max_vdi_size;
223
bool prealloc = false;
224
225
+ assert(options->driver == BLOCKDEV_DRIVER_SHEEPDOG);
226
+
227
s = g_new0(BDRVSheepdogState, 1);
228
229
- if (strstr(filename, "://")) {
230
- sd_parse_uri(&cfg, filename, &err);
231
- } else {
232
- parse_vdiname(&cfg, filename, &err);
233
- }
234
- if (err) {
235
- error_propagate(errp, err);
236
+ /* Steal SocketAddress from QAPI, set NULL to prevent double free */
237
+ s->addr = opts->location->server;
238
+ opts->location->server = NULL;
239
+
240
+ if (strlen(opts->location->vdi) >= sizeof(s->name)) {
241
+ error_setg(errp, "'vdi' string too long");
242
+ ret = -EINVAL;
243
goto out;
116
goto out;
244
}
117
}
245
+ pstrcpy(s->name, sizeof(s->name), opts->location->vdi);
118
+ bdrv_graph_rdunlock_main_loop();
246
119
247
- buf = cfg.port ? g_strdup_printf("%d", cfg.port) : NULL;
120
blk_remove_bs(blk);
248
- s->addr = sd_socket_address(cfg.path, cfg.host, buf);
121
249
- g_free(buf);
122
diff --git a/blockdev.c b/blockdev.c
250
- strcpy(s->name, cfg.vdi);
123
index XXXXXXX..XXXXXXX 100644
251
- sd_config_done(&cfg);
124
--- a/blockdev.c
252
+ s->inode.vdi_size = opts->size;
125
+++ b/blockdev.c
253
+ backing_file = opts->backing_file;
126
@@ -XXX,XX +XXX,XX @@ static void drive_backup_action(DriveBackup *backup,
254
127
}
255
- s->inode.vdi_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
128
256
- BDRV_SECTOR_SIZE);
129
/* Early check to avoid creating target */
257
- backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
130
+ bdrv_graph_rdlock_main_loop();
258
- buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
131
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) {
259
- if (!buf || !strcmp(buf, "off")) {
132
+ bdrv_graph_rdunlock_main_loop();
260
+ if (!opts->has_preallocation) {
261
+ opts->preallocation = PREALLOC_MODE_OFF;
262
+ }
263
+ switch (opts->preallocation) {
264
+ case PREALLOC_MODE_OFF:
265
prealloc = false;
266
- } else if (!strcmp(buf, "full")) {
267
+ break;
268
+ case PREALLOC_MODE_FULL:
269
prealloc = true;
270
- } else {
271
- error_setg(errp, "Invalid preallocation mode: '%s'", buf);
272
+ break;
273
+ default:
274
+ error_setg(errp, "Preallocation mode not supported for Sheepdog");
275
ret = -EINVAL;
276
goto out;
133
goto out;
277
}
134
}
278
135
+ bdrv_graph_rdunlock_main_loop();
279
- g_free(buf);
136
280
- buf = qemu_opt_get_del(opts, BLOCK_OPT_REDUNDANCY);
137
flags = bs->open_flags | BDRV_O_RDWR;
281
- if (buf) {
138
282
- ret = parse_redundancy_str(s, buf);
139
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qmp_block_resize(const char *device, const char *node_name,
283
+ if (opts->has_redundancy) {
140
return;
284
+ ret = parse_redundancy(s, opts->redundancy);
141
}
285
if (ret < 0) {
142
286
- error_setg(errp, "Invalid redundancy mode: '%s'", buf);
143
+ bdrv_graph_co_rdlock();
287
+ error_setg(errp, "Invalid redundancy mode");
144
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_RESIZE, NULL)) {
145
error_setg(errp, QERR_DEVICE_IN_USE, device);
146
+ bdrv_graph_co_rdunlock();
147
return;
148
}
149
+ bdrv_graph_co_rdunlock();
150
151
blk = blk_co_new_with_bs(bs, BLK_PERM_RESIZE, BLK_PERM_ALL, errp);
152
if (!blk) {
153
@@ -XXX,XX +XXX,XX @@ void qmp_block_stream(const char *job_id, const char *device,
154
* Check for op blockers in the whole chain between bs and base (or bottom)
155
*/
156
iter_end = bottom ? bdrv_filter_or_cow_bs(bottom_bs) : base_bs;
157
+ bdrv_graph_rdlock_main_loop();
158
for (iter = bs; iter && iter != iter_end;
159
iter = bdrv_filter_or_cow_bs(iter))
160
{
161
if (bdrv_op_is_blocked(iter, BLOCK_OP_TYPE_STREAM, errp)) {
162
+ bdrv_graph_rdunlock_main_loop();
288
goto out;
163
goto out;
289
}
164
}
290
}
165
}
291
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn sd_co_create_opts(const char *filename, QemuOpts *opts,
166
+ bdrv_graph_rdunlock_main_loop();
167
168
/* if we are streaming the entire chain, the result will have no backing
169
* file, and specifying one is therefore an error */
170
@@ -XXX,XX +XXX,XX @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
171
}
172
173
/* Early check to avoid creating target */
174
+ bdrv_graph_rdlock_main_loop();
175
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_MIRROR_SOURCE, errp)) {
176
+ bdrv_graph_rdunlock_main_loop();
177
return;
178
}
179
+ bdrv_graph_rdunlock_main_loop();
180
181
aio_context = bdrv_get_aio_context(bs);
182
aio_context_acquire(aio_context);
183
@@ -XXX,XX +XXX,XX @@ void qmp_change_backing_file(const char *device,
184
185
/* even though we are not necessarily operating on bs, we need it to
186
* determine if block ops are currently prohibited on the chain */
187
+ bdrv_graph_rdlock_main_loop();
188
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_CHANGE, errp)) {
189
+ bdrv_graph_rdunlock_main_loop();
292
goto out;
190
goto out;
293
}
191
}
294
192
+ bdrv_graph_rdunlock_main_loop();
295
- if (backing_file) {
193
296
+ if (opts->has_backing_file) {
194
/* final sanity check */
297
BlockBackend *blk;
195
if (!bdrv_chain_contains(bs, image_bs)) {
298
BDRVSheepdogState *base;
299
BlockDriver *drv;
300
301
/* Currently, only Sheepdog backing image is supported. */
302
- drv = bdrv_find_protocol(backing_file, true, NULL);
303
+ drv = bdrv_find_protocol(opts->backing_file, true, NULL);
304
if (!drv || strcmp(drv->protocol_name, "sheepdog") != 0) {
305
error_setg(errp, "backing_file must be a sheepdog image");
306
ret = -EINVAL;
307
goto out;
308
}
309
310
- blk = blk_new_open(backing_file, NULL, NULL,
311
+ blk = blk_new_open(opts->backing_file, NULL, NULL,
312
BDRV_O_PROTOCOL, errp);
313
if (blk == NULL) {
314
ret = -EIO;
315
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn sd_co_create_opts(const char *filename, QemuOpts *opts,
316
}
317
318
if (prealloc) {
319
- BlockDriverState *bs;
320
- QDict *opts;
321
-
322
- opts = qdict_new();
323
- qdict_put_str(opts, "driver", "sheepdog");
324
- bs = bdrv_open(filename, NULL, opts, BDRV_O_PROTOCOL | BDRV_O_RDWR,
325
- errp);
326
- if (!bs) {
327
- goto out;
328
- }
329
-
330
- ret = sd_prealloc(bs, 0, s->inode.vdi_size, errp);
331
-
332
- bdrv_unref(bs);
333
+ ret = sd_create_prealloc(opts->location, opts->size, errp);
334
}
335
out:
336
g_free(backing_file);
337
g_free(buf);
338
+ g_free(s->addr);
339
g_free(s);
340
return ret;
341
}
342
343
+static int coroutine_fn sd_co_create_opts(const char *filename, QemuOpts *opts,
344
+ Error **errp)
345
+{
346
+ BlockdevCreateOptions *create_options = NULL;
347
+ QDict *qdict, *location_qdict;
348
+ QObject *crumpled;
349
+ Visitor *v;
350
+ const char *redundancy;
351
+ Error *local_err = NULL;
352
+ int ret;
353
+
354
+ redundancy = qemu_opt_get_del(opts, BLOCK_OPT_REDUNDANCY);
355
+
356
+ qdict = qemu_opts_to_qdict(opts, NULL);
357
+ qdict_put_str(qdict, "driver", "sheepdog");
358
+
359
+ location_qdict = qdict_new();
360
+ qdict_put(qdict, "location", location_qdict);
361
+
362
+ sd_parse_filename(filename, location_qdict, &local_err);
363
+ if (local_err) {
364
+ error_propagate(errp, local_err);
365
+ ret = -EINVAL;
366
+ goto fail;
367
+ }
368
+
369
+ qdict_flatten(qdict);
370
+
371
+ /* Change legacy command line options into QMP ones */
372
+ static const QDictRenames opt_renames[] = {
373
+ { BLOCK_OPT_BACKING_FILE, "backing-file" },
374
+ { BLOCK_OPT_OBJECT_SIZE, "object-size" },
375
+ { NULL, NULL },
376
+ };
377
+
378
+ if (!qdict_rename_keys(qdict, opt_renames, errp)) {
379
+ ret = -EINVAL;
380
+ goto fail;
381
+ }
382
+
383
+ /* Get the QAPI object */
384
+ crumpled = qdict_crumple(qdict, errp);
385
+ if (crumpled == NULL) {
386
+ ret = -EINVAL;
387
+ goto fail;
388
+ }
389
+
390
+ v = qobject_input_visitor_new_keyval(crumpled);
391
+ visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
392
+ visit_free(v);
393
+ qobject_decref(crumpled);
394
+
395
+ if (local_err) {
396
+ error_propagate(errp, local_err);
397
+ ret = -EINVAL;
398
+ goto fail;
399
+ }
400
+
401
+ assert(create_options->driver == BLOCKDEV_DRIVER_SHEEPDOG);
402
+ create_options->u.sheepdog.size =
403
+ ROUND_UP(create_options->u.sheepdog.size, BDRV_SECTOR_SIZE);
404
+
405
+ if (redundancy) {
406
+ create_options->u.sheepdog.has_redundancy = true;
407
+ create_options->u.sheepdog.redundancy =
408
+ parse_redundancy_str(redundancy);
409
+ if (create_options->u.sheepdog.redundancy == NULL) {
410
+ error_setg(errp, "Invalid redundancy mode");
411
+ ret = -EINVAL;
412
+ goto fail;
413
+ }
414
+ }
415
+
416
+ ret = sd_co_create(create_options, errp);
417
+fail:
418
+ qapi_free_BlockdevCreateOptions(create_options);
419
+ QDECREF(qdict);
420
+ return ret;
421
+}
422
+
423
static void sd_close(BlockDriverState *bs)
424
{
425
Error *local_err = NULL;
426
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_sheepdog = {
427
.bdrv_reopen_commit = sd_reopen_commit,
428
.bdrv_reopen_abort = sd_reopen_abort,
429
.bdrv_close = sd_close,
430
+ .bdrv_co_create = sd_co_create,
431
.bdrv_co_create_opts = sd_co_create_opts,
432
.bdrv_has_zero_init = bdrv_has_zero_init_1,
433
.bdrv_getlength = sd_getlength,
434
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_sheepdog_tcp = {
435
.bdrv_reopen_commit = sd_reopen_commit,
436
.bdrv_reopen_abort = sd_reopen_abort,
437
.bdrv_close = sd_close,
438
+ .bdrv_co_create = sd_co_create,
439
.bdrv_co_create_opts = sd_co_create_opts,
440
.bdrv_has_zero_init = bdrv_has_zero_init_1,
441
.bdrv_getlength = sd_getlength,
442
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_sheepdog_unix = {
443
.bdrv_reopen_commit = sd_reopen_commit,
444
.bdrv_reopen_abort = sd_reopen_abort,
445
.bdrv_close = sd_close,
446
+ .bdrv_co_create = sd_co_create,
447
.bdrv_co_create_opts = sd_co_create_opts,
448
.bdrv_has_zero_init = bdrv_has_zero_init_1,
449
.bdrv_getlength = sd_getlength,
450
--
196
--
451
2.13.6
197
2.41.0
452
453
diff view generated by jsdifflib
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
This adds GRAPH_RDLOCK annotations to declare that callers of
2
bdrv_apply_auto_read_only() need to hold a reader lock for the graph
3
because it calls bdrv_can_set_read_only(), which indirectly accesses the
4
parents list of a node.
2
5
3
QED's bdrv_invalidate_cache implementation would like to reuse functions
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
that acquire/release the metadata locks. Call it from coroutine context
7
Message-ID: <20230929145157.45443-19-kwolf@redhat.com>
5
to simplify the logic.
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
6
7
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
8
Message-Id: <1516279431-30424-6-git-send-email-pbonzini@redhat.com>
9
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
10
---
12
include/block/block_int.h | 3 ++-
11
include/block/block-io.h | 6 ++++--
13
block.c | 41 +++++++++++++++++++++++++++++++++++++----
12
block.c | 4 ++--
14
block/iscsi.c | 6 +++---
13
block/bochs.c | 2 ++
15
block/nfs.c | 6 +++---
14
block/cloop.c | 2 ++
16
block/qcow2.c | 7 +++++--
15
block/curl.c | 2 ++
17
block/qed.c | 13 +++++--------
16
block/dmg.c | 2 ++
18
block/rbd.c | 6 +++---
17
block/gluster.c | 2 ++
19
7 files changed, 58 insertions(+), 24 deletions(-)
18
block/iscsi.c | 2 ++
19
block/nbd.c | 3 ++-
20
block/rbd.c | 2 ++
21
10 files changed, 22 insertions(+), 5 deletions(-)
20
22
21
diff --git a/include/block/block_int.h b/include/block/block_int.h
23
diff --git a/include/block/block-io.h b/include/block/block-io.h
22
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
23
--- a/include/block/block_int.h
25
--- a/include/block/block-io.h
24
+++ b/include/block/block_int.h
26
+++ b/include/block/block-io.h
25
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
27
@@ -XXX,XX +XXX,XX @@ bdrv_is_allocated_above(BlockDriverState *bs, BlockDriverState *base,
26
/*
28
int coroutine_fn GRAPH_RDLOCK
27
* Invalidate any cached meta-data.
29
bdrv_co_is_zero_fast(BlockDriverState *bs, int64_t offset, int64_t bytes);
28
*/
30
29
- void (*bdrv_invalidate_cache)(BlockDriverState *bs, Error **errp);
31
-int bdrv_apply_auto_read_only(BlockDriverState *bs, const char *errmsg,
30
+ void coroutine_fn (*bdrv_co_invalidate_cache)(BlockDriverState *bs,
32
- Error **errp);
31
+ Error **errp);
33
+int GRAPH_RDLOCK
32
int (*bdrv_inactivate)(BlockDriverState *bs);
34
+bdrv_apply_auto_read_only(BlockDriverState *bs, const char *errmsg,
33
35
+ Error **errp);
34
/*
36
+
37
bool bdrv_is_read_only(BlockDriverState *bs);
38
bool bdrv_is_writable(BlockDriverState *bs);
39
bool bdrv_is_sg(BlockDriverState *bs);
35
diff --git a/block.c b/block.c
40
diff --git a/block.c b/block.c
36
index XXXXXXX..XXXXXXX 100644
41
index XXXXXXX..XXXXXXX 100644
37
--- a/block.c
42
--- a/block.c
38
+++ b/block.c
43
+++ b/block.c
39
@@ -XXX,XX +XXX,XX @@ void bdrv_init_with_whitelist(void)
44
@@ -XXX,XX +XXX,XX @@ int bdrv_apply_auto_read_only(BlockDriverState *bs, const char *errmsg,
40
bdrv_init();
45
int ret = 0;
41
}
46
IO_CODE();
42
47
43
-void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
48
- assume_graph_lock(); /* FIXME */
44
+static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs,
49
-
45
+ Error **errp)
50
if (!(bs->open_flags & BDRV_O_RDWR)) {
46
{
51
return 0;
47
BdrvChild *child, *parent;
48
uint64_t perm, shared_perm;
49
@@ -XXX,XX +XXX,XX @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
50
}
52
}
51
53
@@ -XXX,XX +XXX,XX @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file,
52
QLIST_FOREACH(child, &bs->children, next) {
54
53
- bdrv_invalidate_cache(child->bs, &local_err);
55
if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv, ro)) {
54
+ bdrv_co_invalidate_cache(child->bs, &local_err);
56
if (!ro && bdrv_is_whitelisted(drv, true)) {
55
if (local_err) {
57
+ bdrv_graph_rdlock_main_loop();
56
error_propagate(errp, local_err);
58
ret = bdrv_apply_auto_read_only(bs, NULL, NULL);
57
return;
59
+ bdrv_graph_rdunlock_main_loop();
58
@@ -XXX,XX +XXX,XX @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
60
} else {
61
ret = -ENOTSUP;
62
}
63
diff --git a/block/bochs.c b/block/bochs.c
64
index XXXXXXX..XXXXXXX 100644
65
--- a/block/bochs.c
66
+++ b/block/bochs.c
67
@@ -XXX,XX +XXX,XX @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
68
int ret;
69
70
/* No write support yet */
71
+ bdrv_graph_rdlock_main_loop();
72
ret = bdrv_apply_auto_read_only(bs, NULL, errp);
73
+ bdrv_graph_rdunlock_main_loop();
74
if (ret < 0) {
75
return ret;
59
}
76
}
60
bdrv_set_perm(bs, perm, shared_perm);
77
diff --git a/block/cloop.c b/block/cloop.c
61
78
index XXXXXXX..XXXXXXX 100644
62
- if (bs->drv->bdrv_invalidate_cache) {
79
--- a/block/cloop.c
63
- bs->drv->bdrv_invalidate_cache(bs, &local_err);
80
+++ b/block/cloop.c
64
+ if (bs->drv->bdrv_co_invalidate_cache) {
81
@@ -XXX,XX +XXX,XX @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
65
+ bs->drv->bdrv_co_invalidate_cache(bs, &local_err);
82
uint32_t offsets_size, max_compressed_block_size = 1, i;
66
if (local_err) {
83
int ret;
67
bs->open_flags |= BDRV_O_INACTIVE;
84
68
error_propagate(errp, local_err);
85
+ bdrv_graph_rdlock_main_loop();
69
@@ -XXX,XX +XXX,XX @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
86
ret = bdrv_apply_auto_read_only(bs, NULL, errp);
87
+ bdrv_graph_rdunlock_main_loop();
88
if (ret < 0) {
89
return ret;
70
}
90
}
71
}
91
diff --git a/block/curl.c b/block/curl.c
72
92
index XXXXXXX..XXXXXXX 100644
73
+typedef struct InvalidateCacheCo {
93
--- a/block/curl.c
74
+ BlockDriverState *bs;
94
+++ b/block/curl.c
75
+ Error **errp;
95
@@ -XXX,XX +XXX,XX @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
76
+ bool done;
96
const char *protocol_delimiter;
77
+} InvalidateCacheCo;
97
int ret;
78
+
98
79
+static void coroutine_fn bdrv_invalidate_cache_co_entry(void *opaque)
99
+ bdrv_graph_rdlock_main_loop();
80
+{
100
ret = bdrv_apply_auto_read_only(bs, "curl driver does not support writes",
81
+ InvalidateCacheCo *ico = opaque;
101
errp);
82
+ bdrv_co_invalidate_cache(ico->bs, ico->errp);
102
+ bdrv_graph_rdunlock_main_loop();
83
+ ico->done = true;
103
if (ret < 0) {
84
+}
104
return ret;
85
+
105
}
86
+void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
106
diff --git a/block/dmg.c b/block/dmg.c
87
+{
107
index XXXXXXX..XXXXXXX 100644
88
+ Coroutine *co;
108
--- a/block/dmg.c
89
+ InvalidateCacheCo ico = {
109
+++ b/block/dmg.c
90
+ .bs = bs,
110
@@ -XXX,XX +XXX,XX @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
91
+ .done = false,
111
int64_t offset;
92
+ .errp = errp
112
int ret;
93
+ };
113
94
+
114
+ bdrv_graph_rdlock_main_loop();
95
+ if (qemu_in_coroutine()) {
115
ret = bdrv_apply_auto_read_only(bs, NULL, errp);
96
+ /* Fast-path if already in coroutine context */
116
+ bdrv_graph_rdunlock_main_loop();
97
+ bdrv_invalidate_cache_co_entry(&ico);
117
if (ret < 0) {
98
+ } else {
118
return ret;
99
+ co = qemu_coroutine_create(bdrv_invalidate_cache_co_entry, &ico);
119
}
100
+ qemu_coroutine_enter(co);
120
diff --git a/block/gluster.c b/block/gluster.c
101
+ BDRV_POLL_WHILE(bs, !ico.done);
121
index XXXXXXX..XXXXXXX 100644
102
+ }
122
--- a/block/gluster.c
103
+}
123
+++ b/block/gluster.c
104
+
124
@@ -XXX,XX +XXX,XX @@ static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
105
void bdrv_invalidate_cache_all(Error **errp)
125
if (ret == -EACCES || ret == -EROFS) {
106
{
126
/* Try to degrade to read-only, but if it doesn't work, still use the
107
BlockDriverState *bs;
127
* normal error message. */
128
+ bdrv_graph_rdlock_main_loop();
129
if (bdrv_apply_auto_read_only(bs, NULL, NULL) == 0) {
130
open_flags = (open_flags & ~O_RDWR) | O_RDONLY;
131
s->fd = glfs_open(s->glfs, gconf->path, open_flags);
132
ret = s->fd ? 0 : -errno;
133
}
134
+ bdrv_graph_rdunlock_main_loop();
135
}
136
137
s->supports_seek_data = qemu_gluster_test_seek(s->fd);
108
diff --git a/block/iscsi.c b/block/iscsi.c
138
diff --git a/block/iscsi.c b/block/iscsi.c
109
index XXXXXXX..XXXXXXX 100644
139
index XXXXXXX..XXXXXXX 100644
110
--- a/block/iscsi.c
140
--- a/block/iscsi.c
111
+++ b/block/iscsi.c
141
+++ b/block/iscsi.c
112
@@ -XXX,XX +XXX,XX @@ static int iscsi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
142
@@ -XXX,XX +XXX,XX @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
113
return 0;
143
/* Check the write protect flag of the LUN if we want to write */
114
}
144
if (iscsilun->type == TYPE_DISK && (flags & BDRV_O_RDWR) &&
115
145
iscsilun->write_protected) {
116
-static void iscsi_invalidate_cache(BlockDriverState *bs,
146
+ bdrv_graph_rdlock_main_loop();
117
- Error **errp)
147
ret = bdrv_apply_auto_read_only(bs, "LUN is write protected", errp);
118
+static void coroutine_fn iscsi_co_invalidate_cache(BlockDriverState *bs,
148
+ bdrv_graph_rdunlock_main_loop();
119
+ Error **errp)
149
if (ret < 0) {
150
goto out;
151
}
152
diff --git a/block/nbd.c b/block/nbd.c
153
index XXXXXXX..XXXXXXX 100644
154
--- a/block/nbd.c
155
+++ b/block/nbd.c
156
@@ -XXX,XX +XXX,XX @@ static bool nbd_client_will_reconnect(BDRVNBDState *s)
157
* Return failure if the server's advertised options are incompatible with the
158
* client's needs.
159
*/
160
-static int nbd_handle_updated_info(BlockDriverState *bs, Error **errp)
161
+static int coroutine_fn GRAPH_RDLOCK
162
+nbd_handle_updated_info(BlockDriverState *bs, Error **errp)
120
{
163
{
121
IscsiLun *iscsilun = bs->opaque;
164
BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
122
iscsi_allocmap_invalidate(iscsilun);
165
int ret;
123
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_iscsi = {
124
.create_opts = &iscsi_create_opts,
125
.bdrv_reopen_prepare = iscsi_reopen_prepare,
126
.bdrv_reopen_commit = iscsi_reopen_commit,
127
- .bdrv_invalidate_cache = iscsi_invalidate_cache,
128
+ .bdrv_co_invalidate_cache = iscsi_co_invalidate_cache,
129
130
.bdrv_getlength = iscsi_getlength,
131
.bdrv_get_info = iscsi_get_info,
132
diff --git a/block/nfs.c b/block/nfs.c
133
index XXXXXXX..XXXXXXX 100644
134
--- a/block/nfs.c
135
+++ b/block/nfs.c
136
@@ -XXX,XX +XXX,XX @@ static void nfs_refresh_filename(BlockDriverState *bs, QDict *options)
137
}
138
139
#ifdef LIBNFS_FEATURE_PAGECACHE
140
-static void nfs_invalidate_cache(BlockDriverState *bs,
141
- Error **errp)
142
+static void coroutine_fn nfs_co_invalidate_cache(BlockDriverState *bs,
143
+ Error **errp)
144
{
145
NFSClient *client = bs->opaque;
146
nfs_pagecache_invalidate(client->context, client->fh);
147
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_nfs = {
148
.bdrv_refresh_filename = nfs_refresh_filename,
149
150
#ifdef LIBNFS_FEATURE_PAGECACHE
151
- .bdrv_invalidate_cache = nfs_invalidate_cache,
152
+ .bdrv_co_invalidate_cache = nfs_co_invalidate_cache,
153
#endif
154
};
155
156
diff --git a/block/qcow2.c b/block/qcow2.c
157
index XXXXXXX..XXXXXXX 100644
158
--- a/block/qcow2.c
159
+++ b/block/qcow2.c
160
@@ -XXX,XX +XXX,XX @@ static void qcow2_close(BlockDriverState *bs)
161
qcow2_free_snapshots(bs);
162
}
163
164
-static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp)
165
+static void coroutine_fn qcow2_co_invalidate_cache(BlockDriverState *bs,
166
+ Error **errp)
167
{
168
BDRVQcow2State *s = bs->opaque;
169
int flags = s->flags;
170
@@ -XXX,XX +XXX,XX @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp)
171
options = qdict_clone_shallow(bs->options);
172
173
flags &= ~BDRV_O_INACTIVE;
174
+ qemu_co_mutex_lock(&s->lock);
175
ret = qcow2_do_open(bs, options, flags, &local_err);
176
+ qemu_co_mutex_unlock(&s->lock);
177
QDECREF(options);
178
if (local_err) {
179
error_propagate(errp, local_err);
180
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_qcow2 = {
181
.bdrv_change_backing_file = qcow2_change_backing_file,
182
183
.bdrv_refresh_limits = qcow2_refresh_limits,
184
- .bdrv_invalidate_cache = qcow2_invalidate_cache,
185
+ .bdrv_co_invalidate_cache = qcow2_co_invalidate_cache,
186
.bdrv_inactivate = qcow2_inactivate,
187
188
.create_opts = &qcow2_create_opts,
189
diff --git a/block/qed.c b/block/qed.c
190
index XXXXXXX..XXXXXXX 100644
191
--- a/block/qed.c
192
+++ b/block/qed.c
193
@@ -XXX,XX +XXX,XX @@ static int bdrv_qed_change_backing_file(BlockDriverState *bs,
194
return ret;
195
}
196
197
-static void bdrv_qed_invalidate_cache(BlockDriverState *bs, Error **errp)
198
+static void coroutine_fn bdrv_qed_co_invalidate_cache(BlockDriverState *bs,
199
+ Error **errp)
200
{
201
BDRVQEDState *s = bs->opaque;
202
Error *local_err = NULL;
203
@@ -XXX,XX +XXX,XX @@ static void bdrv_qed_invalidate_cache(BlockDriverState *bs, Error **errp)
204
bdrv_qed_close(bs);
205
206
bdrv_qed_init_state(bs);
207
- if (qemu_in_coroutine()) {
208
- qemu_co_mutex_lock(&s->table_lock);
209
- }
210
+ qemu_co_mutex_lock(&s->table_lock);
211
ret = bdrv_qed_do_open(bs, NULL, bs->open_flags, &local_err);
212
- if (qemu_in_coroutine()) {
213
- qemu_co_mutex_unlock(&s->table_lock);
214
- }
215
+ qemu_co_mutex_unlock(&s->table_lock);
216
if (local_err) {
217
error_propagate(errp, local_err);
218
error_prepend(errp, "Could not reopen qed layer: ");
219
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_qed = {
220
.bdrv_get_info = bdrv_qed_get_info,
221
.bdrv_refresh_limits = bdrv_qed_refresh_limits,
222
.bdrv_change_backing_file = bdrv_qed_change_backing_file,
223
- .bdrv_invalidate_cache = bdrv_qed_invalidate_cache,
224
+ .bdrv_co_invalidate_cache = bdrv_qed_co_invalidate_cache,
225
.bdrv_check = bdrv_qed_check,
226
.bdrv_detach_aio_context = bdrv_qed_detach_aio_context,
227
.bdrv_attach_aio_context = bdrv_qed_attach_aio_context,
228
diff --git a/block/rbd.c b/block/rbd.c
166
diff --git a/block/rbd.c b/block/rbd.c
229
index XXXXXXX..XXXXXXX 100644
167
index XXXXXXX..XXXXXXX 100644
230
--- a/block/rbd.c
168
--- a/block/rbd.c
231
+++ b/block/rbd.c
169
+++ b/block/rbd.c
232
@@ -XXX,XX +XXX,XX @@ static BlockAIOCB *qemu_rbd_aio_pdiscard(BlockDriverState *bs,
170
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
233
#endif
171
/* If we are using an rbd snapshot, we must be r/o, otherwise
234
172
* leave as-is */
235
#ifdef LIBRBD_SUPPORTS_INVALIDATE
173
if (s->snap != NULL) {
236
-static void qemu_rbd_invalidate_cache(BlockDriverState *bs,
174
+ bdrv_graph_rdlock_main_loop();
237
- Error **errp)
175
r = bdrv_apply_auto_read_only(bs, "rbd snapshots are read-only", errp);
238
+static void coroutine_fn qemu_rbd_co_invalidate_cache(BlockDriverState *bs,
176
+ bdrv_graph_rdunlock_main_loop();
239
+ Error **errp)
177
if (r < 0) {
240
{
178
goto failed_post_open;
241
BDRVRBDState *s = bs->opaque;
179
}
242
int r = rbd_invalidate_cache(s->image);
243
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_rbd = {
244
.bdrv_snapshot_list = qemu_rbd_snap_list,
245
.bdrv_snapshot_goto = qemu_rbd_snap_rollback,
246
#ifdef LIBRBD_SUPPORTS_INVALIDATE
247
- .bdrv_invalidate_cache = qemu_rbd_invalidate_cache,
248
+ .bdrv_co_invalidate_cache = qemu_rbd_co_invalidate_cache,
249
#endif
250
};
251
252
--
180
--
253
2.13.6
181
2.41.0
254
255
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
This function checks that the size of a snapshot's L1 table is not too
4
large, but it doesn't validate the offset.
5
6
We now have a function to take care of this, so let's use it.
7
8
Signed-off-by: Alberto Garcia <berto@igalia.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
12
block/qcow2-snapshot.c | 8 +++++---
13
tests/qemu-iotests/080 | 10 +++++++++-
14
tests/qemu-iotests/080.out | 8 +++++++-
15
3 files changed, 21 insertions(+), 5 deletions(-)
16
17
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/block/qcow2-snapshot.c
20
+++ b/block/qcow2-snapshot.c
21
@@ -XXX,XX +XXX,XX @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs,
22
sn = &s->snapshots[snapshot_index];
23
24
/* Allocate and read in the snapshot's L1 table */
25
- if (sn->l1_size > QCOW_MAX_L1_SIZE / sizeof(uint64_t)) {
26
- error_setg(errp, "Snapshot L1 table too large");
27
- return -EFBIG;
28
+ ret = qcow2_validate_table(bs, sn->l1_table_offset, sn->l1_size,
29
+ sizeof(uint64_t), QCOW_MAX_L1_SIZE,
30
+ "Snapshot L1 table", errp);
31
+ if (ret < 0) {
32
+ return ret;
33
}
34
new_l1_bytes = sn->l1_size * sizeof(uint64_t);
35
new_l1_table = qemu_try_blockalign(bs->file->bs,
36
diff --git a/tests/qemu-iotests/080 b/tests/qemu-iotests/080
37
index XXXXXXX..XXXXXXX 100755
38
--- a/tests/qemu-iotests/080
39
+++ b/tests/qemu-iotests/080
40
@@ -XXX,XX +XXX,XX @@ poke_file "$TEST_IMG" "$offset_l2_table_0" "\x80\x00\x00\xff\xff\xff\x00\x00"
41
{ $QEMU_IMG snapshot -c test $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
42
43
echo
44
-echo "== Invalid snapshot L1 table =="
45
+echo "== Invalid snapshot L1 table offset =="
46
+_make_test_img 64M
47
+{ $QEMU_IO -c "write 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
48
+{ $QEMU_IMG snapshot -c test $TEST_IMG; } 2>&1 | _filter_testdir
49
+poke_file "$TEST_IMG" "$offset_snap1_l1_offset" "\x00\x00\x00\x00\x00\x40\x02\x00"
50
+{ $QEMU_IMG convert -s test $TEST_IMG $TEST_IMG.snap; } 2>&1 | _filter_testdir
51
+
52
+echo
53
+echo "== Invalid snapshot L1 table size =="
54
_make_test_img 64M
55
{ $QEMU_IO -c "write 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
56
{ $QEMU_IMG snapshot -c test $TEST_IMG; } 2>&1 | _filter_testdir
57
diff --git a/tests/qemu-iotests/080.out b/tests/qemu-iotests/080.out
58
index XXXXXXX..XXXXXXX 100644
59
--- a/tests/qemu-iotests/080.out
60
+++ b/tests/qemu-iotests/080.out
61
@@ -XXX,XX +XXX,XX @@ wrote 512/512 bytes at offset 0
62
qemu-img: Could not create snapshot 'test': -27 (File too large)
63
qemu-img: Could not create snapshot 'test': -11 (Resource temporarily unavailable)
64
65
-== Invalid snapshot L1 table ==
66
+== Invalid snapshot L1 table offset ==
67
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
68
+wrote 512/512 bytes at offset 0
69
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
70
+qemu-img: Failed to load snapshot: Snapshot L1 table offset invalid
71
+
72
+== Invalid snapshot L1 table size ==
73
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
74
wrote 512/512 bytes at offset 0
75
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
76
--
77
2.13.6
78
79
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
This function iterates over all snapshots of a qcow2 file in order to
4
expand all zero clusters, but it does not validate the snapshots' L1
5
tables first.
6
7
We now have a function to take care of this, so let's use it.
8
9
We can also take the opportunity to replace the sector-based
10
bdrv_read() with bdrv_pread().
11
12
Cc: Eric Blake <eblake@redhat.com>
13
Signed-off-by: Alberto Garcia <berto@igalia.com>
14
Reviewed-by: Eric Blake <eblake@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
---
17
block/qcow2-cluster.c | 24 +++++++++++++++++-------
18
tests/qemu-iotests/080 | 2 ++
19
tests/qemu-iotests/080.out | 4 ++++
20
3 files changed, 23 insertions(+), 7 deletions(-)
21
22
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
23
index XXXXXXX..XXXXXXX 100644
24
--- a/block/qcow2-cluster.c
25
+++ b/block/qcow2-cluster.c
26
@@ -XXX,XX +XXX,XX @@
27
#include "qemu/osdep.h"
28
#include <zlib.h>
29
30
+#include "qapi/error.h"
31
#include "qemu-common.h"
32
#include "block/block_int.h"
33
#include "block/qcow2.h"
34
@@ -XXX,XX +XXX,XX @@ int qcow2_expand_zero_clusters(BlockDriverState *bs,
35
}
36
37
for (i = 0; i < s->nb_snapshots; i++) {
38
- int l1_sectors = DIV_ROUND_UP(s->snapshots[i].l1_size *
39
- sizeof(uint64_t), BDRV_SECTOR_SIZE);
40
+ int l1_size2;
41
+ uint64_t *new_l1_table;
42
+ Error *local_err = NULL;
43
+
44
+ ret = qcow2_validate_table(bs, s->snapshots[i].l1_table_offset,
45
+ s->snapshots[i].l1_size, sizeof(uint64_t),
46
+ QCOW_MAX_L1_SIZE, "Snapshot L1 table",
47
+ &local_err);
48
+ if (ret < 0) {
49
+ error_report_err(local_err);
50
+ goto fail;
51
+ }
52
53
- uint64_t *new_l1_table =
54
- g_try_realloc(l1_table, l1_sectors * BDRV_SECTOR_SIZE);
55
+ l1_size2 = s->snapshots[i].l1_size * sizeof(uint64_t);
56
+ new_l1_table = g_try_realloc(l1_table, l1_size2);
57
58
if (!new_l1_table) {
59
ret = -ENOMEM;
60
@@ -XXX,XX +XXX,XX @@ int qcow2_expand_zero_clusters(BlockDriverState *bs,
61
62
l1_table = new_l1_table;
63
64
- ret = bdrv_read(bs->file,
65
- s->snapshots[i].l1_table_offset / BDRV_SECTOR_SIZE,
66
- (void *)l1_table, l1_sectors);
67
+ ret = bdrv_pread(bs->file, s->snapshots[i].l1_table_offset,
68
+ l1_table, l1_size2);
69
if (ret < 0) {
70
goto fail;
71
}
72
diff --git a/tests/qemu-iotests/080 b/tests/qemu-iotests/080
73
index XXXXXXX..XXXXXXX 100755
74
--- a/tests/qemu-iotests/080
75
+++ b/tests/qemu-iotests/080
76
@@ -XXX,XX +XXX,XX @@ _make_test_img 64M
77
{ $QEMU_IMG snapshot -c test $TEST_IMG; } 2>&1 | _filter_testdir
78
poke_file "$TEST_IMG" "$offset_snap1_l1_offset" "\x00\x00\x00\x00\x00\x40\x02\x00"
79
{ $QEMU_IMG convert -s test $TEST_IMG $TEST_IMG.snap; } 2>&1 | _filter_testdir
80
+{ $QEMU_IMG amend -o compat=0.10 $TEST_IMG; } 2>&1 | _filter_testdir
81
82
echo
83
echo "== Invalid snapshot L1 table size =="
84
@@ -XXX,XX +XXX,XX @@ _make_test_img 64M
85
{ $QEMU_IMG snapshot -c test $TEST_IMG; } 2>&1 | _filter_testdir
86
poke_file "$TEST_IMG" "$offset_snap1_l1_size" "\x10\x00\x00\x00"
87
{ $QEMU_IMG convert -s test $TEST_IMG $TEST_IMG.snap; } 2>&1 | _filter_testdir
88
+{ $QEMU_IMG amend -o compat=0.10 $TEST_IMG; } 2>&1 | _filter_testdir
89
90
# success, all done
91
echo "*** done"
92
diff --git a/tests/qemu-iotests/080.out b/tests/qemu-iotests/080.out
93
index XXXXXXX..XXXXXXX 100644
94
--- a/tests/qemu-iotests/080.out
95
+++ b/tests/qemu-iotests/080.out
96
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
97
wrote 512/512 bytes at offset 0
98
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
99
qemu-img: Failed to load snapshot: Snapshot L1 table offset invalid
100
+qemu-img: Snapshot L1 table offset invalid
101
+qemu-img: Error while amending options: Invalid argument
102
103
== Invalid snapshot L1 table size ==
104
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
105
wrote 512/512 bytes at offset 0
106
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
107
qemu-img: Failed to load snapshot: Snapshot L1 table too large
108
+qemu-img: Snapshot L1 table too large
109
+qemu-img: Error while amending options: File too large
110
*** done
111
--
112
2.13.6
113
114
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
The inactive-l2 overlap check iterates uses the L1 tables from all
4
snapshots, but it does not validate them first.
5
6
We now have a function to take care of this, so let's use it.
7
8
Signed-off-by: Alberto Garcia <berto@igalia.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
12
block/qcow2-refcount.c | 10 +++++++++-
13
tests/qemu-iotests/080 | 4 ++++
14
tests/qemu-iotests/080.out | 4 ++++
15
3 files changed, 17 insertions(+), 1 deletion(-)
16
17
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/block/qcow2-refcount.c
20
+++ b/block/qcow2-refcount.c
21
@@ -XXX,XX +XXX,XX @@ int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset,
22
uint64_t l1_ofs = s->snapshots[i].l1_table_offset;
23
uint32_t l1_sz = s->snapshots[i].l1_size;
24
uint64_t l1_sz2 = l1_sz * sizeof(uint64_t);
25
- uint64_t *l1 = g_try_malloc(l1_sz2);
26
+ uint64_t *l1;
27
int ret;
28
29
+ ret = qcow2_validate_table(bs, l1_ofs, l1_sz, sizeof(uint64_t),
30
+ QCOW_MAX_L1_SIZE, "", NULL);
31
+ if (ret < 0) {
32
+ return ret;
33
+ }
34
+
35
+ l1 = g_try_malloc(l1_sz2);
36
+
37
if (l1_sz2 && l1 == NULL) {
38
return -ENOMEM;
39
}
40
diff --git a/tests/qemu-iotests/080 b/tests/qemu-iotests/080
41
index XXXXXXX..XXXXXXX 100755
42
--- a/tests/qemu-iotests/080
43
+++ b/tests/qemu-iotests/080
44
@@ -XXX,XX +XXX,XX @@ _make_test_img 64M
45
poke_file "$TEST_IMG" "$offset_snap1_l1_offset" "\x00\x00\x00\x00\x00\x40\x02\x00"
46
{ $QEMU_IMG convert -s test $TEST_IMG $TEST_IMG.snap; } 2>&1 | _filter_testdir
47
{ $QEMU_IMG amend -o compat=0.10 $TEST_IMG; } 2>&1 | _filter_testdir
48
+{ $QEMU_IO -c "open -o overlap-check.inactive-l2=on $TEST_IMG" \
49
+ -c 'write 0 4k'; } 2>&1 | _filter_qemu_io | _filter_testdir
50
51
echo
52
echo "== Invalid snapshot L1 table size =="
53
@@ -XXX,XX +XXX,XX @@ _make_test_img 64M
54
poke_file "$TEST_IMG" "$offset_snap1_l1_size" "\x10\x00\x00\x00"
55
{ $QEMU_IMG convert -s test $TEST_IMG $TEST_IMG.snap; } 2>&1 | _filter_testdir
56
{ $QEMU_IMG amend -o compat=0.10 $TEST_IMG; } 2>&1 | _filter_testdir
57
+{ $QEMU_IO -c "open -o overlap-check.inactive-l2=on $TEST_IMG" \
58
+ -c 'write 0 4k'; } 2>&1 | _filter_qemu_io | _filter_testdir
59
60
# success, all done
61
echo "*** done"
62
diff --git a/tests/qemu-iotests/080.out b/tests/qemu-iotests/080.out
63
index XXXXXXX..XXXXXXX 100644
64
--- a/tests/qemu-iotests/080.out
65
+++ b/tests/qemu-iotests/080.out
66
@@ -XXX,XX +XXX,XX @@ wrote 512/512 bytes at offset 0
67
qemu-img: Failed to load snapshot: Snapshot L1 table offset invalid
68
qemu-img: Snapshot L1 table offset invalid
69
qemu-img: Error while amending options: Invalid argument
70
+Failed to flush the refcount block cache: Invalid argument
71
+write failed: Invalid argument
72
73
== Invalid snapshot L1 table size ==
74
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
75
@@ -XXX,XX +XXX,XX @@ wrote 512/512 bytes at offset 0
76
qemu-img: Failed to load snapshot: Snapshot L1 table too large
77
qemu-img: Snapshot L1 table too large
78
qemu-img: Error while amending options: File too large
79
+Failed to flush the refcount block cache: File too large
80
+write failed: File too large
81
*** done
82
--
83
2.13.6
84
85
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
This function copies a snapshot's L1 table into the active one without
4
validating it first.
5
6
We now have a function to take care of this, so let's use it.
7
8
Cc: Eric Blake <eblake@redhat.com>
9
Signed-off-by: Alberto Garcia <berto@igalia.com>
10
Reviewed-by: Eric Blake <eblake@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
13
block/qcow2-snapshot.c | 9 +++++++++
14
tests/qemu-iotests/080 | 2 ++
15
tests/qemu-iotests/080.out | 4 ++++
16
3 files changed, 15 insertions(+)
17
18
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/block/qcow2-snapshot.c
21
+++ b/block/qcow2-snapshot.c
22
@@ -XXX,XX +XXX,XX @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
23
{
24
BDRVQcow2State *s = bs->opaque;
25
QCowSnapshot *sn;
26
+ Error *local_err = NULL;
27
int i, snapshot_index;
28
int cur_l1_bytes, sn_l1_bytes;
29
int ret;
30
@@ -XXX,XX +XXX,XX @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
31
}
32
sn = &s->snapshots[snapshot_index];
33
34
+ ret = qcow2_validate_table(bs, sn->l1_table_offset, sn->l1_size,
35
+ sizeof(uint64_t), QCOW_MAX_L1_SIZE,
36
+ "Snapshot L1 table", &local_err);
37
+ if (ret < 0) {
38
+ error_report_err(local_err);
39
+ goto fail;
40
+ }
41
+
42
if (sn->disk_size != bs->total_sectors * BDRV_SECTOR_SIZE) {
43
error_report("qcow2: Loading snapshots with different disk "
44
"size is not implemented");
45
diff --git a/tests/qemu-iotests/080 b/tests/qemu-iotests/080
46
index XXXXXXX..XXXXXXX 100755
47
--- a/tests/qemu-iotests/080
48
+++ b/tests/qemu-iotests/080
49
@@ -XXX,XX +XXX,XX @@ poke_file "$TEST_IMG" "$offset_snap1_l1_offset" "\x00\x00\x00\x00\x00\x40\x02\x0
50
{ $QEMU_IMG amend -o compat=0.10 $TEST_IMG; } 2>&1 | _filter_testdir
51
{ $QEMU_IO -c "open -o overlap-check.inactive-l2=on $TEST_IMG" \
52
-c 'write 0 4k'; } 2>&1 | _filter_qemu_io | _filter_testdir
53
+{ $QEMU_IMG snapshot -a test $TEST_IMG; } 2>&1 | _filter_testdir
54
55
echo
56
echo "== Invalid snapshot L1 table size =="
57
@@ -XXX,XX +XXX,XX @@ poke_file "$TEST_IMG" "$offset_snap1_l1_size" "\x10\x00\x00\x00"
58
{ $QEMU_IMG amend -o compat=0.10 $TEST_IMG; } 2>&1 | _filter_testdir
59
{ $QEMU_IO -c "open -o overlap-check.inactive-l2=on $TEST_IMG" \
60
-c 'write 0 4k'; } 2>&1 | _filter_qemu_io | _filter_testdir
61
+{ $QEMU_IMG snapshot -a test $TEST_IMG; } 2>&1 | _filter_testdir
62
63
# success, all done
64
echo "*** done"
65
diff --git a/tests/qemu-iotests/080.out b/tests/qemu-iotests/080.out
66
index XXXXXXX..XXXXXXX 100644
67
--- a/tests/qemu-iotests/080.out
68
+++ b/tests/qemu-iotests/080.out
69
@@ -XXX,XX +XXX,XX @@ qemu-img: Snapshot L1 table offset invalid
70
qemu-img: Error while amending options: Invalid argument
71
Failed to flush the refcount block cache: Invalid argument
72
write failed: Invalid argument
73
+qemu-img: Snapshot L1 table offset invalid
74
+qemu-img: Could not apply snapshot 'test': Failed to load snapshot: Invalid argument
75
76
== Invalid snapshot L1 table size ==
77
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
78
@@ -XXX,XX +XXX,XX @@ qemu-img: Snapshot L1 table too large
79
qemu-img: Error while amending options: File too large
80
Failed to flush the refcount block cache: File too large
81
write failed: File too large
82
+qemu-img: Snapshot L1 table too large
83
+qemu-img: Could not apply snapshot 'test': Failed to load snapshot: File too large
84
*** done
85
--
86
2.13.6
87
88
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
This function deletes a snapshot from disk, removing its entry from
4
the snapshot table, freeing its L1 table and decreasing the refcounts
5
of all clusters.
6
7
The L1 table offset and size are however not validated. If we use
8
invalid values in this function we'll probably corrupt the image even
9
more, so we should return an error instead.
10
11
We now have a function to take care of this, so let's use it.
12
13
Signed-off-by: Alberto Garcia <berto@igalia.com>
14
Reviewed-by: Eric Blake <eblake@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
---
17
block/qcow2-snapshot.c | 7 +++++++
18
tests/qemu-iotests/080 | 2 ++
19
tests/qemu-iotests/080.out | 2 ++
20
3 files changed, 11 insertions(+)
21
22
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
23
index XXXXXXX..XXXXXXX 100644
24
--- a/block/qcow2-snapshot.c
25
+++ b/block/qcow2-snapshot.c
26
@@ -XXX,XX +XXX,XX @@ int qcow2_snapshot_delete(BlockDriverState *bs,
27
}
28
sn = s->snapshots[snapshot_index];
29
30
+ ret = qcow2_validate_table(bs, sn.l1_table_offset, sn.l1_size,
31
+ sizeof(uint64_t), QCOW_MAX_L1_SIZE,
32
+ "Snapshot L1 table", errp);
33
+ if (ret < 0) {
34
+ return ret;
35
+ }
36
+
37
/* Remove it from the snapshot list */
38
memmove(s->snapshots + snapshot_index,
39
s->snapshots + snapshot_index + 1,
40
diff --git a/tests/qemu-iotests/080 b/tests/qemu-iotests/080
41
index XXXXXXX..XXXXXXX 100755
42
--- a/tests/qemu-iotests/080
43
+++ b/tests/qemu-iotests/080
44
@@ -XXX,XX +XXX,XX @@ poke_file "$TEST_IMG" "$offset_snap1_l1_offset" "\x00\x00\x00\x00\x00\x40\x02\x0
45
{ $QEMU_IO -c "open -o overlap-check.inactive-l2=on $TEST_IMG" \
46
-c 'write 0 4k'; } 2>&1 | _filter_qemu_io | _filter_testdir
47
{ $QEMU_IMG snapshot -a test $TEST_IMG; } 2>&1 | _filter_testdir
48
+{ $QEMU_IMG snapshot -d test $TEST_IMG; } 2>&1 | _filter_testdir
49
50
echo
51
echo "== Invalid snapshot L1 table size =="
52
@@ -XXX,XX +XXX,XX @@ poke_file "$TEST_IMG" "$offset_snap1_l1_size" "\x10\x00\x00\x00"
53
{ $QEMU_IO -c "open -o overlap-check.inactive-l2=on $TEST_IMG" \
54
-c 'write 0 4k'; } 2>&1 | _filter_qemu_io | _filter_testdir
55
{ $QEMU_IMG snapshot -a test $TEST_IMG; } 2>&1 | _filter_testdir
56
+{ $QEMU_IMG snapshot -d test $TEST_IMG; } 2>&1 | _filter_testdir
57
58
# success, all done
59
echo "*** done"
60
diff --git a/tests/qemu-iotests/080.out b/tests/qemu-iotests/080.out
61
index XXXXXXX..XXXXXXX 100644
62
--- a/tests/qemu-iotests/080.out
63
+++ b/tests/qemu-iotests/080.out
64
@@ -XXX,XX +XXX,XX @@ Failed to flush the refcount block cache: Invalid argument
65
write failed: Invalid argument
66
qemu-img: Snapshot L1 table offset invalid
67
qemu-img: Could not apply snapshot 'test': Failed to load snapshot: Invalid argument
68
+qemu-img: Could not delete snapshot 'test': Snapshot L1 table offset invalid
69
70
== Invalid snapshot L1 table size ==
71
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
72
@@ -XXX,XX +XXX,XX @@ Failed to flush the refcount block cache: File too large
73
write failed: File too large
74
qemu-img: Snapshot L1 table too large
75
qemu-img: Could not apply snapshot 'test': Failed to load snapshot: File too large
76
+qemu-img: Could not delete snapshot 'test': Snapshot L1 table too large
77
*** done
78
--
79
2.13.6
80
81
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
'qemu-img check' cannot detect if a snapshot's L1 table is corrupted.
4
This patch checks the table's offset and size and reports corruption
5
if the values are not valid.
6
7
This patch doesn't add code to fix that corruption yet, only to detect
8
and report it.
9
10
Signed-off-by: Alberto Garcia <berto@igalia.com>
11
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
14
block/qcow2-refcount.c | 14 ++++++++++++++
15
tests/qemu-iotests/080 | 2 ++
16
tests/qemu-iotests/080.out | 20 ++++++++++++++++++++
17
3 files changed, 36 insertions(+)
18
19
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/block/qcow2-refcount.c
22
+++ b/block/qcow2-refcount.c
23
@@ -XXX,XX +XXX,XX @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
24
/* snapshots */
25
for (i = 0; i < s->nb_snapshots; i++) {
26
sn = s->snapshots + i;
27
+ if (offset_into_cluster(s, sn->l1_table_offset)) {
28
+ fprintf(stderr, "ERROR snapshot %s (%s) l1_offset=%#" PRIx64 ": "
29
+ "L1 table is not cluster aligned; snapshot table entry "
30
+ "corrupted\n", sn->id_str, sn->name, sn->l1_table_offset);
31
+ res->corruptions++;
32
+ continue;
33
+ }
34
+ if (sn->l1_size > QCOW_MAX_L1_SIZE / sizeof(uint64_t)) {
35
+ fprintf(stderr, "ERROR snapshot %s (%s) l1_size=%#" PRIx32 ": "
36
+ "L1 table is too large; snapshot table entry corrupted\n",
37
+ sn->id_str, sn->name, sn->l1_size);
38
+ res->corruptions++;
39
+ continue;
40
+ }
41
ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters,
42
sn->l1_table_offset, sn->l1_size, 0, fix);
43
if (ret < 0) {
44
diff --git a/tests/qemu-iotests/080 b/tests/qemu-iotests/080
45
index XXXXXXX..XXXXXXX 100755
46
--- a/tests/qemu-iotests/080
47
+++ b/tests/qemu-iotests/080
48
@@ -XXX,XX +XXX,XX @@ poke_file "$TEST_IMG" "$offset_snap1_l1_offset" "\x00\x00\x00\x00\x00\x40\x02\x0
49
-c 'write 0 4k'; } 2>&1 | _filter_qemu_io | _filter_testdir
50
{ $QEMU_IMG snapshot -a test $TEST_IMG; } 2>&1 | _filter_testdir
51
{ $QEMU_IMG snapshot -d test $TEST_IMG; } 2>&1 | _filter_testdir
52
+_check_test_img
53
54
echo
55
echo "== Invalid snapshot L1 table size =="
56
@@ -XXX,XX +XXX,XX @@ poke_file "$TEST_IMG" "$offset_snap1_l1_size" "\x10\x00\x00\x00"
57
-c 'write 0 4k'; } 2>&1 | _filter_qemu_io | _filter_testdir
58
{ $QEMU_IMG snapshot -a test $TEST_IMG; } 2>&1 | _filter_testdir
59
{ $QEMU_IMG snapshot -d test $TEST_IMG; } 2>&1 | _filter_testdir
60
+_check_test_img
61
62
# success, all done
63
echo "*** done"
64
diff --git a/tests/qemu-iotests/080.out b/tests/qemu-iotests/080.out
65
index XXXXXXX..XXXXXXX 100644
66
--- a/tests/qemu-iotests/080.out
67
+++ b/tests/qemu-iotests/080.out
68
@@ -XXX,XX +XXX,XX @@ write failed: Invalid argument
69
qemu-img: Snapshot L1 table offset invalid
70
qemu-img: Could not apply snapshot 'test': Failed to load snapshot: Invalid argument
71
qemu-img: Could not delete snapshot 'test': Snapshot L1 table offset invalid
72
+ERROR snapshot 1 (test) l1_offset=0x400200: L1 table is not cluster aligned; snapshot table entry corrupted
73
+Leaked cluster 4 refcount=2 reference=1
74
+Leaked cluster 5 refcount=2 reference=1
75
+Leaked cluster 6 refcount=1 reference=0
76
+
77
+1 errors were found on the image.
78
+Data may be corrupted, or further writes to the image may corrupt it.
79
+
80
+3 leaked clusters were found on the image.
81
+This means waste of disk space, but no harm to data.
82
83
== Invalid snapshot L1 table size ==
84
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
85
@@ -XXX,XX +XXX,XX @@ write failed: File too large
86
qemu-img: Snapshot L1 table too large
87
qemu-img: Could not apply snapshot 'test': Failed to load snapshot: File too large
88
qemu-img: Could not delete snapshot 'test': Snapshot L1 table too large
89
+ERROR snapshot 1 (test) l1_size=0x10000000: L1 table is too large; snapshot table entry corrupted
90
+Leaked cluster 4 refcount=2 reference=1
91
+Leaked cluster 5 refcount=2 reference=1
92
+Leaked cluster 6 refcount=1 reference=0
93
+
94
+1 errors were found on the image.
95
+Data may be corrupted, or further writes to the image may corrupt it.
96
+
97
+3 leaked clusters were found on the image.
98
+This means waste of disk space, but no harm to data.
99
*** done
100
--
101
2.13.6
102
103
diff view generated by jsdifflib
Deleted patch
1
This creates a BlockdevCreateOptions union type that will contain all of
2
the options for image creation. We'll start out with an empty struct
3
type BlockdevCreateNotSupported for all drivers.
4
1
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
---
9
qapi/block-core.json | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++
10
1 file changed, 62 insertions(+)
11
12
diff --git a/qapi/block-core.json b/qapi/block-core.json
13
index XXXXXXX..XXXXXXX 100644
14
--- a/qapi/block-core.json
15
+++ b/qapi/block-core.json
16
@@ -XXX,XX +XXX,XX @@
17
{ 'command': 'blockdev-del', 'data': { 'node-name': 'str' } }
18
19
##
20
+# @BlockdevCreateNotSupported:
21
+#
22
+# This is used for all drivers that don't support creating images.
23
+#
24
+# Since: 2.12
25
+##
26
+{ 'struct': 'BlockdevCreateNotSupported', 'data': {}}
27
+
28
+##
29
+# @BlockdevCreateOptions:
30
+#
31
+# Options for creating an image format on a given node.
32
+#
33
+# @driver block driver to create the image format
34
+#
35
+# Since: 2.12
36
+##
37
+{ 'union': 'BlockdevCreateOptions',
38
+ 'base': {
39
+ 'driver': 'BlockdevDriver' },
40
+ 'discriminator': 'driver',
41
+ 'data': {
42
+ 'blkdebug': 'BlockdevCreateNotSupported',
43
+ 'blkverify': 'BlockdevCreateNotSupported',
44
+ 'bochs': 'BlockdevCreateNotSupported',
45
+ 'cloop': 'BlockdevCreateNotSupported',
46
+ 'dmg': 'BlockdevCreateNotSupported',
47
+ 'file': 'BlockdevCreateNotSupported',
48
+ 'ftp': 'BlockdevCreateNotSupported',
49
+ 'ftps': 'BlockdevCreateNotSupported',
50
+ 'gluster': 'BlockdevCreateNotSupported',
51
+ 'host_cdrom': 'BlockdevCreateNotSupported',
52
+ 'host_device': 'BlockdevCreateNotSupported',
53
+ 'http': 'BlockdevCreateNotSupported',
54
+ 'https': 'BlockdevCreateNotSupported',
55
+ 'iscsi': 'BlockdevCreateNotSupported',
56
+ 'luks': 'BlockdevCreateNotSupported',
57
+ 'nbd': 'BlockdevCreateNotSupported',
58
+ 'nfs': 'BlockdevCreateNotSupported',
59
+ 'null-aio': 'BlockdevCreateNotSupported',
60
+ 'null-co': 'BlockdevCreateNotSupported',
61
+ 'nvme': 'BlockdevCreateNotSupported',
62
+ 'parallels': 'BlockdevCreateNotSupported',
63
+ 'qcow2': 'BlockdevCreateNotSupported',
64
+ 'qcow': 'BlockdevCreateNotSupported',
65
+ 'qed': 'BlockdevCreateNotSupported',
66
+ 'quorum': 'BlockdevCreateNotSupported',
67
+ 'raw': 'BlockdevCreateNotSupported',
68
+ 'rbd': 'BlockdevCreateNotSupported',
69
+ 'replication': 'BlockdevCreateNotSupported',
70
+ 'sheepdog': 'BlockdevCreateNotSupported',
71
+ 'ssh': 'BlockdevCreateNotSupported',
72
+ 'throttle': 'BlockdevCreateNotSupported',
73
+ 'vdi': 'BlockdevCreateNotSupported',
74
+ 'vhdx': 'BlockdevCreateNotSupported',
75
+ 'vmdk': 'BlockdevCreateNotSupported',
76
+ 'vpc': 'BlockdevCreateNotSupported',
77
+ 'vvfat': 'BlockdevCreateNotSupported',
78
+ 'vxhs': 'BlockdevCreateNotSupported'
79
+ } }
80
+
81
+##
82
# @blockdev-open-tray:
83
#
84
# Opens a block device's tray. If there is a block driver state tree inserted as
85
--
86
2.13.6
87
88
diff view generated by jsdifflib
Deleted patch
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Reviewed-by: Eric Blake <eblake@redhat.com>
3
Reviewed-by: Max Reitz <mreitz@redhat.com>
4
---
5
qapi/block-core.json | 45 ++++++++++++++++++++++++++++++++++++++++++++-
6
1 file changed, 44 insertions(+), 1 deletion(-)
7
1
8
diff --git a/qapi/block-core.json b/qapi/block-core.json
9
index XXXXXXX..XXXXXXX 100644
10
--- a/qapi/block-core.json
11
+++ b/qapi/block-core.json
12
@@ -XXX,XX +XXX,XX @@
13
{ 'command': 'blockdev-del', 'data': { 'node-name': 'str' } }
14
15
##
16
+# @BlockdevQcow2Version:
17
+#
18
+# @v2: The original QCOW2 format as introduced in qemu 0.10 (version 2)
19
+# @v3: The extended QCOW2 format as introduced in qemu 1.1 (version 3)
20
+#
21
+# Since: 2.12
22
+##
23
+{ 'enum': 'BlockdevQcow2Version',
24
+ 'data': [ 'v2', 'v3' ] }
25
+
26
+
27
+##
28
+# @BlockdevCreateOptionsQcow2:
29
+#
30
+# Driver specific image creation options for qcow2.
31
+#
32
+# @file Node to create the image format on
33
+# @size Size of the virtual disk in bytes
34
+# @version Compatibility level (default: v3)
35
+# @backing-file File name of the backing file if a backing file
36
+# should be used
37
+# @backing-fmt Name of the block driver to use for the backing file
38
+# @encrypt Encryption options if the image should be encrypted
39
+# @cluster-size qcow2 cluster size in bytes (default: 65536)
40
+# @preallocation Preallocation mode for the new image (default: off)
41
+# @lazy-refcounts True if refcounts may be updated lazily (default: off)
42
+# @refcount-bits Width of reference counts in bits (default: 16)
43
+#
44
+# Since: 2.12
45
+##
46
+{ 'struct': 'BlockdevCreateOptionsQcow2',
47
+ 'data': { 'file': 'BlockdevRef',
48
+ 'size': 'size',
49
+ '*version': 'BlockdevQcow2Version',
50
+ '*backing-file': 'str',
51
+ '*backing-fmt': 'BlockdevDriver',
52
+ '*encrypt': 'QCryptoBlockCreateOptions',
53
+ '*cluster-size': 'size',
54
+ '*preallocation': 'PreallocMode',
55
+ '*lazy-refcounts': 'bool',
56
+ '*refcount-bits': 'int' } }
57
+
58
+##
59
# @BlockdevCreateNotSupported:
60
#
61
# This is used for all drivers that don't support creating images.
62
@@ -XXX,XX +XXX,XX @@
63
'null-co': 'BlockdevCreateNotSupported',
64
'nvme': 'BlockdevCreateNotSupported',
65
'parallels': 'BlockdevCreateNotSupported',
66
- 'qcow2': 'BlockdevCreateNotSupported',
67
+ 'qcow2': 'BlockdevCreateOptionsQcow2',
68
'qcow': 'BlockdevCreateNotSupported',
69
'qed': 'BlockdevCreateNotSupported',
70
'quorum': 'BlockdevCreateNotSupported',
71
--
72
2.13.6
73
74
diff view generated by jsdifflib
Deleted patch
1
The functions originally known as qcow2_create() and qcow2_create2()
2
are now called qcow2_co_create_opts() and qcow2_co_create(), which
3
matches the names of the BlockDriver callbacks that they will implement
4
at the end of this patch series.
5
1
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
---
10
block/qcow2.c | 16 ++++++++--------
11
1 file changed, 8 insertions(+), 8 deletions(-)
12
13
diff --git a/block/qcow2.c b/block/qcow2.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/block/qcow2.c
16
+++ b/block/qcow2.c
17
@@ -XXX,XX +XXX,XX @@ static uint64_t qcow2_opt_get_refcount_bits_del(QemuOpts *opts, int version,
18
}
19
20
static int coroutine_fn
21
-qcow2_co_create2(const char *filename, int64_t total_size,
22
- const char *backing_file, const char *backing_format,
23
- int flags, size_t cluster_size, PreallocMode prealloc,
24
- QemuOpts *opts, int version, int refcount_order,
25
- const char *encryptfmt, Error **errp)
26
+qcow2_co_create(const char *filename, int64_t total_size,
27
+ const char *backing_file, const char *backing_format,
28
+ int flags, size_t cluster_size, PreallocMode prealloc,
29
+ QemuOpts *opts, int version, int refcount_order,
30
+ const char *encryptfmt, Error **errp)
31
{
32
QDict *options;
33
34
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
35
36
refcount_order = ctz32(refcount_bits);
37
38
- ret = qcow2_co_create2(filename, size, backing_file, backing_fmt, flags,
39
- cluster_size, prealloc, opts, version, refcount_order,
40
- encryptfmt, &local_err);
41
+ ret = qcow2_co_create(filename, size, backing_file, backing_fmt, flags,
42
+ cluster_size, prealloc, opts, version, refcount_order,
43
+ encryptfmt, &local_err);
44
error_propagate(errp, local_err);
45
46
finish:
47
--
48
2.13.6
49
50
diff view generated by jsdifflib
Deleted patch
1
Currently, qcow2_create() only parses the QemuOpts and then calls
2
qcow2_co_create() for the actual image creation, which includes both the
3
creation of the actual file on the file system and writing a valid empty
4
qcow2 image into that file.
5
1
6
The plan is that qcow2_co_create() becomes the function that implements
7
the functionality for a future 'blockdev-create' QMP command, which only
8
creates the qcow2 layer on an already opened file node.
9
10
This is a first step towards that goal: Let's move out anything that
11
deals with the protocol layer from qcow2_co_create() into
12
qcow2_create(). This means that qcow2_co_create() doesn't need a file
13
name any more.
14
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
Reviewed-by: Eric Blake <eblake@redhat.com>
17
Reviewed-by: Max Reitz <mreitz@redhat.com>
18
---
19
block/qcow2.c | 64 +++++++++++++++++++++++++++++++++++------------------------
20
1 file changed, 38 insertions(+), 26 deletions(-)
21
22
diff --git a/block/qcow2.c b/block/qcow2.c
23
index XXXXXXX..XXXXXXX 100644
24
--- a/block/qcow2.c
25
+++ b/block/qcow2.c
26
@@ -XXX,XX +XXX,XX @@ static uint64_t qcow2_opt_get_refcount_bits_del(QemuOpts *opts, int version,
27
}
28
29
static int coroutine_fn
30
-qcow2_co_create(const char *filename, int64_t total_size,
31
+qcow2_co_create(BlockDriverState *bs, int64_t total_size,
32
const char *backing_file, const char *backing_format,
33
int flags, size_t cluster_size, PreallocMode prealloc,
34
QemuOpts *opts, int version, int refcount_order,
35
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(const char *filename, int64_t total_size,
36
Error *local_err = NULL;
37
int ret;
38
39
- if (prealloc == PREALLOC_MODE_FULL || prealloc == PREALLOC_MODE_FALLOC) {
40
- int64_t prealloc_size =
41
- qcow2_calc_prealloc_size(total_size, cluster_size, refcount_order);
42
- qemu_opt_set_number(opts, BLOCK_OPT_SIZE, prealloc_size, &error_abort);
43
- qemu_opt_set(opts, BLOCK_OPT_PREALLOC, PreallocMode_str(prealloc),
44
- &error_abort);
45
- }
46
-
47
- ret = bdrv_create_file(filename, opts, &local_err);
48
+ blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
49
+ ret = blk_insert_bs(blk, bs, errp);
50
if (ret < 0) {
51
- error_propagate(errp, local_err);
52
- return ret;
53
- }
54
-
55
- blk = blk_new_open(filename, NULL, NULL,
56
- BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL,
57
- &local_err);
58
- if (blk == NULL) {
59
- error_propagate(errp, local_err);
60
- return -EIO;
61
+ goto out;
62
}
63
-
64
blk_set_allow_write_beyond_eof(blk, true);
65
66
/* Write the header */
67
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(const char *filename, int64_t total_size,
68
*/
69
options = qdict_new();
70
qdict_put_str(options, "driver", "qcow2");
71
- blk = blk_new_open(filename, NULL, options,
72
+ qdict_put_str(options, "file", bs->node_name);
73
+ blk = blk_new_open(NULL, NULL, options,
74
BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_NO_FLUSH,
75
&local_err);
76
if (blk == NULL) {
77
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(const char *filename, int64_t total_size,
78
*/
79
options = qdict_new();
80
qdict_put_str(options, "driver", "qcow2");
81
- blk = blk_new_open(filename, NULL, options,
82
+ qdict_put_str(options, "file", bs->node_name);
83
+ blk = blk_new_open(NULL, NULL, options,
84
BDRV_O_RDWR | BDRV_O_NO_BACKING | BDRV_O_NO_IO,
85
&local_err);
86
if (blk == NULL) {
87
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
88
uint64_t refcount_bits;
89
int refcount_order;
90
char *encryptfmt = NULL;
91
+ BlockDriverState *bs = NULL;
92
Error *local_err = NULL;
93
int ret;
94
95
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
96
97
refcount_order = ctz32(refcount_bits);
98
99
- ret = qcow2_co_create(filename, size, backing_file, backing_fmt, flags,
100
+ /* Create and open the file (protocol layer) */
101
+ if (prealloc == PREALLOC_MODE_FULL || prealloc == PREALLOC_MODE_FALLOC) {
102
+ int64_t prealloc_size =
103
+ qcow2_calc_prealloc_size(size, cluster_size, refcount_order);
104
+ qemu_opt_set_number(opts, BLOCK_OPT_SIZE, prealloc_size, &error_abort);
105
+ qemu_opt_set(opts, BLOCK_OPT_PREALLOC, PreallocMode_str(prealloc),
106
+ &error_abort);
107
+ }
108
+
109
+ ret = bdrv_create_file(filename, opts, errp);
110
+ if (ret < 0) {
111
+ goto finish;
112
+ }
113
+
114
+ bs = bdrv_open(filename, NULL, NULL,
115
+ BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp);
116
+ if (bs == NULL) {
117
+ ret = -EIO;
118
+ goto finish;
119
+ }
120
+
121
+ /* Create the qcow2 image (format layer) */
122
+ ret = qcow2_co_create(bs, size, backing_file, backing_fmt, flags,
123
cluster_size, prealloc, opts, version, refcount_order,
124
- encryptfmt, &local_err);
125
- error_propagate(errp, local_err);
126
+ encryptfmt, errp);
127
+ if (ret < 0) {
128
+ goto finish;
129
+ }
130
131
finish:
132
+ bdrv_unref(bs);
133
+
134
g_free(backing_file);
135
g_free(backing_fmt);
136
g_free(encryptfmt);
137
--
138
2.13.6
139
140
diff view generated by jsdifflib
Deleted patch
1
Once qcow2_co_create() can be called directly on an already existing
2
node, we must provide the 'full' and 'falloc' preallocation modes
3
outside of creating the image on the protocol layer. Fortunately, we
4
have preallocated truncate now which can provide this functionality.
5
1
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
---
10
block/qcow2.c | 28 +++++++++++++++++++---------
11
1 file changed, 19 insertions(+), 9 deletions(-)
12
13
diff --git a/block/qcow2.c b/block/qcow2.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/block/qcow2.c
16
+++ b/block/qcow2.c
17
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
18
}
19
blk_set_allow_write_beyond_eof(blk, true);
20
21
+ /* Clear the protocol layer and preallocate it if necessary */
22
+ ret = blk_truncate(blk, 0, PREALLOC_MODE_OFF, errp);
23
+ if (ret < 0) {
24
+ goto out;
25
+ }
26
+
27
+ if (qcow2_opts->preallocation == PREALLOC_MODE_FULL ||
28
+ qcow2_opts->preallocation == PREALLOC_MODE_FALLOC)
29
+ {
30
+ int64_t prealloc_size =
31
+ qcow2_calc_prealloc_size(qcow2_opts->size, cluster_size,
32
+ refcount_order);
33
+
34
+ ret = blk_truncate(blk, prealloc_size, qcow2_opts->preallocation, errp);
35
+ if (ret < 0) {
36
+ goto out;
37
+ }
38
+ }
39
+
40
/* Write the header */
41
QEMU_BUILD_BUG_ON((1 << MIN_CLUSTER_BITS) < sizeof(*header));
42
header = g_malloc0(cluster_size);
43
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
44
45
46
/* Create and open the file (protocol layer) */
47
- if (prealloc == PREALLOC_MODE_FULL || prealloc == PREALLOC_MODE_FALLOC) {
48
- int refcount_order = ctz32(refcount_bits);
49
- int64_t prealloc_size =
50
- qcow2_calc_prealloc_size(size, cluster_size, refcount_order);
51
- qemu_opt_set_number(opts, BLOCK_OPT_SIZE, prealloc_size, &error_abort);
52
- qemu_opt_set(opts, BLOCK_OPT_PREALLOC, PreallocMode_str(prealloc),
53
- &error_abort);
54
- }
55
-
56
ret = bdrv_create_file(filename, opts, errp);
57
if (ret < 0) {
58
goto finish;
59
--
60
2.13.6
61
62
diff view generated by jsdifflib
Deleted patch
1
This allows, given a QemuOpts for a QemuOptsList that was merged from
2
multiple QemuOptsList, to only consider those options that exist in one
3
specific list. Block drivers need this to separate format-layer create
4
options from protocol-level options.
5
1
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
---
10
include/qemu/option.h | 2 ++
11
util/qemu-option.c | 42 +++++++++++++++++++++++++++++++++++++-----
12
2 files changed, 39 insertions(+), 5 deletions(-)
13
14
diff --git a/include/qemu/option.h b/include/qemu/option.h
15
index XXXXXXX..XXXXXXX 100644
16
--- a/include/qemu/option.h
17
+++ b/include/qemu/option.h
18
@@ -XXX,XX +XXX,XX @@ void qemu_opts_set_defaults(QemuOptsList *list, const char *params,
19
int permit_abbrev);
20
QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict,
21
Error **errp);
22
+QDict *qemu_opts_to_qdict_filtered(QemuOpts *opts, QDict *qdict,
23
+ QemuOptsList *list, bool del);
24
QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict);
25
void qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp);
26
27
diff --git a/util/qemu-option.c b/util/qemu-option.c
28
index XXXXXXX..XXXXXXX 100644
29
--- a/util/qemu-option.c
30
+++ b/util/qemu-option.c
31
@@ -XXX,XX +XXX,XX @@ void qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp)
32
}
33
34
/*
35
- * Convert from QemuOpts to QDict.
36
- * The QDict values are of type QString.
37
+ * Convert from QemuOpts to QDict. The QDict values are of type QString.
38
+ *
39
+ * If @list is given, only add those options to the QDict that are contained in
40
+ * the list. If @del is true, any options added to the QDict are removed from
41
+ * the QemuOpts, otherwise they remain there.
42
+ *
43
+ * If two options in @opts have the same name, they are processed in order
44
+ * so that the last one wins (consistent with the reverse iteration in
45
+ * qemu_opt_find()), but all of them are deleted if @del is true.
46
+ *
47
* TODO We'll want to use types appropriate for opt->desc->type, but
48
* this is enough for now.
49
*/
50
-QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict)
51
+QDict *qemu_opts_to_qdict_filtered(QemuOpts *opts, QDict *qdict,
52
+ QemuOptsList *list, bool del)
53
{
54
- QemuOpt *opt;
55
+ QemuOpt *opt, *next;
56
57
if (!qdict) {
58
qdict = qdict_new();
59
@@ -XXX,XX +XXX,XX @@ QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict)
60
if (opts->id) {
61
qdict_put_str(qdict, "id", opts->id);
62
}
63
- QTAILQ_FOREACH(opt, &opts->head, next) {
64
+ QTAILQ_FOREACH_SAFE(opt, &opts->head, next, next) {
65
+ if (list) {
66
+ QemuOptDesc *desc;
67
+ bool found = false;
68
+ for (desc = list->desc; desc->name; desc++) {
69
+ if (!strcmp(desc->name, opt->name)) {
70
+ found = true;
71
+ break;
72
+ }
73
+ }
74
+ if (!found) {
75
+ continue;
76
+ }
77
+ }
78
qdict_put_str(qdict, opt->name, opt->str);
79
+ if (del) {
80
+ qemu_opt_del(opt);
81
+ }
82
}
83
return qdict;
84
}
85
86
+/* Copy all options in a QemuOpts to the given QDict. See
87
+ * qemu_opts_to_qdict_filtered() for details. */
88
+QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict)
89
+{
90
+ return qemu_opts_to_qdict_filtered(opts, qdict, NULL, false);
91
+}
92
+
93
/* Validate parsed opts against descriptions where no
94
* descriptions were provided in the QemuOptsList.
95
*/
96
--
97
2.13.6
98
99
diff view generated by jsdifflib
Deleted patch
1
Basic test for merging two QemuOptsLists.
2
1
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Reviewed-by: Eric Blake <eblake@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
---
7
tests/test-qemu-opts.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++
8
1 file changed, 128 insertions(+)
9
10
diff --git a/tests/test-qemu-opts.c b/tests/test-qemu-opts.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/tests/test-qemu-opts.c
13
+++ b/tests/test-qemu-opts.c
14
@@ -XXX,XX +XXX,XX @@ static QemuOptsList opts_list_01 = {
15
{
16
.name = "str1",
17
.type = QEMU_OPT_STRING,
18
+ .help = "Help texts are preserved in qemu_opts_append",
19
+ .def_value_str = "default",
20
},{
21
.name = "str2",
22
.type = QEMU_OPT_STRING,
23
@@ -XXX,XX +XXX,XX @@ static QemuOptsList opts_list_01 = {
24
},{
25
.name = "number1",
26
.type = QEMU_OPT_NUMBER,
27
+ .help = "Having help texts only for some options is okay",
28
},{
29
.name = "number2",
30
.type = QEMU_OPT_NUMBER,
31
@@ -XXX,XX +XXX,XX @@ static void test_opts_parse_size(void)
32
qemu_opts_reset(&opts_list_02);
33
}
34
35
+static void append_verify_list_01(QemuOptDesc *desc, bool with_overlapping)
36
+{
37
+ int i = 0;
38
+
39
+ if (with_overlapping) {
40
+ g_assert_cmpstr(desc[i].name, ==, "str1");
41
+ g_assert_cmpint(desc[i].type, ==, QEMU_OPT_STRING);
42
+ g_assert_cmpstr(desc[i].help, ==,
43
+ "Help texts are preserved in qemu_opts_append");
44
+ g_assert_cmpstr(desc[i].def_value_str, ==, "default");
45
+ i++;
46
+
47
+ g_assert_cmpstr(desc[i].name, ==, "str2");
48
+ g_assert_cmpint(desc[i].type, ==, QEMU_OPT_STRING);
49
+ g_assert_cmpstr(desc[i].help, ==, NULL);
50
+ g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
51
+ i++;
52
+ }
53
+
54
+ g_assert_cmpstr(desc[i].name, ==, "str3");
55
+ g_assert_cmpint(desc[i].type, ==, QEMU_OPT_STRING);
56
+ g_assert_cmpstr(desc[i].help, ==, NULL);
57
+ g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
58
+ i++;
59
+
60
+ g_assert_cmpstr(desc[i].name, ==, "number1");
61
+ g_assert_cmpint(desc[i].type, ==, QEMU_OPT_NUMBER);
62
+ g_assert_cmpstr(desc[i].help, ==,
63
+ "Having help texts only for some options is okay");
64
+ g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
65
+ i++;
66
+
67
+ g_assert_cmpstr(desc[i].name, ==, "number2");
68
+ g_assert_cmpint(desc[i].type, ==, QEMU_OPT_NUMBER);
69
+ g_assert_cmpstr(desc[i].help, ==, NULL);
70
+ g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
71
+ i++;
72
+
73
+ g_assert_cmpstr(desc[i].name, ==, NULL);
74
+}
75
+
76
+static void append_verify_list_02(QemuOptDesc *desc)
77
+{
78
+ int i = 0;
79
+
80
+ g_assert_cmpstr(desc[i].name, ==, "str1");
81
+ g_assert_cmpint(desc[i].type, ==, QEMU_OPT_STRING);
82
+ g_assert_cmpstr(desc[i].help, ==, NULL);
83
+ g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
84
+ i++;
85
+
86
+ g_assert_cmpstr(desc[i].name, ==, "str2");
87
+ g_assert_cmpint(desc[i].type, ==, QEMU_OPT_STRING);
88
+ g_assert_cmpstr(desc[i].help, ==, NULL);
89
+ g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
90
+ i++;
91
+
92
+ g_assert_cmpstr(desc[i].name, ==, "bool1");
93
+ g_assert_cmpint(desc[i].type, ==, QEMU_OPT_BOOL);
94
+ g_assert_cmpstr(desc[i].help, ==, NULL);
95
+ g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
96
+ i++;
97
+
98
+ g_assert_cmpstr(desc[i].name, ==, "bool2");
99
+ g_assert_cmpint(desc[i].type, ==, QEMU_OPT_BOOL);
100
+ g_assert_cmpstr(desc[i].help, ==, NULL);
101
+ g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
102
+ i++;
103
+
104
+ g_assert_cmpstr(desc[i].name, ==, "size1");
105
+ g_assert_cmpint(desc[i].type, ==, QEMU_OPT_SIZE);
106
+ g_assert_cmpstr(desc[i].help, ==, NULL);
107
+ g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
108
+ i++;
109
+
110
+ g_assert_cmpstr(desc[i].name, ==, "size2");
111
+ g_assert_cmpint(desc[i].type, ==, QEMU_OPT_SIZE);
112
+ g_assert_cmpstr(desc[i].help, ==, NULL);
113
+ g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
114
+ i++;
115
+
116
+ g_assert_cmpstr(desc[i].name, ==, "size3");
117
+ g_assert_cmpint(desc[i].type, ==, QEMU_OPT_SIZE);
118
+ g_assert_cmpstr(desc[i].help, ==, NULL);
119
+ g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
120
+}
121
+
122
+static void test_opts_append_to_null(void)
123
+{
124
+ QemuOptsList *merged;
125
+
126
+ merged = qemu_opts_append(NULL, &opts_list_01);
127
+ g_assert(merged != &opts_list_01);
128
+
129
+ g_assert_cmpstr(merged->name, ==, NULL);
130
+ g_assert_cmpstr(merged->implied_opt_name, ==, NULL);
131
+ g_assert_false(merged->merge_lists);
132
+
133
+ append_verify_list_01(merged->desc, true);
134
+
135
+ qemu_opts_free(merged);
136
+}
137
+
138
+static void test_opts_append(void)
139
+{
140
+ QemuOptsList *first, *merged;
141
+
142
+ first = qemu_opts_append(NULL, &opts_list_02);
143
+ merged = qemu_opts_append(first, &opts_list_01);
144
+ g_assert(first != &opts_list_02);
145
+ g_assert(merged != &opts_list_01);
146
+
147
+ g_assert_cmpstr(merged->name, ==, NULL);
148
+ g_assert_cmpstr(merged->implied_opt_name, ==, NULL);
149
+ g_assert_false(merged->merge_lists);
150
+
151
+ append_verify_list_02(&merged->desc[0]);
152
+ append_verify_list_01(&merged->desc[7], false);
153
+
154
+ qemu_opts_free(merged);
155
+}
156
+
157
+
158
int main(int argc, char *argv[])
159
{
160
register_opts();
161
@@ -XXX,XX +XXX,XX @@ int main(int argc, char *argv[])
162
g_test_add_func("/qemu-opts/opts_parse/bool", test_opts_parse_bool);
163
g_test_add_func("/qemu-opts/opts_parse/number", test_opts_parse_number);
164
g_test_add_func("/qemu-opts/opts_parse/size", test_opts_parse_size);
165
+ g_test_add_func("/qemu-opts/append_to_null", test_opts_append_to_null);
166
+ g_test_add_func("/qemu-opts/append", test_opts_append);
167
g_test_run();
168
return 0;
169
}
170
--
171
2.13.6
172
173
diff view generated by jsdifflib
Deleted patch
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Reviewed-by: Eric Blake <eblake@redhat.com>
3
Reviewed-by: Max Reitz <mreitz@redhat.com>
4
---
5
tests/test-qemu-opts.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++++
6
1 file changed, 125 insertions(+)
7
1
8
diff --git a/tests/test-qemu-opts.c b/tests/test-qemu-opts.c
9
index XXXXXXX..XXXXXXX 100644
10
--- a/tests/test-qemu-opts.c
11
+++ b/tests/test-qemu-opts.c
12
@@ -XXX,XX +XXX,XX @@
13
#include "qemu/osdep.h"
14
#include "qemu/cutils.h"
15
#include "qemu/option.h"
16
+#include "qemu/option_int.h"
17
#include "qapi/error.h"
18
#include "qapi/qmp/qdict.h"
19
#include "qapi/qmp/qstring.h"
20
@@ -XXX,XX +XXX,XX @@ static void test_opts_append(void)
21
qemu_opts_free(merged);
22
}
23
24
+static void test_opts_to_qdict_basic(void)
25
+{
26
+ QemuOpts *opts;
27
+ QDict *dict;
28
+
29
+ opts = qemu_opts_parse(&opts_list_01, "str1=foo,str2=,str3=bar,number1=42",
30
+ false, &error_abort);
31
+ g_assert(opts != NULL);
32
+
33
+ dict = qemu_opts_to_qdict(opts, NULL);
34
+ g_assert(dict != NULL);
35
+
36
+ g_assert_cmpstr(qdict_get_str(dict, "str1"), ==, "foo");
37
+ g_assert_cmpstr(qdict_get_str(dict, "str2"), ==, "");
38
+ g_assert_cmpstr(qdict_get_str(dict, "str3"), ==, "bar");
39
+ g_assert_cmpstr(qdict_get_str(dict, "number1"), ==, "42");
40
+ g_assert_false(qdict_haskey(dict, "number2"));
41
+
42
+ QDECREF(dict);
43
+ qemu_opts_del(opts);
44
+}
45
+
46
+static void test_opts_to_qdict_filtered(void)
47
+{
48
+ QemuOptsList *first, *merged;
49
+ QemuOpts *opts;
50
+ QDict *dict;
51
+
52
+ first = qemu_opts_append(NULL, &opts_list_02);
53
+ merged = qemu_opts_append(first, &opts_list_01);
54
+
55
+ opts = qemu_opts_parse(merged,
56
+ "str1=foo,str2=,str3=bar,bool1=off,number1=42",
57
+ false, &error_abort);
58
+ g_assert(opts != NULL);
59
+
60
+ /* Convert to QDict without deleting from opts */
61
+ dict = qemu_opts_to_qdict_filtered(opts, NULL, &opts_list_01, false);
62
+ g_assert(dict != NULL);
63
+ g_assert_cmpstr(qdict_get_str(dict, "str1"), ==, "foo");
64
+ g_assert_cmpstr(qdict_get_str(dict, "str2"), ==, "");
65
+ g_assert_cmpstr(qdict_get_str(dict, "str3"), ==, "bar");
66
+ g_assert_cmpstr(qdict_get_str(dict, "number1"), ==, "42");
67
+ g_assert_false(qdict_haskey(dict, "number2"));
68
+ g_assert_false(qdict_haskey(dict, "bool1"));
69
+ QDECREF(dict);
70
+
71
+ dict = qemu_opts_to_qdict_filtered(opts, NULL, &opts_list_02, false);
72
+ g_assert(dict != NULL);
73
+ g_assert_cmpstr(qdict_get_str(dict, "str1"), ==, "foo");
74
+ g_assert_cmpstr(qdict_get_str(dict, "str2"), ==, "");
75
+ g_assert_cmpstr(qdict_get_str(dict, "bool1"), ==, "off");
76
+ g_assert_false(qdict_haskey(dict, "str3"));
77
+ g_assert_false(qdict_haskey(dict, "number1"));
78
+ g_assert_false(qdict_haskey(dict, "number2"));
79
+ QDECREF(dict);
80
+
81
+ /* Now delete converted options from opts */
82
+ dict = qemu_opts_to_qdict_filtered(opts, NULL, &opts_list_01, true);
83
+ g_assert(dict != NULL);
84
+ g_assert_cmpstr(qdict_get_str(dict, "str1"), ==, "foo");
85
+ g_assert_cmpstr(qdict_get_str(dict, "str2"), ==, "");
86
+ g_assert_cmpstr(qdict_get_str(dict, "str3"), ==, "bar");
87
+ g_assert_cmpstr(qdict_get_str(dict, "number1"), ==, "42");
88
+ g_assert_false(qdict_haskey(dict, "number2"));
89
+ g_assert_false(qdict_haskey(dict, "bool1"));
90
+ QDECREF(dict);
91
+
92
+ dict = qemu_opts_to_qdict_filtered(opts, NULL, &opts_list_02, true);
93
+ g_assert(dict != NULL);
94
+ g_assert_cmpstr(qdict_get_str(dict, "bool1"), ==, "off");
95
+ g_assert_false(qdict_haskey(dict, "str1"));
96
+ g_assert_false(qdict_haskey(dict, "str2"));
97
+ g_assert_false(qdict_haskey(dict, "str3"));
98
+ g_assert_false(qdict_haskey(dict, "number1"));
99
+ g_assert_false(qdict_haskey(dict, "number2"));
100
+ QDECREF(dict);
101
+
102
+ g_assert_true(QTAILQ_EMPTY(&opts->head));
103
+
104
+ qemu_opts_del(opts);
105
+ qemu_opts_free(merged);
106
+}
107
+
108
+static void test_opts_to_qdict_duplicates(void)
109
+{
110
+ QemuOpts *opts;
111
+ QemuOpt *opt;
112
+ QDict *dict;
113
+
114
+ opts = qemu_opts_parse(&opts_list_03, "foo=a,foo=b", false, &error_abort);
115
+ g_assert(opts != NULL);
116
+
117
+ /* Verify that opts has two options with the same name */
118
+ opt = QTAILQ_FIRST(&opts->head);
119
+ g_assert_cmpstr(opt->name, ==, "foo");
120
+ g_assert_cmpstr(opt->str , ==, "a");
121
+
122
+ opt = QTAILQ_NEXT(opt, next);
123
+ g_assert_cmpstr(opt->name, ==, "foo");
124
+ g_assert_cmpstr(opt->str , ==, "b");
125
+
126
+ opt = QTAILQ_NEXT(opt, next);
127
+ g_assert(opt == NULL);
128
+
129
+ /* In the conversion to QDict, the last one wins */
130
+ dict = qemu_opts_to_qdict(opts, NULL);
131
+ g_assert(dict != NULL);
132
+ g_assert_cmpstr(qdict_get_str(dict, "foo"), ==, "b");
133
+ QDECREF(dict);
134
+
135
+ /* The last one still wins if entries are deleted, and both are deleted */
136
+ dict = qemu_opts_to_qdict_filtered(opts, NULL, NULL, true);
137
+ g_assert(dict != NULL);
138
+ g_assert_cmpstr(qdict_get_str(dict, "foo"), ==, "b");
139
+ QDECREF(dict);
140
+
141
+ g_assert_true(QTAILQ_EMPTY(&opts->head));
142
+
143
+ qemu_opts_del(opts);
144
+}
145
146
int main(int argc, char *argv[])
147
{
148
@@ -XXX,XX +XXX,XX @@ int main(int argc, char *argv[])
149
g_test_add_func("/qemu-opts/opts_parse/size", test_opts_parse_size);
150
g_test_add_func("/qemu-opts/append_to_null", test_opts_append_to_null);
151
g_test_add_func("/qemu-opts/append", test_opts_append);
152
+ g_test_add_func("/qemu-opts/to_qdict/basic", test_opts_to_qdict_basic);
153
+ g_test_add_func("/qemu-opts/to_qdict/filtered", test_opts_to_qdict_filtered);
154
+ g_test_add_func("/qemu-opts/to_qdict/duplicates", test_opts_to_qdict_duplicates);
155
g_test_run();
156
return 0;
157
}
158
--
159
2.13.6
160
161
diff view generated by jsdifflib
Deleted patch
1
A few block drivers will need to rename .bdrv_create options for their
2
QAPIfication, so let's have a helper function for that.
3
1
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
---
8
include/qapi/qmp/qdict.h | 6 +++
9
qobject/qdict.c | 34 +++++++++++++
10
tests/check-qdict.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++
11
3 files changed, 169 insertions(+)
12
13
diff --git a/include/qapi/qmp/qdict.h b/include/qapi/qmp/qdict.h
14
index XXXXXXX..XXXXXXX 100644
15
--- a/include/qapi/qmp/qdict.h
16
+++ b/include/qapi/qmp/qdict.h
17
@@ -XXX,XX +XXX,XX @@ QObject *qdict_crumple(const QDict *src, Error **errp);
18
19
void qdict_join(QDict *dest, QDict *src, bool overwrite);
20
21
+typedef struct QDictRenames {
22
+ const char *from;
23
+ const char *to;
24
+} QDictRenames;
25
+bool qdict_rename_keys(QDict *qdict, const QDictRenames *renames, Error **errp);
26
+
27
#endif /* QDICT_H */
28
diff --git a/qobject/qdict.c b/qobject/qdict.c
29
index XXXXXXX..XXXXXXX 100644
30
--- a/qobject/qdict.c
31
+++ b/qobject/qdict.c
32
@@ -XXX,XX +XXX,XX @@ void qdict_join(QDict *dest, QDict *src, bool overwrite)
33
entry = next;
34
}
35
}
36
+
37
+/**
38
+ * qdict_rename_keys(): Rename keys in qdict according to the replacements
39
+ * specified in the array renames. The array must be terminated by an entry
40
+ * with from = NULL.
41
+ *
42
+ * The renames are performed individually in the order of the array, so entries
43
+ * may be renamed multiple times and may or may not conflict depending on the
44
+ * order of the renames array.
45
+ *
46
+ * Returns true for success, false in error cases.
47
+ */
48
+bool qdict_rename_keys(QDict *qdict, const QDictRenames *renames, Error **errp)
49
+{
50
+ QObject *qobj;
51
+
52
+ while (renames->from) {
53
+ if (qdict_haskey(qdict, renames->from)) {
54
+ if (qdict_haskey(qdict, renames->to)) {
55
+ error_setg(errp, "'%s' and its alias '%s' can't be used at the "
56
+ "same time", renames->to, renames->from);
57
+ return false;
58
+ }
59
+
60
+ qobj = qdict_get(qdict, renames->from);
61
+ qobject_incref(qobj);
62
+ qdict_put_obj(qdict, renames->to, qobj);
63
+ qdict_del(qdict, renames->from);
64
+ }
65
+
66
+ renames++;
67
+ }
68
+ return true;
69
+}
70
diff --git a/tests/check-qdict.c b/tests/check-qdict.c
71
index XXXXXXX..XXXXXXX 100644
72
--- a/tests/check-qdict.c
73
+++ b/tests/check-qdict.c
74
@@ -XXX,XX +XXX,XX @@ static void qdict_crumple_test_empty(void)
75
QDECREF(dst);
76
}
77
78
+static int qdict_count_entries(QDict *dict)
79
+{
80
+ const QDictEntry *e;
81
+ int count = 0;
82
+
83
+ for (e = qdict_first(dict); e; e = qdict_next(dict, e)) {
84
+ count++;
85
+ }
86
+
87
+ return count;
88
+}
89
+
90
+static void qdict_rename_keys_test(void)
91
+{
92
+ QDict *dict = qdict_new();
93
+ QDict *copy;
94
+ QDictRenames *renames;
95
+ Error *local_err = NULL;
96
+
97
+ qdict_put_str(dict, "abc", "foo");
98
+ qdict_put_str(dict, "abcdef", "bar");
99
+ qdict_put_int(dict, "number", 42);
100
+ qdict_put_bool(dict, "flag", true);
101
+ qdict_put_null(dict, "nothing");
102
+
103
+ /* Empty rename list */
104
+ renames = (QDictRenames[]) {
105
+ { NULL, "this can be anything" }
106
+ };
107
+ copy = qdict_clone_shallow(dict);
108
+ qdict_rename_keys(copy, renames, &error_abort);
109
+
110
+ g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "foo");
111
+ g_assert_cmpstr(qdict_get_str(copy, "abcdef"), ==, "bar");
112
+ g_assert_cmpint(qdict_get_int(copy, "number"), ==, 42);
113
+ g_assert_cmpint(qdict_get_bool(copy, "flag"), ==, true);
114
+ g_assert(qobject_type(qdict_get(copy, "nothing")) == QTYPE_QNULL);
115
+ g_assert_cmpint(qdict_count_entries(copy), ==, 5);
116
+
117
+ QDECREF(copy);
118
+
119
+ /* Simple rename of all entries */
120
+ renames = (QDictRenames[]) {
121
+ { "abc", "str1" },
122
+ { "abcdef", "str2" },
123
+ { "number", "int" },
124
+ { "flag", "bool" },
125
+ { "nothing", "null" },
126
+ { NULL , NULL }
127
+ };
128
+ copy = qdict_clone_shallow(dict);
129
+ qdict_rename_keys(copy, renames, &error_abort);
130
+
131
+ g_assert(!qdict_haskey(copy, "abc"));
132
+ g_assert(!qdict_haskey(copy, "abcdef"));
133
+ g_assert(!qdict_haskey(copy, "number"));
134
+ g_assert(!qdict_haskey(copy, "flag"));
135
+ g_assert(!qdict_haskey(copy, "nothing"));
136
+
137
+ g_assert_cmpstr(qdict_get_str(copy, "str1"), ==, "foo");
138
+ g_assert_cmpstr(qdict_get_str(copy, "str2"), ==, "bar");
139
+ g_assert_cmpint(qdict_get_int(copy, "int"), ==, 42);
140
+ g_assert_cmpint(qdict_get_bool(copy, "bool"), ==, true);
141
+ g_assert(qobject_type(qdict_get(copy, "null")) == QTYPE_QNULL);
142
+ g_assert_cmpint(qdict_count_entries(copy), ==, 5);
143
+
144
+ QDECREF(copy);
145
+
146
+ /* Renames are processed top to bottom */
147
+ renames = (QDictRenames[]) {
148
+ { "abc", "tmp" },
149
+ { "abcdef", "abc" },
150
+ { "number", "abcdef" },
151
+ { "flag", "number" },
152
+ { "nothing", "flag" },
153
+ { "tmp", "nothing" },
154
+ { NULL , NULL }
155
+ };
156
+ copy = qdict_clone_shallow(dict);
157
+ qdict_rename_keys(copy, renames, &error_abort);
158
+
159
+ g_assert_cmpstr(qdict_get_str(copy, "nothing"), ==, "foo");
160
+ g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "bar");
161
+ g_assert_cmpint(qdict_get_int(copy, "abcdef"), ==, 42);
162
+ g_assert_cmpint(qdict_get_bool(copy, "number"), ==, true);
163
+ g_assert(qobject_type(qdict_get(copy, "flag")) == QTYPE_QNULL);
164
+ g_assert(!qdict_haskey(copy, "tmp"));
165
+ g_assert_cmpint(qdict_count_entries(copy), ==, 5);
166
+
167
+ QDECREF(copy);
168
+
169
+ /* Conflicting rename */
170
+ renames = (QDictRenames[]) {
171
+ { "abcdef", "abc" },
172
+ { NULL , NULL }
173
+ };
174
+ copy = qdict_clone_shallow(dict);
175
+ qdict_rename_keys(copy, renames, &local_err);
176
+
177
+ g_assert(local_err != NULL);
178
+ error_free(local_err);
179
+ local_err = NULL;
180
+
181
+ g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "foo");
182
+ g_assert_cmpstr(qdict_get_str(copy, "abcdef"), ==, "bar");
183
+ g_assert_cmpint(qdict_get_int(copy, "number"), ==, 42);
184
+ g_assert_cmpint(qdict_get_bool(copy, "flag"), ==, true);
185
+ g_assert(qobject_type(qdict_get(copy, "nothing")) == QTYPE_QNULL);
186
+ g_assert_cmpint(qdict_count_entries(copy), ==, 5);
187
+
188
+ QDECREF(copy);
189
+
190
+ /* Renames in an empty dict */
191
+ renames = (QDictRenames[]) {
192
+ { "abcdef", "abc" },
193
+ { NULL , NULL }
194
+ };
195
+
196
+ QDECREF(dict);
197
+ dict = qdict_new();
198
+
199
+ qdict_rename_keys(dict, renames, &error_abort);
200
+ g_assert(qdict_first(dict) == NULL);
201
+
202
+ QDECREF(dict);
203
+}
204
+
205
static void qdict_crumple_test_bad_inputs(void)
206
{
207
QDict *src;
208
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
209
g_test_add_func("/public/crumple/bad_inputs",
210
qdict_crumple_test_bad_inputs);
211
212
+ g_test_add_func("/public/rename_keys", qdict_rename_keys_test);
213
+
214
/* The Big one */
215
if (g_test_slow()) {
216
g_test_add_func("/stress/test", qdict_stress_test);
217
--
218
2.13.6
219
220
diff view generated by jsdifflib
Deleted patch
1
Instead of manually creating the BlockdevCreateOptions object, use a
2
visitor to parse the given options into the QAPI object.
3
1
4
This involves translation from the old command line syntax to the syntax
5
mandated by the QAPI schema. Option names are still checked against
6
qcow2_create_opts, so only the old option names are allowed on the
7
command line, even if they are translated in qcow2_create().
8
9
In contrast, new option values are optionally recognised besides the old
10
values: 'compat' accepts 'v2'/'v3' as an alias for '0.10'/'1.1', and
11
'encrypt.format' accepts 'qcow' as an alias for 'aes' now.
12
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Reviewed-by: Max Reitz <mreitz@redhat.com>
15
Reviewed-by: Eric Blake <eblake@redhat.com>
16
---
17
block/qcow2.c | 218 ++++++++++++++++-----------------------------
18
tests/qemu-iotests/049.out | 8 +-
19
tests/qemu-iotests/112.out | 4 +-
20
3 files changed, 84 insertions(+), 146 deletions(-)
21
22
diff --git a/block/qcow2.c b/block/qcow2.c
23
index XXXXXXX..XXXXXXX 100644
24
--- a/block/qcow2.c
25
+++ b/block/qcow2.c
26
@@ -XXX,XX +XXX,XX @@
27
#include "qemu/option_int.h"
28
#include "qemu/cutils.h"
29
#include "qemu/bswap.h"
30
-#include "qapi/opts-visitor.h"
31
+#include "qapi/qobject-input-visitor.h"
32
+#include "qapi/qapi-visit-block-core.h"
33
#include "block/crypto.h"
34
35
/*
36
@@ -XXX,XX +XXX,XX @@ static int qcow2_crypt_method_from_format(const char *encryptfmt)
37
}
38
}
39
40
-static QCryptoBlockCreateOptions *
41
-qcow2_parse_encryption(const char *encryptfmt, QemuOpts *opts, Error **errp)
42
-{
43
- QCryptoBlockCreateOptions *cryptoopts = NULL;
44
- QDict *options, *encryptopts;
45
- int fmt;
46
-
47
- options = qemu_opts_to_qdict(opts, NULL);
48
- qdict_extract_subqdict(options, &encryptopts, "encrypt.");
49
- QDECREF(options);
50
-
51
- fmt = qcow2_crypt_method_from_format(encryptfmt);
52
-
53
- switch (fmt) {
54
- case QCOW_CRYPT_LUKS:
55
- cryptoopts = block_crypto_create_opts_init(
56
- Q_CRYPTO_BLOCK_FORMAT_LUKS, encryptopts, errp);
57
- break;
58
- case QCOW_CRYPT_AES:
59
- cryptoopts = block_crypto_create_opts_init(
60
- Q_CRYPTO_BLOCK_FORMAT_QCOW, encryptopts, errp);
61
- break;
62
- default:
63
- error_setg(errp, "Unknown encryption format '%s'", encryptfmt);
64
- break;
65
- }
66
-
67
- QDECREF(encryptopts);
68
- return cryptoopts;
69
-}
70
-
71
static int qcow2_set_up_encryption(BlockDriverState *bs,
72
QCryptoBlockCreateOptions *cryptoopts,
73
Error **errp)
74
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
75
}
76
if (version < 3 && qcow2_opts->lazy_refcounts) {
77
error_setg(errp, "Lazy refcounts only supported with compatibility "
78
- "level 1.1 and above (use compat=1.1 or greater)");
79
+ "level 1.1 and above (use version=v3 or greater)");
80
ret = -EINVAL;
81
goto out;
82
}
83
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
84
}
85
if (version < 3 && qcow2_opts->refcount_bits != 16) {
86
error_setg(errp, "Different refcount widths than 16 bits require "
87
- "compatibility level 1.1 or above (use compat=1.1 or "
88
+ "compatibility level 1.1 or above (use version=v3 or "
89
"greater)");
90
ret = -EINVAL;
91
goto out;
92
@@ -XXX,XX +XXX,XX @@ out:
93
static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opts,
94
Error **errp)
95
{
96
- BlockdevCreateOptions create_options;
97
- char *backing_file = NULL;
98
- char *backing_fmt = NULL;
99
- BlockdevDriver backing_drv;
100
- char *buf = NULL;
101
- uint64_t size = 0;
102
- int flags = 0;
103
- size_t cluster_size = DEFAULT_CLUSTER_SIZE;
104
- PreallocMode prealloc;
105
- int version;
106
- uint64_t refcount_bits;
107
- char *encryptfmt = NULL;
108
- QCryptoBlockCreateOptions *cryptoopts = NULL;
109
+ BlockdevCreateOptions *create_options = NULL;
110
+ QDict *qdict = NULL;
111
+ QObject *qobj;
112
+ Visitor *v;
113
BlockDriverState *bs = NULL;
114
Error *local_err = NULL;
115
+ const char *val;
116
int ret;
117
118
- /* Read out options */
119
- size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
120
- BDRV_SECTOR_SIZE);
121
- backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
122
- backing_fmt = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FMT);
123
- backing_drv = qapi_enum_parse(&BlockdevDriver_lookup, backing_fmt,
124
- 0, &local_err);
125
- if (local_err) {
126
- error_propagate(errp, local_err);
127
+ /* Only the keyval visitor supports the dotted syntax needed for
128
+ * encryption, so go through a QDict before getting a QAPI type. Ignore
129
+ * options meant for the protocol layer so that the visitor doesn't
130
+ * complain. */
131
+ qdict = qemu_opts_to_qdict_filtered(opts, NULL, bdrv_qcow2.create_opts,
132
+ true);
133
+
134
+ /* Handle encryption options */
135
+ val = qdict_get_try_str(qdict, BLOCK_OPT_ENCRYPT);
136
+ if (val && !strcmp(val, "on")) {
137
+ qdict_put_str(qdict, BLOCK_OPT_ENCRYPT, "qcow");
138
+ } else if (val && !strcmp(val, "off")) {
139
+ qdict_del(qdict, BLOCK_OPT_ENCRYPT);
140
+ }
141
+
142
+ val = qdict_get_try_str(qdict, BLOCK_OPT_ENCRYPT_FORMAT);
143
+ if (val && !strcmp(val, "aes")) {
144
+ qdict_put_str(qdict, BLOCK_OPT_ENCRYPT_FORMAT, "qcow");
145
+ }
146
+
147
+ /* Convert compat=0.10/1.1 into compat=v2/v3, to be renamed into
148
+ * version=v2/v3 below. */
149
+ val = qdict_get_try_str(qdict, BLOCK_OPT_COMPAT_LEVEL);
150
+ if (val && !strcmp(val, "0.10")) {
151
+ qdict_put_str(qdict, BLOCK_OPT_COMPAT_LEVEL, "v2");
152
+ } else if (val && !strcmp(val, "1.1")) {
153
+ qdict_put_str(qdict, BLOCK_OPT_COMPAT_LEVEL, "v3");
154
+ }
155
+
156
+ /* Change legacy command line options into QMP ones */
157
+ static const QDictRenames opt_renames[] = {
158
+ { BLOCK_OPT_BACKING_FILE, "backing-file" },
159
+ { BLOCK_OPT_BACKING_FMT, "backing-fmt" },
160
+ { BLOCK_OPT_CLUSTER_SIZE, "cluster-size" },
161
+ { BLOCK_OPT_LAZY_REFCOUNTS, "lazy-refcounts" },
162
+ { BLOCK_OPT_REFCOUNT_BITS, "refcount-bits" },
163
+ { BLOCK_OPT_ENCRYPT, BLOCK_OPT_ENCRYPT_FORMAT },
164
+ { BLOCK_OPT_COMPAT_LEVEL, "version" },
165
+ { NULL, NULL },
166
+ };
167
+
168
+ if (!qdict_rename_keys(qdict, opt_renames, errp)) {
169
ret = -EINVAL;
170
goto finish;
171
}
172
173
- encryptfmt = qemu_opt_get_del(opts, BLOCK_OPT_ENCRYPT_FORMAT);
174
- if (encryptfmt) {
175
- if (qemu_opt_get(opts, BLOCK_OPT_ENCRYPT)) {
176
- error_setg(errp, "Options " BLOCK_OPT_ENCRYPT " and "
177
- BLOCK_OPT_ENCRYPT_FORMAT " are mutually exclusive");
178
- ret = -EINVAL;
179
- goto finish;
180
- }
181
- } else if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ENCRYPT, false)) {
182
- encryptfmt = g_strdup("aes");
183
- }
184
- if (encryptfmt) {
185
- cryptoopts = qcow2_parse_encryption(encryptfmt, opts, errp);
186
- if (cryptoopts == NULL) {
187
- ret = -EINVAL;
188
- goto finish;
189
- }
190
- }
191
-
192
- cluster_size = qcow2_opt_get_cluster_size_del(opts, &local_err);
193
- if (local_err) {
194
- error_propagate(errp, local_err);
195
- ret = -EINVAL;
196
+ /* Create and open the file (protocol layer) */
197
+ ret = bdrv_create_file(filename, opts, errp);
198
+ if (ret < 0) {
199
goto finish;
200
}
201
- buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
202
- prealloc = qapi_enum_parse(&PreallocMode_lookup, buf,
203
- PREALLOC_MODE_OFF, &local_err);
204
- if (local_err) {
205
- error_propagate(errp, local_err);
206
- ret = -EINVAL;
207
+
208
+ bs = bdrv_open(filename, NULL, NULL,
209
+ BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp);
210
+ if (bs == NULL) {
211
+ ret = -EIO;
212
goto finish;
213
}
214
215
- version = qcow2_opt_get_version_del(opts, &local_err);
216
- if (local_err) {
217
- error_propagate(errp, local_err);
218
+ /* Set 'driver' and 'node' options */
219
+ qdict_put_str(qdict, "driver", "qcow2");
220
+ qdict_put_str(qdict, "file", bs->node_name);
221
+
222
+ /* Now get the QAPI type BlockdevCreateOptions */
223
+ qobj = qdict_crumple(qdict, errp);
224
+ QDECREF(qdict);
225
+ qdict = qobject_to_qdict(qobj);
226
+ if (qdict == NULL) {
227
ret = -EINVAL;
228
goto finish;
229
}
230
231
- if (qemu_opt_get_bool_del(opts, BLOCK_OPT_LAZY_REFCOUNTS, false)) {
232
- flags |= BLOCK_FLAG_LAZY_REFCOUNTS;
233
- }
234
+ v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
235
+ visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
236
+ visit_free(v);
237
238
- refcount_bits = qcow2_opt_get_refcount_bits_del(opts, version, &local_err);
239
if (local_err) {
240
error_propagate(errp, local_err);
241
ret = -EINVAL;
242
goto finish;
243
}
244
245
-
246
- /* Create and open the file (protocol layer) */
247
- ret = bdrv_create_file(filename, opts, errp);
248
- if (ret < 0) {
249
- goto finish;
250
- }
251
-
252
- bs = bdrv_open(filename, NULL, NULL,
253
- BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp);
254
- if (bs == NULL) {
255
- ret = -EIO;
256
- goto finish;
257
- }
258
+ /* Silently round up size */
259
+ create_options->u.qcow2.size = ROUND_UP(create_options->u.qcow2.size,
260
+ BDRV_SECTOR_SIZE);
261
262
/* Create the qcow2 image (format layer) */
263
- create_options = (BlockdevCreateOptions) {
264
- .driver = BLOCKDEV_DRIVER_QCOW2,
265
- .u.qcow2 = {
266
- .file = &(BlockdevRef) {
267
- .type = QTYPE_QSTRING,
268
- .u.reference = bs->node_name,
269
- },
270
- .size = size,
271
- .has_version = true,
272
- .version = version == 2
273
- ? BLOCKDEV_QCOW2_VERSION_V2
274
- : BLOCKDEV_QCOW2_VERSION_V3,
275
- .has_backing_file = (backing_file != NULL),
276
- .backing_file = backing_file,
277
- .has_backing_fmt = (backing_fmt != NULL),
278
- .backing_fmt = backing_drv,
279
- .has_encrypt = (encryptfmt != NULL),
280
- .encrypt = cryptoopts,
281
- .has_cluster_size = true,
282
- .cluster_size = cluster_size,
283
- .has_preallocation = true,
284
- .preallocation = prealloc,
285
- .has_lazy_refcounts = true,
286
- .lazy_refcounts = (flags & BLOCK_FLAG_LAZY_REFCOUNTS),
287
- .has_refcount_bits = true,
288
- .refcount_bits = refcount_bits,
289
- },
290
- };
291
- ret = qcow2_co_create(&create_options, errp);
292
+ ret = qcow2_co_create(create_options, errp);
293
if (ret < 0) {
294
goto finish;
295
}
296
297
+ ret = 0;
298
finish:
299
+ QDECREF(qdict);
300
bdrv_unref(bs);
301
-
302
- qapi_free_QCryptoBlockCreateOptions(cryptoopts);
303
- g_free(backing_file);
304
- g_free(backing_fmt);
305
- g_free(encryptfmt);
306
- g_free(buf);
307
+ qapi_free_BlockdevCreateOptions(create_options);
308
return ret;
309
}
310
311
diff --git a/tests/qemu-iotests/049.out b/tests/qemu-iotests/049.out
312
index XXXXXXX..XXXXXXX 100644
313
--- a/tests/qemu-iotests/049.out
314
+++ b/tests/qemu-iotests/049.out
315
@@ -XXX,XX +XXX,XX @@ qemu-img create -f qcow2 -o compat=1.1 TEST_DIR/t.qcow2 64M
316
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 cluster_size=65536 lazy_refcounts=off refcount_bits=16
317
318
qemu-img create -f qcow2 -o compat=0.42 TEST_DIR/t.qcow2 64M
319
-qemu-img: TEST_DIR/t.qcow2: Invalid compatibility level: '0.42'
320
+qemu-img: TEST_DIR/t.qcow2: Invalid parameter '0.42'
321
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.42 cluster_size=65536 lazy_refcounts=off refcount_bits=16
322
323
qemu-img create -f qcow2 -o compat=foobar TEST_DIR/t.qcow2 64M
324
-qemu-img: TEST_DIR/t.qcow2: Invalid compatibility level: 'foobar'
325
+qemu-img: TEST_DIR/t.qcow2: Invalid parameter 'foobar'
326
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=foobar cluster_size=65536 lazy_refcounts=off refcount_bits=16
327
328
== Check preallocation option ==
329
@@ -XXX,XX +XXX,XX @@ qemu-img create -f qcow2 -o preallocation=metadata TEST_DIR/t.qcow2 64M
330
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=65536 preallocation=metadata lazy_refcounts=off refcount_bits=16
331
332
qemu-img create -f qcow2 -o preallocation=1234 TEST_DIR/t.qcow2 64M
333
-qemu-img: TEST_DIR/t.qcow2: invalid parameter value: 1234
334
+qemu-img: TEST_DIR/t.qcow2: Invalid parameter '1234'
335
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=65536 preallocation=1234 lazy_refcounts=off refcount_bits=16
336
337
== Check encryption option ==
338
@@ -XXX,XX +XXX,XX @@ qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=off TEST_DIR/t.qcow2 64M
339
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 cluster_size=65536 lazy_refcounts=off refcount_bits=16
340
341
qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=on TEST_DIR/t.qcow2 64M
342
-qemu-img: TEST_DIR/t.qcow2: Lazy refcounts only supported with compatibility level 1.1 and above (use compat=1.1 or greater)
343
+qemu-img: TEST_DIR/t.qcow2: Lazy refcounts only supported with compatibility level 1.1 and above (use version=v3 or greater)
344
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 cluster_size=65536 lazy_refcounts=on refcount_bits=16
345
346
*** done
347
diff --git a/tests/qemu-iotests/112.out b/tests/qemu-iotests/112.out
348
index XXXXXXX..XXXXXXX 100644
349
--- a/tests/qemu-iotests/112.out
350
+++ b/tests/qemu-iotests/112.out
351
@@ -XXX,XX +XXX,XX @@ refcount bits: 16
352
353
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
354
refcount bits: 16
355
-qemu-img: TEST_DIR/t.IMGFMT: Different refcount widths than 16 bits require compatibility level 1.1 or above (use or greater)
356
+qemu-img: TEST_DIR/t.IMGFMT: Different refcount widths than 16 bits require compatibility level 1.1 or above (use version=v3 or greater)
357
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
358
-qemu-img: TEST_DIR/t.IMGFMT: Different refcount widths than 16 bits require compatibility level 1.1 or above (use or greater)
359
+qemu-img: TEST_DIR/t.IMGFMT: Different refcount widths than 16 bits require compatibility level 1.1 or above (use version=v3 or greater)
360
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
361
362
=== Snapshot limit on refcount_bits=1 ===
363
--
364
2.13.6
365
366
diff view generated by jsdifflib
Deleted patch
1
This adds a synchronous x-blockdev-create QMP command that can create
2
qcow2 images on a given node name.
3
1
4
We don't want to block while creating an image, so this is not the final
5
interface in all aspects, but BlockdevCreateOptionsQcow2 and
6
.bdrv_co_create() are what they actually might look like in the end. In
7
any case, this should be good enough to test whether we interpret
8
BlockdevCreateOptions as we should.
9
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Reviewed-by: Max Reitz <mreitz@redhat.com>
12
Reviewed-by: Eric Blake <eblake@redhat.com>
13
---
14
qapi/block-core.json | 12 ++++++++
15
include/block/block_int.h | 5 +++-
16
block/create.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++
17
block/qcow2.c | 1 +
18
block/Makefile.objs | 2 +-
19
5 files changed, 94 insertions(+), 2 deletions(-)
20
create mode 100644 block/create.c
21
22
diff --git a/qapi/block-core.json b/qapi/block-core.json
23
index XXXXXXX..XXXXXXX 100644
24
--- a/qapi/block-core.json
25
+++ b/qapi/block-core.json
26
@@ -XXX,XX +XXX,XX @@
27
} }
28
29
##
30
+# @x-blockdev-create:
31
+#
32
+# Create an image format on a given node.
33
+# TODO Replace with something asynchronous (block job?)
34
+#
35
+# Since: 2.12
36
+##
37
+{ 'command': 'x-blockdev-create',
38
+ 'data': 'BlockdevCreateOptions',
39
+ 'boxed': true }
40
+
41
+##
42
# @blockdev-open-tray:
43
#
44
# Opens a block device's tray. If there is a block driver state tree inserted as
45
diff --git a/include/block/block_int.h b/include/block/block_int.h
46
index XXXXXXX..XXXXXXX 100644
47
--- a/include/block/block_int.h
48
+++ b/include/block/block_int.h
49
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
50
int (*bdrv_file_open)(BlockDriverState *bs, QDict *options, int flags,
51
Error **errp);
52
void (*bdrv_close)(BlockDriverState *bs);
53
- int coroutine_fn (*bdrv_co_create_opts)(const char *filename, QemuOpts *opts,
54
+ int coroutine_fn (*bdrv_co_create)(BlockdevCreateOptions *opts,
55
Error **errp);
56
+ int coroutine_fn (*bdrv_co_create_opts)(const char *filename,
57
+ QemuOpts *opts,
58
+ Error **errp);
59
int (*bdrv_make_empty)(BlockDriverState *bs);
60
61
void (*bdrv_refresh_filename)(BlockDriverState *bs, QDict *options);
62
diff --git a/block/create.c b/block/create.c
63
new file mode 100644
64
index XXXXXXX..XXXXXXX
65
--- /dev/null
66
+++ b/block/create.c
67
@@ -XXX,XX +XXX,XX @@
68
+/*
69
+ * Block layer code related to image creation
70
+ *
71
+ * Copyright (c) 2018 Kevin Wolf <kwolf@redhat.com>
72
+ *
73
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
74
+ * of this software and associated documentation files (the "Software"), to deal
75
+ * in the Software without restriction, including without limitation the rights
76
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
77
+ * copies of the Software, and to permit persons to whom the Software is
78
+ * furnished to do so, subject to the following conditions:
79
+ *
80
+ * The above copyright notice and this permission notice shall be included in
81
+ * all copies or substantial portions of the Software.
82
+ *
83
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
84
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
85
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
86
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
87
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
88
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
89
+ * THE SOFTWARE.
90
+ */
91
+
92
+#include "qemu/osdep.h"
93
+#include "block/block_int.h"
94
+#include "qapi/qapi-commands-block-core.h"
95
+#include "qapi/error.h"
96
+
97
+typedef struct BlockdevCreateCo {
98
+ BlockDriver *drv;
99
+ BlockdevCreateOptions *opts;
100
+ int ret;
101
+ Error **errp;
102
+} BlockdevCreateCo;
103
+
104
+static void coroutine_fn bdrv_co_create_co_entry(void *opaque)
105
+{
106
+ BlockdevCreateCo *cco = opaque;
107
+ cco->ret = cco->drv->bdrv_co_create(cco->opts, cco->errp);
108
+}
109
+
110
+void qmp_x_blockdev_create(BlockdevCreateOptions *options, Error **errp)
111
+{
112
+ const char *fmt = BlockdevDriver_str(options->driver);
113
+ BlockDriver *drv = bdrv_find_format(fmt);
114
+ Coroutine *co;
115
+ BlockdevCreateCo cco;
116
+
117
+ /* If the driver is in the schema, we know that it exists. But it may not
118
+ * be whitelisted. */
119
+ assert(drv);
120
+ if (bdrv_uses_whitelist() && !bdrv_is_whitelisted(drv, false)) {
121
+ error_setg(errp, "Driver is not whitelisted");
122
+ return;
123
+ }
124
+
125
+ /* Call callback if it exists */
126
+ if (!drv->bdrv_co_create) {
127
+ error_setg(errp, "Driver does not support blockdev-create");
128
+ return;
129
+ }
130
+
131
+ cco = (BlockdevCreateCo) {
132
+ .drv = drv,
133
+ .opts = options,
134
+ .ret = -EINPROGRESS,
135
+ .errp = errp,
136
+ };
137
+
138
+ co = qemu_coroutine_create(bdrv_co_create_co_entry, &cco);
139
+ qemu_coroutine_enter(co);
140
+ while (cco.ret == -EINPROGRESS) {
141
+ aio_poll(qemu_get_aio_context(), true);
142
+ }
143
+}
144
diff --git a/block/qcow2.c b/block/qcow2.c
145
index XXXXXXX..XXXXXXX 100644
146
--- a/block/qcow2.c
147
+++ b/block/qcow2.c
148
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_qcow2 = {
149
.bdrv_join_options = qcow2_join_options,
150
.bdrv_child_perm = bdrv_format_default_perms,
151
.bdrv_co_create_opts = qcow2_co_create_opts,
152
+ .bdrv_co_create = qcow2_co_create,
153
.bdrv_has_zero_init = bdrv_has_zero_init_1,
154
.bdrv_co_block_status = qcow2_co_block_status,
155
156
diff --git a/block/Makefile.objs b/block/Makefile.objs
157
index XXXXXXX..XXXXXXX 100644
158
--- a/block/Makefile.objs
159
+++ b/block/Makefile.objs
160
@@ -XXX,XX +XXX,XX @@ block-obj-y += block-backend.o snapshot.o qapi.o
161
block-obj-$(CONFIG_WIN32) += file-win32.o win32-aio.o
162
block-obj-$(CONFIG_POSIX) += file-posix.o
163
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
164
-block-obj-y += null.o mirror.o commit.o io.o
165
+block-obj-y += null.o mirror.o commit.o io.o create.o
166
block-obj-y += throttle-groups.o
167
block-obj-$(CONFIG_LINUX) += nvme.o
168
169
--
170
2.13.6
171
172
diff view generated by jsdifflib
Deleted patch
1
This adds the .bdrv_co_create driver callback to file-win32, which
2
enables image creation over QMP.
3
1
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
---
8
block/file-win32.c | 47 ++++++++++++++++++++++++++++++++++++++---------
9
1 file changed, 38 insertions(+), 9 deletions(-)
10
11
diff --git a/block/file-win32.c b/block/file-win32.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/block/file-win32.c
14
+++ b/block/file-win32.c
15
@@ -XXX,XX +XXX,XX @@ static int64_t raw_get_allocated_file_size(BlockDriverState *bs)
16
return st.st_size;
17
}
18
19
-static int coroutine_fn raw_co_create_opts(const char *filename, QemuOpts *opts,
20
- Error **errp)
21
+static int raw_co_create(BlockdevCreateOptions *options, Error **errp)
22
{
23
+ BlockdevCreateOptionsFile *file_opts;
24
int fd;
25
- int64_t total_size = 0;
26
27
- strstart(filename, "file:", &filename);
28
+ assert(options->driver == BLOCKDEV_DRIVER_FILE);
29
+ file_opts = &options->u.file;
30
31
- /* Read out options */
32
- total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
33
- BDRV_SECTOR_SIZE);
34
+ if (file_opts->has_preallocation) {
35
+ error_setg(errp, "Preallocation is not supported on Windows");
36
+ return -EINVAL;
37
+ }
38
+ if (file_opts->has_nocow) {
39
+ error_setg(errp, "nocow is not supported on Windows");
40
+ return -EINVAL;
41
+ }
42
43
- fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
44
+ fd = qemu_open(file_opts->filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
45
0644);
46
if (fd < 0) {
47
error_setg_errno(errp, errno, "Could not create file");
48
return -EIO;
49
}
50
set_sparse(fd);
51
- ftruncate(fd, total_size);
52
+ ftruncate(fd, file_opts->size);
53
qemu_close(fd);
54
+
55
return 0;
56
}
57
58
+static int coroutine_fn raw_co_create_opts(const char *filename, QemuOpts *opts,
59
+ Error **errp)
60
+{
61
+ BlockdevCreateOptions options;
62
+ int64_t total_size = 0;
63
+
64
+ strstart(filename, "file:", &filename);
65
+
66
+ /* Read out options */
67
+ total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
68
+ BDRV_SECTOR_SIZE);
69
+
70
+ options = (BlockdevCreateOptions) {
71
+ .driver = BLOCKDEV_DRIVER_FILE,
72
+ .u.file = {
73
+ .filename = (char *) filename,
74
+ .size = total_size,
75
+ .has_preallocation = false,
76
+ .has_nocow = false,
77
+ },
78
+ };
79
+ return raw_co_create(&options, errp);
80
+}
81
82
static QemuOptsList raw_create_opts = {
83
.name = "raw-create-opts",
84
--
85
2.13.6
86
87
diff view generated by jsdifflib
Deleted patch
1
This adds the .bdrv_co_create driver callback to gluster, which enables
2
image creation over QMP.
3
1
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
---
8
qapi/block-core.json | 18 ++++++-
9
block/gluster.c | 135 ++++++++++++++++++++++++++++++++++-----------------
10
2 files changed, 108 insertions(+), 45 deletions(-)
11
12
diff --git a/qapi/block-core.json b/qapi/block-core.json
13
index XXXXXXX..XXXXXXX 100644
14
--- a/qapi/block-core.json
15
+++ b/qapi/block-core.json
16
@@ -XXX,XX +XXX,XX @@
17
'*nocow': 'bool' } }
18
19
##
20
+# @BlockdevCreateOptionsGluster:
21
+#
22
+# Driver specific image creation options for gluster.
23
+#
24
+# @location Where to store the new image file
25
+# @size Size of the virtual disk in bytes
26
+# @preallocation Preallocation mode for the new image (default: off)
27
+#
28
+# Since: 2.12
29
+##
30
+{ 'struct': 'BlockdevCreateOptionsGluster',
31
+ 'data': { 'location': 'BlockdevOptionsGluster',
32
+ 'size': 'size',
33
+ '*preallocation': 'PreallocMode' } }
34
+
35
+##
36
# @BlockdevQcow2Version:
37
#
38
# @v2: The original QCOW2 format as introduced in qemu 0.10 (version 2)
39
@@ -XXX,XX +XXX,XX @@
40
'file': 'BlockdevCreateOptionsFile',
41
'ftp': 'BlockdevCreateNotSupported',
42
'ftps': 'BlockdevCreateNotSupported',
43
- 'gluster': 'BlockdevCreateNotSupported',
44
+ 'gluster': 'BlockdevCreateOptionsGluster',
45
'host_cdrom': 'BlockdevCreateNotSupported',
46
'host_device': 'BlockdevCreateNotSupported',
47
'http': 'BlockdevCreateNotSupported',
48
diff --git a/block/gluster.c b/block/gluster.c
49
index XXXXXXX..XXXXXXX 100644
50
--- a/block/gluster.c
51
+++ b/block/gluster.c
52
@@ -XXX,XX +XXX,XX @@ out:
53
return -errno;
54
}
55
56
-static struct glfs *qemu_gluster_init(BlockdevOptionsGluster *gconf,
57
- const char *filename,
58
- QDict *options, Error **errp)
59
+/* Converts options given in @filename and the @options QDict into the QAPI
60
+ * object @gconf. */
61
+static int qemu_gluster_parse(BlockdevOptionsGluster *gconf,
62
+ const char *filename,
63
+ QDict *options, Error **errp)
64
{
65
int ret;
66
if (filename) {
67
@@ -XXX,XX +XXX,XX @@ static struct glfs *qemu_gluster_init(BlockdevOptionsGluster *gconf,
68
"[host[:port]]volume/path[?socket=...]"
69
"[,file.debug=N]"
70
"[,file.logfile=/path/filename.log]\n");
71
- errno = -ret;
72
- return NULL;
73
+ return ret;
74
}
75
} else {
76
ret = qemu_gluster_parse_json(gconf, options, errp);
77
@@ -XXX,XX +XXX,XX @@ static struct glfs *qemu_gluster_init(BlockdevOptionsGluster *gconf,
78
"file.server.1.transport=unix,"
79
"file.server.1.socket=/var/run/glusterd.socket ..."
80
"\n");
81
- errno = -ret;
82
- return NULL;
83
+ return ret;
84
}
85
+ }
86
87
+ return 0;
88
+}
89
+
90
+static struct glfs *qemu_gluster_init(BlockdevOptionsGluster *gconf,
91
+ const char *filename,
92
+ QDict *options, Error **errp)
93
+{
94
+ int ret;
95
+
96
+ ret = qemu_gluster_parse(gconf, filename, options, errp);
97
+ if (ret < 0) {
98
+ errno = -ret;
99
+ return NULL;
100
}
101
102
return qemu_gluster_glfs_init(gconf, errp);
103
@@ -XXX,XX +XXX,XX @@ static int qemu_gluster_do_truncate(struct glfs_fd *fd, int64_t offset,
104
return 0;
105
}
106
107
+static int qemu_gluster_co_create(BlockdevCreateOptions *options,
108
+ Error **errp)
109
+{
110
+ BlockdevCreateOptionsGluster *opts = &options->u.gluster;
111
+ struct glfs *glfs;
112
+ struct glfs_fd *fd = NULL;
113
+ int ret = 0;
114
+
115
+ assert(options->driver == BLOCKDEV_DRIVER_GLUSTER);
116
+
117
+ glfs = qemu_gluster_glfs_init(opts->location, errp);
118
+ if (!glfs) {
119
+ ret = -errno;
120
+ goto out;
121
+ }
122
+
123
+ fd = glfs_creat(glfs, opts->location->path,
124
+ O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRUSR | S_IWUSR);
125
+ if (!fd) {
126
+ ret = -errno;
127
+ goto out;
128
+ }
129
+
130
+ ret = qemu_gluster_do_truncate(fd, opts->size, opts->preallocation, errp);
131
+
132
+out:
133
+ if (fd) {
134
+ if (glfs_close(fd) != 0 && ret == 0) {
135
+ ret = -errno;
136
+ }
137
+ }
138
+ glfs_clear_preopened(glfs);
139
+ return ret;
140
+}
141
+
142
static int coroutine_fn qemu_gluster_co_create_opts(const char *filename,
143
QemuOpts *opts,
144
Error **errp)
145
{
146
+ BlockdevCreateOptions *options;
147
+ BlockdevCreateOptionsGluster *gopts;
148
BlockdevOptionsGluster *gconf;
149
- struct glfs *glfs;
150
- struct glfs_fd *fd = NULL;
151
- int ret = 0;
152
- PreallocMode prealloc;
153
- int64_t total_size = 0;
154
char *tmp = NULL;
155
Error *local_err = NULL;
156
+ int ret;
157
+
158
+ options = g_new0(BlockdevCreateOptions, 1);
159
+ options->driver = BLOCKDEV_DRIVER_GLUSTER;
160
+ gopts = &options->u.gluster;
161
162
gconf = g_new0(BlockdevOptionsGluster, 1);
163
+ gopts->location = gconf;
164
+
165
+ gopts->size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
166
+ BDRV_SECTOR_SIZE);
167
+
168
+ tmp = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
169
+ gopts->preallocation = qapi_enum_parse(&PreallocMode_lookup, tmp,
170
+ PREALLOC_MODE_OFF, &local_err);
171
+ g_free(tmp);
172
+ if (local_err) {
173
+ error_propagate(errp, local_err);
174
+ ret = -EINVAL;
175
+ goto fail;
176
+ }
177
+
178
gconf->debug = qemu_opt_get_number_del(opts, GLUSTER_OPT_DEBUG,
179
GLUSTER_DEBUG_DEFAULT);
180
if (gconf->debug < 0) {
181
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qemu_gluster_co_create_opts(const char *filename,
182
}
183
gconf->has_logfile = true;
184
185
- glfs = qemu_gluster_init(gconf, filename, NULL, errp);
186
- if (!glfs) {
187
- ret = -errno;
188
- goto out;
189
- }
190
-
191
- total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
192
- BDRV_SECTOR_SIZE);
193
-
194
- tmp = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
195
- prealloc = qapi_enum_parse(&PreallocMode_lookup, tmp, PREALLOC_MODE_OFF,
196
- &local_err);
197
- g_free(tmp);
198
- if (local_err) {
199
- error_propagate(errp, local_err);
200
- ret = -EINVAL;
201
- goto out;
202
+ ret = qemu_gluster_parse(gconf, filename, NULL, errp);
203
+ if (ret < 0) {
204
+ goto fail;
205
}
206
207
- fd = glfs_creat(glfs, gconf->path,
208
- O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRUSR | S_IWUSR);
209
- if (!fd) {
210
- ret = -errno;
211
- goto out;
212
+ ret = qemu_gluster_co_create(options, errp);
213
+ if (ret < 0) {
214
+ goto fail;
215
}
216
217
- ret = qemu_gluster_do_truncate(fd, total_size, prealloc, errp);
218
-
219
-out:
220
- if (fd) {
221
- if (glfs_close(fd) != 0 && ret == 0) {
222
- ret = -errno;
223
- }
224
- }
225
- qapi_free_BlockdevOptionsGluster(gconf);
226
- glfs_clear_preopened(glfs);
227
+ ret = 0;
228
+fail:
229
+ qapi_free_BlockdevCreateOptions(options);
230
return ret;
231
}
232
233
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_gluster = {
234
.bdrv_reopen_commit = qemu_gluster_reopen_commit,
235
.bdrv_reopen_abort = qemu_gluster_reopen_abort,
236
.bdrv_close = qemu_gluster_close,
237
+ .bdrv_co_create = qemu_gluster_co_create,
238
.bdrv_co_create_opts = qemu_gluster_co_create_opts,
239
.bdrv_getlength = qemu_gluster_getlength,
240
.bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
241
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_gluster_tcp = {
242
.bdrv_reopen_commit = qemu_gluster_reopen_commit,
243
.bdrv_reopen_abort = qemu_gluster_reopen_abort,
244
.bdrv_close = qemu_gluster_close,
245
+ .bdrv_co_create = qemu_gluster_co_create,
246
.bdrv_co_create_opts = qemu_gluster_co_create_opts,
247
.bdrv_getlength = qemu_gluster_getlength,
248
.bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
249
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_gluster_unix = {
250
.bdrv_reopen_commit = qemu_gluster_reopen_commit,
251
.bdrv_reopen_abort = qemu_gluster_reopen_abort,
252
.bdrv_close = qemu_gluster_close,
253
+ .bdrv_co_create = qemu_gluster_co_create,
254
.bdrv_co_create_opts = qemu_gluster_co_create_opts,
255
.bdrv_getlength = qemu_gluster_getlength,
256
.bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
257
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_gluster_rdma = {
258
.bdrv_reopen_commit = qemu_gluster_reopen_commit,
259
.bdrv_reopen_abort = qemu_gluster_reopen_abort,
260
.bdrv_close = qemu_gluster_close,
261
+ .bdrv_co_create = qemu_gluster_co_create,
262
.bdrv_co_create_opts = qemu_gluster_co_create_opts,
263
.bdrv_getlength = qemu_gluster_getlength,
264
.bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
265
--
266
2.13.6
267
268
diff view generated by jsdifflib
Deleted patch
1
If we want to include the invalid option name in the error message, we
2
can't free the string earlier than that.
3
1
4
Cc: qemu-stable@nongnu.org
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
---
9
block/rbd.c | 3 ++-
10
1 file changed, 2 insertions(+), 1 deletion(-)
11
12
diff --git a/block/rbd.c b/block/rbd.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/block/rbd.c
15
+++ b/block/rbd.c
16
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_set_keypairs(rados_t cluster, const char *keypairs_json,
17
key = qstring_get_str(name);
18
19
ret = rados_conf_set(cluster, key, qstring_get_str(value));
20
- QDECREF(name);
21
QDECREF(value);
22
if (ret < 0) {
23
error_setg_errno(errp, -ret, "invalid conf option %s", key);
24
+ QDECREF(name);
25
ret = -EINVAL;
26
break;
27
}
28
+ QDECREF(name);
29
}
30
31
QDECREF(keypairs);
32
--
33
2.13.6
34
35
diff view generated by jsdifflib
1
This adds the .bdrv_co_create driver callback to ssh, which enables
1
This adds GRAPH_RDLOCK annotations to declare that callers of
2
image creation over QMP.
2
bdrv_get_specific_info() need to hold a reader lock for the graph.
3
This removes an assume_graph_lock() call in vmdk's implementation.
3
4
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Message-ID: <20230929145157.45443-20-kwolf@redhat.com>
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
9
---
7
qapi/block-core.json | 16 +++++++++-
10
include/block/block-io.h | 5 +++--
8
block/ssh.c | 83 ++++++++++++++++++++++++++++++----------------------
11
include/block/block_int-common.h | 4 ++--
9
2 files changed, 63 insertions(+), 36 deletions(-)
12
block/vmdk.c | 6 ++----
13
qemu-io-cmds.c | 3 +++
14
4 files changed, 10 insertions(+), 8 deletions(-)
10
15
11
diff --git a/qapi/block-core.json b/qapi/block-core.json
16
diff --git a/include/block/block-io.h b/include/block/block-io.h
12
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
13
--- a/qapi/block-core.json
18
--- a/include/block/block-io.h
14
+++ b/qapi/block-core.json
19
+++ b/include/block/block-io.h
15
@@ -XXX,XX +XXX,XX @@
20
@@ -XXX,XX +XXX,XX @@ bdrv_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi);
16
'*object-size': 'size' } }
21
int co_wrapper_mixed_bdrv_rdlock
17
22
bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi);
18
##
23
19
+# @BlockdevCreateOptionsSsh:
24
-ImageInfoSpecific *bdrv_get_specific_info(BlockDriverState *bs,
20
+#
25
- Error **errp);
21
+# Driver specific image creation options for SSH.
26
+ImageInfoSpecific * GRAPH_RDLOCK
22
+#
27
+bdrv_get_specific_info(BlockDriverState *bs, Error **errp);
23
+# @location Where to store the new image file
24
+# @size Size of the virtual disk in bytes
25
+#
26
+# Since: 2.12
27
+##
28
+{ 'struct': 'BlockdevCreateOptionsSsh',
29
+ 'data': { 'location': 'BlockdevOptionsSsh',
30
+ 'size': 'size' } }
31
+
28
+
32
+##
29
BlockStatsSpecific *bdrv_get_specific_stats(BlockDriverState *bs);
33
# @BlockdevCreateNotSupported:
30
void bdrv_round_to_subclusters(BlockDriverState *bs,
34
#
31
int64_t offset, int64_t bytes,
35
# This is used for all drivers that don't support creating images.
32
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
36
@@ -XXX,XX +XXX,XX @@
37
'rbd': 'BlockdevCreateOptionsRbd',
38
'replication': 'BlockdevCreateNotSupported',
39
'sheepdog': 'BlockdevCreateOptionsSheepdog',
40
- 'ssh': 'BlockdevCreateNotSupported',
41
+ 'ssh': 'BlockdevCreateOptionsSsh',
42
'throttle': 'BlockdevCreateNotSupported',
43
'vdi': 'BlockdevCreateNotSupported',
44
'vhdx': 'BlockdevCreateNotSupported',
45
diff --git a/block/ssh.c b/block/ssh.c
46
index XXXXXXX..XXXXXXX 100644
33
index XXXXXXX..XXXXXXX 100644
47
--- a/block/ssh.c
34
--- a/include/block/block_int-common.h
48
+++ b/block/ssh.c
35
+++ b/include/block/block_int-common.h
49
@@ -XXX,XX +XXX,XX @@ static QemuOptsList ssh_create_opts = {
36
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
50
}
37
int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_get_info)(
51
};
38
BlockDriverState *bs, BlockDriverInfo *bdi);
52
39
53
+static int ssh_co_create(BlockdevCreateOptions *options, Error **errp)
40
- ImageInfoSpecific *(*bdrv_get_specific_info)(BlockDriverState *bs,
54
+{
41
- Error **errp);
55
+ BlockdevCreateOptionsSsh *opts = &options->u.ssh;
42
+ ImageInfoSpecific * GRAPH_RDLOCK_PTR (*bdrv_get_specific_info)(
56
+ BDRVSSHState s;
43
+ BlockDriverState *bs, Error **errp);
57
+ int ret;
44
BlockStatsSpecific *(*bdrv_get_specific_stats)(BlockDriverState *bs);
58
+
45
59
+ assert(options->driver == BLOCKDEV_DRIVER_SSH);
46
int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_save_vmstate)(
60
+
47
diff --git a/block/vmdk.c b/block/vmdk.c
61
+ ssh_state_init(&s);
48
index XXXXXXX..XXXXXXX 100644
62
+
49
--- a/block/vmdk.c
63
+ ret = connect_to_ssh(&s, opts->location,
50
+++ b/block/vmdk.c
64
+ LIBSSH2_FXF_READ|LIBSSH2_FXF_WRITE|
51
@@ -XXX,XX +XXX,XX @@ vmdk_co_check(BlockDriverState *bs, BdrvCheckResult *result, BdrvCheckMode fix)
65
+ LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC,
66
+ 0644, errp);
67
+ if (ret < 0) {
68
+ goto fail;
69
+ }
70
+
71
+ if (opts->size > 0) {
72
+ ret = ssh_grow_file(&s, opts->size, errp);
73
+ if (ret < 0) {
74
+ goto fail;
75
+ }
76
+ }
77
+
78
+ ret = 0;
79
+fail:
80
+ ssh_state_free(&s);
81
+ return ret;
82
+}
83
+
84
static int coroutine_fn ssh_co_create_opts(const char *filename, QemuOpts *opts,
85
Error **errp)
86
{
87
- int r, ret;
88
- int64_t total_size = 0;
89
+ BlockdevCreateOptions *create_options;
90
+ BlockdevCreateOptionsSsh *ssh_opts;
91
+ int ret;
92
QDict *uri_options = NULL;
93
- BlockdevOptionsSsh *ssh_opts = NULL;
94
- BDRVSSHState s;
95
96
- ssh_state_init(&s);
97
+ create_options = g_new0(BlockdevCreateOptions, 1);
98
+ create_options->driver = BLOCKDEV_DRIVER_SSH;
99
+ ssh_opts = &create_options->u.ssh;
100
101
/* Get desired file size. */
102
- total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
103
- BDRV_SECTOR_SIZE);
104
- DPRINTF("total_size=%" PRIi64, total_size);
105
+ ssh_opts->size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
106
+ BDRV_SECTOR_SIZE);
107
+ DPRINTF("total_size=%" PRIi64, ssh_opts->size);
108
109
uri_options = qdict_new();
110
- r = parse_uri(filename, uri_options, errp);
111
- if (r < 0) {
112
- ret = r;
113
+ ret = parse_uri(filename, uri_options, errp);
114
+ if (ret < 0) {
115
goto out;
116
}
117
118
- ssh_opts = ssh_parse_options(uri_options, errp);
119
- if (ssh_opts == NULL) {
120
+ ssh_opts->location = ssh_parse_options(uri_options, errp);
121
+ if (ssh_opts->location == NULL) {
122
ret = -EINVAL;
123
goto out;
124
}
125
126
- r = connect_to_ssh(&s, ssh_opts,
127
- LIBSSH2_FXF_READ|LIBSSH2_FXF_WRITE|
128
- LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC,
129
- 0644, errp);
130
- if (r < 0) {
131
- ret = r;
132
- goto out;
133
- }
134
-
135
- if (total_size > 0) {
136
- ret = ssh_grow_file(&s, total_size, errp);
137
- if (ret < 0) {
138
- goto out;
139
- }
140
- }
141
-
142
- ret = 0;
143
+ ret = ssh_co_create(create_options, errp);
144
145
out:
146
- ssh_state_free(&s);
147
- if (uri_options != NULL) {
148
- QDECREF(uri_options);
149
- }
150
- qapi_free_BlockdevOptionsSsh(ssh_opts);
151
+ QDECREF(uri_options);
152
+ qapi_free_BlockdevCreateOptions(create_options);
153
return ret;
52
return ret;
154
}
53
}
155
54
156
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_ssh = {
55
-static ImageInfoSpecific *vmdk_get_specific_info(BlockDriverState *bs,
157
.instance_size = sizeof(BDRVSSHState),
56
- Error **errp)
158
.bdrv_parse_filename = ssh_parse_filename,
57
+static ImageInfoSpecific * GRAPH_RDLOCK
159
.bdrv_file_open = ssh_file_open,
58
+vmdk_get_specific_info(BlockDriverState *bs, Error **errp)
160
+ .bdrv_co_create = ssh_co_create,
59
{
161
.bdrv_co_create_opts = ssh_co_create_opts,
60
int i;
162
.bdrv_close = ssh_close,
61
BDRVVmdkState *s = bs->opaque;
163
.bdrv_has_zero_init = ssh_has_zero_init,
62
ImageInfoSpecific *spec_info = g_new0(ImageInfoSpecific, 1);
63
VmdkExtentInfoList **tail;
64
65
- assume_graph_lock(); /* FIXME */
66
-
67
*spec_info = (ImageInfoSpecific){
68
.type = IMAGE_INFO_SPECIFIC_KIND_VMDK,
69
.u = {
70
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
71
index XXXXXXX..XXXXXXX 100644
72
--- a/qemu-io-cmds.c
73
+++ b/qemu-io-cmds.c
74
@@ -XXX,XX +XXX,XX @@ static int info_f(BlockBackend *blk, int argc, char **argv)
75
char s1[64], s2[64];
76
int ret;
77
78
+ GLOBAL_STATE_CODE();
79
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
80
+
81
if (bs->drv && bs->drv->format_name) {
82
printf("format name: %s\n", bs->drv->format_name);
83
}
164
--
84
--
165
2.13.6
85
2.41.0
166
167
diff view generated by jsdifflib
1
With the conversion to a QAPI options object, the function is now
1
Almost all functions that access the parent link already take the graph
2
prepared to be used in a .bdrv_co_create implementation.
2
lock now. Add locking to the remaining user in a test case and finally
3
annotate the struct field itself as protected by the graph lock.
3
4
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Message-ID: <20230929145157.45443-21-kwolf@redhat.com>
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
9
---
7
block/rbd.c | 115 +++++++++++++++++++++++++++++-------------------------------
10
include/block/block_int-common.h | 4 ++--
8
1 file changed, 55 insertions(+), 60 deletions(-)
11
tests/unit/test-block-iothread.c | 5 +++++
12
2 files changed, 7 insertions(+), 2 deletions(-)
9
13
10
diff --git a/block/rbd.c b/block/rbd.c
14
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
11
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
12
--- a/block/rbd.c
16
--- a/include/block/block_int-common.h
13
+++ b/block/rbd.c
17
+++ b/include/block/block_int-common.h
14
@@ -XXX,XX +XXX,XX @@
18
@@ -XXX,XX +XXX,XX @@ struct BdrvChild {
15
#include "qapi/qmp/qdict.h"
19
bool quiesced_parent;
16
#include "qapi/qmp/qjson.h"
20
17
#include "qapi/qmp/qlist.h"
21
QLIST_ENTRY(BdrvChild) next;
18
+#include "qapi/qobject-input-visitor.h"
22
- QLIST_ENTRY(BdrvChild) next_parent;
19
+#include "qapi/qapi-visit-block-core.h"
23
+ QLIST_ENTRY(BdrvChild GRAPH_RDLOCK_PTR) next_parent;
24
};
20
25
21
/*
26
/*
22
* When specifying the image filename use:
27
@@ -XXX,XX +XXX,XX @@ struct BlockDriverState {
23
@@ -XXX,XX +XXX,XX @@ static void qemu_rbd_complete_aio(RADOSCB *rcb)
28
BdrvChild *backing;
24
qemu_aio_unref(acb);
29
BdrvChild *file;
25
}
30
26
31
- QLIST_HEAD(, BdrvChild) parents;
27
-static char *qemu_rbd_mon_host(QDict *options, Error **errp)
32
+ QLIST_HEAD(, BdrvChild GRAPH_RDLOCK_PTR) parents;
28
+static char *qemu_rbd_mon_host(BlockdevOptionsRbd *opts, Error **errp)
33
29
{
34
QDict *options;
30
- const char **vals = g_new(const char *, qdict_size(options) + 1);
35
QDict *explicit_options;
31
- char keybuf[32];
36
diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c
32
+ const char **vals;
37
index XXXXXXX..XXXXXXX 100644
33
const char *host, *port;
38
--- a/tests/unit/test-block-iothread.c
34
char *rados_str;
39
+++ b/tests/unit/test-block-iothread.c
35
- int i;
40
@@ -XXX,XX +XXX,XX @@ static void test_sync_op(const void *opaque)
36
-
41
BlockDriverState *bs;
37
- for (i = 0;; i++) {
42
BdrvChild *c;
38
- sprintf(keybuf, "server.%d.host", i);
43
39
- host = qdict_get_try_str(options, keybuf);
44
+ GLOBAL_STATE_CODE();
40
- qdict_del(options, keybuf);
41
- sprintf(keybuf, "server.%d.port", i);
42
- port = qdict_get_try_str(options, keybuf);
43
- qdict_del(options, keybuf);
44
- if (!host && !port) {
45
- break;
46
- }
47
- if (!host) {
48
- error_setg(errp, "Parameter server.%d.host is missing", i);
49
- rados_str = NULL;
50
- goto out;
51
- }
52
+ InetSocketAddressBaseList *p;
53
+ int i, cnt;
54
+
45
+
55
+ if (!opts->has_server) {
46
blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
56
+ return NULL;
47
bs = bdrv_new_open_driver(&bdrv_test, "base", BDRV_O_RDWR, &error_abort);
57
+ }
48
bs->total_sectors = 65536 / BDRV_SECTOR_SIZE;
49
blk_insert_bs(blk, bs, &error_abort);
58
+
50
+
59
+ for (cnt = 0, p = opts->server; p; p = p->next) {
51
+ bdrv_graph_rdlock_main_loop();
60
+ cnt++;
52
c = QLIST_FIRST(&bs->parents);
61
+ }
53
+ bdrv_graph_rdunlock_main_loop();
62
+
54
63
+ vals = g_new(const char *, cnt + 1);
55
blk_set_aio_context(blk, ctx, &error_abort);
64
+
56
aio_context_acquire(ctx);
65
+ for (i = 0, p = opts->server; p; p = p->next, i++) {
66
+ host = p->value->host;
67
+ port = p->value->port;
68
69
if (strchr(host, ':')) {
70
- vals[i] = port ? g_strdup_printf("[%s]:%s", host, port)
71
- : g_strdup_printf("[%s]", host);
72
+ vals[i] = g_strdup_printf("[%s]:%s", host, port);
73
} else {
74
- vals[i] = port ? g_strdup_printf("%s:%s", host, port)
75
- : g_strdup(host);
76
+ vals[i] = g_strdup_printf("%s:%s", host, port);
77
}
78
}
79
vals[i] = NULL;
80
81
rados_str = i ? g_strjoinv(";", (char **)vals) : NULL;
82
-out:
83
g_strfreev((char **)vals);
84
return rados_str;
85
}
86
87
static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
88
char **s_snap, char **s_image_name,
89
- QDict *options, bool cache,
90
+ BlockdevOptionsRbd *opts, bool cache,
91
const char *keypairs, const char *secretid,
92
Error **errp)
93
{
94
- QemuOpts *opts;
95
char *mon_host = NULL;
96
- const char *pool, *snap, *conf, *user, *image_name;
97
Error *local_err = NULL;
98
int r;
99
100
- opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
101
- qemu_opts_absorb_qdict(opts, options, &local_err);
102
- if (local_err) {
103
- error_propagate(errp, local_err);
104
- r = -EINVAL;
105
- goto failed_opts;
106
- }
107
-
108
- mon_host = qemu_rbd_mon_host(options, &local_err);
109
+ mon_host = qemu_rbd_mon_host(opts, &local_err);
110
if (local_err) {
111
error_propagate(errp, local_err);
112
r = -EINVAL;
113
goto failed_opts;
114
}
115
116
- pool = qemu_opt_get(opts, "pool");
117
- conf = qemu_opt_get(opts, "conf");
118
- snap = qemu_opt_get(opts, "snapshot");
119
- user = qemu_opt_get(opts, "user");
120
- image_name = qemu_opt_get(opts, "image");
121
-
122
- if (!pool || !image_name) {
123
- error_setg(errp, "Parameters 'pool' and 'image' are required");
124
- r = -EINVAL;
125
- goto failed_opts;
126
- }
127
-
128
- r = rados_create(cluster, user);
129
+ r = rados_create(cluster, opts->user);
130
if (r < 0) {
131
error_setg_errno(errp, -r, "error initializing");
132
goto failed_opts;
133
}
134
135
- *s_snap = g_strdup(snap);
136
- *s_image_name = g_strdup(image_name);
137
+ *s_snap = g_strdup(opts->snapshot);
138
+ *s_image_name = g_strdup(opts->image);
139
140
/* try default location when conf=NULL, but ignore failure */
141
- r = rados_conf_read_file(*cluster, conf);
142
- if (conf && r < 0) {
143
- error_setg_errno(errp, -r, "error reading conf file %s", conf);
144
+ r = rados_conf_read_file(*cluster, opts->conf);
145
+ if (opts->has_conf && r < 0) {
146
+ error_setg_errno(errp, -r, "error reading conf file %s", opts->conf);
147
goto failed_shutdown;
148
}
149
150
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
151
goto failed_shutdown;
152
}
153
154
- r = rados_ioctx_create(*cluster, pool, io_ctx);
155
+ r = rados_ioctx_create(*cluster, opts->pool, io_ctx);
156
if (r < 0) {
157
- error_setg_errno(errp, -r, "error opening pool %s", pool);
158
+ error_setg_errno(errp, -r, "error opening pool %s", opts->pool);
159
goto failed_shutdown;
160
}
161
162
- qemu_opts_del(opts);
163
return 0;
164
165
failed_shutdown:
166
@@ -XXX,XX +XXX,XX @@ failed_shutdown:
167
g_free(*s_snap);
168
g_free(*s_image_name);
169
failed_opts:
170
- qemu_opts_del(opts);
171
g_free(mon_host);
172
return r;
173
}
174
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
175
Error **errp)
176
{
177
BDRVRBDState *s = bs->opaque;
178
+ BlockdevOptionsRbd *opts = NULL;
179
+ Visitor *v;
180
+ QObject *crumpled = NULL;
181
Error *local_err = NULL;
182
const char *filename;
183
char *keypairs, *secretid;
184
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
185
qdict_del(options, "password-secret");
186
}
187
188
+ /* Convert the remaining options into a QAPI object */
189
+ crumpled = qdict_crumple(options, errp);
190
+ if (crumpled == NULL) {
191
+ r = -EINVAL;
192
+ goto out;
193
+ }
194
+
195
+ v = qobject_input_visitor_new_keyval(crumpled);
196
+ visit_type_BlockdevOptionsRbd(v, NULL, &opts, &local_err);
197
+ visit_free(v);
198
+ qobject_decref(crumpled);
199
+
200
+ if (local_err) {
201
+ error_propagate(errp, local_err);
202
+ r = -EINVAL;
203
+ goto out;
204
+ }
205
+
206
r = qemu_rbd_connect(&s->cluster, &s->io_ctx, &s->snap, &s->image_name,
207
- options, !(flags & BDRV_O_NOCACHE), keypairs, secretid,
208
+ opts, !(flags & BDRV_O_NOCACHE), keypairs, secretid,
209
errp);
210
if (r < 0) {
211
goto out;
212
@@ -XXX,XX +XXX,XX @@ failed_open:
213
g_free(s->image_name);
214
rados_shutdown(s->cluster);
215
out:
216
+ qapi_free_BlockdevOptionsRbd(opts);
217
g_free(keypairs);
218
g_free(secretid);
219
return r;
220
--
57
--
221
2.13.6
58
2.41.0
222
223
diff view generated by jsdifflib
Deleted patch
1
This adds the .bdrv_co_create driver callback to rbd, which enables
2
image creation over QMP.
3
1
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
---
7
qapi/block-core.json | 19 ++++++-
8
block/rbd.c | 150 ++++++++++++++++++++++++++++++++++-----------------
9
2 files changed, 118 insertions(+), 51 deletions(-)
10
11
diff --git a/qapi/block-core.json b/qapi/block-core.json
12
index XXXXXXX..XXXXXXX 100644
13
--- a/qapi/block-core.json
14
+++ b/qapi/block-core.json
15
@@ -XXX,XX +XXX,XX @@
16
'*refcount-bits': 'int' } }
17
18
##
19
+# @BlockdevCreateOptionsRbd:
20
+#
21
+# Driver specific image creation options for rbd/Ceph.
22
+#
23
+# @location Where to store the new image file. This location cannot
24
+# point to a snapshot.
25
+# @size Size of the virtual disk in bytes
26
+# @cluster-size RBD object size
27
+#
28
+# Since: 2.12
29
+##
30
+{ 'struct': 'BlockdevCreateOptionsRbd',
31
+ 'data': { 'location': 'BlockdevOptionsRbd',
32
+ 'size': 'size',
33
+ '*cluster-size' : 'size' } }
34
+
35
+##
36
# @BlockdevCreateNotSupported:
37
#
38
# This is used for all drivers that don't support creating images.
39
@@ -XXX,XX +XXX,XX @@
40
'qed': 'BlockdevCreateNotSupported',
41
'quorum': 'BlockdevCreateNotSupported',
42
'raw': 'BlockdevCreateNotSupported',
43
- 'rbd': 'BlockdevCreateNotSupported',
44
+ 'rbd': 'BlockdevCreateOptionsRbd',
45
'replication': 'BlockdevCreateNotSupported',
46
'sheepdog': 'BlockdevCreateNotSupported',
47
'ssh': 'BlockdevCreateNotSupported',
48
diff --git a/block/rbd.c b/block/rbd.c
49
index XXXXXXX..XXXXXXX 100644
50
--- a/block/rbd.c
51
+++ b/block/rbd.c
52
@@ -XXX,XX +XXX,XX @@ static QemuOptsList runtime_opts = {
53
},
54
};
55
56
-static int coroutine_fn qemu_rbd_co_create_opts(const char *filename,
57
- QemuOpts *opts,
58
- Error **errp)
59
+/* FIXME Deprecate and remove keypairs or make it available in QMP.
60
+ * password_secret should eventually be configurable in opts->location. Support
61
+ * for it in .bdrv_open will make it work here as well. */
62
+static int qemu_rbd_do_create(BlockdevCreateOptions *options,
63
+ const char *keypairs, const char *password_secret,
64
+ Error **errp)
65
{
66
- Error *local_err = NULL;
67
- int64_t bytes = 0;
68
- int64_t objsize;
69
- int obj_order = 0;
70
- const char *pool, *image_name, *conf, *user, *keypairs;
71
- const char *secretid;
72
+ BlockdevCreateOptionsRbd *opts = &options->u.rbd;
73
rados_t cluster;
74
rados_ioctx_t io_ctx;
75
- QDict *options = NULL;
76
- int ret = 0;
77
+ int obj_order = 0;
78
+ int ret;
79
+
80
+ assert(options->driver == BLOCKDEV_DRIVER_RBD);
81
+ if (opts->location->has_snapshot) {
82
+ error_setg(errp, "Can't use snapshot name for image creation");
83
+ return -EINVAL;
84
+ }
85
86
- secretid = qemu_opt_get(opts, "password-secret");
87
+ /* TODO Remove the limitation */
88
+ if (opts->location->has_server) {
89
+ error_setg(errp, "Can't specify server for image creation");
90
+ return -EINVAL;
91
+ }
92
93
- /* Read out options */
94
- bytes = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
95
- BDRV_SECTOR_SIZE);
96
- objsize = qemu_opt_get_size_del(opts, BLOCK_OPT_CLUSTER_SIZE, 0);
97
- if (objsize) {
98
+ if (opts->has_cluster_size) {
99
+ int64_t objsize = opts->cluster_size;
100
if ((objsize - 1) & objsize) { /* not a power of 2? */
101
error_setg(errp, "obj size needs to be power of 2");
102
- ret = -EINVAL;
103
- goto exit;
104
+ return -EINVAL;
105
}
106
if (objsize < 4096) {
107
error_setg(errp, "obj size too small");
108
- ret = -EINVAL;
109
- goto exit;
110
+ return -EINVAL;
111
}
112
obj_order = ctz32(objsize);
113
}
114
115
- options = qdict_new();
116
- qemu_rbd_parse_filename(filename, options, &local_err);
117
- if (local_err) {
118
- ret = -EINVAL;
119
- error_propagate(errp, local_err);
120
- goto exit;
121
- }
122
-
123
- /*
124
- * Caution: while qdict_get_try_str() is fine, getting non-string
125
- * types would require more care. When @options come from -blockdev
126
- * or blockdev_add, its members are typed according to the QAPI
127
- * schema, but when they come from -drive, they're all QString.
128
- */
129
- pool = qdict_get_try_str(options, "pool");
130
- conf = qdict_get_try_str(options, "conf");
131
- user = qdict_get_try_str(options, "user");
132
- image_name = qdict_get_try_str(options, "image");
133
- keypairs = qdict_get_try_str(options, "=keyvalue-pairs");
134
-
135
- ret = rados_create(&cluster, user);
136
+ ret = rados_create(&cluster, opts->location->user);
137
if (ret < 0) {
138
error_setg_errno(errp, -ret, "error initializing");
139
- goto exit;
140
+ return ret;
141
}
142
143
/* try default location when conf=NULL, but ignore failure */
144
- ret = rados_conf_read_file(cluster, conf);
145
- if (conf && ret < 0) {
146
- error_setg_errno(errp, -ret, "error reading conf file %s", conf);
147
+ ret = rados_conf_read_file(cluster, opts->location->conf);
148
+ if (opts->location->conf && ret < 0) {
149
+ error_setg_errno(errp, -ret, "error reading conf file %s",
150
+ opts->location->conf);
151
ret = -EIO;
152
goto shutdown;
153
}
154
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qemu_rbd_co_create_opts(const char *filename,
155
goto shutdown;
156
}
157
158
- if (qemu_rbd_set_auth(cluster, secretid, errp) < 0) {
159
+ if (qemu_rbd_set_auth(cluster, password_secret, errp) < 0) {
160
ret = -EIO;
161
goto shutdown;
162
}
163
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qemu_rbd_co_create_opts(const char *filename,
164
goto shutdown;
165
}
166
167
- ret = rados_ioctx_create(cluster, pool, &io_ctx);
168
+ ret = rados_ioctx_create(cluster, opts->location->pool, &io_ctx);
169
if (ret < 0) {
170
- error_setg_errno(errp, -ret, "error opening pool %s", pool);
171
+ error_setg_errno(errp, -ret, "error opening pool %s",
172
+ opts->location->pool);
173
goto shutdown;
174
}
175
176
- ret = rbd_create(io_ctx, image_name, bytes, &obj_order);
177
+ ret = rbd_create(io_ctx, opts->location->image, opts->size, &obj_order);
178
if (ret < 0) {
179
error_setg_errno(errp, -ret, "error rbd create");
180
}
181
182
rados_ioctx_destroy(io_ctx);
183
184
+ ret = 0;
185
shutdown:
186
rados_shutdown(cluster);
187
+ return ret;
188
+}
189
+
190
+static int qemu_rbd_co_create(BlockdevCreateOptions *options, Error **errp)
191
+{
192
+ return qemu_rbd_do_create(options, NULL, NULL, errp);
193
+}
194
+
195
+static int coroutine_fn qemu_rbd_co_create_opts(const char *filename,
196
+ QemuOpts *opts,
197
+ Error **errp)
198
+{
199
+ BlockdevCreateOptions *create_options;
200
+ BlockdevCreateOptionsRbd *rbd_opts;
201
+ BlockdevOptionsRbd *loc;
202
+ Error *local_err = NULL;
203
+ const char *keypairs, *password_secret;
204
+ QDict *options = NULL;
205
+ int ret = 0;
206
+
207
+ create_options = g_new0(BlockdevCreateOptions, 1);
208
+ create_options->driver = BLOCKDEV_DRIVER_RBD;
209
+ rbd_opts = &create_options->u.rbd;
210
+
211
+ rbd_opts->location = g_new0(BlockdevOptionsRbd, 1);
212
+
213
+ password_secret = qemu_opt_get(opts, "password-secret");
214
+
215
+ /* Read out options */
216
+ rbd_opts->size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
217
+ BDRV_SECTOR_SIZE);
218
+ rbd_opts->cluster_size = qemu_opt_get_size_del(opts,
219
+ BLOCK_OPT_CLUSTER_SIZE, 0);
220
+ rbd_opts->has_cluster_size = (rbd_opts->cluster_size != 0);
221
+
222
+ options = qdict_new();
223
+ qemu_rbd_parse_filename(filename, options, &local_err);
224
+ if (local_err) {
225
+ ret = -EINVAL;
226
+ error_propagate(errp, local_err);
227
+ goto exit;
228
+ }
229
+
230
+ /*
231
+ * Caution: while qdict_get_try_str() is fine, getting non-string
232
+ * types would require more care. When @options come from -blockdev
233
+ * or blockdev_add, its members are typed according to the QAPI
234
+ * schema, but when they come from -drive, they're all QString.
235
+ */
236
+ loc = rbd_opts->location;
237
+ loc->pool = g_strdup(qdict_get_try_str(options, "pool"));
238
+ loc->conf = g_strdup(qdict_get_try_str(options, "conf"));
239
+ loc->has_conf = !!loc->conf;
240
+ loc->user = g_strdup(qdict_get_try_str(options, "user"));
241
+ loc->has_user = !!loc->user;
242
+ loc->image = g_strdup(qdict_get_try_str(options, "image"));
243
+ keypairs = qdict_get_try_str(options, "=keyvalue-pairs");
244
+
245
+ ret = qemu_rbd_do_create(create_options, keypairs, password_secret, errp);
246
+ if (ret < 0) {
247
+ goto exit;
248
+ }
249
250
exit:
251
QDECREF(options);
252
+ qapi_free_BlockdevCreateOptions(create_options);
253
return ret;
254
}
255
256
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_rbd = {
257
.bdrv_file_open = qemu_rbd_open,
258
.bdrv_close = qemu_rbd_close,
259
.bdrv_reopen_prepare = qemu_rbd_reopen_prepare,
260
+ .bdrv_co_create = qemu_rbd_co_create,
261
.bdrv_co_create_opts = qemu_rbd_co_create_opts,
262
.bdrv_has_zero_init = bdrv_has_zero_init_1,
263
.bdrv_get_info = qemu_rbd_getinfo,
264
--
265
2.13.6
266
267
diff view generated by jsdifflib
Deleted patch
1
This is almost exactly the same code. The differences are that
2
qemu_rbd_connect() supports BlockdevOptionsRbd.server and that the cache
3
mode is set explicitly.
4
1
5
Supporting 'server' is a welcome new feature for image creation.
6
Caching is disabled by default, so leave it that way.
7
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
---
11
block/rbd.c | 54 ++++++++++--------------------------------------------
12
1 file changed, 10 insertions(+), 44 deletions(-)
13
14
diff --git a/block/rbd.c b/block/rbd.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/block/rbd.c
17
+++ b/block/rbd.c
18
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVRBDState {
19
char *snap;
20
} BDRVRBDState;
21
22
+static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
23
+ BlockdevOptionsRbd *opts, bool cache,
24
+ const char *keypairs, const char *secretid,
25
+ Error **errp);
26
+
27
static char *qemu_rbd_next_tok(char *src, char delim, char **p)
28
{
29
char *end;
30
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_do_create(BlockdevCreateOptions *options,
31
return -EINVAL;
32
}
33
34
- /* TODO Remove the limitation */
35
- if (opts->location->has_server) {
36
- error_setg(errp, "Can't specify server for image creation");
37
- return -EINVAL;
38
- }
39
-
40
if (opts->has_cluster_size) {
41
int64_t objsize = opts->cluster_size;
42
if ((objsize - 1) & objsize) { /* not a power of 2? */
43
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_do_create(BlockdevCreateOptions *options,
44
obj_order = ctz32(objsize);
45
}
46
47
- ret = rados_create(&cluster, opts->location->user);
48
+ ret = qemu_rbd_connect(&cluster, &io_ctx, opts->location, false, keypairs,
49
+ password_secret, errp);
50
if (ret < 0) {
51
- error_setg_errno(errp, -ret, "error initializing");
52
return ret;
53
}
54
55
- /* try default location when conf=NULL, but ignore failure */
56
- ret = rados_conf_read_file(cluster, opts->location->conf);
57
- if (opts->location->conf && ret < 0) {
58
- error_setg_errno(errp, -ret, "error reading conf file %s",
59
- opts->location->conf);
60
- ret = -EIO;
61
- goto shutdown;
62
- }
63
-
64
- ret = qemu_rbd_set_keypairs(cluster, keypairs, errp);
65
- if (ret < 0) {
66
- ret = -EIO;
67
- goto shutdown;
68
- }
69
-
70
- if (qemu_rbd_set_auth(cluster, password_secret, errp) < 0) {
71
- ret = -EIO;
72
- goto shutdown;
73
- }
74
-
75
- ret = rados_connect(cluster);
76
- if (ret < 0) {
77
- error_setg_errno(errp, -ret, "error connecting");
78
- goto shutdown;
79
- }
80
-
81
- ret = rados_ioctx_create(cluster, opts->location->pool, &io_ctx);
82
- if (ret < 0) {
83
- error_setg_errno(errp, -ret, "error opening pool %s",
84
- opts->location->pool);
85
- goto shutdown;
86
- }
87
-
88
ret = rbd_create(io_ctx, opts->location->image, opts->size, &obj_order);
89
if (ret < 0) {
90
error_setg_errno(errp, -ret, "error rbd create");
91
+ goto out;
92
}
93
94
- rados_ioctx_destroy(io_ctx);
95
-
96
ret = 0;
97
-shutdown:
98
+out:
99
+ rados_ioctx_destroy(io_ctx);
100
rados_shutdown(cluster);
101
return ret;
102
}
103
--
104
2.13.6
105
106
diff view generated by jsdifflib
1
The "redundancy" option for Sheepdog image creation is currently a
1
Almost all functions that access the child links already take the graph
2
string that can encode one or two integers depending on its format,
2
lock now. Add locking to the remaining users and finally annotate the
3
which at the same time implicitly selects a mode.
3
struct field itself as protected by the graph lock.
4
5
This patch turns it into a QAPI union and converts the string into such
6
a QAPI object before interpreting the values.
7
4
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Message-ID: <20230929145157.45443-22-kwolf@redhat.com>
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
9
---
11
qapi/block-core.json | 45 +++++++++++++++++++++++++
10
include/block/block_int-common.h | 4 ++--
12
block/sheepdog.c | 94 +++++++++++++++++++++++++++++++++++++---------------
11
block.c | 2 ++
13
2 files changed, 112 insertions(+), 27 deletions(-)
12
block/replication.c | 3 ++-
13
tests/unit/test-bdrv-drain.c | 4 ++++
14
4 files changed, 10 insertions(+), 3 deletions(-)
14
15
15
diff --git a/qapi/block-core.json b/qapi/block-core.json
16
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
16
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
17
--- a/qapi/block-core.json
18
--- a/include/block/block_int-common.h
18
+++ b/qapi/block-core.json
19
+++ b/include/block/block_int-common.h
19
@@ -XXX,XX +XXX,XX @@
20
@@ -XXX,XX +XXX,XX @@ struct BdrvChild {
20
'*cluster-size' : 'size' } }
21
*/
21
22
bool quiesced_parent;
22
##
23
23
+# @SheepdogRedundancyType:
24
- QLIST_ENTRY(BdrvChild) next;
24
+#
25
+ QLIST_ENTRY(BdrvChild GRAPH_RDLOCK_PTR) next;
25
+# @full Create a fully replicated vdi with x copies
26
QLIST_ENTRY(BdrvChild GRAPH_RDLOCK_PTR) next_parent;
26
+# @erasure-coded Create an erasure coded vdi with x data strips and
27
};
27
+# y parity strips
28
28
+#
29
@@ -XXX,XX +XXX,XX @@ struct BlockDriverState {
29
+# Since: 2.12
30
* See also comment in include/block/block.h, to learn how backing and file
30
+##
31
* are connected with BdrvChildRole.
31
+{ 'enum': 'SheepdogRedundancyType',
32
*/
32
+ 'data': [ 'full', 'erasure-coded' ] }
33
- QLIST_HEAD(, BdrvChild) children;
34
+ QLIST_HEAD(, BdrvChild GRAPH_RDLOCK_PTR) children;
35
BdrvChild *backing;
36
BdrvChild *file;
37
38
diff --git a/block.c b/block.c
39
index XXXXXXX..XXXXXXX 100644
40
--- a/block.c
41
+++ b/block.c
42
@@ -XXX,XX +XXX,XX @@ static void bdrv_child_free(BdrvChild *child)
43
{
44
assert(!child->bs);
45
GLOBAL_STATE_CODE();
46
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
33
+
47
+
34
+##
48
assert(!child->next.le_prev); /* not in children list */
35
+# @SheepdogRedundancyFull:
49
36
+#
50
g_free(child->name);
37
+# @copies Number of copies to use (between 1 and 31)
51
diff --git a/block/replication.c b/block/replication.c
38
+#
39
+# Since: 2.12
40
+##
41
+{ 'struct': 'SheepdogRedundancyFull',
42
+ 'data': { 'copies': 'int' }}
43
+
44
+##
45
+# @SheepdogRedundancyErasureCoded:
46
+#
47
+# @data-strips Number of data strips to use (one of {2,4,8,16})
48
+# @parity-strips Number of parity strips to use (between 1 and 15)
49
+#
50
+# Since: 2.12
51
+##
52
+{ 'struct': 'SheepdogRedundancyErasureCoded',
53
+ 'data': { 'data-strips': 'int',
54
+ 'parity-strips': 'int' }}
55
+
56
+##
57
+# @SheepdogRedundancy:
58
+#
59
+# Since: 2.12
60
+##
61
+{ 'union': 'SheepdogRedundancy',
62
+ 'base': { 'type': 'SheepdogRedundancyType' },
63
+ 'discriminator': 'type',
64
+ 'data': { 'full': 'SheepdogRedundancyFull',
65
+ 'erasure-coded': 'SheepdogRedundancyErasureCoded' } }
66
+
67
+##
68
# @BlockdevCreateNotSupported:
69
#
70
# This is used for all drivers that don't support creating images.
71
diff --git a/block/sheepdog.c b/block/sheepdog.c
72
index XXXXXXX..XXXXXXX 100644
52
index XXXXXXX..XXXXXXX 100644
73
--- a/block/sheepdog.c
53
--- a/block/replication.c
74
+++ b/block/sheepdog.c
54
+++ b/block/replication.c
75
@@ -XXX,XX +XXX,XX @@ out_with_err_set:
55
@@ -XXX,XX +XXX,XX @@ static void backup_job_completed(void *opaque, int ret)
76
return ret;
56
backup_job_cleanup(bs);
77
}
57
}
78
58
79
+static int parse_redundancy(BDRVSheepdogState *s, SheepdogRedundancy *opt)
59
-static bool check_top_bs(BlockDriverState *top_bs, BlockDriverState *bs)
80
+{
60
+static bool GRAPH_RDLOCK
81
+ struct SheepdogInode *inode = &s->inode;
61
+check_top_bs(BlockDriverState *top_bs, BlockDriverState *bs)
82
+
83
+ switch (opt->type) {
84
+ case SHEEPDOG_REDUNDANCY_TYPE_FULL:
85
+ if (opt->u.full.copies > SD_MAX_COPIES || opt->u.full.copies < 1) {
86
+ return -EINVAL;
87
+ }
88
+ inode->copy_policy = 0;
89
+ inode->nr_copies = opt->u.full.copies;
90
+ return 0;
91
+
92
+ case SHEEPDOG_REDUNDANCY_TYPE_ERASURE_CODED:
93
+ {
94
+ int64_t copy = opt->u.erasure_coded.data_strips;
95
+ int64_t parity = opt->u.erasure_coded.parity_strips;
96
+
97
+ if (copy != 2 && copy != 4 && copy != 8 && copy != 16) {
98
+ return -EINVAL;
99
+ }
100
+
101
+ if (parity >= SD_EC_MAX_STRIP || parity < 1) {
102
+ return -EINVAL;
103
+ }
104
+
105
+ /*
106
+ * 4 bits for parity and 4 bits for data.
107
+ * We have to compress upper data bits because it can't represent 16
108
+ */
109
+ inode->copy_policy = ((copy / 2) << 4) + parity;
110
+ inode->nr_copies = copy + parity;
111
+ return 0;
112
+ }
113
+
114
+ default:
115
+ g_assert_not_reached();
116
+ }
117
+
118
+ return -EINVAL;
119
+}
120
+
121
/*
122
* Sheepdog support two kinds of redundancy, full replication and erasure
123
* coding.
124
@@ -XXX,XX +XXX,XX @@ out_with_err_set:
125
* # create a erasure coded vdi with x data strips and y parity strips
126
* -o redundancy=x:y (x must be one of {2,4,8,16} and 1 <= y < SD_EC_MAX_STRIP)
127
*/
128
-static int parse_redundancy(BDRVSheepdogState *s, const char *opt)
129
+static int parse_redundancy_str(BDRVSheepdogState *s, const char *opt)
130
{
62
{
131
- struct SheepdogInode *inode = &s->inode;
63
BdrvChild *child;
132
+ struct SheepdogRedundancy redundancy;
64
133
const char *n1, *n2;
65
diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c
134
long copy, parity;
66
index XXXXXXX..XXXXXXX 100644
135
char p[10];
67
--- a/tests/unit/test-bdrv-drain.c
136
+ int ret;
68
+++ b/tests/unit/test-bdrv-drain.c
137
69
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn test_co_delete_by_drain(void *opaque)
138
pstrcpy(p, sizeof(p), opt);
70
blk_co_unref(blk);
139
n1 = strtok(p, ":");
71
} else {
140
@@ -XXX,XX +XXX,XX @@ static int parse_redundancy(BDRVSheepdogState *s, const char *opt)
72
BdrvChild *c, *next_c;
141
return -EINVAL;
73
+ bdrv_graph_co_rdlock();
74
QLIST_FOREACH_SAFE(c, &bs->children, next, next_c) {
75
+ bdrv_graph_co_rdunlock();
76
bdrv_co_unref_child(bs, c);
77
+ bdrv_graph_co_rdlock();
78
}
79
+ bdrv_graph_co_rdunlock();
142
}
80
}
143
81
144
- copy = strtol(n1, NULL, 10);
82
dbdd->done = true;
145
- /* FIXME fix error checking by switching to qemu_strtol() */
146
- if (copy > SD_MAX_COPIES || copy < 1) {
147
- return -EINVAL;
148
- }
149
- if (!n2) {
150
- inode->copy_policy = 0;
151
- inode->nr_copies = copy;
152
- return 0;
153
+ ret = qemu_strtol(n1, NULL, 10, &copy);
154
+ if (ret < 0) {
155
+ return ret;
156
}
157
158
- if (copy != 2 && copy != 4 && copy != 8 && copy != 16) {
159
- return -EINVAL;
160
- }
161
+ if (!n2) {
162
+ redundancy = (SheepdogRedundancy) {
163
+ .type = SHEEPDOG_REDUNDANCY_TYPE_FULL,
164
+ .u.full.copies = copy,
165
+ };
166
+ } else {
167
+ ret = qemu_strtol(n2, NULL, 10, &parity);
168
+ if (ret < 0) {
169
+ return ret;
170
+ }
171
172
- parity = strtol(n2, NULL, 10);
173
- /* FIXME fix error checking by switching to qemu_strtol() */
174
- if (parity >= SD_EC_MAX_STRIP || parity < 1) {
175
- return -EINVAL;
176
+ redundancy = (SheepdogRedundancy) {
177
+ .type = SHEEPDOG_REDUNDANCY_TYPE_ERASURE_CODED,
178
+ .u.erasure_coded = {
179
+ .data_strips = copy,
180
+ .parity_strips = parity,
181
+ },
182
+ };
183
}
184
185
- /*
186
- * 4 bits for parity and 4 bits for data.
187
- * We have to compress upper data bits because it can't represent 16
188
- */
189
- inode->copy_policy = ((copy / 2) << 4) + parity;
190
- inode->nr_copies = copy + parity;
191
-
192
- return 0;
193
+ return parse_redundancy(s, &redundancy);
194
}
195
196
static int parse_block_size_shift(BDRVSheepdogState *s, QemuOpts *opt)
197
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn sd_co_create_opts(const char *filename, QemuOpts *opts,
198
g_free(buf);
199
buf = qemu_opt_get_del(opts, BLOCK_OPT_REDUNDANCY);
200
if (buf) {
201
- ret = parse_redundancy(s, buf);
202
+ ret = parse_redundancy_str(s, buf);
203
if (ret < 0) {
204
error_setg(errp, "Invalid redundancy mode: '%s'", buf);
205
goto out;
206
--
83
--
207
2.13.6
84
2.41.0
208
209
diff view generated by jsdifflib
1
Create a BlockdevOptionsSsh object in connect_to_ssh() and take the
1
bdrv_graph_wrlock() can't run in a coroutine (because it polls) and
2
options from there. 'host_key_check' is still processed separately
2
requires holding the BQL. We already have GLOBAL_STATE_CODE() to assert
3
because it's not in the schema yet.
3
the latter. Assert the former as well and add a no_coroutine_fn marker.
4
4
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Message-ID: <20230929145157.45443-23-kwolf@redhat.com>
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
9
---
8
block/ssh.c | 137 +++++++++++++++++++++++++++---------------------------------
10
include/block/graph-lock.h | 3 ++-
9
1 file changed, 62 insertions(+), 75 deletions(-)
11
block/graph-lock.c | 3 ++-
12
2 files changed, 4 insertions(+), 2 deletions(-)
10
13
11
diff --git a/block/ssh.c b/block/ssh.c
14
diff --git a/include/block/graph-lock.h b/include/block/graph-lock.h
12
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
13
--- a/block/ssh.c
16
--- a/include/block/graph-lock.h
14
+++ b/block/ssh.c
17
+++ b/include/block/graph-lock.h
15
@@ -XXX,XX +XXX,XX @@
18
@@ -XXX,XX +XXX,XX @@ void unregister_aiocontext(AioContext *ctx);
16
#include "qemu/sockets.h"
19
* This function polls. Callers must not hold the lock of any AioContext other
17
#include "qemu/uri.h"
20
* than the current one and the one of @bs.
18
#include "qapi/qapi-visit-sockets.h"
21
*/
19
+#include "qapi/qapi-visit-block-core.h"
22
-void bdrv_graph_wrlock(BlockDriverState *bs) TSA_ACQUIRE(graph_lock) TSA_NO_TSA;
20
#include "qapi/qmp/qdict.h"
23
+void no_coroutine_fn TSA_ACQUIRE(graph_lock) TSA_NO_TSA
21
#include "qapi/qmp/qstring.h"
24
+bdrv_graph_wrlock(BlockDriverState *bs);
22
#include "qapi/qobject-input-visitor.h"
25
23
@@ -XXX,XX +XXX,XX @@ static QemuOptsList ssh_runtime_opts = {
26
/*
24
.type = QEMU_OPT_NUMBER,
27
* bdrv_graph_wrunlock:
25
.help = "Port to connect to",
28
diff --git a/block/graph-lock.c b/block/graph-lock.c
26
},
29
index XXXXXXX..XXXXXXX 100644
27
- {
30
--- a/block/graph-lock.c
28
- .name = "path",
31
+++ b/block/graph-lock.c
29
- .type = QEMU_OPT_STRING,
32
@@ -XXX,XX +XXX,XX @@ static uint32_t reader_count(void)
30
- .help = "Path of the image on the host",
33
return rd;
31
- },
32
- {
33
- .name = "user",
34
- .type = QEMU_OPT_STRING,
35
- .help = "User as which to connect",
36
- },
37
- {
38
- .name = "host_key_check",
39
- .type = QEMU_OPT_STRING,
40
- .help = "Defines how and what to check the host key against",
41
- },
42
{ /* end of list */ }
43
},
44
};
45
@@ -XXX,XX +XXX,XX @@ static bool ssh_process_legacy_socket_options(QDict *output_opts,
46
return true;
47
}
34
}
48
35
49
-static InetSocketAddress *ssh_config(QDict *options, Error **errp)
36
-void bdrv_graph_wrlock(BlockDriverState *bs)
50
+static BlockdevOptionsSsh *ssh_parse_options(QDict *options, Error **errp)
37
+void no_coroutine_fn bdrv_graph_wrlock(BlockDriverState *bs)
51
{
38
{
52
- InetSocketAddress *inet = NULL;
39
AioContext *ctx = NULL;
53
- QDict *addr = NULL;
40
54
- QObject *crumpled_addr = NULL;
41
GLOBAL_STATE_CODE();
55
- Visitor *iv = NULL;
42
assert(!qatomic_read(&has_writer));
56
- Error *local_error = NULL;
43
+ assert(!qemu_in_coroutine());
57
-
58
- qdict_extract_subqdict(options, &addr, "server.");
59
- if (!qdict_size(addr)) {
60
- error_setg(errp, "SSH server address missing");
61
- goto out;
62
+ BlockdevOptionsSsh *result = NULL;
63
+ QemuOpts *opts = NULL;
64
+ Error *local_err = NULL;
65
+ QObject *crumpled;
66
+ const QDictEntry *e;
67
+ Visitor *v;
68
+
69
+ /* Translate legacy options */
70
+ opts = qemu_opts_create(&ssh_runtime_opts, NULL, 0, &error_abort);
71
+ qemu_opts_absorb_qdict(opts, options, &local_err);
72
+ if (local_err) {
73
+ error_propagate(errp, local_err);
74
+ goto fail;
75
}
76
77
- crumpled_addr = qdict_crumple(addr, errp);
78
- if (!crumpled_addr) {
79
- goto out;
80
+ if (!ssh_process_legacy_socket_options(options, opts, errp)) {
81
+ goto fail;
82
+ }
83
+
84
+ /* Create the QAPI object */
85
+ crumpled = qdict_crumple(options, errp);
86
+ if (crumpled == NULL) {
87
+ goto fail;
88
}
89
44
90
/*
45
/*
91
@@ -XXX,XX +XXX,XX @@ static InetSocketAddress *ssh_config(QDict *options, Error **errp)
46
* Release only non-mainloop AioContext. The mainloop often relies on the
92
* but when they come from -drive, they're all QString. The
93
* visitor expects the former.
94
*/
95
- iv = qobject_input_visitor_new(crumpled_addr);
96
- visit_type_InetSocketAddress(iv, NULL, &inet, &local_error);
97
- if (local_error) {
98
- error_propagate(errp, local_error);
99
- goto out;
100
+ v = qobject_input_visitor_new(crumpled);
101
+ visit_type_BlockdevOptionsSsh(v, NULL, &result, &local_err);
102
+ visit_free(v);
103
+ qobject_decref(crumpled);
104
+
105
+ if (local_err) {
106
+ error_propagate(errp, local_err);
107
+ goto fail;
108
}
109
110
-out:
111
- QDECREF(addr);
112
- qobject_decref(crumpled_addr);
113
- visit_free(iv);
114
- return inet;
115
+ /* Remove the processed options from the QDict (the visitor processes
116
+ * _all_ options in the QDict) */
117
+ while ((e = qdict_first(options))) {
118
+ qdict_del(options, e->key);
119
+ }
120
+
121
+fail:
122
+ qemu_opts_del(opts);
123
+ return result;
124
}
125
126
static int connect_to_ssh(BDRVSSHState *s, QDict *options,
127
int ssh_flags, int creat_mode, Error **errp)
128
{
129
+ BlockdevOptionsSsh *opts;
130
int r, ret;
131
- QemuOpts *opts = NULL;
132
- Error *local_err = NULL;
133
- const char *user, *path, *host_key_check;
134
+ const char *user, *host_key_check;
135
long port = 0;
136
137
- opts = qemu_opts_create(&ssh_runtime_opts, NULL, 0, &error_abort);
138
- qemu_opts_absorb_qdict(opts, options, &local_err);
139
- if (local_err) {
140
- ret = -EINVAL;
141
- error_propagate(errp, local_err);
142
- goto err;
143
- }
144
-
145
- if (!ssh_process_legacy_socket_options(options, opts, errp)) {
146
- ret = -EINVAL;
147
- goto err;
148
+ host_key_check = qdict_get_try_str(options, "host_key_check");
149
+ if (!host_key_check) {
150
+ host_key_check = "yes";
151
+ } else {
152
+ qdict_del(options, "host_key_check");
153
}
154
155
- path = qemu_opt_get(opts, "path");
156
- if (!path) {
157
- ret = -EINVAL;
158
- error_setg(errp, "No path was specified");
159
- goto err;
160
+ opts = ssh_parse_options(options, errp);
161
+ if (opts == NULL) {
162
+ return -EINVAL;
163
}
164
165
- user = qemu_opt_get(opts, "user");
166
- if (!user) {
167
+ if (opts->has_user) {
168
+ user = opts->user;
169
+ } else {
170
user = g_get_user_name();
171
if (!user) {
172
error_setg_errno(errp, errno, "Can't get user name");
173
@@ -XXX,XX +XXX,XX @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
174
}
175
}
176
177
- host_key_check = qemu_opt_get(opts, "host_key_check");
178
- if (!host_key_check) {
179
- host_key_check = "yes";
180
- }
181
-
182
/* Pop the config into our state object, Exit if invalid */
183
- s->inet = ssh_config(options, errp);
184
- if (!s->inet) {
185
- ret = -EINVAL;
186
- goto err;
187
- }
188
+ s->inet = opts->server;
189
+ opts->server = NULL;
190
191
if (qemu_strtol(s->inet->port, NULL, 10, &port) < 0) {
192
error_setg(errp, "Use only numeric port value");
193
@@ -XXX,XX +XXX,XX @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
194
195
/* Open the remote file. */
196
DPRINTF("opening file %s flags=0x%x creat_mode=0%o",
197
- path, ssh_flags, creat_mode);
198
- s->sftp_handle = libssh2_sftp_open(s->sftp, path, ssh_flags, creat_mode);
199
+ opts->path, ssh_flags, creat_mode);
200
+ s->sftp_handle = libssh2_sftp_open(s->sftp, opts->path, ssh_flags,
201
+ creat_mode);
202
if (!s->sftp_handle) {
203
- session_error_setg(errp, s, "failed to open remote file '%s'", path);
204
+ session_error_setg(errp, s, "failed to open remote file '%s'",
205
+ opts->path);
206
ret = -EINVAL;
207
goto err;
208
}
209
210
- qemu_opts_del(opts);
211
+ qapi_free_BlockdevOptionsSsh(opts);
212
213
r = libssh2_sftp_fstat(s->sftp_handle, &s->attrs);
214
if (r < 0) {
215
@@ -XXX,XX +XXX,XX @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
216
}
217
s->session = NULL;
218
219
- qemu_opts_del(opts);
220
+ qapi_free_BlockdevOptionsSsh(opts);
221
222
return ret;
223
}
224
--
47
--
225
2.13.6
48
2.41.0
226
227
diff view generated by jsdifflib
Deleted patch
1
If bdrv_truncate() is called, but the requested size is the same as
2
before, don't call posix_fallocate(), which returns -EINVAL for length
3
zero and would therefore make bdrv_truncate() fail.
4
1
5
The problem can be triggered by creating a zero-sized raw image with
6
'falloc' preallocation mode.
7
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Reviewed-by: Eric Blake <eblake@redhat.com>
11
---
12
block/file-posix.c | 14 +++++++++-----
13
1 file changed, 9 insertions(+), 5 deletions(-)
14
15
diff --git a/block/file-posix.c b/block/file-posix.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/block/file-posix.c
18
+++ b/block/file-posix.c
19
@@ -XXX,XX +XXX,XX @@ static int raw_regular_truncate(int fd, int64_t offset, PreallocMode prealloc,
20
* file systems that do not support fallocate(), trying to check if a
21
* block is allocated before allocating it, so don't do that here.
22
*/
23
- result = -posix_fallocate(fd, current_length, offset - current_length);
24
- if (result != 0) {
25
- /* posix_fallocate() doesn't set errno. */
26
- error_setg_errno(errp, -result,
27
- "Could not preallocate new data");
28
+ if (offset != current_length) {
29
+ result = -posix_fallocate(fd, current_length, offset - current_length);
30
+ if (result != 0) {
31
+ /* posix_fallocate() doesn't set errno. */
32
+ error_setg_errno(errp, -result,
33
+ "Could not preallocate new data");
34
+ }
35
+ } else {
36
+ result = 0;
37
}
38
goto out;
39
#endif
40
--
41
2.13.6
42
43
diff view generated by jsdifflib
Deleted patch
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Reviewed-by: Max Reitz <mreitz@redhat.com>
3
---
4
tests/qemu-iotests/206 | 436 +++++++++++++++++++++++++++++++++++++++++++++
5
tests/qemu-iotests/206.out | 209 ++++++++++++++++++++++
6
tests/qemu-iotests/group | 1 +
7
3 files changed, 646 insertions(+)
8
create mode 100755 tests/qemu-iotests/206
9
create mode 100644 tests/qemu-iotests/206.out
10
1
11
diff --git a/tests/qemu-iotests/206 b/tests/qemu-iotests/206
12
new file mode 100755
13
index XXXXXXX..XXXXXXX
14
--- /dev/null
15
+++ b/tests/qemu-iotests/206
16
@@ -XXX,XX +XXX,XX @@
17
+#!/bin/bash
18
+#
19
+# Test qcow2 and file image creation
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
+
37
+# creator
38
+owner=kwolf@redhat.com
39
+
40
+seq=`basename $0`
41
+echo "QA output created by $seq"
42
+
43
+here=`pwd`
44
+status=1    # failure is the default!
45
+
46
+# get standard environment, filters and checks
47
+. ./common.rc
48
+. ./common.filter
49
+
50
+_supported_fmt qcow2
51
+_supported_proto file
52
+_supported_os Linux
53
+
54
+function do_run_qemu()
55
+{
56
+ echo Testing: "$@"
57
+ $QEMU -nographic -qmp stdio -serial none "$@"
58
+ echo
59
+}
60
+
61
+function run_qemu()
62
+{
63
+ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \
64
+ | _filter_qemu | _filter_imgfmt \
65
+ | _filter_actual_image_size
66
+}
67
+
68
+echo
69
+echo "=== Successful image creation (defaults) ==="
70
+echo
71
+
72
+size=$((128 * 1024 * 1024))
73
+
74
+run_qemu <<EOF
75
+{ "execute": "qmp_capabilities" }
76
+{ "execute": "x-blockdev-create",
77
+ "arguments": {
78
+ "driver": "file",
79
+ "filename": "$TEST_IMG",
80
+ "size": 0
81
+ }
82
+}
83
+{ "execute": "blockdev-add",
84
+ "arguments": {
85
+ "driver": "file",
86
+ "node-name": "imgfile",
87
+ "filename": "$TEST_IMG"
88
+ }
89
+}
90
+{ "execute": "x-blockdev-create",
91
+ "arguments": {
92
+ "driver": "$IMGFMT",
93
+ "file": "imgfile",
94
+ "size": $size
95
+ }
96
+}
97
+{ "execute": "quit" }
98
+EOF
99
+
100
+_img_info --format-specific
101
+
102
+echo
103
+echo "=== Successful image creation (inline blockdev-add, explicit defaults) ==="
104
+echo
105
+
106
+# Choose a different size to show that we got a new image
107
+size=$((64 * 1024 * 1024))
108
+
109
+run_qemu <<EOF
110
+{ "execute": "qmp_capabilities" }
111
+{ "execute": "x-blockdev-create",
112
+ "arguments": {
113
+ "driver": "file",
114
+ "filename": "$TEST_IMG",
115
+ "size": 0,
116
+ "preallocation": "off",
117
+ "nocow": false
118
+ }
119
+}
120
+{ "execute": "x-blockdev-create",
121
+ "arguments": {
122
+ "driver": "$IMGFMT",
123
+ "file": {
124
+ "driver": "file",
125
+ "filename": "$TEST_IMG"
126
+ },
127
+ "size": $size,
128
+ "version": "v3",
129
+ "cluster-size": 65536,
130
+ "preallocation": "off",
131
+ "lazy-refcounts": false,
132
+ "refcount-bits": 16
133
+ }
134
+}
135
+{ "execute": "quit" }
136
+EOF
137
+
138
+_img_info --format-specific
139
+
140
+echo
141
+echo "=== Successful image creation (v3 non-default options) ==="
142
+echo
143
+
144
+# Choose a different size to show that we got a new image
145
+size=$((32 * 1024 * 1024))
146
+
147
+run_qemu <<EOF
148
+{ "execute": "qmp_capabilities" }
149
+{ "execute": "x-blockdev-create",
150
+ "arguments": {
151
+ "driver": "file",
152
+ "filename": "$TEST_IMG",
153
+ "size": 0,
154
+ "preallocation": "falloc",
155
+ "nocow": true
156
+ }
157
+}
158
+{ "execute": "x-blockdev-create",
159
+ "arguments": {
160
+ "driver": "$IMGFMT",
161
+ "file": {
162
+ "driver": "file",
163
+ "filename": "$TEST_IMG"
164
+ },
165
+ "size": $size,
166
+ "version": "v3",
167
+ "cluster-size": 2097152,
168
+ "preallocation": "metadata",
169
+ "lazy-refcounts": true,
170
+ "refcount-bits": 1
171
+ }
172
+}
173
+{ "execute": "quit" }
174
+EOF
175
+
176
+_img_info --format-specific
177
+
178
+echo
179
+echo "=== Successful image creation (v2 non-default options) ==="
180
+echo
181
+
182
+mv $TEST_IMG $TEST_IMG.base
183
+
184
+run_qemu <<EOF
185
+{ "execute": "qmp_capabilities" }
186
+{ "execute": "x-blockdev-create",
187
+ "arguments": {
188
+ "driver": "file",
189
+ "filename": "$TEST_IMG",
190
+ "size": 0
191
+ }
192
+}
193
+{ "execute": "x-blockdev-create",
194
+ "arguments": {
195
+ "driver": "$IMGFMT",
196
+ "file": {
197
+ "driver": "file",
198
+ "filename": "$TEST_IMG"
199
+ },
200
+ "size": $size,
201
+ "backing-file": "$TEST_IMG.base",
202
+ "backing-fmt": "qcow2",
203
+ "version": "v2",
204
+ "cluster-size": 512
205
+ }
206
+}
207
+{ "execute": "quit" }
208
+EOF
209
+
210
+_img_info --format-specific
211
+
212
+echo
213
+echo "=== Successful image creation (encrypted) ==="
214
+echo
215
+
216
+run_qemu -object secret,id=keysec0,data="foo" <<EOF
217
+{ "execute": "qmp_capabilities" }
218
+{ "execute": "x-blockdev-create",
219
+ "arguments": {
220
+ "driver": "$IMGFMT",
221
+ "file": {
222
+ "driver": "file",
223
+ "filename": "$TEST_IMG"
224
+ },
225
+ "size": $size,
226
+ "encrypt": {
227
+ "format": "luks",
228
+ "key-secret": "keysec0",
229
+ "cipher-alg": "twofish-128",
230
+ "cipher-mode": "ctr",
231
+ "ivgen-alg": "plain64",
232
+ "ivgen-hash-alg": "md5",
233
+ "hash-alg": "sha1",
234
+ "iter-time": 10
235
+ }
236
+ }
237
+}
238
+{ "execute": "quit" }
239
+EOF
240
+
241
+_img_info --format-specific | _filter_img_info --format-specific
242
+
243
+echo
244
+echo "=== Invalid BlockdevRef ==="
245
+echo
246
+
247
+run_qemu <<EOF
248
+{ "execute": "qmp_capabilities" }
249
+{ "execute": "x-blockdev-create",
250
+ "arguments": {
251
+ "driver": "$IMGFMT",
252
+ "file": "this doesn't exist",
253
+ "size": $size
254
+ }
255
+}
256
+{ "execute": "quit" }
257
+EOF
258
+
259
+
260
+echo
261
+echo "=== Invalid sizes ==="
262
+echo
263
+
264
+# TODO Negative image sizes aren't handled correctly, but this is a problem
265
+# with QAPI's implementation of the 'size' type and affects other commands as
266
+# well. Once this is fixed, we may want to add a test case here.
267
+
268
+# 1. Misaligned image size
269
+# 2. 2^64 - 512
270
+# 3. 2^63 = 8 EB (qemu-img enforces image sizes less than this)
271
+# 4. 2^63 - 512 (generally valid, but qcow2 can't handle images this size)
272
+
273
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
274
+{ "execute": "qmp_capabilities" }
275
+{ "execute": "x-blockdev-create",
276
+ "arguments": {
277
+ "driver": "$IMGFMT",
278
+ "file": "node0",
279
+ "size": 1234
280
+ }
281
+}
282
+{ "execute": "x-blockdev-create",
283
+ "arguments": {
284
+ "driver": "$IMGFMT",
285
+ "file": "node0",
286
+ "size": 18446744073709551104
287
+ }
288
+}
289
+{ "execute": "x-blockdev-create",
290
+ "arguments": {
291
+ "driver": "$IMGFMT",
292
+ "file": "node0",
293
+ "size": 9223372036854775808
294
+ }
295
+}
296
+{ "execute": "x-blockdev-create",
297
+ "arguments": {
298
+ "driver": "$IMGFMT",
299
+ "file": "node0",
300
+ "size": 9223372036854775296
301
+ }
302
+}
303
+{ "execute": "quit" }
304
+EOF
305
+
306
+echo
307
+echo "=== Invalid version ==="
308
+echo
309
+
310
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
311
+{ "execute": "qmp_capabilities" }
312
+{ "execute": "x-blockdev-create",
313
+ "arguments": {
314
+ "driver": "$IMGFMT",
315
+ "file": "node0",
316
+ "size": 67108864,
317
+ "version": "v1"
318
+ }
319
+}
320
+{ "execute": "x-blockdev-create",
321
+ "arguments": {
322
+ "driver": "$IMGFMT",
323
+ "file": "node0",
324
+ "size": 67108864,
325
+ "version": "v2",
326
+ "lazy-refcounts": true
327
+ }
328
+}
329
+{ "execute": "x-blockdev-create",
330
+ "arguments": {
331
+ "driver": "$IMGFMT",
332
+ "file": "node0",
333
+ "size": 67108864,
334
+ "version": "v2",
335
+ "refcount-bits": 8
336
+ }
337
+}
338
+{ "execute": "quit" }
339
+EOF
340
+
341
+echo
342
+echo "=== Invalid backing file options ==="
343
+echo
344
+
345
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
346
+{ "execute": "qmp_capabilities" }
347
+{ "execute": "x-blockdev-create",
348
+ "arguments": {
349
+ "driver": "$IMGFMT",
350
+ "file": "node0",
351
+ "size": 67108864,
352
+ "backing-file": "/dev/null",
353
+ "preallocation": "full"
354
+ }
355
+}
356
+{ "execute": "x-blockdev-create",
357
+ "arguments": {
358
+ "driver": "$IMGFMT",
359
+ "file": "node0",
360
+ "size": 67108864,
361
+ "backing-fmt": "$IMGFMT"
362
+ }
363
+}
364
+{ "execute": "quit" }
365
+EOF
366
+
367
+echo
368
+echo "=== Invalid cluster size ==="
369
+echo
370
+
371
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
372
+{ "execute": "qmp_capabilities" }
373
+{ "execute": "x-blockdev-create",
374
+ "arguments": {
375
+ "driver": "$IMGFMT",
376
+ "file": "node0",
377
+ "size": 67108864,
378
+ "cluster-size": 1234
379
+ }
380
+}
381
+{ "execute": "x-blockdev-create",
382
+ "arguments": {
383
+ "driver": "$IMGFMT",
384
+ "file": "node0",
385
+ "size": 67108864,
386
+ "cluster-size": 128
387
+ }
388
+}
389
+{ "execute": "x-blockdev-create",
390
+ "arguments": {
391
+ "driver": "$IMGFMT",
392
+ "file": "node0",
393
+ "size": 67108864,
394
+ "cluster-size": 4194304
395
+ }
396
+}
397
+{ "execute": "x-blockdev-create",
398
+ "arguments": {
399
+ "driver": "$IMGFMT",
400
+ "file": "node0",
401
+ "size": 67108864,
402
+ "cluster-size": 0
403
+ }
404
+}
405
+{ "execute": "x-blockdev-create",
406
+ "arguments": {
407
+ "driver": "$IMGFMT",
408
+ "file": "node0",
409
+ "size": 281474976710656,
410
+ "cluster-size": 512
411
+ }
412
+}
413
+{ "execute": "quit" }
414
+EOF
415
+
416
+echo
417
+echo "=== Invalid refcount width ==="
418
+echo
419
+
420
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
421
+{ "execute": "qmp_capabilities" }
422
+{ "execute": "x-blockdev-create",
423
+ "arguments": {
424
+ "driver": "$IMGFMT",
425
+ "file": "node0",
426
+ "size": 67108864,
427
+ "refcount-bits": 128
428
+ }
429
+}
430
+{ "execute": "x-blockdev-create",
431
+ "arguments": {
432
+ "driver": "$IMGFMT",
433
+ "file": "node0",
434
+ "size": 67108864,
435
+ "refcount-bits": 0
436
+ }
437
+}
438
+{ "execute": "x-blockdev-create",
439
+ "arguments": {
440
+ "driver": "$IMGFMT",
441
+ "file": "node0",
442
+ "size": 67108864,
443
+ "refcount-bits": 7
444
+ }
445
+}
446
+{ "execute": "quit" }
447
+EOF
448
+
449
+# success, all done
450
+echo "*** done"
451
+rm -f $seq.full
452
+status=0
453
diff --git a/tests/qemu-iotests/206.out b/tests/qemu-iotests/206.out
454
new file mode 100644
455
index XXXXXXX..XXXXXXX
456
--- /dev/null
457
+++ b/tests/qemu-iotests/206.out
458
@@ -XXX,XX +XXX,XX @@
459
+QA output created by 206
460
+
461
+=== Successful image creation (defaults) ===
462
+
463
+Testing:
464
+QMP_VERSION
465
+{"return": {}}
466
+{"return": {}}
467
+{"return": {}}
468
+{"return": {}}
469
+{"return": {}}
470
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
471
+
472
+image: TEST_DIR/t.IMGFMT
473
+file format: IMGFMT
474
+virtual size: 128M (134217728 bytes)
475
+cluster_size: 65536
476
+Format specific information:
477
+ compat: 1.1
478
+ lazy refcounts: false
479
+ refcount bits: 16
480
+ corrupt: false
481
+
482
+=== Successful image creation (inline blockdev-add, explicit defaults) ===
483
+
484
+Testing:
485
+QMP_VERSION
486
+{"return": {}}
487
+{"return": {}}
488
+{"return": {}}
489
+{"return": {}}
490
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
491
+
492
+image: TEST_DIR/t.IMGFMT
493
+file format: IMGFMT
494
+virtual size: 64M (67108864 bytes)
495
+cluster_size: 65536
496
+Format specific information:
497
+ compat: 1.1
498
+ lazy refcounts: false
499
+ refcount bits: 16
500
+ corrupt: false
501
+
502
+=== Successful image creation (v3 non-default options) ===
503
+
504
+Testing:
505
+QMP_VERSION
506
+{"return": {}}
507
+{"return": {}}
508
+{"return": {}}
509
+{"return": {}}
510
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
511
+
512
+image: TEST_DIR/t.IMGFMT
513
+file format: IMGFMT
514
+virtual size: 32M (33554432 bytes)
515
+cluster_size: 2097152
516
+Format specific information:
517
+ compat: 1.1
518
+ lazy refcounts: true
519
+ refcount bits: 1
520
+ corrupt: false
521
+
522
+=== Successful image creation (v2 non-default options) ===
523
+
524
+Testing:
525
+QMP_VERSION
526
+{"return": {}}
527
+{"return": {}}
528
+{"return": {}}
529
+{"return": {}}
530
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
531
+
532
+image: TEST_DIR/t.IMGFMT
533
+file format: IMGFMT
534
+virtual size: 32M (33554432 bytes)
535
+cluster_size: 512
536
+backing file: TEST_DIR/t.IMGFMT.base
537
+backing file format: IMGFMT
538
+Format specific information:
539
+ compat: 0.10
540
+ refcount bits: 16
541
+
542
+=== Successful image creation (encrypted) ===
543
+
544
+Testing: -object secret,id=keysec0,data=foo
545
+QMP_VERSION
546
+{"return": {}}
547
+{"return": {}}
548
+{"return": {}}
549
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
550
+
551
+image: TEST_DIR/t.IMGFMT
552
+file format: IMGFMT
553
+virtual size: 32M (33554432 bytes)
554
+Format specific information:
555
+ compat: 1.1
556
+ lazy refcounts: false
557
+ refcount bits: 16
558
+ encrypt:
559
+ ivgen alg: plain64
560
+ hash alg: sha1
561
+ cipher alg: twofish-128
562
+ uuid: 00000000-0000-0000-0000-000000000000
563
+ format: luks
564
+ cipher mode: ctr
565
+ slots:
566
+ [0]:
567
+ active: true
568
+ iters: 1024
569
+ key offset: 4096
570
+ stripes: 4000
571
+ [1]:
572
+ active: false
573
+ key offset: 69632
574
+ [2]:
575
+ active: false
576
+ key offset: 135168
577
+ [3]:
578
+ active: false
579
+ key offset: 200704
580
+ [4]:
581
+ active: false
582
+ key offset: 266240
583
+ [5]:
584
+ active: false
585
+ key offset: 331776
586
+ [6]:
587
+ active: false
588
+ key offset: 397312
589
+ [7]:
590
+ active: false
591
+ key offset: 462848
592
+ payload offset: 528384
593
+ master key iters: 1024
594
+ corrupt: false
595
+
596
+=== Invalid BlockdevRef ===
597
+
598
+Testing:
599
+QMP_VERSION
600
+{"return": {}}
601
+{"error": {"class": "GenericError", "desc": "Cannot find device=this doesn't exist nor node_name=this doesn't exist"}}
602
+{"return": {}}
603
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
604
+
605
+
606
+=== Invalid sizes ===
607
+
608
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
609
+QMP_VERSION
610
+{"return": {}}
611
+{"error": {"class": "GenericError", "desc": "Image size must be a multiple of 512 bytes"}}
612
+{"error": {"class": "GenericError", "desc": "Could not resize image: Image size cannot be negative"}}
613
+{"error": {"class": "GenericError", "desc": "Could not resize image: Image size cannot be negative"}}
614
+{"error": {"class": "GenericError", "desc": "Could not resize image: Failed to grow the L1 table: File too large"}}
615
+{"return": {}}
616
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
617
+
618
+
619
+=== Invalid version ===
620
+
621
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
622
+QMP_VERSION
623
+{"return": {}}
624
+{"error": {"class": "GenericError", "desc": "Invalid parameter 'v1'"}}
625
+{"error": {"class": "GenericError", "desc": "Lazy refcounts only supported with compatibility level 1.1 and above (use version=v3 or greater)"}}
626
+{"error": {"class": "GenericError", "desc": "Different refcount widths than 16 bits require compatibility level 1.1 or above (use version=v3 or greater)"}}
627
+{"return": {}}
628
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
629
+
630
+
631
+=== Invalid backing file options ===
632
+
633
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
634
+QMP_VERSION
635
+{"return": {}}
636
+{"error": {"class": "GenericError", "desc": "Backing file and preallocation cannot be used at the same time"}}
637
+{"error": {"class": "GenericError", "desc": "Backing format cannot be used without backing file"}}
638
+{"return": {}}
639
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
640
+
641
+
642
+=== Invalid cluster size ===
643
+
644
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
645
+QMP_VERSION
646
+{"return": {}}
647
+{"error": {"class": "GenericError", "desc": "Cluster size must be a power of two between 512 and 2048k"}}
648
+{"error": {"class": "GenericError", "desc": "Cluster size must be a power of two between 512 and 2048k"}}
649
+{"error": {"class": "GenericError", "desc": "Cluster size must be a power of two between 512 and 2048k"}}
650
+{"error": {"class": "GenericError", "desc": "Cluster size must be a power of two between 512 and 2048k"}}
651
+{"error": {"class": "GenericError", "desc": "Could not resize image: Failed to grow the L1 table: File too large"}}
652
+{"return": {}}
653
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
654
+
655
+
656
+=== Invalid refcount width ===
657
+
658
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
659
+QMP_VERSION
660
+{"return": {}}
661
+{"error": {"class": "GenericError", "desc": "Refcount width must be a power of two and may not exceed 64 bits"}}
662
+{"error": {"class": "GenericError", "desc": "Refcount width must be a power of two and may not exceed 64 bits"}}
663
+{"error": {"class": "GenericError", "desc": "Refcount width must be a power of two and may not exceed 64 bits"}}
664
+{"return": {}}
665
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
666
+
667
+*** done
668
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
669
index XXXXXXX..XXXXXXX 100644
670
--- a/tests/qemu-iotests/group
671
+++ b/tests/qemu-iotests/group
672
@@ -XXX,XX +XXX,XX @@
673
203 rw auto
674
204 rw auto quick
675
205 rw auto quick
676
+206 rw auto
677
--
678
2.13.6
679
680
diff view generated by jsdifflib
Deleted patch
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Reviewed-by: Max Reitz <mreitz@redhat.com>
3
---
4
tests/qemu-iotests/207 | 261 +++++++++++++++++++++++++++++++++++++++++++++
5
tests/qemu-iotests/207.out | 75 +++++++++++++
6
tests/qemu-iotests/group | 1 +
7
3 files changed, 337 insertions(+)
8
create mode 100755 tests/qemu-iotests/207
9
create mode 100644 tests/qemu-iotests/207.out
10
1
11
diff --git a/tests/qemu-iotests/207 b/tests/qemu-iotests/207
12
new file mode 100755
13
index XXXXXXX..XXXXXXX
14
--- /dev/null
15
+++ b/tests/qemu-iotests/207
16
@@ -XXX,XX +XXX,XX @@
17
+#!/bin/bash
18
+#
19
+# Test ssh image creation
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
+
37
+# creator
38
+owner=kwolf@redhat.com
39
+
40
+seq=`basename $0`
41
+echo "QA output created by $seq"
42
+
43
+here=`pwd`
44
+status=1    # failure is the default!
45
+
46
+# get standard environment, filters and checks
47
+. ./common.rc
48
+. ./common.filter
49
+
50
+_supported_fmt raw
51
+_supported_proto ssh
52
+_supported_os Linux
53
+
54
+function do_run_qemu()
55
+{
56
+ echo Testing: "$@"
57
+ $QEMU -nographic -qmp stdio -serial none "$@"
58
+ echo
59
+}
60
+
61
+function run_qemu()
62
+{
63
+ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \
64
+ | _filter_qemu | _filter_imgfmt \
65
+ | _filter_actual_image_size
66
+}
67
+
68
+echo
69
+echo "=== Successful image creation (defaults) ==="
70
+echo
71
+
72
+run_qemu <<EOF
73
+{ "execute": "qmp_capabilities" }
74
+{ "execute": "x-blockdev-create",
75
+ "arguments": {
76
+ "driver": "ssh",
77
+ "location": {
78
+ "path": "$TEST_IMG_FILE",
79
+ "server": {
80
+ "host": "127.0.0.1",
81
+ "port": "22"
82
+ }
83
+ },
84
+ "size": 4194304
85
+ }
86
+}
87
+{ "execute": "quit" }
88
+EOF
89
+
90
+_img_info | _filter_img_info
91
+echo
92
+TEST_IMG=$TEST_IMG_FILE _img_info | _filter_img_info
93
+
94
+echo
95
+echo "=== Test host-key-check options ==="
96
+echo
97
+
98
+run_qemu <<EOF
99
+{ "execute": "qmp_capabilities" }
100
+{ "execute": "x-blockdev-create",
101
+ "arguments": {
102
+ "driver": "ssh",
103
+ "location": {
104
+ "path": "$TEST_IMG_FILE",
105
+ "server": {
106
+ "host": "127.0.0.1",
107
+ "port": "22"
108
+ },
109
+ "host-key-check": {
110
+ "mode": "none"
111
+ }
112
+ },
113
+ "size": 8388608
114
+ }
115
+}
116
+{ "execute": "quit" }
117
+EOF
118
+
119
+_img_info | _filter_img_info
120
+
121
+run_qemu <<EOF
122
+{ "execute": "qmp_capabilities" }
123
+{ "execute": "x-blockdev-create",
124
+ "arguments": {
125
+ "driver": "ssh",
126
+ "location": {
127
+ "path": "$TEST_IMG_FILE",
128
+ "server": {
129
+ "host": "127.0.0.1",
130
+ "port": "22"
131
+ },
132
+ "host-key-check": {
133
+ "mode": "known_hosts"
134
+ }
135
+ },
136
+ "size": 4194304
137
+ }
138
+}
139
+{ "execute": "quit" }
140
+EOF
141
+
142
+_img_info | _filter_img_info
143
+
144
+
145
+key=$(ssh-keyscan -t rsa 127.0.0.1 2>/dev/null | grep -v "\\^#" |
146
+ cut -d" " -f3 | base64 -d | md5sum -b | cut -d" " -f1)
147
+
148
+run_qemu <<EOF
149
+{ "execute": "qmp_capabilities" }
150
+{ "execute": "x-blockdev-create",
151
+ "arguments": {
152
+ "driver": "ssh",
153
+ "location": {
154
+ "path": "$TEST_IMG_FILE",
155
+ "server": {
156
+ "host": "127.0.0.1",
157
+ "port": "22"
158
+ },
159
+ "host-key-check": {
160
+ "mode": "hash",
161
+ "type": "md5",
162
+ "hash": "wrong"
163
+ }
164
+ },
165
+ "size": 8388608
166
+ }
167
+}
168
+{ "execute": "x-blockdev-create",
169
+ "arguments": {
170
+ "driver": "ssh",
171
+ "location": {
172
+ "path": "$TEST_IMG_FILE",
173
+ "server": {
174
+ "host": "127.0.0.1",
175
+ "port": "22"
176
+ },
177
+ "host-key-check": {
178
+ "mode": "hash",
179
+ "type": "md5",
180
+ "hash": "$key"
181
+ }
182
+ },
183
+ "size": 8388608
184
+ }
185
+}
186
+{ "execute": "quit" }
187
+EOF
188
+
189
+_img_info | _filter_img_info
190
+
191
+
192
+key=$(ssh-keyscan -t rsa 127.0.0.1 2>/dev/null | grep -v "\\^#" |
193
+ cut -d" " -f3 | base64 -d | sha1sum -b | cut -d" " -f1)
194
+
195
+run_qemu <<EOF
196
+{ "execute": "qmp_capabilities" }
197
+{ "execute": "x-blockdev-create",
198
+ "arguments": {
199
+ "driver": "ssh",
200
+ "location": {
201
+ "path": "$TEST_IMG_FILE",
202
+ "server": {
203
+ "host": "127.0.0.1",
204
+ "port": "22"
205
+ },
206
+ "host-key-check": {
207
+ "mode": "hash",
208
+ "type": "sha1",
209
+ "hash": "wrong"
210
+ }
211
+ },
212
+ "size": 4194304
213
+ }
214
+}
215
+{ "execute": "x-blockdev-create",
216
+ "arguments": {
217
+ "driver": "ssh",
218
+ "location": {
219
+ "path": "$TEST_IMG_FILE",
220
+ "server": {
221
+ "host": "127.0.0.1",
222
+ "port": "22"
223
+ },
224
+ "host-key-check": {
225
+ "mode": "hash",
226
+ "type": "sha1",
227
+ "hash": "$key"
228
+ }
229
+ },
230
+ "size": 4194304
231
+ }
232
+}
233
+{ "execute": "quit" }
234
+EOF
235
+
236
+_img_info | _filter_img_info
237
+
238
+echo
239
+echo "=== Invalid path and user ==="
240
+echo
241
+
242
+run_qemu <<EOF
243
+{ "execute": "qmp_capabilities" }
244
+{ "execute": "x-blockdev-create",
245
+ "arguments": {
246
+ "driver": "ssh",
247
+ "location": {
248
+ "path": "/this/is/not/an/existing/path",
249
+ "server": {
250
+ "host": "127.0.0.1",
251
+ "port": "22"
252
+ }
253
+ },
254
+ "size": 4194304
255
+ }
256
+}
257
+{ "execute": "x-blockdev-create",
258
+ "arguments": {
259
+ "driver": "ssh",
260
+ "location": {
261
+ "path": "$TEST_IMG_FILE",
262
+ "user": "invalid user",
263
+ "server": {
264
+ "host": "127.0.0.1",
265
+ "port": "22"
266
+ }
267
+ },
268
+ "size": 4194304
269
+ }
270
+}
271
+{ "execute": "quit" }
272
+EOF
273
+
274
+# success, all done
275
+echo "*** done"
276
+rm -f $seq.full
277
+status=0
278
diff --git a/tests/qemu-iotests/207.out b/tests/qemu-iotests/207.out
279
new file mode 100644
280
index XXXXXXX..XXXXXXX
281
--- /dev/null
282
+++ b/tests/qemu-iotests/207.out
283
@@ -XXX,XX +XXX,XX @@
284
+QA output created by 207
285
+
286
+=== Successful image creation (defaults) ===
287
+
288
+Testing:
289
+QMP_VERSION
290
+{"return": {}}
291
+{"return": {}}
292
+{"return": {}}
293
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
294
+
295
+image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_DIR/t.IMGFMT"}}
296
+file format: IMGFMT
297
+virtual size: 4.0M (4194304 bytes)
298
+
299
+image: TEST_DIR/t.IMGFMT
300
+file format: IMGFMT
301
+virtual size: 4.0M (4194304 bytes)
302
+
303
+=== Test host-key-check options ===
304
+
305
+Testing:
306
+QMP_VERSION
307
+{"return": {}}
308
+{"return": {}}
309
+{"return": {}}
310
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
311
+
312
+image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_DIR/t.IMGFMT"}}
313
+file format: IMGFMT
314
+virtual size: 8.0M (8388608 bytes)
315
+Testing:
316
+QMP_VERSION
317
+{"return": {}}
318
+{"return": {}}
319
+{"return": {}}
320
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
321
+
322
+image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_DIR/t.IMGFMT"}}
323
+file format: IMGFMT
324
+virtual size: 4.0M (4194304 bytes)
325
+Testing:
326
+QMP_VERSION
327
+{"return": {}}
328
+{"error": {"class": "GenericError", "desc": "remote host key does not match host_key_check 'wrong'"}}
329
+{"return": {}}
330
+{"return": {}}
331
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
332
+
333
+image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_DIR/t.IMGFMT"}}
334
+file format: IMGFMT
335
+virtual size: 8.0M (8388608 bytes)
336
+Testing:
337
+QMP_VERSION
338
+{"return": {}}
339
+{"error": {"class": "GenericError", "desc": "remote host key does not match host_key_check 'wrong'"}}
340
+{"return": {}}
341
+{"return": {}}
342
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
343
+
344
+image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_DIR/t.IMGFMT"}}
345
+file format: IMGFMT
346
+virtual size: 4.0M (4194304 bytes)
347
+
348
+=== Invalid path and user ===
349
+
350
+Testing:
351
+QMP_VERSION
352
+{"return": {}}
353
+{"error": {"class": "GenericError", "desc": "failed to open remote file '/this/is/not/an/existing/path': Failed opening remote file (libssh2 error code: -31)"}}
354
+{"error": {"class": "GenericError", "desc": "failed to authenticate using publickey authentication and the identities held by your ssh-agent"}}
355
+{"return": {}}
356
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
357
+
358
+*** done
359
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
360
index XXXXXXX..XXXXXXX 100644
361
--- a/tests/qemu-iotests/group
362
+++ b/tests/qemu-iotests/group
363
@@ -XXX,XX +XXX,XX @@
364
204 rw auto quick
365
205 rw auto quick
366
206 rw auto
367
+207 rw auto
368
--
369
2.13.6
370
371
diff view generated by jsdifflib
Deleted patch
1
From: Fam Zheng <famz@redhat.com>
2
1
3
Signed-off-by: Fam Zheng <famz@redhat.com>
4
Message-id: 20171225025107.23985-1-famz@redhat.com
5
Reviewed-by: Eric Blake <eblake@redhat.com>
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
---
8
tests/qemu-iotests/153 | 8 +++++---
9
tests/qemu-iotests/153.out | 7 ++++---
10
2 files changed, 9 insertions(+), 6 deletions(-)
11
12
diff --git a/tests/qemu-iotests/153 b/tests/qemu-iotests/153
13
index XXXXXXX..XXXXXXX 100755
14
--- a/tests/qemu-iotests/153
15
+++ b/tests/qemu-iotests/153
16
@@ -XXX,XX +XXX,XX @@ _cleanup()
17
{
18
_cleanup_test_img
19
rm -f "${TEST_IMG}.base"
20
+ rm -f "${TEST_IMG}.overlay"
21
rm -f "${TEST_IMG}.convert"
22
rm -f "${TEST_IMG}.a"
23
rm -f "${TEST_IMG}.b"
24
@@ -XXX,XX +XXX,XX @@ rm -f "${TEST_IMG}.lnk" &>/dev/null
25
ln -s ${TEST_IMG} "${TEST_IMG}.lnk" || echo "Failed to create link"
26
_run_qemu_with_images "${TEST_IMG}.lnk" "${TEST_IMG}"
27
28
-echo
29
-echo "== Closing an image should unlock it =="
30
_launch_qemu
31
32
_send_qemu_cmd $QEMU_HANDLE \
33
@@ -XXX,XX +XXX,XX @@ _send_qemu_cmd $QEMU_HANDLE \
34
35
_run_cmd $QEMU_IO "${TEST_IMG}" -c 'write 0 512'
36
37
-echo "Closing drive"
38
+echo "Creating overlay with qemu-img when the guest is running should be allowed"
39
+_run_cmd $QEMU_IMG create -f $IMGFMT -b "${TEST_IMG}" "${TEST_IMG}.overlay"
40
+
41
+echo "== Closing an image should unlock it =="
42
_send_qemu_cmd $QEMU_HANDLE \
43
"{ 'execute': 'human-monitor-command',
44
'arguments': { 'command-line': 'drive_del d0' } }" \
45
diff --git a/tests/qemu-iotests/153.out b/tests/qemu-iotests/153.out
46
index XXXXXXX..XXXXXXX 100644
47
--- a/tests/qemu-iotests/153.out
48
+++ b/tests/qemu-iotests/153.out
49
@@ -XXX,XX +XXX,XX @@ Is another process using the image?
50
== Symbolic link ==
51
QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2: Failed to get "write" lock
52
Is another process using the image?
53
-
54
-== Closing an image should unlock it ==
55
{"return": {}}
56
Adding drive
57
58
_qemu_io_wrapper TEST_DIR/t.qcow2 -c write 0 512
59
can't open device TEST_DIR/t.qcow2: Failed to get "write" lock
60
Is another process using the image?
61
-Closing drive
62
+Creating overlay with qemu-img when the guest is running should be allowed
63
+
64
+_qemu_img_wrapper create -f qcow2 -b TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.overlay
65
+== Closing an image should unlock it ==
66
67
_qemu_io_wrapper TEST_DIR/t.qcow2 -c write 0 512
68
Adding two and closing one
69
--
70
2.13.6
71
72
diff view generated by jsdifflib
Deleted patch
1
From: Fam Zheng <famz@redhat.com>
2
1
3
The AFL image is to exercise the code validating image size, which
4
doesn't work on 32 bit or when out of memory (there is a large
5
allocation before the interesting point). So check that and skip the
6
test, instead of faking the result.
7
8
Signed-off-by: Fam Zheng <famz@redhat.com>
9
Message-id: 20180301011413.11531-1-famz@redhat.com
10
Reviewed-by: Eric Blake <eblake@redhat.com>
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
13
tests/qemu-iotests/059 | 5 ++---
14
1 file changed, 2 insertions(+), 3 deletions(-)
15
16
diff --git a/tests/qemu-iotests/059 b/tests/qemu-iotests/059
17
index XXXXXXX..XXXXXXX 100755
18
--- a/tests/qemu-iotests/059
19
+++ b/tests/qemu-iotests/059
20
@@ -XXX,XX +XXX,XX @@ done
21
echo
22
echo "=== Testing afl image with a very large capacity ==="
23
_use_sample_img afl9.vmdk.bz2
24
-# The sed makes this test pass on machines with little RAM
25
-# (and also with 32 bit builds)
26
-_img_info | sed -e 's/Cannot allocate memory/Invalid argument/'
27
+_img_info | grep -q 'Cannot allocate memory' && _notrun "Insufficent memory, skipped test"
28
+_img_info
29
_cleanup_test_img
30
31
# success, all done
32
--
33
2.13.6
34
35
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
This patch tweaks TestParallelOps in iotest 030 so it allocates data
4
in smaller regions (256KB/512KB instead of 512KB/1MB) and the
5
block-stream job in test_stream_commit() only needs to copy data that
6
is at the very end of the image.
7
8
This way when the block-stream job is awakened it will finish right
9
away without any chance of being stopped by block_job_sleep_ns(). This
10
triggers the bug that was fixed by 3d5d319e1221082974711af1d09d82f and
11
1a63a907507fbbcfaee3f622907ec24 and is therefore a more useful test
12
case for parallel block jobs.
13
14
After this patch the aforementiond bug can also be reproduced with the
15
test_stream_parallel() test case.
16
17
Since with this change the stream job in test_stream_commit() finishes
18
early, this patch introduces a similar test case where both jobs are
19
slowed down so they can actually run in parallel.
20
21
Signed-off-by: Alberto Garcia <berto@igalia.com>
22
Cc: John Snow <jsnow@redhat.com>
23
Message-id: 20180306130121.30243-1-berto@igalia.com
24
Signed-off-by: Max Reitz <mreitz@redhat.com>
25
---
26
tests/qemu-iotests/030 | 52 ++++++++++++++++++++++++++++++++++++++--------
27
tests/qemu-iotests/030.out | 4 ++--
28
2 files changed, 45 insertions(+), 11 deletions(-)
29
30
diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030
31
index XXXXXXX..XXXXXXX 100755
32
--- a/tests/qemu-iotests/030
33
+++ b/tests/qemu-iotests/030
34
@@ -XXX,XX +XXX,XX @@ class TestSingleDrive(iotests.QMPTestCase):
35
class TestParallelOps(iotests.QMPTestCase):
36
num_ops = 4 # Number of parallel block-stream operations
37
num_imgs = num_ops * 2 + 1
38
- image_len = num_ops * 1024 * 1024
39
+ image_len = num_ops * 512 * 1024
40
imgs = []
41
42
def setUp(self):
43
@@ -XXX,XX +XXX,XX @@ class TestParallelOps(iotests.QMPTestCase):
44
'-o', 'backing_file=%s' % self.imgs[i-1], self.imgs[i])
45
46
# Put data into the images we are copying data from
47
- for i in range(self.num_imgs / 2):
48
- img_index = i * 2 + 1
49
- # Alternate between 512k and 1M.
50
+ odd_img_indexes = [x for x in reversed(range(self.num_imgs)) if x % 2 == 1]
51
+ for i in range(len(odd_img_indexes)):
52
+ # Alternate between 256KB and 512KB.
53
# This way jobs will not finish in the same order they were created
54
- num_kb = 512 + 512 * (i % 2)
55
+ num_kb = 256 + 256 * (i % 2)
56
qemu_io('-f', iotests.imgfmt,
57
- '-c', 'write -P %d %d %d' % (i, i*1024*1024, num_kb * 1024),
58
- self.imgs[img_index])
59
+ '-c', 'write -P 0xFF %dk %dk' % (i * 512, num_kb),
60
+ self.imgs[odd_img_indexes[i]])
61
62
# Attach the drive to the VM
63
self.vm = iotests.VM()
64
@@ -XXX,XX +XXX,XX @@ class TestParallelOps(iotests.QMPTestCase):
65
self.wait_until_completed(drive='commit-drive0')
66
67
# Test a block-stream and a block-commit job in parallel
68
- def test_stream_commit(self):
69
+ # Here the stream job is supposed to finish quickly in order to reproduce
70
+ # the scenario that triggers the bug fixed in 3d5d319e1221 and 1a63a907507
71
+ def test_stream_commit_1(self):
72
self.assertLessEqual(8, self.num_imgs)
73
self.assert_no_active_block_jobs()
74
75
# Stream from node0 into node2
76
- result = self.vm.qmp('block-stream', device='node2', job_id='node2')
77
+ result = self.vm.qmp('block-stream', device='node2', base_node='node0', job_id='node2')
78
self.assert_qmp(result, 'return', {})
79
80
# Commit from the active layer into node3
81
@@ -XXX,XX +XXX,XX @@ class TestParallelOps(iotests.QMPTestCase):
82
83
self.assert_no_active_block_jobs()
84
85
+ # This is similar to test_stream_commit_1 but both jobs are slowed
86
+ # down so they can run in parallel for a little while.
87
+ def test_stream_commit_2(self):
88
+ self.assertLessEqual(8, self.num_imgs)
89
+ self.assert_no_active_block_jobs()
90
+
91
+ # Stream from node0 into node4
92
+ result = self.vm.qmp('block-stream', device='node4', base_node='node0', job_id='node4', speed=1024*1024)
93
+ self.assert_qmp(result, 'return', {})
94
+
95
+ # Commit from the active layer into node5
96
+ result = self.vm.qmp('block-commit', device='drive0', base=self.imgs[5], speed=1024*1024)
97
+ self.assert_qmp(result, 'return', {})
98
+
99
+ # Wait for all jobs to be finished.
100
+ pending_jobs = ['node4', 'drive0']
101
+ while len(pending_jobs) > 0:
102
+ for event in self.vm.get_qmp_events(wait=True):
103
+ if event['event'] == 'BLOCK_JOB_COMPLETED':
104
+ node_name = self.dictpath(event, 'data/device')
105
+ self.assertTrue(node_name in pending_jobs)
106
+ self.assert_qmp_absent(event, 'data/error')
107
+ pending_jobs.remove(node_name)
108
+ if event['event'] == 'BLOCK_JOB_READY':
109
+ self.assert_qmp(event, 'data/device', 'drive0')
110
+ self.assert_qmp(event, 'data/type', 'commit')
111
+ self.assert_qmp_absent(event, 'data/error')
112
+ self.assertTrue('drive0' in pending_jobs)
113
+ self.vm.qmp('block-job-complete', device='drive0')
114
+
115
+ self.assert_no_active_block_jobs()
116
+
117
# Test the base_node parameter
118
def test_stream_base_node_name(self):
119
self.assert_no_active_block_jobs()
120
diff --git a/tests/qemu-iotests/030.out b/tests/qemu-iotests/030.out
121
index XXXXXXX..XXXXXXX 100644
122
--- a/tests/qemu-iotests/030.out
123
+++ b/tests/qemu-iotests/030.out
124
@@ -XXX,XX +XXX,XX @@
125
-.......................
126
+........................
127
----------------------------------------------------------------------
128
-Ran 23 tests
129
+Ran 24 tests
130
131
OK
132
--
133
2.13.6
134
135
diff view generated by jsdifflib
Deleted patch
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
1
3
There is a race between the test's 'query-migrate' QMP command after the
4
QMP 'STOP' event and completing the migration:
5
6
The test case invokes 'query-migrate' upon receiving 'STOP'. At this
7
point the migration thread may still be in the process of completing.
8
Therefore 'query-migrate' can return 'status': 'active' for a brief
9
window of time instead of 'status': 'completed'. This results in
10
qemu-iotests 203 hanging.
11
12
Solve the race by enabling the 'events' migration capability, which
13
causes QEMU to emit migration-specific QMP events that do not suffer
14
from this race condition. Wait for the QMP 'MIGRATION' event with
15
'status': 'completed'.
16
17
Reported-by: Max Reitz <mreitz@redhat.com>
18
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
19
Message-id: 20180305155926.25858-1-stefanha@redhat.com
20
Reviewed-by: Max Reitz <mreitz@redhat.com>
21
Signed-off-by: Max Reitz <mreitz@redhat.com>
22
---
23
tests/qemu-iotests/203 | 15 +++++++++++----
24
tests/qemu-iotests/203.out | 5 +++++
25
2 files changed, 16 insertions(+), 4 deletions(-)
26
27
diff --git a/tests/qemu-iotests/203 b/tests/qemu-iotests/203
28
index XXXXXXX..XXXXXXX 100755
29
--- a/tests/qemu-iotests/203
30
+++ b/tests/qemu-iotests/203
31
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('disk0.img') as disk0_img_path, \
32
node_name='drive1-node', iothread='iothread0',
33
force=True))
34
35
+ iotests.log('Enabling migration QMP events...')
36
+ iotests.log(vm.qmp('migrate-set-capabilities', capabilities=[
37
+ {
38
+ 'capability': 'events',
39
+ 'state': True
40
+ }
41
+ ]))
42
+
43
iotests.log('Starting migration...')
44
iotests.log(vm.qmp('migrate', uri='exec:cat >/dev/null'))
45
while True:
46
- vm.get_qmp_event(wait=60.0)
47
- result = vm.qmp('query-migrate')
48
- status = result.get('return', {}).get('status', None)
49
- if status == 'completed':
50
+ event = vm.event_wait('MIGRATION')
51
+ iotests.log(event, filters=[iotests.filter_qmp_event])
52
+ if event['data']['status'] == 'completed':
53
break
54
diff --git a/tests/qemu-iotests/203.out b/tests/qemu-iotests/203.out
55
index XXXXXXX..XXXXXXX 100644
56
--- a/tests/qemu-iotests/203.out
57
+++ b/tests/qemu-iotests/203.out
58
@@ -XXX,XX +XXX,XX @@ Launching VM...
59
Setting IOThreads...
60
{u'return': {}}
61
{u'return': {}}
62
+Enabling migration QMP events...
63
+{u'return': {}}
64
Starting migration...
65
{u'return': {}}
66
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'setup'}, u'event': u'MIGRATION'}
67
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'active'}, u'event': u'MIGRATION'}
68
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'completed'}, u'event': u'MIGRATION'}
69
--
70
2.13.6
71
72
diff view generated by jsdifflib