1
The following changes since commit d9bbfea646e86426d549bd612cd9f91e49aa50c2:
1
The following changes since commit ac5f7bf8e208cd7893dbb1a9520559e569a4677c:
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 'migration-20230424-pull-request' of https://gitlab.com/juan.quintela/qemu into staging (2023-04-24 15:00:39 +0100)
4
4
5
are available in the git repository at:
5
are available in the Git repository at:
6
6
7
git://repo.or.cz/qemu/kevin.git tags/for-upstream
7
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 8c1e8fb2e7fc2cbeb57703e143965a4cd3ad301a:
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/monitor: Fix crash when executing HMP commit (2023-04-25 15:11:57 +0200)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block layer patches
14
Block layer patches
15
15
16
- Protect BlockBackend.queued_requests with its own lock
17
- Switch to AIO_WAIT_WHILE_UNLOCKED() where possible
18
- AioContext removal: LinuxAioState/LuringState/ThreadPool
19
- Add more coroutine_fn annotations, use bdrv/blk_co_*
20
- Fix crash when execute hmp_commit
21
16
----------------------------------------------------------------
22
----------------------------------------------------------------
17
Alberto Garcia (8):
23
Emanuele Giuseppe Esposito (4):
18
qcow2: Generalize validate_table_offset() into qcow2_validate_table()
24
linux-aio: use LinuxAioState from the running thread
19
qcow2: Check L1 table offset in qcow2_snapshot_load_tmp()
25
io_uring: use LuringState from the running thread
20
qcow2: Check L1 table parameters in qcow2_expand_zero_clusters()
26
thread-pool: use ThreadPool from the running thread
21
qcow2: Check snapshot L1 tables in qcow2_check_metadata_overlap()
27
thread-pool: avoid passing the pool parameter every time
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
28
27
Daniel P. Berrangé (1):
29
Paolo Bonzini (9):
28
block: implement the bdrv_reopen_prepare helper for LUKS driver
30
vvfat: mark various functions as coroutine_fn
31
blkdebug: add missing coroutine_fn annotation
32
mirror: make mirror_flush a coroutine_fn, do not use co_wrappers
33
nbd: mark more coroutine_fns, do not use co_wrappers
34
9pfs: mark more coroutine_fns
35
qemu-pr-helper: mark more coroutine_fns
36
tests: mark more coroutine_fns
37
qcow2: mark various functions as coroutine_fn and GRAPH_RDLOCK
38
vmdk: make vmdk_is_cid_valid a coroutine_fn
29
39
30
Eric Blake (1):
40
Stefan Hajnoczi (10):
31
iotests: Mark all tests executable
41
block: make BlockBackend->quiesce_counter atomic
42
block: make BlockBackend->disable_request_queuing atomic
43
block: protect BlockBackend->queued_requests with a lock
44
block: don't acquire AioContext lock in bdrv_drain_all()
45
block: convert blk_exp_close_all_type() to AIO_WAIT_WHILE_UNLOCKED()
46
block: convert bdrv_graph_wrlock() to AIO_WAIT_WHILE_UNLOCKED()
47
block: convert bdrv_drain_all_begin() to AIO_WAIT_WHILE_UNLOCKED()
48
hmp: convert handle_hmp_command() to AIO_WAIT_WHILE_UNLOCKED()
49
monitor: convert monitor_cleanup() to AIO_WAIT_WHILE_UNLOCKED()
50
block: add missing coroutine_fn to bdrv_sum_allocated_file_size()
32
51
33
Fam Zheng (2):
52
Wang Liang (1):
34
iotests: Test creating overlay when guest running
53
block/monitor: Fix crash when executing HMP commit
35
iotests: Skip test for ENOMEM error
36
54
37
Kevin Wolf (38):
55
Wilfred Mallawa (1):
38
block/qapi: Introduce BlockdevCreateOptions
56
include/block: fixup typos
39
block/qapi: Add qcow2 create options to schema
40
qcow2: Rename qcow2_co_create2() to qcow2_co_create()
41
qcow2: Let qcow2_create() handle protocol layer
42
qcow2: Pass BlockdevCreateOptions to qcow2_co_create()
43
qcow2: Use BlockdevRef in qcow2_co_create()
44
qcow2: Use QCryptoBlockCreateOptions in qcow2_co_create()
45
qcow2: Handle full/falloc preallocation in qcow2_co_create()
46
util: Add qemu_opts_to_qdict_filtered()
47
test-qemu-opts: Test qemu_opts_append()
48
test-qemu-opts: Test qemu_opts_to_qdict_filtered()
49
qdict: Introduce qdict_rename_keys()
50
qcow2: Use visitor for options in qcow2_create()
51
block: Make bdrv_is_whitelisted() public
52
block: x-blockdev-create QMP command
53
file-posix: Support .bdrv_co_create
54
file-win32: Support .bdrv_co_create
55
gluster: Support .bdrv_co_create
56
rbd: Fix use after free in qemu_rbd_set_keypairs() error path
57
rbd: Factor out qemu_rbd_connect()
58
rbd: Remove non-schema options from runtime_opts
59
rbd: Pass BlockdevOptionsRbd to qemu_rbd_connect()
60
rbd: Support .bdrv_co_create
61
rbd: Assign s->snap/image_name in qemu_rbd_open()
62
rbd: Use qemu_rbd_connect() in qemu_rbd_do_create()
63
nfs: Use QAPI options in nfs_client_open()
64
nfs: Support .bdrv_co_create
65
sheepdog: QAPIfy "redundancy" create option
66
sheepdog: Support .bdrv_co_create
67
ssh: Use QAPI BlockdevOptionsSsh object
68
ssh: QAPIfy host-key-check option
69
ssh: Pass BlockdevOptionsSsh to connect_to_ssh()
70
ssh: Support .bdrv_co_create
71
file-posix: Fix no-op bdrv_truncate() with falloc preallocation
72
block: Fail bdrv_truncate() with negative size
73
qemu-iotests: Test qcow2 over file image creation with QMP
74
qemu-iotests: Test ssh image creation over QMP
75
Merge remote-tracking branch 'mreitz/tags/pull-block-2018-03-09' into queue-block
76
57
77
Paolo Bonzini (6):
58
block/qcow2.h | 15 +++++-----
78
qcow2: introduce qcow2_write_caches and qcow2_flush_caches
59
hw/9pfs/9p.h | 4 +--
79
qcow2: fix flushing after dirty bitmap metadata writes
60
include/block/aio-wait.h | 2 +-
80
qcow2: make qcow2_do_open a coroutine_fn
61
include/block/aio.h | 8 ------
81
qed: make bdrv_qed_do_open a coroutine_fn
62
include/block/block_int-common.h | 2 +-
82
block: convert bdrv_invalidate_cache callback to coroutine_fn
63
include/block/raw-aio.h | 33 +++++++++++++++-------
83
block: convert bdrv_check callback to coroutine_fn
64
include/block/thread-pool.h | 15 ++++++----
84
65
include/sysemu/block-backend-io.h | 5 ++++
85
Stefan Hajnoczi (1):
66
backends/tpm/tpm_backend.c | 4 +--
86
qemu-iotests: fix 203 migration completion race
67
block.c | 2 +-
87
68
block/blkdebug.c | 4 +--
88
qapi/block-core.json | 326 +++++++++++++++++++++++++-
69
block/block-backend.c | 45 ++++++++++++++++++------------
89
block/qcow2.h | 12 +-
70
block/export/export.c | 2 +-
90
include/block/block.h | 2 +
71
block/file-posix.c | 45 ++++++++++++------------------
91
include/block/block_int.h | 13 +-
72
block/file-win32.c | 4 +--
92
include/qapi/qmp/qdict.h | 6 +
73
block/graph-lock.c | 2 +-
93
include/qemu/option.h | 2 +
74
block/io.c | 2 +-
94
block.c | 138 +++++++++++-
75
block/io_uring.c | 23 ++++++++++------
95
block/create.c | 76 +++++++
76
block/linux-aio.c | 29 ++++++++++++--------
96
block/crypto.c | 7 +
77
block/mirror.c | 4 +--
97
block/file-posix.c | 93 +++++---
78
block/monitor/block-hmp-cmds.c | 10 ++++---
98
block/file-win32.c | 47 +++-
79
block/qcow2-bitmap.c | 2 +-
99
block/gluster.c | 135 +++++++----
80
block/qcow2-cluster.c | 21 ++++++++------
100
block/iscsi.c | 6 +-
81
block/qcow2-refcount.c | 8 +++---
101
block/nfs.c | 244 +++++++++-----------
82
block/qcow2-snapshot.c | 25 +++++++++--------
102
block/parallels.c | 17 +-
83
block/qcow2-threads.c | 3 +-
103
block/qcow2-bitmap.c | 4 +-
84
block/qcow2.c | 27 +++++++++---------
104
block/qcow2-cluster.c | 24 +-
85
block/vmdk.c | 2 +-
105
block/qcow2-refcount.c | 52 ++++-
86
block/vvfat.c | 58 ++++++++++++++++++++-------------------
106
block/qcow2-snapshot.c | 24 +-
87
hw/9pfs/codir.c | 6 ++--
107
block/qcow2.c | 552 ++++++++++++++++++++++++++++-----------------
88
hw/9pfs/coth.c | 3 +-
108
block/qed-check.c | 1 +
89
hw/ppc/spapr_nvdimm.c | 6 ++--
109
block/qed-table.c | 26 +--
90
hw/virtio/virtio-pmem.c | 3 +-
110
block/qed.c | 66 ++++--
91
monitor/hmp.c | 2 +-
111
block/rbd.c | 403 +++++++++++++++++----------------
92
monitor/monitor.c | 4 +--
112
block/sheepdog.c | 321 ++++++++++++++++++--------
93
nbd/server.c | 48 ++++++++++++++++----------------
113
block/ssh.c | 290 +++++++++++++-----------
94
scsi/pr-manager.c | 3 +-
114
block/vdi.c | 6 +-
95
scsi/qemu-pr-helper.c | 25 ++++++++---------
115
block/vhdx.c | 7 +-
96
tests/unit/test-thread-pool.c | 14 ++++------
116
block/vmdk.c | 7 +-
97
util/thread-pool.c | 25 ++++++++---------
117
qobject/qdict.c | 34 +++
98
40 files changed, 283 insertions(+), 262 deletions(-)
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: Alberto Garcia <berto@igalia.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
'qemu-img check' cannot detect if a snapshot's L1 table is corrupted.
3
The main loop thread increments/decrements BlockBackend->quiesce_counter
4
This patch checks the table's offset and size and reports corruption
4
when drained sections begin/end. The counter is read in the I/O code
5
if the values are not valid.
5
path. Therefore this field is used to communicate between threads
6
without a lock.
6
7
7
This patch doesn't add code to fix that corruption yet, only to detect
8
Acquire/release are not necessary because the BlockBackend->in_flight
8
and report it.
9
counter already uses sequentially consistent accesses and running I/O
10
requests hold that counter when blk_wait_while_drained() is called.
11
qatomic_read() can be used.
9
12
10
Signed-off-by: Alberto Garcia <berto@igalia.com>
13
Use qatomic_fetch_inc()/qatomic_fetch_dec() for modifications even
11
Reviewed-by: Eric Blake <eblake@redhat.com>
14
though sequentially consistent atomic accesses are not strictly required
15
here. They are, however, nicer to read than multiple calls to
16
qatomic_read() and qatomic_set(). Since beginning and ending drain is
17
not a hot path the extra cost doesn't matter.
18
19
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
20
Message-Id: <20230307210427.269214-2-stefanha@redhat.com>
21
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
22
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
23
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
24
---
14
block/qcow2-refcount.c | 14 ++++++++++++++
25
block/block-backend.c | 14 +++++++-------
15
tests/qemu-iotests/080 | 2 ++
26
1 file changed, 7 insertions(+), 7 deletions(-)
16
tests/qemu-iotests/080.out | 20 ++++++++++++++++++++
17
3 files changed, 36 insertions(+)
18
27
19
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
28
diff --git a/block/block-backend.c b/block/block-backend.c
20
index XXXXXXX..XXXXXXX 100644
29
index XXXXXXX..XXXXXXX 100644
21
--- a/block/qcow2-refcount.c
30
--- a/block/block-backend.c
22
+++ b/block/qcow2-refcount.c
31
+++ b/block/block-backend.c
23
@@ -XXX,XX +XXX,XX @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
32
@@ -XXX,XX +XXX,XX @@ struct BlockBackend {
24
/* snapshots */
33
NotifierList remove_bs_notifiers, insert_bs_notifiers;
25
for (i = 0; i < s->nb_snapshots; i++) {
34
QLIST_HEAD(, BlockBackendAioNotifier) aio_notifiers;
26
sn = s->snapshots + i;
35
27
+ if (offset_into_cluster(s, sn->l1_table_offset)) {
36
- int quiesce_counter;
28
+ fprintf(stderr, "ERROR snapshot %s (%s) l1_offset=%#" PRIx64 ": "
37
+ int quiesce_counter; /* atomic: written under BQL, read by other threads */
29
+ "L1 table is not cluster aligned; snapshot table entry "
38
CoQueue queued_requests;
30
+ "corrupted\n", sn->id_str, sn->name, sn->l1_table_offset);
39
bool disable_request_queuing;
31
+ res->corruptions++;
40
32
+ continue;
41
@@ -XXX,XX +XXX,XX @@ void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops,
33
+ }
42
blk->dev_opaque = opaque;
34
+ if (sn->l1_size > QCOW_MAX_L1_SIZE / sizeof(uint64_t)) {
43
35
+ fprintf(stderr, "ERROR snapshot %s (%s) l1_size=%#" PRIx32 ": "
44
/* Are we currently quiesced? Should we enforce this right now? */
36
+ "L1 table is too large; snapshot table entry corrupted\n",
45
- if (blk->quiesce_counter && ops && ops->drained_begin) {
37
+ sn->id_str, sn->name, sn->l1_size);
46
+ if (qatomic_read(&blk->quiesce_counter) && ops && ops->drained_begin) {
38
+ res->corruptions++;
47
ops->drained_begin(opaque);
39
+ continue;
48
}
40
+ }
49
}
41
ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters,
50
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn blk_wait_while_drained(BlockBackend *blk)
42
sn->l1_table_offset, sn->l1_size, 0, fix);
51
{
43
if (ret < 0) {
52
assert(blk->in_flight > 0);
44
diff --git a/tests/qemu-iotests/080 b/tests/qemu-iotests/080
53
45
index XXXXXXX..XXXXXXX 100755
54
- if (blk->quiesce_counter && !blk->disable_request_queuing) {
46
--- a/tests/qemu-iotests/080
55
+ if (qatomic_read(&blk->quiesce_counter) && !blk->disable_request_queuing) {
47
+++ b/tests/qemu-iotests/080
56
blk_dec_in_flight(blk);
48
@@ -XXX,XX +XXX,XX @@ poke_file "$TEST_IMG" "$offset_snap1_l1_offset" "\x00\x00\x00\x00\x00\x40\x02\x0
57
qemu_co_queue_wait(&blk->queued_requests, NULL);
49
-c 'write 0 4k'; } 2>&1 | _filter_qemu_io | _filter_testdir
58
blk_inc_in_flight(blk);
50
{ $QEMU_IMG snapshot -a test $TEST_IMG; } 2>&1 | _filter_testdir
59
@@ -XXX,XX +XXX,XX @@ static void blk_root_drained_begin(BdrvChild *child)
51
{ $QEMU_IMG snapshot -d test $TEST_IMG; } 2>&1 | _filter_testdir
60
BlockBackend *blk = child->opaque;
52
+_check_test_img
61
ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
53
62
54
echo
63
- if (++blk->quiesce_counter == 1) {
55
echo "== Invalid snapshot L1 table size =="
64
+ if (qatomic_fetch_inc(&blk->quiesce_counter) == 0) {
56
@@ -XXX,XX +XXX,XX @@ poke_file "$TEST_IMG" "$offset_snap1_l1_size" "\x10\x00\x00\x00"
65
if (blk->dev_ops && blk->dev_ops->drained_begin) {
57
-c 'write 0 4k'; } 2>&1 | _filter_qemu_io | _filter_testdir
66
blk->dev_ops->drained_begin(blk->dev_opaque);
58
{ $QEMU_IMG snapshot -a test $TEST_IMG; } 2>&1 | _filter_testdir
67
}
59
{ $QEMU_IMG snapshot -d test $TEST_IMG; } 2>&1 | _filter_testdir
68
@@ -XXX,XX +XXX,XX @@ static bool blk_root_drained_poll(BdrvChild *child)
60
+_check_test_img
69
{
61
70
BlockBackend *blk = child->opaque;
62
# success, all done
71
bool busy = false;
63
echo "*** done"
72
- assert(blk->quiesce_counter);
64
diff --git a/tests/qemu-iotests/080.out b/tests/qemu-iotests/080.out
73
+ assert(qatomic_read(&blk->quiesce_counter));
65
index XXXXXXX..XXXXXXX 100644
74
66
--- a/tests/qemu-iotests/080.out
75
if (blk->dev_ops && blk->dev_ops->drained_poll) {
67
+++ b/tests/qemu-iotests/080.out
76
busy = blk->dev_ops->drained_poll(blk->dev_opaque);
68
@@ -XXX,XX +XXX,XX @@ write failed: Invalid argument
77
@@ -XXX,XX +XXX,XX @@ static bool blk_root_drained_poll(BdrvChild *child)
69
qemu-img: Snapshot L1 table offset invalid
78
static void blk_root_drained_end(BdrvChild *child)
70
qemu-img: Could not apply snapshot 'test': Failed to load snapshot: Invalid argument
79
{
71
qemu-img: Could not delete snapshot 'test': Snapshot L1 table offset invalid
80
BlockBackend *blk = child->opaque;
72
+ERROR snapshot 1 (test) l1_offset=0x400200: L1 table is not cluster aligned; snapshot table entry corrupted
81
- assert(blk->quiesce_counter);
73
+Leaked cluster 4 refcount=2 reference=1
82
+ assert(qatomic_read(&blk->quiesce_counter));
74
+Leaked cluster 5 refcount=2 reference=1
83
75
+Leaked cluster 6 refcount=1 reference=0
84
assert(blk->public.throttle_group_member.io_limits_disabled);
76
+
85
qatomic_dec(&blk->public.throttle_group_member.io_limits_disabled);
77
+1 errors were found on the image.
86
78
+Data may be corrupted, or further writes to the image may corrupt it.
87
- if (--blk->quiesce_counter == 0) {
79
+
88
+ if (qatomic_fetch_dec(&blk->quiesce_counter) == 1) {
80
+3 leaked clusters were found on the image.
89
if (blk->dev_ops && blk->dev_ops->drained_end) {
81
+This means waste of disk space, but no harm to data.
90
blk->dev_ops->drained_end(blk->dev_opaque);
82
91
}
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
--
92
--
101
2.13.6
93
2.40.0
102
94
103
95
diff view generated by jsdifflib
1
From: "Daniel P. Berrange" <berrange@redhat.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
If the bdrv_reopen_prepare helper isn't provided, the qemu-img commit
3
This field is accessed by multiple threads without a lock. Use explicit
4
command fails to re-open the base layer after committing changes into
4
qatomic_read()/qatomic_set() calls. There is no need for acquire/release
5
it. Provide a no-op implementation for the LUKS driver, since there
5
because blk_set_disable_request_queuing() doesn't provide any
6
is not any custom work that needs doing to re-open it.
6
guarantees (it helps that it's used at BlockBackend creation time and
7
not when there is I/O in flight).
7
8
8
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
11
Message-Id: <20230307210427.269214-3-stefanha@redhat.com>
12
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
13
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
15
---
11
block/crypto.c | 7 +++++++
16
block/block-backend.c | 7 ++++---
12
1 file changed, 7 insertions(+)
17
1 file changed, 4 insertions(+), 3 deletions(-)
13
18
14
diff --git a/block/crypto.c b/block/crypto.c
19
diff --git a/block/block-backend.c b/block/block-backend.c
15
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
16
--- a/block/crypto.c
21
--- a/block/block-backend.c
17
+++ b/block/crypto.c
22
+++ b/block/block-backend.c
18
@@ -XXX,XX +XXX,XX @@ static void block_crypto_close(BlockDriverState *bs)
23
@@ -XXX,XX +XXX,XX @@ struct BlockBackend {
19
qcrypto_block_free(crypto->block);
24
25
int quiesce_counter; /* atomic: written under BQL, read by other threads */
26
CoQueue queued_requests;
27
- bool disable_request_queuing;
28
+ bool disable_request_queuing; /* atomic */
29
30
VMChangeStateEntry *vmsh;
31
bool force_allow_inactivate;
32
@@ -XXX,XX +XXX,XX @@ void blk_set_allow_aio_context_change(BlockBackend *blk, bool allow)
33
void blk_set_disable_request_queuing(BlockBackend *blk, bool disable)
34
{
35
IO_CODE();
36
- blk->disable_request_queuing = disable;
37
+ qatomic_set(&blk->disable_request_queuing, disable);
20
}
38
}
21
39
22
+static int block_crypto_reopen_prepare(BDRVReopenState *state,
40
static int coroutine_fn GRAPH_RDLOCK
23
+ BlockReopenQueue *queue, Error **errp)
41
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn blk_wait_while_drained(BlockBackend *blk)
24
+{
42
{
25
+ /* nothing needs checking */
43
assert(blk->in_flight > 0);
26
+ return 0;
44
27
+}
45
- if (qatomic_read(&blk->quiesce_counter) && !blk->disable_request_queuing) {
28
46
+ if (qatomic_read(&blk->quiesce_counter) &&
29
/*
47
+ !qatomic_read(&blk->disable_request_queuing)) {
30
* 1 MB bounce buffer gives good performance / memory tradeoff
48
blk_dec_in_flight(blk);
31
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_crypto_luks = {
49
qemu_co_queue_wait(&blk->queued_requests, NULL);
32
.bdrv_truncate = block_crypto_truncate,
50
blk_inc_in_flight(blk);
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
--
51
--
40
2.13.6
52
2.40.0
41
53
42
54
diff view generated by jsdifflib
1
The code to establish an RBD connection is duplicated between open and
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
create. In order to be able to share the code, factor out the code from
3
qemu_rbd_open() as a first step.
4
2
3
The CoQueue API offers thread-safety via the lock argument that
4
qemu_co_queue_wait() and qemu_co_enter_next() take. BlockBackend
5
currently does not make use of the lock argument. This means that
6
multiple threads submitting I/O requests can corrupt the CoQueue's
7
QSIMPLEQ.
8
9
Add a QemuMutex and pass it to CoQueue APIs so that the queue is
10
protected. While we're at it, also assert that the queue is empty when
11
the BlockBackend is deleted.
12
13
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
14
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
15
Message-Id: <20230307210427.269214-4-stefanha@redhat.com>
16
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
---
18
---
8
block/rbd.c | 100 ++++++++++++++++++++++++++++++++++++------------------------
19
block/block-backend.c | 18 ++++++++++++++++--
9
1 file changed, 60 insertions(+), 40 deletions(-)
20
1 file changed, 16 insertions(+), 2 deletions(-)
10
21
11
diff --git a/block/rbd.c b/block/rbd.c
22
diff --git a/block/block-backend.c b/block/block-backend.c
12
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
13
--- a/block/rbd.c
24
--- a/block/block-backend.c
14
+++ b/block/rbd.c
25
+++ b/block/block-backend.c
15
@@ -XXX,XX +XXX,XX @@ out:
26
@@ -XXX,XX +XXX,XX @@ struct BlockBackend {
16
return rados_str;
27
QLIST_HEAD(, BlockBackendAioNotifier) aio_notifiers;
28
29
int quiesce_counter; /* atomic: written under BQL, read by other threads */
30
+ QemuMutex queued_requests_lock; /* protects queued_requests */
31
CoQueue queued_requests;
32
bool disable_request_queuing; /* atomic */
33
34
@@ -XXX,XX +XXX,XX @@ BlockBackend *blk_new(AioContext *ctx, uint64_t perm, uint64_t shared_perm)
35
36
block_acct_init(&blk->stats);
37
38
+ qemu_mutex_init(&blk->queued_requests_lock);
39
qemu_co_queue_init(&blk->queued_requests);
40
notifier_list_init(&blk->remove_bs_notifiers);
41
notifier_list_init(&blk->insert_bs_notifiers);
42
@@ -XXX,XX +XXX,XX @@ static void blk_delete(BlockBackend *blk)
43
assert(QLIST_EMPTY(&blk->remove_bs_notifiers.notifiers));
44
assert(QLIST_EMPTY(&blk->insert_bs_notifiers.notifiers));
45
assert(QLIST_EMPTY(&blk->aio_notifiers));
46
+ assert(qemu_co_queue_empty(&blk->queued_requests));
47
+ qemu_mutex_destroy(&blk->queued_requests_lock);
48
QTAILQ_REMOVE(&block_backends, blk, link);
49
drive_info_del(blk->legacy_dinfo);
50
block_acct_cleanup(&blk->stats);
51
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn blk_wait_while_drained(BlockBackend *blk)
52
53
if (qatomic_read(&blk->quiesce_counter) &&
54
!qatomic_read(&blk->disable_request_queuing)) {
55
+ /*
56
+ * Take lock before decrementing in flight counter so main loop thread
57
+ * waits for us to enqueue ourselves before it can leave the drained
58
+ * section.
59
+ */
60
+ qemu_mutex_lock(&blk->queued_requests_lock);
61
blk_dec_in_flight(blk);
62
- qemu_co_queue_wait(&blk->queued_requests, NULL);
63
+ qemu_co_queue_wait(&blk->queued_requests, &blk->queued_requests_lock);
64
blk_inc_in_flight(blk);
65
+ qemu_mutex_unlock(&blk->queued_requests_lock);
66
}
17
}
67
}
18
68
19
-static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
69
@@ -XXX,XX +XXX,XX @@ static void blk_root_drained_end(BdrvChild *child)
20
- Error **errp)
70
if (blk->dev_ops && blk->dev_ops->drained_end) {
21
+static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
71
blk->dev_ops->drained_end(blk->dev_opaque);
22
+ char **s_snap, char **s_image_name,
72
}
23
+ QDict *options, bool cache, Error **errp)
73
- while (qemu_co_enter_next(&blk->queued_requests, NULL)) {
24
{
74
+ qemu_mutex_lock(&blk->queued_requests_lock);
25
- BDRVRBDState *s = bs->opaque;
75
+ while (qemu_co_enter_next(&blk->queued_requests,
26
- const char *pool, *snap, *conf, *user, *image_name, *keypairs;
76
+ &blk->queued_requests_lock)) {
27
- const char *secretid, *filename;
77
/* Resume all queued requests */
28
QemuOpts *opts;
78
}
29
- Error *local_err = NULL;
79
+ qemu_mutex_unlock(&blk->queued_requests_lock);
30
char *mon_host = NULL;
31
+ const char *pool, *snap, *conf, *user, *image_name, *keypairs;
32
+ const char *secretid;
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
}
80
}
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
}
81
}
188
82
189
--
83
--
190
2.13.6
84
2.40.0
191
192
diff view generated by jsdifflib
1
This makes the host-key-check option available in blockdev-add.
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
There is no need for the AioContext lock in bdrv_drain_all() because
4
nothing in AIO_WAIT_WHILE() needs the lock and the condition is atomic.
5
6
AIO_WAIT_WHILE_UNLOCKED() has no use for the AioContext parameter other
7
than performing a check that is nowadays already done by the
8
GLOBAL_STATE_CODE()/IO_CODE() macros. Set the ctx argument to NULL here
9
to help us keep track of all converted callers. Eventually all callers
10
will have been converted and then the argument can be dropped entirely.
11
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
13
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
14
Message-Id: <20230309190855.414275-2-stefanha@redhat.com>
15
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
16
Reviewed-by: Wilfred Mallawa <wilfred.mallawa@wdc.com>
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Reviewed-by: Max Reitz <mreitz@redhat.com>
5
---
18
---
6
qapi/block-core.json | 63 +++++++++++++++++++++++++++++++++++--
19
block/block-backend.c | 8 +-------
7
block/ssh.c | 88 +++++++++++++++++++++++++++++++++-------------------
20
1 file changed, 1 insertion(+), 7 deletions(-)
8
2 files changed, 117 insertions(+), 34 deletions(-)
9
21
10
diff --git a/qapi/block-core.json b/qapi/block-core.json
22
diff --git a/block/block-backend.c b/block/block-backend.c
11
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
12
--- a/qapi/block-core.json
24
--- a/block/block-backend.c
13
+++ b/qapi/block-core.json
25
+++ b/block/block-backend.c
14
@@ -XXX,XX +XXX,XX @@
26
@@ -XXX,XX +XXX,XX @@ void blk_drain_all(void)
15
'*encrypt': 'BlockdevQcow2Encryption' } }
27
bdrv_drain_all_begin();
16
28
17
##
29
while ((blk = blk_all_next(blk)) != NULL) {
18
+# @SshHostKeyCheckMode:
30
- AioContext *ctx = blk_get_aio_context(blk);
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
}
103
104
static int check_host_key(BDRVSSHState *s, const char *host, int port,
105
- const char *host_key_check, Error **errp)
106
+ SshHostKeyCheck *hkc, Error **errp)
107
{
108
- /* host_key_check=no */
109
- if (strcmp(host_key_check, "no") == 0) {
110
- return 0;
111
- }
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
-
31
-
120
- /* host_key_check=sha1:xx:yy:zz:... */
32
- aio_context_acquire(ctx);
121
- if (strncmp(host_key_check, "sha1:", 5) == 0) {
33
-
122
- return check_host_key_hash(s, &host_key_check[5],
34
/* We may have -ENOMEDIUM completions in flight */
123
- LIBSSH2_HOSTKEY_HASH_SHA1, 20, errp);
35
- AIO_WAIT_WHILE(ctx, qatomic_read(&blk->in_flight) > 0);
124
+ if (hkc) {
36
-
125
+ mode = hkc->mode;
37
- aio_context_release(ctx);
126
+ } else {
38
+ AIO_WAIT_WHILE_UNLOCKED(NULL, qatomic_read(&blk->in_flight) > 0);
127
+ mode = SSH_HOST_KEY_CHECK_MODE_KNOWN_HOSTS;
128
}
39
}
129
40
130
- /* host_key_check=yes */
41
bdrv_drain_all_end();
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
}
154
155
@@ -XXX,XX +XXX,XX @@ static QemuOptsList ssh_runtime_opts = {
156
.type = QEMU_OPT_NUMBER,
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
{
175
const char *host = qemu_opt_get(legacy_opts, "host");
176
const char *port = qemu_opt_get(legacy_opts, "port");
177
+ const char *host_key_check = qemu_opt_get(legacy_opts, "host_key_check");
178
179
if (!host && port) {
180
error_setg(errp, "port may not be used without host");
181
@@ -XXX,XX +XXX,XX @@ static bool ssh_process_legacy_socket_options(QDict *output_opts,
182
qdict_put_str(output_opts, "server.port", port ?: stringify(22));
183
}
184
185
+ if (host_key_check) {
186
+ if (strcmp(host_key_check, "no") == 0) {
187
+ qdict_put_str(output_opts, "host-key-check.mode", "none");
188
+ } else if (strncmp(host_key_check, "md5:", 4) == 0) {
189
+ qdict_put_str(output_opts, "host-key-check.mode", "hash");
190
+ qdict_put_str(output_opts, "host-key-check.type", "md5");
191
+ qdict_put_str(output_opts, "host-key-check.hash",
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
--
42
--
248
2.13.6
43
2.40.0
249
250
diff view generated by jsdifflib
1
This adds the .bdrv_co_create driver callback to rbd, which enables
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
image creation over QMP.
3
2
3
There is no change in behavior. Switch to AIO_WAIT_WHILE_UNLOCKED()
4
instead of AIO_WAIT_WHILE() to document that this code has already been
5
audited and converted. The AioContext argument is already NULL so
6
aio_context_release() is never called anyway.
7
8
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
9
Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org>
10
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Message-Id: <20230309190855.414275-3-stefanha@redhat.com>
13
Reviewed-by: Wilfred Mallawa <wilfred.mallawa@wdc.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
---
15
---
7
qapi/block-core.json | 19 ++++++-
16
block/export/export.c | 2 +-
8
block/rbd.c | 150 ++++++++++++++++++++++++++++++++++-----------------
17
1 file changed, 1 insertion(+), 1 deletion(-)
9
2 files changed, 118 insertions(+), 51 deletions(-)
10
18
11
diff --git a/qapi/block-core.json b/qapi/block-core.json
19
diff --git a/block/export/export.c b/block/export/export.c
12
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
13
--- a/qapi/block-core.json
21
--- a/block/export/export.c
14
+++ b/qapi/block-core.json
22
+++ b/block/export/export.c
15
@@ -XXX,XX +XXX,XX @@
23
@@ -XXX,XX +XXX,XX @@ void blk_exp_close_all_type(BlockExportType type)
16
'*refcount-bits': 'int' } }
24
blk_exp_request_shutdown(exp);
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
}
25
}
114
26
115
- options = qdict_new();
27
- AIO_WAIT_WHILE(NULL, blk_exp_has_type(type));
116
- qemu_rbd_parse_filename(filename, options, &local_err);
28
+ AIO_WAIT_WHILE_UNLOCKED(NULL, blk_exp_has_type(type));
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
}
29
}
255
30
256
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_rbd = {
31
void blk_exp_close_all(void)
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
--
32
--
265
2.13.6
33
2.40.0
266
34
267
35
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
This function deletes a snapshot from disk, removing its entry from
3
The following conversion is safe and does not change behavior:
4
the snapshot table, freeing its L1 table and decreasing the refcounts
5
of all clusters.
6
4
7
The L1 table offset and size are however not validated. If we use
5
GLOBAL_STATE_CODE();
8
invalid values in this function we'll probably corrupt the image even
6
...
9
more, so we should return an error instead.
7
- AIO_WAIT_WHILE(qemu_get_aio_context(), ...);
8
+ AIO_WAIT_WHILE_UNLOCKED(NULL, ...);
10
9
11
We now have a function to take care of this, so let's use it.
10
Since we're in GLOBAL_STATE_CODE(), qemu_get_aio_context() is our home
11
thread's AioContext. Thus AIO_WAIT_WHILE() does not unlock the
12
AioContext:
12
13
13
Signed-off-by: Alberto Garcia <berto@igalia.com>
14
if (ctx_ && in_aio_context_home_thread(ctx_)) { \
14
Reviewed-by: Eric Blake <eblake@redhat.com>
15
while ((cond)) { \
16
aio_poll(ctx_, true); \
17
waited_ = true; \
18
} \
19
20
And that means AIO_WAIT_WHILE_UNLOCKED(NULL, ...) can be substituted.
21
22
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
23
Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org>
24
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
25
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
26
Message-Id: <20230309190855.414275-4-stefanha@redhat.com>
27
Reviewed-by: Wilfred Mallawa <wilfred.mallawa@wdc.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
28
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
---
29
---
17
block/qcow2-snapshot.c | 7 +++++++
30
block/graph-lock.c | 2 +-
18
tests/qemu-iotests/080 | 2 ++
31
1 file changed, 1 insertion(+), 1 deletion(-)
19
tests/qemu-iotests/080.out | 2 ++
20
3 files changed, 11 insertions(+)
21
32
22
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
33
diff --git a/block/graph-lock.c b/block/graph-lock.c
23
index XXXXXXX..XXXXXXX 100644
34
index XXXXXXX..XXXXXXX 100644
24
--- a/block/qcow2-snapshot.c
35
--- a/block/graph-lock.c
25
+++ b/block/qcow2-snapshot.c
36
+++ b/block/graph-lock.c
26
@@ -XXX,XX +XXX,XX @@ int qcow2_snapshot_delete(BlockDriverState *bs,
37
@@ -XXX,XX +XXX,XX @@ void bdrv_graph_wrlock(void)
27
}
38
* reader lock.
28
sn = s->snapshots[snapshot_index];
39
*/
29
40
qatomic_set(&has_writer, 0);
30
+ ret = qcow2_validate_table(bs, sn.l1_table_offset, sn.l1_size,
41
- AIO_WAIT_WHILE(qemu_get_aio_context(), reader_count() >= 1);
31
+ sizeof(uint64_t), QCOW_MAX_L1_SIZE,
42
+ AIO_WAIT_WHILE_UNLOCKED(NULL, reader_count() >= 1);
32
+ "Snapshot L1 table", errp);
43
qatomic_set(&has_writer, 1);
33
+ if (ret < 0) {
44
34
+ return ret;
45
/*
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
--
46
--
79
2.13.6
47
2.40.0
80
48
81
49
diff view generated by jsdifflib
1
From: Stefan Hajnoczi <stefanha@redhat.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
There is a race between the test's 'query-migrate' QMP command after the
3
Since the AioContext argument was already NULL, AIO_WAIT_WHILE() was
4
QMP 'STOP' event and completing the migration:
4
never going to unlock the AioContext. Therefore it is possible to
5
replace AIO_WAIT_WHILE() with AIO_WAIT_WHILE_UNLOCKED().
5
6
6
The test case invokes 'query-migrate' upon receiving 'STOP'. At this
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
7
point the migration thread may still be in the process of completing.
8
Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org>
8
Therefore 'query-migrate' can return 'status': 'active' for a brief
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9
window of time instead of 'status': 'completed'. This results in
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
qemu-iotests 203 hanging.
11
Message-Id: <20230309190855.414275-5-stefanha@redhat.com>
12
Reviewed-by: Wilfred Mallawa <wilfred.mallawa@wdc.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
15
block/io.c | 2 +-
16
1 file changed, 1 insertion(+), 1 deletion(-)
11
17
12
Solve the race by enabling the 'events' migration capability, which
18
diff --git a/block/io.c b/block/io.c
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
19
index XXXXXXX..XXXXXXX 100644
56
--- a/tests/qemu-iotests/203.out
20
--- a/block/io.c
57
+++ b/tests/qemu-iotests/203.out
21
+++ b/block/io.c
58
@@ -XXX,XX +XXX,XX @@ Launching VM...
22
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
59
Setting IOThreads...
23
bdrv_drain_all_begin_nopoll();
60
{u'return': {}}
24
61
{u'return': {}}
25
/* Now poll the in-flight requests */
62
+Enabling migration QMP events...
26
- AIO_WAIT_WHILE(NULL, bdrv_drain_all_poll());
63
+{u'return': {}}
27
+ AIO_WAIT_WHILE_UNLOCKED(NULL, bdrv_drain_all_poll());
64
Starting migration...
28
65
{u'return': {}}
29
while ((bs = bdrv_next_all_states(bs))) {
66
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'setup'}, u'event': u'MIGRATION'}
30
bdrv_drain_assert_idle(bs);
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
--
31
--
70
2.13.6
32
2.40.0
71
33
72
34
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
This function iterates over all snapshots of a qcow2 file in order to
3
The HMP monitor runs in the main loop thread. Calling
4
expand all zero clusters, but it does not validate the snapshots' L1
4
AIO_WAIT_WHILE(qemu_get_aio_context(), ...) from the main loop thread is
5
tables first.
5
equivalent to AIO_WAIT_WHILE_UNLOCKED(NULL, ...) because neither unlocks
6
the AioContext and the latter's assertion that we're in the main loop
7
succeeds.
6
8
7
We now have a function to take care of this, so let's use it.
9
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
8
10
Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org>
9
We can also take the opportunity to replace the sector-based
11
Reviewed-by: Markus Armbruster <armbru@redhat.com>
10
bdrv_read() with bdrv_pread().
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
11
13
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Cc: Eric Blake <eblake@redhat.com>
14
Message-Id: <20230309190855.414275-6-stefanha@redhat.com>
13
Signed-off-by: Alberto Garcia <berto@igalia.com>
15
Reviewed-by: Wilfred Mallawa <wilfred.mallawa@wdc.com>
14
Reviewed-by: Eric Blake <eblake@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
---
17
---
17
block/qcow2-cluster.c | 24 +++++++++++++++++-------
18
monitor/hmp.c | 2 +-
18
tests/qemu-iotests/080 | 2 ++
19
1 file changed, 1 insertion(+), 1 deletion(-)
19
tests/qemu-iotests/080.out | 4 ++++
20
3 files changed, 23 insertions(+), 7 deletions(-)
21
20
22
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
21
diff --git a/monitor/hmp.c b/monitor/hmp.c
23
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
24
--- a/block/qcow2-cluster.c
23
--- a/monitor/hmp.c
25
+++ b/block/qcow2-cluster.c
24
+++ b/monitor/hmp.c
26
@@ -XXX,XX +XXX,XX @@
25
@@ -XXX,XX +XXX,XX @@ void handle_hmp_command(MonitorHMP *mon, const char *cmdline)
27
#include "qemu/osdep.h"
26
Coroutine *co = qemu_coroutine_create(handle_hmp_command_co, &data);
28
#include <zlib.h>
27
monitor_set_cur(co, &mon->common);
29
28
aio_co_enter(qemu_get_aio_context(), co);
30
+#include "qapi/error.h"
29
- AIO_WAIT_WHILE(qemu_get_aio_context(), !data.done);
31
#include "qemu-common.h"
30
+ AIO_WAIT_WHILE_UNLOCKED(NULL, !data.done);
32
#include "block/block_int.h"
33
#include "block/qcow2.h"
34
@@ -XXX,XX +XXX,XX @@ int qcow2_expand_zero_clusters(BlockDriverState *bs,
35
}
31
}
36
32
37
for (i = 0; i < s->nb_snapshots; i++) {
33
qobject_unref(qdict);
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
--
34
--
112
2.13.6
35
2.40.0
113
36
114
37
diff view generated by jsdifflib
1
Move the parsing of the QDict options up to the callers, in preparation
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
for the .bdrv_co_create implementation that directly gets a QAPI type.
3
2
3
monitor_cleanup() is called from the main loop thread. Calling
4
AIO_WAIT_WHILE(qemu_get_aio_context(), ...) from the main loop thread is
5
equivalent to AIO_WAIT_WHILE_UNLOCKED(NULL, ...) because neither unlocks
6
the AioContext and the latter's assertion that we're in the main loop
7
succeeds.
8
9
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
10
Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org>
11
Reviewed-by: Markus Armbruster <armbru@redhat.com>
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
13
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
14
Message-Id: <20230309190855.414275-7-stefanha@redhat.com>
15
Reviewed-by: Wilfred Mallawa <wilfred.mallawa@wdc.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
---
17
---
7
block/ssh.c | 34 +++++++++++++++++++++-------------
18
monitor/monitor.c | 4 ++--
8
1 file changed, 21 insertions(+), 13 deletions(-)
19
1 file changed, 2 insertions(+), 2 deletions(-)
9
20
10
diff --git a/block/ssh.c b/block/ssh.c
21
diff --git a/monitor/monitor.c b/monitor/monitor.c
11
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
12
--- a/block/ssh.c
23
--- a/monitor/monitor.c
13
+++ b/block/ssh.c
24
+++ b/monitor/monitor.c
14
@@ -XXX,XX +XXX,XX @@ fail:
25
@@ -XXX,XX +XXX,XX @@ void monitor_cleanup(void)
15
return result;
26
* We need to poll both qemu_aio_context and iohandler_ctx to make
16
}
27
* sure that the dispatcher coroutine keeps making progress and
17
28
* eventually terminates. qemu_aio_context is automatically
18
-static int connect_to_ssh(BDRVSSHState *s, QDict *options,
29
- * polled by calling AIO_WAIT_WHILE on it, but we must poll
19
+static int connect_to_ssh(BDRVSSHState *s, BlockdevOptionsSsh *opts,
30
+ * polled by calling AIO_WAIT_WHILE_UNLOCKED on it, but we must poll
20
int ssh_flags, int creat_mode, Error **errp)
31
* iohandler_ctx manually.
21
{
32
*
22
- BlockdevOptionsSsh *opts;
33
* Letting the iothread continue while shutting down the dispatcher
23
int r, ret;
34
@@ -XXX,XX +XXX,XX @@ void monitor_cleanup(void)
24
const char *user;
35
aio_co_wake(qmp_dispatcher_co);
25
long port = 0;
26
27
- opts = ssh_parse_options(options, errp);
28
- if (opts == NULL) {
29
- return -EINVAL;
30
- }
31
-
32
if (opts->has_user) {
33
user = opts->user;
34
} else {
35
@@ -XXX,XX +XXX,XX @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
36
goto err;
37
}
36
}
38
37
39
- qapi_free_BlockdevOptionsSsh(opts);
38
- AIO_WAIT_WHILE(qemu_get_aio_context(),
40
-
39
+ AIO_WAIT_WHILE_UNLOCKED(NULL,
41
r = libssh2_sftp_fstat(s->sftp_handle, &s->attrs);
40
(aio_poll(iohandler_get_aio_context(), false),
42
if (r < 0) {
41
qatomic_mb_read(&qmp_dispatcher_co_busy)));
43
sftp_error_setg(errp, s, "failed to read file attributes");
44
@@ -XXX,XX +XXX,XX @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
45
}
46
s->session = NULL;
47
48
- qapi_free_BlockdevOptionsSsh(opts);
49
-
50
return ret;
51
}
52
53
@@ -XXX,XX +XXX,XX @@ static int ssh_file_open(BlockDriverState *bs, QDict *options, int bdrv_flags,
54
Error **errp)
55
{
56
BDRVSSHState *s = bs->opaque;
57
+ BlockdevOptionsSsh *opts;
58
int ret;
59
int ssh_flags;
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
42
125
--
43
--
126
2.13.6
44
2.40.0
127
45
128
46
diff view generated by jsdifflib
1
This adds the .bdrv_co_create driver callback to nfs, which enables
1
From: Wilfred Mallawa <wilfred.mallawa@wdc.com>
2
image creation over QMP.
3
2
3
Fixup a few minor typos
4
5
Signed-off-by: Wilfred Mallawa <wilfred.mallawa@wdc.com>
6
Message-Id: <20230313003744.55476-1-wilfred.mallawa@opensource.wdc.com>
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
8
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
---
10
---
7
qapi/block-core.json | 16 ++++++++++-
11
include/block/aio-wait.h | 2 +-
8
block/nfs.c | 76 +++++++++++++++++++++++++++++++++++++++++-----------
12
include/block/block_int-common.h | 2 +-
9
2 files changed, 75 insertions(+), 17 deletions(-)
13
2 files changed, 2 insertions(+), 2 deletions(-)
10
14
11
diff --git a/qapi/block-core.json b/qapi/block-core.json
15
diff --git a/include/block/aio-wait.h b/include/block/aio-wait.h
12
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
13
--- a/qapi/block-core.json
17
--- a/include/block/aio-wait.h
14
+++ b/qapi/block-core.json
18
+++ b/include/block/aio-wait.h
15
@@ -XXX,XX +XXX,XX @@
19
@@ -XXX,XX +XXX,XX @@ extern AioWait global_aio_wait;
16
'*preallocation': 'PreallocMode' } }
20
* @ctx: the aio context, or NULL if multiple aio contexts (for which the
17
21
* caller does not hold a lock) are involved in the polling condition.
18
##
22
* @cond: wait while this conditional expression is true
19
+# @BlockdevCreateOptionsNfs:
23
- * @unlock: whether to unlock and then lock again @ctx. This apples
20
+#
24
+ * @unlock: whether to unlock and then lock again @ctx. This applies
21
+# Driver specific image creation options for NFS.
25
* only when waiting for another AioContext from the main loop.
22
+#
26
* Otherwise it's ignored.
23
+# @location Where to store the new image file
27
*
24
+# @size Size of the virtual disk in bytes
28
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
25
+#
26
+# Since: 2.12
27
+##
28
+{ 'struct': 'BlockdevCreateOptionsNfs',
29
+ 'data': { 'location': 'BlockdevOptionsNfs',
30
+ 'size': 'size' } }
31
+
32
+##
33
# @BlockdevQcow2Version:
34
#
35
# @v2: The original QCOW2 format as introduced in qemu 0.10 (version 2)
36
@@ -XXX,XX +XXX,XX @@
37
'iscsi': 'BlockdevCreateNotSupported',
38
'luks': 'BlockdevCreateNotSupported',
39
'nbd': 'BlockdevCreateNotSupported',
40
- 'nfs': 'BlockdevCreateNotSupported',
41
+ 'nfs': 'BlockdevCreateOptionsNfs',
42
'null-aio': 'BlockdevCreateNotSupported',
43
'null-co': 'BlockdevCreateNotSupported',
44
'nvme': 'BlockdevCreateNotSupported',
45
diff --git a/block/nfs.c b/block/nfs.c
46
index XXXXXXX..XXXXXXX 100644
29
index XXXXXXX..XXXXXXX 100644
47
--- a/block/nfs.c
30
--- a/include/block/block_int-common.h
48
+++ b/block/nfs.c
31
+++ b/include/block/block_int-common.h
49
@@ -XXX,XX +XXX,XX @@ out:
32
@@ -XXX,XX +XXX,XX @@ extern QemuOptsList bdrv_create_opts_simple;
50
return ret;
33
/*
51
}
34
* Common functions that are neither I/O nor Global State.
52
35
*
53
-static int64_t nfs_client_open_qdict(NFSClient *client, QDict *options,
36
- * See include/block/block-commmon.h for more information about
54
- int flags, int open_flags, Error **errp)
37
+ * See include/block/block-common.h for more information about
55
+static BlockdevOptionsNfs *nfs_options_qdict_to_qapi(QDict *options,
38
* the Common API.
56
+ Error **errp)
39
*/
57
{
58
BlockdevOptionsNfs *opts = NULL;
59
QObject *crumpled = NULL;
60
Visitor *v;
61
Error *local_err = NULL;
62
- int ret;
63
64
crumpled = qdict_crumple(options, errp);
65
if (crumpled == NULL) {
66
- return -EINVAL;
67
+ return NULL;
68
}
69
70
v = qobject_input_visitor_new_keyval(crumpled);
71
visit_type_BlockdevOptionsNfs(v, NULL, &opts, &local_err);
72
visit_free(v);
73
+ qobject_decref(crumpled);
74
75
if (local_err) {
76
- error_propagate(errp, local_err);
77
+ return NULL;
78
+ }
79
+
80
+ return opts;
81
+}
82
+
83
+static int64_t nfs_client_open_qdict(NFSClient *client, QDict *options,
84
+ int flags, int open_flags, Error **errp)
85
+{
86
+ BlockdevOptionsNfs *opts;
87
+ int ret;
88
+
89
+ opts = nfs_options_qdict_to_qapi(options, errp);
90
+ if (opts == NULL) {
91
ret = -EINVAL;
92
goto fail;
93
}
94
95
ret = nfs_client_open(client, opts, flags, open_flags, errp);
96
fail:
97
- qobject_decref(crumpled);
98
qapi_free_BlockdevOptionsNfs(opts);
99
return ret;
100
}
101
@@ -XXX,XX +XXX,XX @@ static QemuOptsList nfs_create_opts = {
102
}
103
};
104
105
-static int coroutine_fn nfs_file_co_create_opts(const char *url, QemuOpts *opts,
106
- Error **errp)
107
+static int nfs_file_co_create(BlockdevCreateOptions *options, Error **errp)
108
{
109
- int64_t ret, total_size;
110
+ BlockdevCreateOptionsNfs *opts = &options->u.nfs;
111
NFSClient *client = g_new0(NFSClient, 1);
112
- QDict *options = NULL;
113
+ int ret;
114
+
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
40
185
--
41
--
186
2.13.6
42
2.40.0
187
43
188
44
diff view generated by jsdifflib
1
Most callers have their own checks, but something like this should also
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
be checked centrally. As it happens, x-blockdev-create can pass negative
3
image sizes to format drivers (because there is no QAPI type that would
4
reject negative numbers) and triggers the check added by this patch.
5
2
3
Not a coroutine_fn, you say?
4
5
static int64_t bdrv_sum_allocated_file_size(BlockDriverState *bs)
6
{
7
BdrvChild *child;
8
int64_t child_size, sum = 0;
9
10
QLIST_FOREACH(child, &bs->children, next) {
11
if (child->role & (BDRV_CHILD_DATA | BDRV_CHILD_METADATA |
12
BDRV_CHILD_FILTERED))
13
{
14
child_size = bdrv_co_get_allocated_file_size(child->bs);
15
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
16
17
Well what do we have here?!
18
19
I rest my case, your honor.
20
21
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
22
Message-Id: <20230308211435.346375-1-stefanha@redhat.com>
23
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
24
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
9
---
25
---
10
block.c | 5 +++++
26
block.c | 2 +-
11
1 file changed, 5 insertions(+)
27
1 file changed, 1 insertion(+), 1 deletion(-)
12
28
13
diff --git a/block.c b/block.c
29
diff --git a/block.c b/block.c
14
index XXXXXXX..XXXXXXX 100644
30
index XXXXXXX..XXXXXXX 100644
15
--- a/block.c
31
--- a/block.c
16
+++ b/block.c
32
+++ b/block.c
17
@@ -XXX,XX +XXX,XX @@ int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc,
33
@@ -XXX,XX +XXX,XX @@ exit:
18
error_setg(errp, "No medium inserted");
34
* sums the size of all data-bearing children. (This excludes backing
19
return -ENOMEDIUM;
35
* children.)
20
}
36
*/
21
+ if (offset < 0) {
37
-static int64_t bdrv_sum_allocated_file_size(BlockDriverState *bs)
22
+ error_setg(errp, "Image size cannot be negative");
38
+static int64_t coroutine_fn bdrv_sum_allocated_file_size(BlockDriverState *bs)
23
+ return -EINVAL;
39
{
24
+ }
40
BdrvChild *child;
25
+
41
int64_t child_size, sum = 0;
26
if (!drv->bdrv_truncate) {
27
if (bs->file && drv->is_filter) {
28
return bdrv_truncate(bs->file, offset, prealloc, errp);
29
--
42
--
30
2.13.6
43
2.40.0
31
32
diff view generated by jsdifflib
1
If bdrv_truncate() is called, but the requested size is the same as
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
2
before, don't call posix_fallocate(), which returns -EINVAL for length
2
3
zero and would therefore make bdrv_truncate() fail.
3
Remove usage of aio_context_acquire by always submitting asynchronous
4
4
AIO to the current thread's LinuxAioState.
5
The problem can be triggered by creating a zero-sized raw image with
5
6
'falloc' preallocation mode.
6
In order to prevent mistakes from the caller side, avoid passing LinuxAioState
7
7
in laio_io_{plug/unplug} and laio_co_submit, and document the functions
8
to make clear that they work in the current thread's AioContext.
9
10
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
11
Message-Id: <20230203131731.851116-2-eesposit@redhat.com>
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
13
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
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
---
15
---
12
block/file-posix.c | 14 +++++++++-----
16
include/block/aio.h | 4 ----
13
1 file changed, 9 insertions(+), 5 deletions(-)
17
include/block/raw-aio.h | 18 ++++++++++++------
14
18
include/sysemu/block-backend-io.h | 5 +++++
19
block/file-posix.c | 10 +++-------
20
block/linux-aio.c | 29 +++++++++++++++++------------
21
5 files changed, 37 insertions(+), 29 deletions(-)
22
23
diff --git a/include/block/aio.h b/include/block/aio.h
24
index XXXXXXX..XXXXXXX 100644
25
--- a/include/block/aio.h
26
+++ b/include/block/aio.h
27
@@ -XXX,XX +XXX,XX @@ struct AioContext {
28
struct ThreadPool *thread_pool;
29
30
#ifdef CONFIG_LINUX_AIO
31
- /*
32
- * State for native Linux AIO. Uses aio_context_acquire/release for
33
- * locking.
34
- */
35
struct LinuxAioState *linux_aio;
36
#endif
37
#ifdef CONFIG_LINUX_IO_URING
38
diff --git a/include/block/raw-aio.h b/include/block/raw-aio.h
39
index XXXXXXX..XXXXXXX 100644
40
--- a/include/block/raw-aio.h
41
+++ b/include/block/raw-aio.h
42
@@ -XXX,XX +XXX,XX @@
43
typedef struct LinuxAioState LinuxAioState;
44
LinuxAioState *laio_init(Error **errp);
45
void laio_cleanup(LinuxAioState *s);
46
-int coroutine_fn laio_co_submit(BlockDriverState *bs, LinuxAioState *s, int fd,
47
- uint64_t offset, QEMUIOVector *qiov, int type,
48
- uint64_t dev_max_batch);
49
+
50
+/* laio_co_submit: submit I/O requests in the thread's current AioContext. */
51
+int coroutine_fn laio_co_submit(int fd, uint64_t offset, QEMUIOVector *qiov,
52
+ int type, uint64_t dev_max_batch);
53
+
54
void laio_detach_aio_context(LinuxAioState *s, AioContext *old_context);
55
void laio_attach_aio_context(LinuxAioState *s, AioContext *new_context);
56
-void laio_io_plug(BlockDriverState *bs, LinuxAioState *s);
57
-void laio_io_unplug(BlockDriverState *bs, LinuxAioState *s,
58
- uint64_t dev_max_batch);
59
+
60
+/*
61
+ * laio_io_plug/unplug work in the thread's current AioContext, therefore the
62
+ * caller must ensure that they are paired in the same IOThread.
63
+ */
64
+void laio_io_plug(void);
65
+void laio_io_unplug(uint64_t dev_max_batch);
66
#endif
67
/* io_uring.c - Linux io_uring implementation */
68
#ifdef CONFIG_LINUX_IO_URING
69
diff --git a/include/sysemu/block-backend-io.h b/include/sysemu/block-backend-io.h
70
index XXXXXXX..XXXXXXX 100644
71
--- a/include/sysemu/block-backend-io.h
72
+++ b/include/sysemu/block-backend-io.h
73
@@ -XXX,XX +XXX,XX @@ void blk_iostatus_set_err(BlockBackend *blk, int error);
74
int blk_get_max_iov(BlockBackend *blk);
75
int blk_get_max_hw_iov(BlockBackend *blk);
76
77
+/*
78
+ * blk_io_plug/unplug are thread-local operations. This means that multiple
79
+ * IOThreads can simultaneously call plug/unplug, but the caller must ensure
80
+ * that each unplug() is called in the same IOThread of the matching plug().
81
+ */
82
void coroutine_fn blk_co_io_plug(BlockBackend *blk);
83
void co_wrapper blk_io_plug(BlockBackend *blk);
84
15
diff --git a/block/file-posix.c b/block/file-posix.c
85
diff --git a/block/file-posix.c b/block/file-posix.c
16
index XXXXXXX..XXXXXXX 100644
86
index XXXXXXX..XXXXXXX 100644
17
--- a/block/file-posix.c
87
--- a/block/file-posix.c
18
+++ b/block/file-posix.c
88
+++ b/block/file-posix.c
19
@@ -XXX,XX +XXX,XX @@ static int raw_regular_truncate(int fd, int64_t offset, PreallocMode prealloc,
89
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_prw(BlockDriverState *bs, uint64_t offset,
20
* file systems that do not support fallocate(), trying to check if a
90
#endif
21
* block is allocated before allocating it, so don't do that here.
91
#ifdef CONFIG_LINUX_AIO
22
*/
92
} else if (s->use_linux_aio) {
23
- result = -posix_fallocate(fd, current_length, offset - current_length);
93
- LinuxAioState *aio = aio_get_linux_aio(bdrv_get_aio_context(bs));
24
- if (result != 0) {
94
assert(qiov->size == bytes);
25
- /* posix_fallocate() doesn't set errno. */
95
- return laio_co_submit(bs, aio, s->fd, offset, qiov, type,
26
- error_setg_errno(errp, -result,
96
- s->aio_max_batch);
27
- "Could not preallocate new data");
97
+ return laio_co_submit(s->fd, offset, qiov, type, s->aio_max_batch);
28
+ if (offset != current_length) {
98
#endif
29
+ result = -posix_fallocate(fd, current_length, offset - current_length);
99
}
30
+ if (result != 0) {
100
31
+ /* posix_fallocate() doesn't set errno. */
101
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn raw_co_io_plug(BlockDriverState *bs)
32
+ error_setg_errno(errp, -result,
102
BDRVRawState __attribute__((unused)) *s = bs->opaque;
33
+ "Could not preallocate new data");
103
#ifdef CONFIG_LINUX_AIO
34
+ }
104
if (s->use_linux_aio) {
35
+ } else {
105
- LinuxAioState *aio = aio_get_linux_aio(bdrv_get_aio_context(bs));
36
+ result = 0;
106
- laio_io_plug(bs, aio);
37
}
107
+ laio_io_plug();
38
goto out;
108
}
39
#endif
109
#endif
110
#ifdef CONFIG_LINUX_IO_URING
111
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn raw_co_io_unplug(BlockDriverState *bs)
112
BDRVRawState __attribute__((unused)) *s = bs->opaque;
113
#ifdef CONFIG_LINUX_AIO
114
if (s->use_linux_aio) {
115
- LinuxAioState *aio = aio_get_linux_aio(bdrv_get_aio_context(bs));
116
- laio_io_unplug(bs, aio, s->aio_max_batch);
117
+ laio_io_unplug(s->aio_max_batch);
118
}
119
#endif
120
#ifdef CONFIG_LINUX_IO_URING
121
diff --git a/block/linux-aio.c b/block/linux-aio.c
122
index XXXXXXX..XXXXXXX 100644
123
--- a/block/linux-aio.c
124
+++ b/block/linux-aio.c
125
@@ -XXX,XX +XXX,XX @@
126
#include "qemu/coroutine.h"
127
#include "qapi/error.h"
128
129
+/* Only used for assertions. */
130
+#include "qemu/coroutine_int.h"
131
+
132
#include <libaio.h>
133
134
/*
135
@@ -XXX,XX +XXX,XX @@ struct LinuxAioState {
136
io_context_t ctx;
137
EventNotifier e;
138
139
- /* io queue for submit at batch. Protected by AioContext lock. */
140
+ /* No locking required, only accessed from AioContext home thread */
141
LaioQueue io_q;
142
-
143
- /* I/O completion processing. Only runs in I/O thread. */
144
QEMUBH *completion_bh;
145
int event_idx;
146
int event_max;
147
@@ -XXX,XX +XXX,XX @@ static void qemu_laio_process_completion(struct qemu_laiocb *laiocb)
148
* later. Coroutines cannot be entered recursively so avoid doing
149
* that!
150
*/
151
+ assert(laiocb->co->ctx == laiocb->ctx->aio_context);
152
if (!qemu_coroutine_entered(laiocb->co)) {
153
aio_co_wake(laiocb->co);
154
}
155
@@ -XXX,XX +XXX,XX @@ static void qemu_laio_process_completions(LinuxAioState *s)
156
157
static void qemu_laio_process_completions_and_submit(LinuxAioState *s)
158
{
159
- aio_context_acquire(s->aio_context);
160
qemu_laio_process_completions(s);
161
162
if (!s->io_q.plugged && !QSIMPLEQ_EMPTY(&s->io_q.pending)) {
163
ioq_submit(s);
164
}
165
- aio_context_release(s->aio_context);
166
}
167
168
static void qemu_laio_completion_bh(void *opaque)
169
@@ -XXX,XX +XXX,XX @@ static uint64_t laio_max_batch(LinuxAioState *s, uint64_t dev_max_batch)
170
return max_batch;
171
}
172
173
-void laio_io_plug(BlockDriverState *bs, LinuxAioState *s)
174
+void laio_io_plug(void)
175
{
176
+ AioContext *ctx = qemu_get_current_aio_context();
177
+ LinuxAioState *s = aio_get_linux_aio(ctx);
178
+
179
s->io_q.plugged++;
180
}
181
182
-void laio_io_unplug(BlockDriverState *bs, LinuxAioState *s,
183
- uint64_t dev_max_batch)
184
+void laio_io_unplug(uint64_t dev_max_batch)
185
{
186
+ AioContext *ctx = qemu_get_current_aio_context();
187
+ LinuxAioState *s = aio_get_linux_aio(ctx);
188
+
189
assert(s->io_q.plugged);
190
s->io_q.plugged--;
191
192
@@ -XXX,XX +XXX,XX @@ static int laio_do_submit(int fd, struct qemu_laiocb *laiocb, off_t offset,
193
return 0;
194
}
195
196
-int coroutine_fn laio_co_submit(BlockDriverState *bs, LinuxAioState *s, int fd,
197
- uint64_t offset, QEMUIOVector *qiov, int type,
198
- uint64_t dev_max_batch)
199
+int coroutine_fn laio_co_submit(int fd, uint64_t offset, QEMUIOVector *qiov,
200
+ int type, uint64_t dev_max_batch)
201
{
202
int ret;
203
+ AioContext *ctx = qemu_get_current_aio_context();
204
struct qemu_laiocb laiocb = {
205
.co = qemu_coroutine_self(),
206
.nbytes = qiov->size,
207
- .ctx = s,
208
+ .ctx = aio_get_linux_aio(ctx),
209
.ret = -EINPROGRESS,
210
.is_read = (type == QEMU_AIO_READ),
211
.qiov = qiov,
40
--
212
--
41
2.13.6
213
2.40.0
42
43
diff view generated by jsdifflib
1
This adds the .bdrv_co_create driver callback to sheepdog, which enables
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
2
image creation over QMP.
3
2
3
Remove usage of aio_context_acquire by always submitting asynchronous
4
AIO to the current thread's LuringState.
5
6
In order to prevent mistakes from the caller side, avoid passing LuringState
7
in luring_io_{plug/unplug} and luring_co_submit, and document the functions
8
to make clear that they work in the current thread's AioContext.
9
10
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
11
Message-Id: <20230203131731.851116-3-eesposit@redhat.com>
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
13
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
---
15
---
7
qapi/block-core.json | 24 ++++-
16
include/block/aio.h | 4 ----
8
block/sheepdog.c | 243 +++++++++++++++++++++++++++++++++++----------------
17
include/block/raw-aio.h | 15 +++++++++++----
9
2 files changed, 192 insertions(+), 75 deletions(-)
18
block/file-posix.c | 12 ++++--------
19
block/io_uring.c | 23 +++++++++++++++--------
20
4 files changed, 30 insertions(+), 24 deletions(-)
10
21
11
diff --git a/qapi/block-core.json b/qapi/block-core.json
22
diff --git a/include/block/aio.h b/include/block/aio.h
12
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
13
--- a/qapi/block-core.json
24
--- a/include/block/aio.h
14
+++ b/qapi/block-core.json
25
+++ b/include/block/aio.h
26
@@ -XXX,XX +XXX,XX @@ struct AioContext {
27
struct LinuxAioState *linux_aio;
28
#endif
29
#ifdef CONFIG_LINUX_IO_URING
30
- /*
31
- * State for Linux io_uring. Uses aio_context_acquire/release for
32
- * locking.
33
- */
34
struct LuringState *linux_io_uring;
35
36
/* State for file descriptor monitoring using Linux io_uring */
37
diff --git a/include/block/raw-aio.h b/include/block/raw-aio.h
38
index XXXXXXX..XXXXXXX 100644
39
--- a/include/block/raw-aio.h
40
+++ b/include/block/raw-aio.h
41
@@ -XXX,XX +XXX,XX @@ void laio_io_unplug(uint64_t dev_max_batch);
42
typedef struct LuringState LuringState;
43
LuringState *luring_init(Error **errp);
44
void luring_cleanup(LuringState *s);
45
-int coroutine_fn luring_co_submit(BlockDriverState *bs, LuringState *s, int fd,
46
- uint64_t offset, QEMUIOVector *qiov, int type);
47
+
48
+/* luring_co_submit: submit I/O requests in the thread's current AioContext. */
49
+int coroutine_fn luring_co_submit(BlockDriverState *bs, int fd, uint64_t offset,
50
+ QEMUIOVector *qiov, int type);
51
void luring_detach_aio_context(LuringState *s, AioContext *old_context);
52
void luring_attach_aio_context(LuringState *s, AioContext *new_context);
53
-void luring_io_plug(BlockDriverState *bs, LuringState *s);
54
-void luring_io_unplug(BlockDriverState *bs, LuringState *s);
55
+
56
+/*
57
+ * luring_io_plug/unplug work in the thread's current AioContext, therefore the
58
+ * caller must ensure that they are paired in the same IOThread.
59
+ */
60
+void luring_io_plug(void);
61
+void luring_io_unplug(void);
62
#endif
63
64
#ifdef _WIN32
65
diff --git a/block/file-posix.c b/block/file-posix.c
66
index XXXXXXX..XXXXXXX 100644
67
--- a/block/file-posix.c
68
+++ b/block/file-posix.c
69
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_prw(BlockDriverState *bs, uint64_t offset,
70
type |= QEMU_AIO_MISALIGNED;
71
#ifdef CONFIG_LINUX_IO_URING
72
} else if (s->use_linux_io_uring) {
73
- LuringState *aio = aio_get_linux_io_uring(bdrv_get_aio_context(bs));
74
assert(qiov->size == bytes);
75
- return luring_co_submit(bs, aio, s->fd, offset, qiov, type);
76
+ return luring_co_submit(bs, s->fd, offset, qiov, type);
77
#endif
78
#ifdef CONFIG_LINUX_AIO
79
} else if (s->use_linux_aio) {
80
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn raw_co_io_plug(BlockDriverState *bs)
81
#endif
82
#ifdef CONFIG_LINUX_IO_URING
83
if (s->use_linux_io_uring) {
84
- LuringState *aio = aio_get_linux_io_uring(bdrv_get_aio_context(bs));
85
- luring_io_plug(bs, aio);
86
+ luring_io_plug();
87
}
88
#endif
89
}
90
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn raw_co_io_unplug(BlockDriverState *bs)
91
#endif
92
#ifdef CONFIG_LINUX_IO_URING
93
if (s->use_linux_io_uring) {
94
- LuringState *aio = aio_get_linux_io_uring(bdrv_get_aio_context(bs));
95
- luring_io_unplug(bs, aio);
96
+ luring_io_unplug();
97
}
98
#endif
99
}
100
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_flush_to_disk(BlockDriverState *bs)
101
102
#ifdef CONFIG_LINUX_IO_URING
103
if (s->use_linux_io_uring) {
104
- LuringState *aio = aio_get_linux_io_uring(bdrv_get_aio_context(bs));
105
- return luring_co_submit(bs, aio, s->fd, 0, NULL, QEMU_AIO_FLUSH);
106
+ return luring_co_submit(bs, s->fd, 0, NULL, QEMU_AIO_FLUSH);
107
}
108
#endif
109
return raw_thread_pool_submit(bs, handle_aiocb_flush, &acb);
110
diff --git a/block/io_uring.c b/block/io_uring.c
111
index XXXXXXX..XXXXXXX 100644
112
--- a/block/io_uring.c
113
+++ b/block/io_uring.c
15
@@ -XXX,XX +XXX,XX @@
114
@@ -XXX,XX +XXX,XX @@
16
'erasure-coded': 'SheepdogRedundancyErasureCoded' } }
115
#include "qapi/error.h"
17
116
#include "trace.h"
18
##
117
19
+# @BlockdevCreateOptionsSheepdog:
118
+/* Only used for assertions. */
20
+#
119
+#include "qemu/coroutine_int.h"
21
+# Driver specific image creation options for Sheepdog.
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
+
120
+
40
+##
121
/* io_uring ring size */
41
# @BlockdevCreateNotSupported:
122
#define MAX_ENTRIES 128
42
#
123
43
# This is used for all drivers that don't support creating images.
124
@@ -XXX,XX +XXX,XX @@ typedef struct LuringState {
44
@@ -XXX,XX +XXX,XX @@
125
45
'raw': 'BlockdevCreateNotSupported',
126
struct io_uring ring;
46
'rbd': 'BlockdevCreateOptionsRbd',
127
47
'replication': 'BlockdevCreateNotSupported',
128
- /* io queue for submit at batch. Protected by AioContext lock. */
48
- 'sheepdog': 'BlockdevCreateNotSupported',
129
+ /* No locking required, only accessed from AioContext home thread */
49
+ 'sheepdog': 'BlockdevCreateOptionsSheepdog',
130
LuringQueue io_q;
50
'ssh': 'BlockdevCreateNotSupported',
131
51
'throttle': 'BlockdevCreateNotSupported',
132
- /* I/O completion processing. Only runs in I/O thread. */
52
'vdi': 'BlockdevCreateNotSupported',
133
QEMUBH *completion_bh;
53
diff --git a/block/sheepdog.c b/block/sheepdog.c
134
} LuringState;
54
index XXXXXXX..XXXXXXX 100644
135
55
--- a/block/sheepdog.c
136
@@ -XXX,XX +XXX,XX @@ end:
56
+++ b/block/sheepdog.c
137
* eventually runs later. Coroutines cannot be entered recursively
57
@@ -XXX,XX +XXX,XX @@
138
* so avoid doing that!
58
#include "qemu/osdep.h"
139
*/
59
#include "qapi/error.h"
140
+ assert(luringcb->co->ctx == s->aio_context);
60
#include "qapi/qapi-visit-sockets.h"
141
if (!qemu_coroutine_entered(luringcb->co)) {
61
+#include "qapi/qapi-visit-block-core.h"
142
aio_co_wake(luringcb->co);
62
#include "qapi/qmp/qdict.h"
143
}
63
#include "qapi/qobject-input-visitor.h"
144
@@ -XXX,XX +XXX,XX @@ static int ioq_submit(LuringState *s)
64
+#include "qapi/qobject-output-visitor.h"
145
65
#include "qemu/uri.h"
146
static void luring_process_completions_and_submit(LuringState *s)
66
#include "qemu/error-report.h"
147
{
67
#include "qemu/option.h"
148
- aio_context_acquire(s->aio_context);
68
@@ -XXX,XX +XXX,XX @@ static void sd_aio_setup(SheepdogAIOCB *acb, BDRVSheepdogState *s,
149
luring_process_completions(s);
69
qemu_co_mutex_unlock(&s->queue_lock);
150
151
if (!s->io_q.plugged && s->io_q.in_queue > 0) {
152
ioq_submit(s);
153
}
154
- aio_context_release(s->aio_context);
70
}
155
}
71
156
72
-static SocketAddress *sd_socket_address(const char *path,
157
static void qemu_luring_completion_bh(void *opaque)
73
- const char *host, const char *port)
158
@@ -XXX,XX +XXX,XX @@ static void ioq_init(LuringQueue *io_q)
74
-{
159
io_q->blocked = false;
75
- SocketAddress *addr = g_new0(SocketAddress, 1);
160
}
76
-
161
77
- if (path) {
162
-void luring_io_plug(BlockDriverState *bs, LuringState *s)
78
- addr->type = SOCKET_ADDRESS_TYPE_UNIX;
163
+void luring_io_plug(void)
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
{
164
{
91
QDict *server = NULL;
165
+ AioContext *ctx = qemu_get_current_aio_context();
92
@@ -XXX,XX +XXX,XX @@ out_with_err_set:
166
+ LuringState *s = aio_get_linux_io_uring(ctx);
93
return ret;
167
trace_luring_io_plug(s);
168
s->io_q.plugged++;
94
}
169
}
95
170
96
+static int sd_create_prealloc(BlockdevOptionsSheepdog *location, int64_t size,
171
-void luring_io_unplug(BlockDriverState *bs, LuringState *s)
97
+ Error **errp)
172
+void luring_io_unplug(void)
98
+{
99
+ BlockDriverState *bs;
100
+ Visitor *v;
101
+ QObject *obj = NULL;
102
+ QDict *qdict;
103
+ Error *local_err = NULL;
104
+ int ret;
105
+
106
+ v = qobject_output_visitor_new(&obj);
107
+ visit_type_BlockdevOptionsSheepdog(v, NULL, &location, &local_err);
108
+ visit_free(v);
109
+
110
+ if (local_err) {
111
+ error_propagate(errp, local_err);
112
+ qobject_decref(obj);
113
+ return -EINVAL;
114
+ }
115
+
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
{
173
{
136
struct SheepdogInode *inode = &s->inode;
174
+ AioContext *ctx = qemu_get_current_aio_context();
137
@@ -XXX,XX +XXX,XX @@ static int parse_redundancy(BDRVSheepdogState *s, SheepdogRedundancy *opt)
175
+ LuringState *s = aio_get_linux_io_uring(ctx);
138
* # create a erasure coded vdi with x data strips and y parity strips
176
assert(s->io_q.plugged);
139
* -o redundancy=x:y (x must be one of {2,4,8,16} and 1 <= y < SD_EC_MAX_STRIP)
177
trace_luring_io_unplug(s, s->io_q.blocked, s->io_q.plugged,
140
*/
178
s->io_q.in_queue, s->io_q.in_flight);
141
-static int parse_redundancy_str(BDRVSheepdogState *s, const char *opt)
179
@@ -XXX,XX +XXX,XX @@ static int luring_do_submit(int fd, LuringAIOCB *luringcb, LuringState *s,
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;
180
return 0;
208
}
181
}
209
182
210
-static int coroutine_fn sd_co_create_opts(const char *filename, QemuOpts *opts,
183
-int coroutine_fn luring_co_submit(BlockDriverState *bs, LuringState *s, int fd,
211
- Error **errp)
184
- uint64_t offset, QEMUIOVector *qiov, int type)
212
+static int sd_co_create(BlockdevCreateOptions *options, Error **errp)
185
+int coroutine_fn luring_co_submit(BlockDriverState *bs, int fd, uint64_t offset,
186
+ QEMUIOVector *qiov, int type)
213
{
187
{
214
- Error *err = NULL;
188
int ret;
215
+ BlockdevCreateOptionsSheepdog *opts = &options->u.sheepdog;
189
+ AioContext *ctx = qemu_get_current_aio_context();
216
int ret = 0;
190
+ LuringState *s = aio_get_linux_io_uring(ctx);
217
uint32_t vid = 0;
191
LuringAIOCB luringcb = {
218
char *backing_file = NULL;
192
.co = qemu_coroutine_self(),
219
char *buf = NULL;
193
.ret = -EINPROGRESS,
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;
244
}
245
+ pstrcpy(s->name, sizeof(s->name), opts->location->vdi);
246
247
- buf = cfg.port ? g_strdup_printf("%d", cfg.port) : NULL;
248
- s->addr = sd_socket_address(cfg.path, cfg.host, buf);
249
- g_free(buf);
250
- strcpy(s->name, cfg.vdi);
251
- sd_config_done(&cfg);
252
+ s->inode.vdi_size = opts->size;
253
+ backing_file = opts->backing_file;
254
255
- s->inode.vdi_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
256
- BDRV_SECTOR_SIZE);
257
- backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
258
- buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
259
- if (!buf || !strcmp(buf, "off")) {
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;
277
}
278
279
- g_free(buf);
280
- buf = qemu_opt_get_del(opts, BLOCK_OPT_REDUNDANCY);
281
- if (buf) {
282
- ret = parse_redundancy_str(s, buf);
283
+ if (opts->has_redundancy) {
284
+ ret = parse_redundancy(s, opts->redundancy);
285
if (ret < 0) {
286
- error_setg(errp, "Invalid redundancy mode: '%s'", buf);
287
+ error_setg(errp, "Invalid redundancy mode");
288
goto out;
289
}
290
}
291
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn sd_co_create_opts(const char *filename, QemuOpts *opts,
292
goto out;
293
}
294
295
- if (backing_file) {
296
+ if (opts->has_backing_file) {
297
BlockBackend *blk;
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
--
194
--
451
2.13.6
195
2.40.0
452
453
diff view generated by jsdifflib
1
This adds the .bdrv_co_create driver callback to file, which enables
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
2
image creation over QMP.
2
3
3
Use qemu_get_current_aio_context() where possible, since we always
4
submit work to the current thread anyways.
5
6
We want to also be sure that the thread submitting the work is
7
the same as the one processing the pool, to avoid adding
8
synchronization to the pool list.
9
10
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
11
Message-Id: <20230203131731.851116-4-eesposit@redhat.com>
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
13
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
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
---
15
---
8
qapi/block-core.json | 20 ++++++++++++-
16
include/block/thread-pool.h | 5 +++++
9
block/file-posix.c | 79 +++++++++++++++++++++++++++++++++++++---------------
17
block/file-posix.c | 21 ++++++++++-----------
10
2 files changed, 75 insertions(+), 24 deletions(-)
18
block/file-win32.c | 2 +-
11
19
block/qcow2-threads.c | 2 +-
12
diff --git a/qapi/block-core.json b/qapi/block-core.json
20
util/thread-pool.c | 9 ++++-----
13
index XXXXXXX..XXXXXXX 100644
21
5 files changed, 21 insertions(+), 18 deletions(-)
14
--- a/qapi/block-core.json
22
15
+++ b/qapi/block-core.json
23
diff --git a/include/block/thread-pool.h b/include/block/thread-pool.h
16
@@ -XXX,XX +XXX,XX @@
24
index XXXXXXX..XXXXXXX 100644
17
{ 'command': 'blockdev-del', 'data': { 'node-name': 'str' } }
25
--- a/include/block/thread-pool.h
18
26
+++ b/include/block/thread-pool.h
19
##
27
@@ -XXX,XX +XXX,XX @@ typedef struct ThreadPool ThreadPool;
20
+# @BlockdevCreateOptionsFile:
28
ThreadPool *thread_pool_new(struct AioContext *ctx);
21
+#
29
void thread_pool_free(ThreadPool *pool);
22
+# Driver specific image creation options for file.
30
23
+#
31
+/*
24
+# @filename Filename for the new image file
32
+ * thread_pool_submit* API: submit I/O requests in the thread's
25
+# @size Size of the virtual disk in bytes
33
+ * current AioContext.
26
+# @preallocation Preallocation mode for the new image (default: off)
34
+ */
27
+# @nocow Turn off copy-on-write (valid only on btrfs; default: off)
35
BlockAIOCB *thread_pool_submit_aio(ThreadPool *pool,
28
+#
36
ThreadPoolFunc *func, void *arg,
29
+# Since: 2.12
37
BlockCompletionFunc *cb, void *opaque);
30
+##
38
int coroutine_fn thread_pool_submit_co(ThreadPool *pool,
31
+{ 'struct': 'BlockdevCreateOptionsFile',
39
ThreadPoolFunc *func, void *arg);
32
+ 'data': { 'filename': 'str',
40
void thread_pool_submit(ThreadPool *pool, ThreadPoolFunc *func, void *arg);
33
+ 'size': 'size',
34
+ '*preallocation': 'PreallocMode',
35
+ '*nocow': 'bool' } }
36
+
41
+
37
+##
42
void thread_pool_update_params(ThreadPool *pool, struct AioContext *ctx);
38
# @BlockdevQcow2Version:
43
39
#
44
#endif
40
# @v2: The original QCOW2 format as introduced in qemu 0.10 (version 2)
41
@@ -XXX,XX +XXX,XX @@
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
45
diff --git a/block/file-posix.c b/block/file-posix.c
51
index XXXXXXX..XXXXXXX 100644
46
index XXXXXXX..XXXXXXX 100644
52
--- a/block/file-posix.c
47
--- a/block/file-posix.c
53
+++ b/block/file-posix.c
48
+++ 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
}
57
58
-static int coroutine_fn raw_co_create_opts(const char *filename, QemuOpts *opts,
59
- Error **errp)
60
+static int raw_co_create(BlockdevCreateOptions *options, Error **errp)
61
{
62
+ BlockdevCreateOptionsFile *file_opts;
63
int fd;
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:
49
@@ -XXX,XX +XXX,XX @@ out:
121
return result;
50
return result;
122
}
51
}
123
52
124
+static int coroutine_fn raw_co_create_opts(const char *filename, QemuOpts *opts,
53
-static int coroutine_fn raw_thread_pool_submit(BlockDriverState *bs,
125
+ Error **errp)
54
- ThreadPoolFunc func, void *arg)
126
+{
55
+static int coroutine_fn raw_thread_pool_submit(ThreadPoolFunc func, void *arg)
127
+ BlockdevCreateOptions options;
56
{
128
+ int64_t total_size = 0;
57
/* @bs can be NULL, bdrv_get_aio_context() returns the main context then */
129
+ bool nocow = false;
58
- ThreadPool *pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
130
+ PreallocMode prealloc;
59
+ ThreadPool *pool = aio_get_thread_pool(qemu_get_current_aio_context());
131
+ char *buf = NULL;
60
return thread_pool_submit_co(pool, func, arg);
132
+ Error *local_err = NULL;
61
}
62
63
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_prw(BlockDriverState *bs, uint64_t offset,
64
};
65
66
assert(qiov->size == bytes);
67
- return raw_thread_pool_submit(bs, handle_aiocb_rw, &acb);
68
+ return raw_thread_pool_submit(handle_aiocb_rw, &acb);
69
}
70
71
static int coroutine_fn raw_co_preadv(BlockDriverState *bs, int64_t offset,
72
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_flush_to_disk(BlockDriverState *bs)
73
return luring_co_submit(bs, s->fd, 0, NULL, QEMU_AIO_FLUSH);
74
}
75
#endif
76
- return raw_thread_pool_submit(bs, handle_aiocb_flush, &acb);
77
+ return raw_thread_pool_submit(handle_aiocb_flush, &acb);
78
}
79
80
static void raw_aio_attach_aio_context(BlockDriverState *bs,
81
@@ -XXX,XX +XXX,XX @@ raw_regular_truncate(BlockDriverState *bs, int fd, int64_t offset,
82
},
83
};
84
85
- return raw_thread_pool_submit(bs, handle_aiocb_truncate, &acb);
86
+ return raw_thread_pool_submit(handle_aiocb_truncate, &acb);
87
}
88
89
static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
90
@@ -XXX,XX +XXX,XX @@ raw_do_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes,
91
acb.aio_type |= QEMU_AIO_BLKDEV;
92
}
93
94
- ret = raw_thread_pool_submit(bs, handle_aiocb_discard, &acb);
95
+ ret = raw_thread_pool_submit(handle_aiocb_discard, &acb);
96
raw_account_discard(s, bytes, ret);
97
return ret;
98
}
99
@@ -XXX,XX +XXX,XX @@ raw_do_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes,
100
handler = handle_aiocb_write_zeroes;
101
}
102
103
- return raw_thread_pool_submit(bs, handler, &acb);
104
+ return raw_thread_pool_submit(handler, &acb);
105
}
106
107
static int coroutine_fn raw_co_pwrite_zeroes(
108
@@ -XXX,XX +XXX,XX @@ raw_co_copy_range_to(BlockDriverState *bs,
109
},
110
};
111
112
- return raw_thread_pool_submit(bs, handle_aiocb_copy_range, &acb);
113
+ return raw_thread_pool_submit(handle_aiocb_copy_range, &acb);
114
}
115
116
BlockDriver bdrv_file = {
117
@@ -XXX,XX +XXX,XX @@ hdev_co_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
118
struct sg_io_hdr *io_hdr = buf;
119
if (io_hdr->cmdp[0] == PERSISTENT_RESERVE_OUT ||
120
io_hdr->cmdp[0] == PERSISTENT_RESERVE_IN) {
121
- return pr_manager_execute(s->pr_mgr, bdrv_get_aio_context(bs),
122
+ return pr_manager_execute(s->pr_mgr, qemu_get_current_aio_context(),
123
s->fd, io_hdr);
124
}
125
}
126
@@ -XXX,XX +XXX,XX @@ hdev_co_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
127
},
128
};
129
130
- return raw_thread_pool_submit(bs, handle_aiocb_ioctl, &acb);
131
+ return raw_thread_pool_submit(handle_aiocb_ioctl, &acb);
132
}
133
#endif /* linux */
134
135
diff --git a/block/file-win32.c b/block/file-win32.c
136
index XXXXXXX..XXXXXXX 100644
137
--- a/block/file-win32.c
138
+++ b/block/file-win32.c
139
@@ -XXX,XX +XXX,XX @@ static BlockAIOCB *paio_submit(BlockDriverState *bs, HANDLE hfile,
140
acb->aio_offset = offset;
141
142
trace_file_paio_submit(acb, opaque, offset, count, type);
143
- pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
144
+ pool = aio_get_thread_pool(qemu_get_current_aio_context());
145
return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque);
146
}
147
148
diff --git a/block/qcow2-threads.c b/block/qcow2-threads.c
149
index XXXXXXX..XXXXXXX 100644
150
--- a/block/qcow2-threads.c
151
+++ b/block/qcow2-threads.c
152
@@ -XXX,XX +XXX,XX @@ qcow2_co_process(BlockDriverState *bs, ThreadPoolFunc *func, void *arg)
153
{
154
int ret;
155
BDRVQcow2State *s = bs->opaque;
156
- ThreadPool *pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
157
+ ThreadPool *pool = aio_get_thread_pool(qemu_get_current_aio_context());
158
159
qemu_co_mutex_lock(&s->lock);
160
while (s->nb_threads >= QCOW2_MAX_THREADS) {
161
diff --git a/util/thread-pool.c b/util/thread-pool.c
162
index XXXXXXX..XXXXXXX 100644
163
--- a/util/thread-pool.c
164
+++ b/util/thread-pool.c
165
@@ -XXX,XX +XXX,XX @@ struct ThreadPoolElement {
166
/* Access to this list is protected by lock. */
167
QTAILQ_ENTRY(ThreadPoolElement) reqs;
168
169
- /* Access to this list is protected by the global mutex. */
170
+ /* This list is only written by the thread pool's mother thread. */
171
QLIST_ENTRY(ThreadPoolElement) all;
172
};
173
174
@@ -XXX,XX +XXX,XX @@ static void thread_pool_completion_bh(void *opaque)
175
ThreadPool *pool = opaque;
176
ThreadPoolElement *elem, *next;
177
178
- aio_context_acquire(pool->ctx);
179
restart:
180
QLIST_FOREACH_SAFE(elem, &pool->head, all, next) {
181
if (elem->state != THREAD_DONE) {
182
@@ -XXX,XX +XXX,XX @@ restart:
183
*/
184
qemu_bh_schedule(pool->completion_bh);
185
186
- aio_context_release(pool->ctx);
187
elem->common.cb(elem->common.opaque, elem->ret);
188
- aio_context_acquire(pool->ctx);
189
190
/* We can safely cancel the completion_bh here regardless of someone
191
* else having scheduled it meanwhile because we reenter the
192
@@ -XXX,XX +XXX,XX @@ restart:
193
qemu_aio_unref(elem);
194
}
195
}
196
- aio_context_release(pool->ctx);
197
}
198
199
static void thread_pool_cancel(BlockAIOCB *acb)
200
@@ -XXX,XX +XXX,XX @@ BlockAIOCB *thread_pool_submit_aio(ThreadPool *pool,
201
{
202
ThreadPoolElement *req;
203
204
+ /* Assert that the thread submitting work is the same running the pool */
205
+ assert(pool->ctx == qemu_get_current_aio_context());
133
+
206
+
134
+ /* Skip file: protocol prefix */
207
req = qemu_aio_get(&thread_pool_aiocb_info, NULL, cb, opaque);
135
+ strstart(filename, "file:", &filename);
208
req->func = func;
136
+
209
req->arg = arg;
137
+ /* Read out options */
138
+ total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
139
+ BDRV_SECTOR_SIZE);
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
--
210
--
176
2.13.6
211
2.40.0
177
178
diff view generated by jsdifflib
1
This adds the .bdrv_co_create driver callback to file-win32, which
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
2
enables image creation over QMP.
3
2
3
thread_pool_submit_aio() is always called on a pool taken from
4
qemu_get_current_aio_context(), and that is the only intended
5
use: each pool runs only in the same thread that is submitting
6
work to it, it can't run anywhere else.
7
8
Therefore simplify the thread_pool_submit* API and remove the
9
ThreadPool function parameter.
10
11
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
12
Message-Id: <20230203131731.851116-5-eesposit@redhat.com>
13
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
14
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
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
---
16
---
8
block/file-win32.c | 47 ++++++++++++++++++++++++++++++++++++++---------
17
include/block/thread-pool.h | 10 ++++------
9
1 file changed, 38 insertions(+), 9 deletions(-)
18
backends/tpm/tpm_backend.c | 4 +---
19
block/file-posix.c | 4 +---
20
block/file-win32.c | 4 +---
21
block/qcow2-threads.c | 3 +--
22
hw/9pfs/coth.c | 3 +--
23
hw/ppc/spapr_nvdimm.c | 6 ++----
24
hw/virtio/virtio-pmem.c | 3 +--
25
scsi/pr-manager.c | 3 +--
26
scsi/qemu-pr-helper.c | 3 +--
27
tests/unit/test-thread-pool.c | 12 +++++-------
28
util/thread-pool.c | 16 ++++++++--------
29
12 files changed, 27 insertions(+), 44 deletions(-)
10
30
31
diff --git a/include/block/thread-pool.h b/include/block/thread-pool.h
32
index XXXXXXX..XXXXXXX 100644
33
--- a/include/block/thread-pool.h
34
+++ b/include/block/thread-pool.h
35
@@ -XXX,XX +XXX,XX @@ void thread_pool_free(ThreadPool *pool);
36
* thread_pool_submit* API: submit I/O requests in the thread's
37
* current AioContext.
38
*/
39
-BlockAIOCB *thread_pool_submit_aio(ThreadPool *pool,
40
- ThreadPoolFunc *func, void *arg,
41
- BlockCompletionFunc *cb, void *opaque);
42
-int coroutine_fn thread_pool_submit_co(ThreadPool *pool,
43
- ThreadPoolFunc *func, void *arg);
44
-void thread_pool_submit(ThreadPool *pool, ThreadPoolFunc *func, void *arg);
45
+BlockAIOCB *thread_pool_submit_aio(ThreadPoolFunc *func, void *arg,
46
+ BlockCompletionFunc *cb, void *opaque);
47
+int coroutine_fn thread_pool_submit_co(ThreadPoolFunc *func, void *arg);
48
+void thread_pool_submit(ThreadPoolFunc *func, void *arg);
49
50
void thread_pool_update_params(ThreadPool *pool, struct AioContext *ctx);
51
52
diff --git a/backends/tpm/tpm_backend.c b/backends/tpm/tpm_backend.c
53
index XXXXXXX..XXXXXXX 100644
54
--- a/backends/tpm/tpm_backend.c
55
+++ b/backends/tpm/tpm_backend.c
56
@@ -XXX,XX +XXX,XX @@ bool tpm_backend_had_startup_error(TPMBackend *s)
57
58
void tpm_backend_deliver_request(TPMBackend *s, TPMBackendCmd *cmd)
59
{
60
- ThreadPool *pool = aio_get_thread_pool(qemu_get_aio_context());
61
-
62
if (s->cmd != NULL) {
63
error_report("There is a TPM request pending");
64
return;
65
@@ -XXX,XX +XXX,XX @@ void tpm_backend_deliver_request(TPMBackend *s, TPMBackendCmd *cmd)
66
67
s->cmd = cmd;
68
object_ref(OBJECT(s));
69
- thread_pool_submit_aio(pool, tpm_backend_worker_thread, s,
70
+ thread_pool_submit_aio(tpm_backend_worker_thread, s,
71
tpm_backend_request_completed, s);
72
}
73
74
diff --git a/block/file-posix.c b/block/file-posix.c
75
index XXXXXXX..XXXXXXX 100644
76
--- a/block/file-posix.c
77
+++ b/block/file-posix.c
78
@@ -XXX,XX +XXX,XX @@ out:
79
80
static int coroutine_fn raw_thread_pool_submit(ThreadPoolFunc func, void *arg)
81
{
82
- /* @bs can be NULL, bdrv_get_aio_context() returns the main context then */
83
- ThreadPool *pool = aio_get_thread_pool(qemu_get_current_aio_context());
84
- return thread_pool_submit_co(pool, func, arg);
85
+ return thread_pool_submit_co(func, arg);
86
}
87
88
/*
11
diff --git a/block/file-win32.c b/block/file-win32.c
89
diff --git a/block/file-win32.c b/block/file-win32.c
12
index XXXXXXX..XXXXXXX 100644
90
index XXXXXXX..XXXXXXX 100644
13
--- a/block/file-win32.c
91
--- a/block/file-win32.c
14
+++ b/block/file-win32.c
92
+++ b/block/file-win32.c
15
@@ -XXX,XX +XXX,XX @@ static int64_t raw_get_allocated_file_size(BlockDriverState *bs)
93
@@ -XXX,XX +XXX,XX @@ static BlockAIOCB *paio_submit(BlockDriverState *bs, HANDLE hfile,
16
return st.st_size;
94
BlockCompletionFunc *cb, void *opaque, int type)
17
}
95
{
18
96
RawWin32AIOData *acb = g_new(RawWin32AIOData, 1);
19
-static int coroutine_fn raw_co_create_opts(const char *filename, QemuOpts *opts,
97
- ThreadPool *pool;
20
- Error **errp)
98
21
+static int raw_co_create(BlockdevCreateOptions *options, Error **errp)
99
acb->bs = bs;
22
{
100
acb->hfile = hfile;
23
+ BlockdevCreateOptionsFile *file_opts;
101
@@ -XXX,XX +XXX,XX @@ static BlockAIOCB *paio_submit(BlockDriverState *bs, HANDLE hfile,
102
acb->aio_offset = offset;
103
104
trace_file_paio_submit(acb, opaque, offset, count, type);
105
- pool = aio_get_thread_pool(qemu_get_current_aio_context());
106
- return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque);
107
+ return thread_pool_submit_aio(aio_worker, acb, cb, opaque);
108
}
109
110
int qemu_ftruncate64(int fd, int64_t length)
111
diff --git a/block/qcow2-threads.c b/block/qcow2-threads.c
112
index XXXXXXX..XXXXXXX 100644
113
--- a/block/qcow2-threads.c
114
+++ b/block/qcow2-threads.c
115
@@ -XXX,XX +XXX,XX @@ qcow2_co_process(BlockDriverState *bs, ThreadPoolFunc *func, void *arg)
116
{
117
int ret;
118
BDRVQcow2State *s = bs->opaque;
119
- ThreadPool *pool = aio_get_thread_pool(qemu_get_current_aio_context());
120
121
qemu_co_mutex_lock(&s->lock);
122
while (s->nb_threads >= QCOW2_MAX_THREADS) {
123
@@ -XXX,XX +XXX,XX @@ qcow2_co_process(BlockDriverState *bs, ThreadPoolFunc *func, void *arg)
124
s->nb_threads++;
125
qemu_co_mutex_unlock(&s->lock);
126
127
- ret = thread_pool_submit_co(pool, func, arg);
128
+ ret = thread_pool_submit_co(func, arg);
129
130
qemu_co_mutex_lock(&s->lock);
131
s->nb_threads--;
132
diff --git a/hw/9pfs/coth.c b/hw/9pfs/coth.c
133
index XXXXXXX..XXXXXXX 100644
134
--- a/hw/9pfs/coth.c
135
+++ b/hw/9pfs/coth.c
136
@@ -XXX,XX +XXX,XX @@ static int coroutine_enter_func(void *arg)
137
void co_run_in_worker_bh(void *opaque)
138
{
139
Coroutine *co = opaque;
140
- thread_pool_submit_aio(aio_get_thread_pool(qemu_get_aio_context()),
141
- coroutine_enter_func, co, coroutine_enter_cb, co);
142
+ thread_pool_submit_aio(coroutine_enter_func, co, coroutine_enter_cb, co);
143
}
144
diff --git a/hw/ppc/spapr_nvdimm.c b/hw/ppc/spapr_nvdimm.c
145
index XXXXXXX..XXXXXXX 100644
146
--- a/hw/ppc/spapr_nvdimm.c
147
+++ b/hw/ppc/spapr_nvdimm.c
148
@@ -XXX,XX +XXX,XX @@ static int spapr_nvdimm_flush_post_load(void *opaque, int version_id)
149
{
150
SpaprNVDIMMDevice *s_nvdimm = (SpaprNVDIMMDevice *)opaque;
151
SpaprNVDIMMDeviceFlushState *state;
152
- ThreadPool *pool = aio_get_thread_pool(qemu_get_aio_context());
153
HostMemoryBackend *backend = MEMORY_BACKEND(PC_DIMM(s_nvdimm)->hostmem);
154
bool is_pmem = object_property_get_bool(OBJECT(backend), "pmem", NULL);
155
bool pmem_override = object_property_get_bool(OBJECT(s_nvdimm),
156
@@ -XXX,XX +XXX,XX @@ static int spapr_nvdimm_flush_post_load(void *opaque, int version_id)
157
}
158
159
QLIST_FOREACH(state, &s_nvdimm->pending_nvdimm_flush_states, node) {
160
- thread_pool_submit_aio(pool, flush_worker_cb, state,
161
+ thread_pool_submit_aio(flush_worker_cb, state,
162
spapr_nvdimm_flush_completion_cb, state);
163
}
164
165
@@ -XXX,XX +XXX,XX @@ static target_ulong h_scm_flush(PowerPCCPU *cpu, SpaprMachineState *spapr,
166
PCDIMMDevice *dimm;
167
HostMemoryBackend *backend = NULL;
168
SpaprNVDIMMDeviceFlushState *state;
169
- ThreadPool *pool = aio_get_thread_pool(qemu_get_aio_context());
24
int fd;
170
int fd;
25
- int64_t total_size = 0;
171
26
172
if (!drc || !drc->dev ||
27
- strstart(filename, "file:", &filename);
173
@@ -XXX,XX +XXX,XX @@ static target_ulong h_scm_flush(PowerPCCPU *cpu, SpaprMachineState *spapr,
28
+ assert(options->driver == BLOCKDEV_DRIVER_FILE);
174
29
+ file_opts = &options->u.file;
175
state->drcidx = drc_index;
30
176
31
- /* Read out options */
177
- thread_pool_submit_aio(pool, flush_worker_cb, state,
32
- total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
178
+ thread_pool_submit_aio(flush_worker_cb, state,
33
- BDRV_SECTOR_SIZE);
179
spapr_nvdimm_flush_completion_cb, state);
34
+ if (file_opts->has_preallocation) {
180
35
+ error_setg(errp, "Preallocation is not supported on Windows");
181
continue_token = state->continue_token;
36
+ return -EINVAL;
182
diff --git a/hw/virtio/virtio-pmem.c b/hw/virtio/virtio-pmem.c
37
+ }
183
index XXXXXXX..XXXXXXX 100644
38
+ if (file_opts->has_nocow) {
184
--- a/hw/virtio/virtio-pmem.c
39
+ error_setg(errp, "nocow is not supported on Windows");
185
+++ b/hw/virtio/virtio-pmem.c
40
+ return -EINVAL;
186
@@ -XXX,XX +XXX,XX @@ static void virtio_pmem_flush(VirtIODevice *vdev, VirtQueue *vq)
41
+ }
187
VirtIODeviceRequest *req_data;
42
188
VirtIOPMEM *pmem = VIRTIO_PMEM(vdev);
43
- fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
189
HostMemoryBackend *backend = MEMORY_BACKEND(pmem->memdev);
44
+ fd = qemu_open(file_opts->filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
190
- ThreadPool *pool = aio_get_thread_pool(qemu_get_aio_context());
45
0644);
191
46
if (fd < 0) {
192
trace_virtio_pmem_flush_request();
47
error_setg_errno(errp, errno, "Could not create file");
193
req_data = virtqueue_pop(vq, sizeof(VirtIODeviceRequest));
48
return -EIO;
194
@@ -XXX,XX +XXX,XX @@ static void virtio_pmem_flush(VirtIODevice *vdev, VirtQueue *vq)
49
}
195
req_data->fd = memory_region_get_fd(&backend->mr);
50
set_sparse(fd);
196
req_data->pmem = pmem;
51
- ftruncate(fd, total_size);
197
req_data->vdev = vdev;
52
+ ftruncate(fd, file_opts->size);
198
- thread_pool_submit_aio(pool, worker_cb, req_data, done_cb, req_data);
53
qemu_close(fd);
199
+ thread_pool_submit_aio(worker_cb, req_data, done_cb, req_data);
54
+
200
}
55
return 0;
201
56
}
202
static void virtio_pmem_get_config(VirtIODevice *vdev, uint8_t *config)
57
203
diff --git a/scsi/pr-manager.c b/scsi/pr-manager.c
58
+static int coroutine_fn raw_co_create_opts(const char *filename, QemuOpts *opts,
204
index XXXXXXX..XXXXXXX 100644
59
+ Error **errp)
205
--- a/scsi/pr-manager.c
60
+{
206
+++ b/scsi/pr-manager.c
61
+ BlockdevCreateOptions options;
207
@@ -XXX,XX +XXX,XX @@ static int pr_manager_worker(void *opaque)
62
+ int64_t total_size = 0;
208
int coroutine_fn pr_manager_execute(PRManager *pr_mgr, AioContext *ctx, int fd,
63
+
209
struct sg_io_hdr *hdr)
64
+ strstart(filename, "file:", &filename);
210
{
65
+
211
- ThreadPool *pool = aio_get_thread_pool(ctx);
66
+ /* Read out options */
212
PRManagerData data = {
67
+ total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
213
.pr_mgr = pr_mgr,
68
+ BDRV_SECTOR_SIZE);
214
.fd = fd,
69
+
215
@@ -XXX,XX +XXX,XX @@ int coroutine_fn pr_manager_execute(PRManager *pr_mgr, AioContext *ctx, int fd,
70
+ options = (BlockdevCreateOptions) {
216
71
+ .driver = BLOCKDEV_DRIVER_FILE,
217
/* The matching object_unref is in pr_manager_worker. */
72
+ .u.file = {
218
object_ref(OBJECT(pr_mgr));
73
+ .filename = (char *) filename,
219
- return thread_pool_submit_co(pool, pr_manager_worker, &data);
74
+ .size = total_size,
220
+ return thread_pool_submit_co(pr_manager_worker, &data);
75
+ .has_preallocation = false,
221
}
76
+ .has_nocow = false,
222
77
+ },
223
bool pr_manager_is_connected(PRManager *pr_mgr)
78
+ };
224
diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c
79
+ return raw_co_create(&options, errp);
225
index XXXXXXX..XXXXXXX 100644
80
+}
226
--- a/scsi/qemu-pr-helper.c
81
227
+++ b/scsi/qemu-pr-helper.c
82
static QemuOptsList raw_create_opts = {
228
@@ -XXX,XX +XXX,XX @@ static int do_sgio_worker(void *opaque)
83
.name = "raw-create-opts",
229
static int do_sgio(int fd, const uint8_t *cdb, uint8_t *sense,
230
uint8_t *buf, int *sz, int dir)
231
{
232
- ThreadPool *pool = aio_get_thread_pool(qemu_get_aio_context());
233
int r;
234
235
PRHelperSGIOData data = {
236
@@ -XXX,XX +XXX,XX @@ static int do_sgio(int fd, const uint8_t *cdb, uint8_t *sense,
237
.dir = dir,
238
};
239
240
- r = thread_pool_submit_co(pool, do_sgio_worker, &data);
241
+ r = thread_pool_submit_co(do_sgio_worker, &data);
242
*sz = data.sz;
243
return r;
244
}
245
diff --git a/tests/unit/test-thread-pool.c b/tests/unit/test-thread-pool.c
246
index XXXXXXX..XXXXXXX 100644
247
--- a/tests/unit/test-thread-pool.c
248
+++ b/tests/unit/test-thread-pool.c
249
@@ -XXX,XX +XXX,XX @@
250
#include "qemu/main-loop.h"
251
252
static AioContext *ctx;
253
-static ThreadPool *pool;
254
static int active;
255
256
typedef struct {
257
@@ -XXX,XX +XXX,XX @@ static void done_cb(void *opaque, int ret)
258
static void test_submit(void)
259
{
260
WorkerTestData data = { .n = 0 };
261
- thread_pool_submit(pool, worker_cb, &data);
262
+ thread_pool_submit(worker_cb, &data);
263
while (data.n == 0) {
264
aio_poll(ctx, true);
265
}
266
@@ -XXX,XX +XXX,XX @@ static void test_submit(void)
267
static void test_submit_aio(void)
268
{
269
WorkerTestData data = { .n = 0, .ret = -EINPROGRESS };
270
- data.aiocb = thread_pool_submit_aio(pool, worker_cb, &data,
271
+ data.aiocb = thread_pool_submit_aio(worker_cb, &data,
272
done_cb, &data);
273
274
/* The callbacks are not called until after the first wait. */
275
@@ -XXX,XX +XXX,XX @@ static void co_test_cb(void *opaque)
276
active = 1;
277
data->n = 0;
278
data->ret = -EINPROGRESS;
279
- thread_pool_submit_co(pool, worker_cb, data);
280
+ thread_pool_submit_co(worker_cb, data);
281
282
/* The test continues in test_submit_co, after qemu_coroutine_enter... */
283
284
@@ -XXX,XX +XXX,XX @@ static void test_submit_many(void)
285
for (i = 0; i < 100; i++) {
286
data[i].n = 0;
287
data[i].ret = -EINPROGRESS;
288
- thread_pool_submit_aio(pool, worker_cb, &data[i], done_cb, &data[i]);
289
+ thread_pool_submit_aio(worker_cb, &data[i], done_cb, &data[i]);
290
}
291
292
active = 100;
293
@@ -XXX,XX +XXX,XX @@ static void do_test_cancel(bool sync)
294
for (i = 0; i < 100; i++) {
295
data[i].n = 0;
296
data[i].ret = -EINPROGRESS;
297
- data[i].aiocb = thread_pool_submit_aio(pool, long_cb, &data[i],
298
+ data[i].aiocb = thread_pool_submit_aio(long_cb, &data[i],
299
done_cb, &data[i]);
300
}
301
302
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
303
{
304
qemu_init_main_loop(&error_abort);
305
ctx = qemu_get_current_aio_context();
306
- pool = aio_get_thread_pool(ctx);
307
308
g_test_init(&argc, &argv, NULL);
309
g_test_add_func("/thread-pool/submit", test_submit);
310
diff --git a/util/thread-pool.c b/util/thread-pool.c
311
index XXXXXXX..XXXXXXX 100644
312
--- a/util/thread-pool.c
313
+++ b/util/thread-pool.c
314
@@ -XXX,XX +XXX,XX @@ static const AIOCBInfo thread_pool_aiocb_info = {
315
.get_aio_context = thread_pool_get_aio_context,
316
};
317
318
-BlockAIOCB *thread_pool_submit_aio(ThreadPool *pool,
319
- ThreadPoolFunc *func, void *arg,
320
- BlockCompletionFunc *cb, void *opaque)
321
+BlockAIOCB *thread_pool_submit_aio(ThreadPoolFunc *func, void *arg,
322
+ BlockCompletionFunc *cb, void *opaque)
323
{
324
ThreadPoolElement *req;
325
+ AioContext *ctx = qemu_get_current_aio_context();
326
+ ThreadPool *pool = aio_get_thread_pool(ctx);
327
328
/* Assert that the thread submitting work is the same running the pool */
329
assert(pool->ctx == qemu_get_current_aio_context());
330
@@ -XXX,XX +XXX,XX @@ static void thread_pool_co_cb(void *opaque, int ret)
331
aio_co_wake(co->co);
332
}
333
334
-int coroutine_fn thread_pool_submit_co(ThreadPool *pool, ThreadPoolFunc *func,
335
- void *arg)
336
+int coroutine_fn thread_pool_submit_co(ThreadPoolFunc *func, void *arg)
337
{
338
ThreadPoolCo tpc = { .co = qemu_coroutine_self(), .ret = -EINPROGRESS };
339
assert(qemu_in_coroutine());
340
- thread_pool_submit_aio(pool, func, arg, thread_pool_co_cb, &tpc);
341
+ thread_pool_submit_aio(func, arg, thread_pool_co_cb, &tpc);
342
qemu_coroutine_yield();
343
return tpc.ret;
344
}
345
346
-void thread_pool_submit(ThreadPool *pool, ThreadPoolFunc *func, void *arg)
347
+void thread_pool_submit(ThreadPoolFunc *func, void *arg)
348
{
349
- thread_pool_submit_aio(pool, func, arg, NULL, NULL);
350
+ thread_pool_submit_aio(func, arg, NULL, NULL);
351
}
352
353
void thread_pool_update_params(ThreadPool *pool, AioContext *ctx)
84
--
354
--
85
2.13.6
355
2.40.0
86
87
diff view generated by jsdifflib
1
Instead of passing the encryption format name and the QemuOpts down, use
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
the QCryptoBlockCreateOptions contained in BlockdevCreateOptions.
2
3
3
Functions that can do I/O are prime candidates for being coroutine_fns. Make the
4
change for those that are themselves called only from coroutine_fns.
5
6
In addition, coroutine_fns should do I/O using bdrv_co_*() functions, for
7
which it is required to hold the BlockDriverState graph lock. So also nnotate
8
functions on the I/O path with TSA attributes, making it possible to
9
switch them to use bdrv_co_*() functions.
10
11
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
12
Message-Id: <20230309084456.304669-2-pbonzini@redhat.com>
13
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Eric Blake <eblake@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
---
15
---
8
block/qcow2.c | 62 +++++++++++++++++++++++++++++++++++++++++++----------------
16
block/vvfat.c | 58 ++++++++++++++++++++++++++-------------------------
9
1 file changed, 45 insertions(+), 17 deletions(-)
17
1 file changed, 30 insertions(+), 28 deletions(-)
10
18
11
diff --git a/block/qcow2.c b/block/qcow2.c
19
diff --git a/block/vvfat.c b/block/vvfat.c
12
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
13
--- a/block/qcow2.c
21
--- a/block/vvfat.c
14
+++ b/block/qcow2.c
22
+++ b/block/vvfat.c
15
@@ -XXX,XX +XXX,XX @@ static int qcow2_crypt_method_from_format(const char *encryptfmt)
23
@@ -XXX,XX +XXX,XX @@ static BDRVVVFATState *vvv = NULL;
24
#endif
25
26
static int enable_write_target(BlockDriverState *bs, Error **errp);
27
-static int is_consistent(BDRVVVFATState *s);
28
+static int coroutine_fn is_consistent(BDRVVVFATState *s);
29
30
static QemuOptsList runtime_opts = {
31
.name = "vvfat",
32
@@ -XXX,XX +XXX,XX @@ static void print_mapping(const mapping_t* mapping)
33
}
34
#endif
35
36
-static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
37
- uint8_t *buf, int nb_sectors)
38
+static int coroutine_fn GRAPH_RDLOCK
39
+vvfat_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors)
40
{
41
BDRVVVFATState *s = bs->opaque;
42
int i;
43
@@ -XXX,XX +XXX,XX @@ static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
44
DLOG(fprintf(stderr, "sectors %" PRId64 "+%" PRId64
45
" allocated\n", sector_num,
46
n >> BDRV_SECTOR_BITS));
47
- if (bdrv_pread(s->qcow, sector_num * BDRV_SECTOR_SIZE, n,
48
- buf + i * 0x200, 0) < 0) {
49
+ if (bdrv_co_pread(s->qcow, sector_num * BDRV_SECTOR_SIZE, n,
50
+ buf + i * 0x200, 0) < 0) {
51
return -1;
52
}
53
i += (n >> BDRV_SECTOR_BITS) - 1;
54
@@ -XXX,XX +XXX,XX @@ static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
55
return 0;
56
}
57
58
-static int coroutine_fn
59
+static int coroutine_fn GRAPH_RDLOCK
60
vvfat_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
61
QEMUIOVector *qiov, BdrvRequestFlags flags)
62
{
63
@@ -XXX,XX +XXX,XX @@ static inline uint32_t modified_fat_get(BDRVVVFATState* s,
16
}
64
}
17
}
65
}
18
66
19
-static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt,
67
-static inline bool cluster_was_modified(BDRVVVFATState *s,
20
- QemuOpts *opts, Error **errp)
68
- uint32_t cluster_num)
21
+static QCryptoBlockCreateOptions *
69
+static inline bool coroutine_fn GRAPH_RDLOCK
22
+qcow2_parse_encryption(const char *encryptfmt, QemuOpts *opts, Error **errp)
70
+cluster_was_modified(BDRVVVFATState *s, uint32_t cluster_num)
23
{
71
{
24
- BDRVQcow2State *s = bs->opaque;
72
int was_modified = 0;
25
QCryptoBlockCreateOptions *cryptoopts = NULL;
73
int i;
26
- QCryptoBlock *crypto = NULL;
74
@@ -XXX,XX +XXX,XX @@ typedef enum {
27
- int ret = -EINVAL;
75
* Further, the files/directories handled by this function are
28
QDict *options, *encryptopts;
76
* assumed to be *not* deleted (and *only* those).
29
int fmt;
77
*/
30
78
-static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
31
@@ -XXX,XX +XXX,XX @@ static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt,
79
- direntry_t* direntry, const char* path)
32
error_setg(errp, "Unknown encryption format '%s'", encryptfmt);
80
+static uint32_t coroutine_fn GRAPH_RDLOCK
33
break;
81
+get_cluster_count_for_direntry(BDRVVVFATState* s, direntry_t* direntry, const char* path)
34
}
82
{
35
- if (!cryptoopts) {
83
/*
36
- ret = -EINVAL;
84
* This is a little bit tricky:
37
- goto out;
85
@@ -XXX,XX +XXX,XX @@ static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
38
+
86
if (res) {
39
+ QDECREF(encryptopts);
87
return -1;
40
+ return cryptoopts;
88
}
41
+}
89
- res = bdrv_pwrite(s->qcow, offset * BDRV_SECTOR_SIZE,
42
+
90
- BDRV_SECTOR_SIZE, s->cluster_buffer,
43
+static int qcow2_set_up_encryption(BlockDriverState *bs,
91
- 0);
44
+ QCryptoBlockCreateOptions *cryptoopts,
92
+ res = bdrv_co_pwrite(s->qcow, offset * BDRV_SECTOR_SIZE,
45
+ Error **errp)
93
+ BDRV_SECTOR_SIZE, s->cluster_buffer,
46
+{
94
+ 0);
47
+ BDRVQcow2State *s = bs->opaque;
95
if (res < 0) {
48
+ QCryptoBlock *crypto = NULL;
96
return -2;
49
+ int fmt, ret;
97
}
50
+
98
@@ -XXX,XX +XXX,XX @@ static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
51
+ switch (cryptoopts->format) {
99
* It returns 0 upon inconsistency or error, and the number of clusters
52
+ case Q_CRYPTO_BLOCK_FORMAT_LUKS:
100
* used by the directory, its subdirectories and their files.
53
+ fmt = QCOW_CRYPT_LUKS;
101
*/
54
+ break;
102
-static int check_directory_consistency(BDRVVVFATState *s,
55
+ case Q_CRYPTO_BLOCK_FORMAT_QCOW:
103
- int cluster_num, const char* path)
56
+ fmt = QCOW_CRYPT_AES;
104
+static int coroutine_fn GRAPH_RDLOCK
57
+ break;
105
+check_directory_consistency(BDRVVVFATState *s, int cluster_num, const char* path)
58
+ default:
106
{
59
+ error_setg(errp, "Crypto format not supported in qcow2");
107
int ret = 0;
60
+ return -EINVAL;
108
unsigned char* cluster = g_malloc(s->cluster_size);
61
}
109
@@ -XXX,XX +XXX,XX @@ DLOG(fprintf(stderr, "check direntry %d:\n", i); print_direntry(direntries + i))
62
+
110
}
63
s->crypt_method_header = fmt;
111
64
112
/* returns 1 on success */
65
crypto = qcrypto_block_create(cryptoopts, "encrypt.",
113
-static int is_consistent(BDRVVVFATState* s)
66
@@ -XXX,XX +XXX,XX @@ static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt,
114
+static int coroutine_fn GRAPH_RDLOCK
67
qcow2_crypto_hdr_write_func,
115
+is_consistent(BDRVVVFATState* s)
68
bs, errp);
116
{
69
if (!crypto) {
117
int i, check;
70
- ret = -EINVAL;
118
int used_clusters_count = 0;
71
- goto out;
119
@@ -XXX,XX +XXX,XX @@ static int commit_mappings(BDRVVVFATState* s,
72
+ return -EINVAL;
120
return 0;
73
}
121
}
74
122
75
ret = qcow2_update_header(bs);
123
-static int commit_direntries(BDRVVVFATState* s,
76
@@ -XXX,XX +XXX,XX @@ static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt,
124
- int dir_index, int parent_mapping_index)
77
goto out;
125
+static int coroutine_fn GRAPH_RDLOCK
78
}
126
+commit_direntries(BDRVVVFATState* s, int dir_index, int parent_mapping_index)
79
127
{
80
+ ret = 0;
128
direntry_t* direntry = array_get(&(s->directory), dir_index);
81
out:
129
uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
82
- QDECREF(encryptopts);
130
@@ -XXX,XX +XXX,XX @@ static int commit_direntries(BDRVVVFATState* s,
83
qcrypto_block_free(crypto);
131
84
- qapi_free_QCryptoBlockCreateOptions(cryptoopts);
132
/* commit one file (adjust contents, adjust mapping),
85
return ret;
133
return first_mapping_index */
86
}
134
-static int commit_one_file(BDRVVVFATState* s,
87
135
- int dir_index, uint32_t offset)
88
@@ -XXX,XX +XXX,XX @@ static uint64_t qcow2_opt_get_refcount_bits_del(QemuOpts *opts, int version,
136
+static int coroutine_fn GRAPH_RDLOCK
89
}
137
+commit_one_file(BDRVVVFATState* s, int dir_index, uint32_t offset)
90
138
{
91
static int coroutine_fn
139
direntry_t* direntry = array_get(&(s->directory), dir_index);
92
-qcow2_co_create(BlockdevCreateOptions *create_options, QemuOpts *opts,
140
uint32_t c = begin_of_direntry(direntry);
93
- const char *encryptfmt, Error **errp)
141
@@ -XXX,XX +XXX,XX @@ static int handle_renames_and_mkdirs(BDRVVVFATState* s)
94
+qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
142
/*
95
{
143
* TODO: make sure that the short name is not matching *another* file
96
BlockdevCreateOptionsQcow2 *qcow2_opts;
144
*/
97
QDict *options;
145
-static int handle_commits(BDRVVVFATState* s)
98
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, QemuOpts *opts,
146
+static int coroutine_fn GRAPH_RDLOCK handle_commits(BDRVVVFATState* s)
99
}
147
{
100
148
int i, fail = 0;
101
/* Want encryption? There you go. */
149
102
- if (encryptfmt) {
150
@@ -XXX,XX +XXX,XX @@ static int handle_deletes(BDRVVVFATState* s)
103
- ret = qcow2_set_up_encryption(blk_bs(blk), encryptfmt, opts, errp);
151
* - recurse direntries from root (using bs->bdrv_pread)
104
+ if (qcow2_opts->has_encrypt) {
152
* - delete files corresponding to mappings marked as deleted
105
+ ret = qcow2_set_up_encryption(blk_bs(blk), qcow2_opts->encrypt, errp);
153
*/
106
if (ret < 0) {
154
-static int do_commit(BDRVVVFATState* s)
107
goto out;
155
+static int coroutine_fn GRAPH_RDLOCK do_commit(BDRVVVFATState* s)
108
}
156
{
109
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
157
int ret = 0;
110
int version;
158
111
uint64_t refcount_bits;
159
@@ -XXX,XX +XXX,XX @@ DLOG(checkpoint());
112
char *encryptfmt = NULL;
160
return 0;
113
+ QCryptoBlockCreateOptions *cryptoopts = NULL;
161
}
114
BlockDriverState *bs = NULL;
162
115
Error *local_err = NULL;
163
-static int try_commit(BDRVVVFATState* s)
116
int ret;
164
+static int coroutine_fn GRAPH_RDLOCK try_commit(BDRVVVFATState* s)
117
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
165
{
118
ret = -EINVAL;
166
vvfat_close_current_file(s);
119
goto finish;
167
DLOG(checkpoint());
120
}
168
@@ -XXX,XX +XXX,XX @@ DLOG(checkpoint());
121
+
169
return do_commit(s);
122
encryptfmt = qemu_opt_get_del(opts, BLOCK_OPT_ENCRYPT_FORMAT);
170
}
123
if (encryptfmt) {
171
124
if (qemu_opt_get(opts, BLOCK_OPT_ENCRYPT)) {
172
-static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
125
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
173
- const uint8_t *buf, int nb_sectors)
126
} else if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ENCRYPT, false)) {
174
+static int coroutine_fn GRAPH_RDLOCK
127
encryptfmt = g_strdup("aes");
175
+vvfat_write(BlockDriverState *bs, int64_t sector_num,
128
}
176
+ const uint8_t *buf, int nb_sectors)
129
+ if (encryptfmt) {
177
{
130
+ cryptoopts = qcow2_parse_encryption(encryptfmt, opts, errp);
178
BDRVVVFATState *s = bs->opaque;
131
+ if (cryptoopts == NULL) {
179
int i, ret;
132
+ ret = -EINVAL;
180
@@ -XXX,XX +XXX,XX @@ DLOG(checkpoint());
133
+ goto finish;
181
* Use qcow backend. Commit later.
134
+ }
182
*/
135
+ }
183
DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
136
+
184
- ret = bdrv_pwrite(s->qcow, sector_num * BDRV_SECTOR_SIZE,
137
cluster_size = qcow2_opt_get_cluster_size_del(opts, &local_err);
185
- nb_sectors * BDRV_SECTOR_SIZE, buf, 0);
138
if (local_err) {
186
+ ret = bdrv_co_pwrite(s->qcow, sector_num * BDRV_SECTOR_SIZE,
139
error_propagate(errp, local_err);
187
+ nb_sectors * BDRV_SECTOR_SIZE, buf, 0);
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) {
188
if (ret < 0) {
156
goto finish;
189
fprintf(stderr, "Error writing to qcow backend\n");
157
}
190
return ret;
158
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
191
@@ -XXX,XX +XXX,XX @@ DLOG(checkpoint());
159
finish:
192
return 0;
160
bdrv_unref(bs);
193
}
161
194
162
+ qapi_free_QCryptoBlockCreateOptions(cryptoopts);
195
-static int coroutine_fn
163
g_free(backing_file);
196
+static int coroutine_fn GRAPH_RDLOCK
164
g_free(backing_fmt);
197
vvfat_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
165
g_free(encryptfmt);
198
QEMUIOVector *qiov, BdrvRequestFlags flags)
199
{
166
--
200
--
167
2.13.6
201
2.40.0
168
169
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
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>
3
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
8
Message-Id: <1516279431-30424-5-git-send-email-pbonzini@redhat.com>
4
Message-Id: <20230309084456.304669-3-pbonzini@redhat.com>
9
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
5
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
7
---
12
block/qed.c | 40 +++++++++++++++++++++++++++++++++++++---
8
block/blkdebug.c | 4 ++--
13
1 file changed, 37 insertions(+), 3 deletions(-)
9
1 file changed, 2 insertions(+), 2 deletions(-)
14
10
15
diff --git a/block/qed.c b/block/qed.c
11
diff --git a/block/blkdebug.c b/block/blkdebug.c
16
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
17
--- a/block/qed.c
13
--- a/block/blkdebug.c
18
+++ b/block/qed.c
14
+++ b/block/blkdebug.c
19
@@ -XXX,XX +XXX,XX @@ static void bdrv_qed_init_state(BlockDriverState *bs)
20
qemu_co_queue_init(&s->allocating_write_reqs);
21
}
22
23
-static int bdrv_qed_do_open(BlockDriverState *bs, QDict *options, int flags,
24
- Error **errp)
25
+/* Called with table_lock held. */
26
+static int coroutine_fn bdrv_qed_do_open(BlockDriverState *bs, QDict *options,
27
+ int flags, Error **errp)
28
{
29
BDRVQEDState *s = bs->opaque;
30
QEDHeader le_header;
31
@@ -XXX,XX +XXX,XX @@ out:
15
@@ -XXX,XX +XXX,XX @@ out:
32
return ret;
16
return ret;
33
}
17
}
34
18
35
+typedef struct QEDOpenCo {
19
-static int rule_check(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
36
+ BlockDriverState *bs;
20
- BlkdebugIOType iotype)
37
+ QDict *options;
21
+static int coroutine_fn rule_check(BlockDriverState *bs, uint64_t offset,
38
+ int flags;
22
+ uint64_t bytes, BlkdebugIOType iotype)
39
+ Error **errp;
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
{
23
{
56
+ QEDOpenCo qoc = {
24
BDRVBlkdebugState *s = bs->opaque;
57
+ .bs = bs,
25
BlkdebugRule *rule = NULL;
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
}
69
70
bdrv_qed_init_state(bs);
71
- return bdrv_qed_do_open(bs, options, flags, errp);
72
+ if (qemu_in_coroutine()) {
73
+ bdrv_qed_open_entry(&qoc);
74
+ } else {
75
+ qemu_coroutine_enter(qemu_coroutine_create(bdrv_qed_open_entry, &qoc));
76
+ BDRV_POLL_WHILE(bs, qoc.ret == -EINPROGRESS);
77
+ }
78
+ BDRV_POLL_WHILE(bs, qoc.ret == -EINPROGRESS);
79
+ return qoc.ret;
80
}
81
82
static void bdrv_qed_refresh_limits(BlockDriverState *bs, Error **errp)
83
--
26
--
84
2.13.6
27
2.40.0
85
86
diff view generated by jsdifflib
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
update_header_sync itself does not need to flush the caches to disk.
3
mirror_flush calls a mixed function blk_flush but it is only called
4
The only paths that allocate clusters are:
4
from mirror_run; so call the coroutine version and make mirror_flush
5
5
a coroutine_fn too.
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
6
16
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
7
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
8
Message-Id: <20230309084456.304669-4-pbonzini@redhat.com>
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
---
11
---
19
block/qcow2-bitmap.c | 4 ++--
12
block/mirror.c | 4 ++--
20
1 file changed, 2 insertions(+), 2 deletions(-)
13
1 file changed, 2 insertions(+), 2 deletions(-)
21
14
22
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
15
diff --git a/block/mirror.c b/block/mirror.c
23
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
24
--- a/block/qcow2-bitmap.c
17
--- a/block/mirror.c
25
+++ b/block/qcow2-bitmap.c
18
+++ b/block/mirror.c
26
@@ -XXX,XX +XXX,XX @@ static int update_header_sync(BlockDriverState *bs)
19
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s)
27
return ret;
20
/* Called when going out of the streaming phase to flush the bulk of the
28
}
21
* data to the medium, or just before completing.
29
22
*/
30
- return bdrv_flush(bs);
23
-static int mirror_flush(MirrorBlockJob *s)
31
+ return bdrv_flush(bs->file->bs);
24
+static int coroutine_fn mirror_flush(MirrorBlockJob *s)
32
}
25
{
33
26
- int ret = blk_flush(s->target);
34
static inline void bitmap_table_to_be(uint64_t *bitmap_table, size_t size)
27
+ int ret = blk_co_flush(s->target);
35
@@ -XXX,XX +XXX,XX @@ static int update_ext_header_and_dir(BlockDriverState *bs,
28
if (ret < 0) {
36
return ret;
29
if (mirror_error_action(s, false, -ret) == BLOCK_ERROR_ACTION_REPORT) {
37
}
30
s->ret = ret;
38
39
- ret = bdrv_flush(bs->file->bs);
40
+ ret = qcow2_flush_caches(bs);
41
if (ret < 0) {
42
goto fail;
43
}
44
--
31
--
45
2.13.6
32
2.40.0
46
47
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
This function checks that the offset and size of a table are valid.
3
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
4
4
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
5
While the offset checks are fine, the size check is too generic, since
6
it only verifies that the total size in bytes fits in a 64-bit
7
integer. In practice all tables used in qcow2 have much smaller size
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>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
21
---
6
---
22
block/qcow2.h | 10 +++---
7
nbd/server.c | 48 ++++++++++++++++++++++++------------------------
23
block/qcow2.c | 77 ++++++++++++++++++----------------------------
8
1 file changed, 24 insertions(+), 24 deletions(-)
24
tests/qemu-iotests/080.out | 16 +++++-----
25
3 files changed, 43 insertions(+), 60 deletions(-)
26
9
27
diff --git a/block/qcow2.h b/block/qcow2.h
10
diff --git a/nbd/server.c b/nbd/server.c
28
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
29
--- a/block/qcow2.h
12
--- a/nbd/server.c
30
+++ b/block/qcow2.h
13
+++ b/nbd/server.c
31
@@ -XXX,XX +XXX,XX @@ static inline int64_t qcow2_vm_state_offset(BDRVQcow2State *s)
14
@@ -XXX,XX +XXX,XX @@ nbd_read_eof(NBDClient *client, void *buffer, size_t size, Error **errp)
32
return (int64_t)s->l1_vm_state_index << (s->cluster_bits + s->l2_bits);
15
return 1;
33
}
16
}
34
17
35
-static inline uint64_t qcow2_max_refcount_clusters(BDRVQcow2State *s)
18
-static int nbd_receive_request(NBDClient *client, NBDRequest *request,
36
-{
19
- Error **errp)
37
- return QCOW_MAX_REFTABLE_SIZE >> s->cluster_bits;
20
+static int coroutine_fn nbd_receive_request(NBDClient *client, NBDRequest *request,
38
-}
21
+ Error **errp)
39
-
40
static inline QCow2ClusterType qcow2_get_cluster_type(uint64_t l2_entry)
41
{
22
{
42
if (l2_entry & QCOW_OFLAG_COMPRESSED) {
23
uint8_t buf[NBD_REQUEST_SIZE];
43
@@ -XXX,XX +XXX,XX @@ void qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset,
24
uint32_t magic;
44
int64_t size, const char *message_format, ...)
25
@@ -XXX,XX +XXX,XX @@ static inline void set_be_simple_reply(NBDSimpleReply *reply, uint64_t error,
45
GCC_FMT_ATTR(5, 6);
26
stq_be_p(&reply->handle, handle);
46
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);
55
diff --git a/block/qcow2.c b/block/qcow2.c
56
index XXXXXXX..XXXXXXX 100644
57
--- a/block/qcow2.c
58
+++ b/block/qcow2.c
59
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_check(BlockDriverState *bs,
60
return ret;
61
}
27
}
62
28
63
-static int validate_table_offset(BlockDriverState *bs, uint64_t offset,
29
-static int nbd_co_send_simple_reply(NBDClient *client,
64
- uint64_t entries, size_t entry_len)
30
- uint64_t handle,
65
+int qcow2_validate_table(BlockDriverState *bs, uint64_t offset,
31
- uint32_t error,
66
+ uint64_t entries, size_t entry_len,
32
- void *data,
67
+ int64_t max_size_bytes, const char *table_name,
33
- size_t len,
68
+ Error **errp)
34
- Error **errp)
35
+static int coroutine_fn nbd_co_send_simple_reply(NBDClient *client,
36
+ uint64_t handle,
37
+ uint32_t error,
38
+ void *data,
39
+ size_t len,
40
+ Error **errp)
69
{
41
{
70
BDRVQcow2State *s = bs->opaque;
42
NBDSimpleReply reply;
71
- uint64_t size;
43
int nbd_err = system_errno_to_nbd_errno(error);
72
44
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn nbd_co_send_sparse_read(NBDClient *client,
73
- /* Use signed INT64_MAX as the maximum even for uint64_t header fields,
45
stl_be_p(&chunk.length, pnum);
74
- * because values will be passed to qemu functions taking int64_t. */
46
ret = nbd_co_send_iov(client, iov, 1, errp);
75
- if (entries > INT64_MAX / entry_len) {
47
} else {
76
- return -EINVAL;
48
- ret = blk_pread(exp->common.blk, offset + progress, pnum,
77
- }
49
- data + progress, 0);
78
-
50
+ ret = blk_co_pread(exp->common.blk, offset + progress, pnum,
79
- size = entries * entry_len;
51
+ data + progress, 0);
80
-
52
if (ret < 0) {
81
- if (INT64_MAX - size < offset) {
53
error_setg_errno(errp, -ret, "reading from file failed");
82
- return -EINVAL;
54
break;
83
+ if (entries > max_size_bytes / entry_len) {
55
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn blockalloc_to_extents(BlockBackend *blk,
84
+ error_setg(errp, "%s too large", table_name);
56
* @ea is converted to BE by the function
85
+ return -EFBIG;
57
* @last controls whether NBD_REPLY_FLAG_DONE is sent.
58
*/
59
-static int nbd_co_send_extents(NBDClient *client, uint64_t handle,
60
- NBDExtentArray *ea,
61
- bool last, uint32_t context_id, Error **errp)
62
+static int coroutine_fn
63
+nbd_co_send_extents(NBDClient *client, uint64_t handle, NBDExtentArray *ea,
64
+ bool last, uint32_t context_id, Error **errp)
65
{
66
NBDStructuredMeta chunk;
67
struct iovec iov[] = {
68
@@ -XXX,XX +XXX,XX @@ static void bitmap_to_extents(BdrvDirtyBitmap *bitmap,
69
bdrv_dirty_bitmap_unlock(bitmap);
70
}
71
72
-static int nbd_co_send_bitmap(NBDClient *client, uint64_t handle,
73
- BdrvDirtyBitmap *bitmap, uint64_t offset,
74
- uint32_t length, bool dont_fragment, bool last,
75
- uint32_t context_id, Error **errp)
76
+static int coroutine_fn nbd_co_send_bitmap(NBDClient *client, uint64_t handle,
77
+ BdrvDirtyBitmap *bitmap, uint64_t offset,
78
+ uint32_t length, bool dont_fragment, bool last,
79
+ uint32_t context_id, Error **errp)
80
{
81
unsigned int nb_extents = dont_fragment ? 1 : NBD_MAX_BLOCK_STATUS_EXTENTS;
82
g_autoptr(NBDExtentArray) ea = nbd_extent_array_new(nb_extents);
83
@@ -XXX,XX +XXX,XX @@ static int nbd_co_send_bitmap(NBDClient *client, uint64_t handle,
84
* to the client (although the caller may still need to disconnect after
85
* reporting the error).
86
*/
87
-static int nbd_co_receive_request(NBDRequestData *req, NBDRequest *request,
88
- Error **errp)
89
+static int coroutine_fn nbd_co_receive_request(NBDRequestData *req, NBDRequest *request,
90
+ Error **errp)
91
{
92
NBDClient *client = req->client;
93
int valid_flags;
94
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int nbd_do_cmd_read(NBDClient *client, NBDRequest *request,
95
data, request->len, errp);
86
}
96
}
87
97
88
- /* Tables must be cluster aligned */
98
- ret = blk_pread(exp->common.blk, request->from, request->len, data, 0);
89
- if (offset_into_cluster(s, offset) != 0) {
99
+ ret = blk_co_pread(exp->common.blk, request->from, request->len, data, 0);
90
+ /* Use signed INT64_MAX as the maximum even for uint64_t header fields,
91
+ * because values will be passed to qemu functions taking int64_t. */
92
+ if ((INT64_MAX - entries * entry_len < offset) ||
93
+ (offset_into_cluster(s, offset) != 0)) {
94
+ error_setg(errp, "%s offset invalid", table_name);
95
return -EINVAL;
96
}
97
98
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
99
s->refcount_table_size =
100
header.refcount_table_clusters << (s->cluster_bits - 3);
101
102
- if (header.refcount_table_clusters > qcow2_max_refcount_clusters(s)) {
103
- error_setg(errp, "Reference count table too large");
104
- ret = -EINVAL;
105
- goto fail;
106
- }
107
-
108
if (header.refcount_table_clusters == 0 && !(flags & BDRV_O_CHECK)) {
109
error_setg(errp, "Image does not contain a reference count table");
110
ret = -EINVAL;
111
goto fail;
112
}
113
114
- ret = validate_table_offset(bs, s->refcount_table_offset,
115
- s->refcount_table_size, sizeof(uint64_t));
116
+ ret = qcow2_validate_table(bs, s->refcount_table_offset,
117
+ header.refcount_table_clusters,
118
+ s->cluster_size, QCOW_MAX_REFTABLE_SIZE,
119
+ "Reference count table", errp);
120
if (ret < 0) {
100
if (ret < 0) {
121
- error_setg(errp, "Invalid reference count table offset");
101
return nbd_send_generic_reply(client, request->handle, ret,
122
goto fail;
102
"reading from file failed", errp);
123
}
103
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int nbd_handle_request(NBDClient *client,
124
104
if (request->flags & NBD_CMD_FLAG_FUA) {
125
- /* Snapshot table offset/length */
105
flags |= BDRV_REQ_FUA;
126
- if (header.nb_snapshots > QCOW_MAX_SNAPSHOTS) {
106
}
127
- error_setg(errp, "Too many snapshots");
107
- ret = blk_pwrite(exp->common.blk, request->from, request->len, data,
128
- ret = -EINVAL;
108
- flags);
129
- goto fail;
109
+ ret = blk_co_pwrite(exp->common.blk, request->from, request->len, data,
130
- }
110
+ flags);
131
-
111
return nbd_send_generic_reply(client, request->handle, ret,
132
- ret = validate_table_offset(bs, header.snapshots_offset,
112
"writing to file failed", errp);
133
- header.nb_snapshots,
113
134
- sizeof(QCowSnapshotHeader));
114
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int nbd_handle_request(NBDClient *client,
135
+ /* The total size in bytes of the snapshot table is checked in
115
if (request->flags & NBD_CMD_FLAG_FAST_ZERO) {
136
+ * qcow2_read_snapshots() because the size of each snapshot is
116
flags |= BDRV_REQ_NO_FALLBACK;
137
+ * variable and we don't know it yet.
117
}
138
+ * Here we only check the offset and number of snapshots. */
118
- ret = blk_pwrite_zeroes(exp->common.blk, request->from, request->len,
139
+ ret = qcow2_validate_table(bs, header.snapshots_offset,
119
- flags);
140
+ header.nb_snapshots,
120
+ ret = blk_co_pwrite_zeroes(exp->common.blk, request->from, request->len,
141
+ sizeof(QCowSnapshotHeader),
121
+ flags);
142
+ sizeof(QCowSnapshotHeader) * QCOW_MAX_SNAPSHOTS,
122
return nbd_send_generic_reply(client, request->handle, ret,
143
+ "Snapshot table", errp);
123
"writing to file failed", errp);
144
if (ret < 0) {
124
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
--
125
--
221
2.13.6
126
2.40.0
222
223
diff view generated by jsdifflib
1
Instead of manually creating the BlockdevCreateOptions object, use a
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
visitor to parse the given options into the QAPI object.
3
2
4
This involves translation from the old command line syntax to the syntax
3
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
5
mandated by the QAPI schema. Option names are still checked against
4
Message-Id: <20230309084456.304669-6-pbonzini@redhat.com>
6
qcow2_create_opts, so only the old option names are allowed on the
5
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
7
command line, even if they are translated in qcow2_create().
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
8
hw/9pfs/9p.h | 4 ++--
9
hw/9pfs/codir.c | 6 +++---
10
2 files changed, 5 insertions(+), 5 deletions(-)
8
11
9
In contrast, new option values are optionally recognised besides the old
12
diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h
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
13
index XXXXXXX..XXXXXXX 100644
24
--- a/block/qcow2.c
14
--- a/hw/9pfs/9p.h
25
+++ b/block/qcow2.c
15
+++ b/hw/9pfs/9p.h
26
@@ -XXX,XX +XXX,XX @@
16
@@ -XXX,XX +XXX,XX @@ typedef struct V9fsDir {
27
#include "qemu/option_int.h"
17
QemuMutex readdir_mutex_L;
28
#include "qemu/cutils.h"
18
} V9fsDir;
29
#include "qemu/bswap.h"
19
30
-#include "qapi/opts-visitor.h"
20
-static inline void v9fs_readdir_lock(V9fsDir *dir)
31
+#include "qapi/qobject-input-visitor.h"
21
+static inline void coroutine_fn v9fs_readdir_lock(V9fsDir *dir)
32
+#include "qapi/qapi-visit-block-core.h"
22
{
33
#include "block/crypto.h"
23
if (dir->proto_version == V9FS_PROTO_2000U) {
34
24
qemu_co_mutex_lock(&dir->readdir_mutex_u);
35
/*
25
@@ -XXX,XX +XXX,XX @@ static inline void v9fs_readdir_lock(V9fsDir *dir)
36
@@ -XXX,XX +XXX,XX @@ static int qcow2_crypt_method_from_format(const char *encryptfmt)
37
}
26
}
38
}
27
}
39
28
40
-static QCryptoBlockCreateOptions *
29
-static inline void v9fs_readdir_unlock(V9fsDir *dir)
41
-qcow2_parse_encryption(const char *encryptfmt, QemuOpts *opts, Error **errp)
30
+static inline void coroutine_fn v9fs_readdir_unlock(V9fsDir *dir)
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
{
31
{
96
- BlockdevCreateOptions create_options;
32
if (dir->proto_version == V9FS_PROTO_2000U) {
97
- char *backing_file = NULL;
33
qemu_co_mutex_unlock(&dir->readdir_mutex_u);
98
- char *backing_fmt = NULL;
34
diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c
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
35
index XXXXXXX..XXXXXXX 100644
313
--- a/tests/qemu-iotests/049.out
36
--- a/hw/9pfs/codir.c
314
+++ b/tests/qemu-iotests/049.out
37
+++ b/hw/9pfs/codir.c
315
@@ -XXX,XX +XXX,XX @@ qemu-img create -f qcow2 -o compat=1.1 TEST_DIR/t.qcow2 64M
38
@@ -XXX,XX +XXX,XX @@ int coroutine_fn v9fs_co_readdir(V9fsPDU *pdu, V9fsFidState *fidp,
316
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 cluster_size=65536 lazy_refcounts=off refcount_bits=16
39
*
317
40
* See v9fs_co_readdir_many() (as its only user) below for details.
318
qemu-img create -f qcow2 -o compat=0.42 TEST_DIR/t.qcow2 64M
41
*/
319
-qemu-img: TEST_DIR/t.qcow2: Invalid compatibility level: '0.42'
42
-static int do_readdir_many(V9fsPDU *pdu, V9fsFidState *fidp,
320
+qemu-img: TEST_DIR/t.qcow2: Invalid parameter '0.42'
43
- struct V9fsDirEnt **entries, off_t offset,
321
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.42 cluster_size=65536 lazy_refcounts=off refcount_bits=16
44
- int32_t maxsize, bool dostat)
322
45
+static int coroutine_fn
323
qemu-img create -f qcow2 -o compat=foobar TEST_DIR/t.qcow2 64M
46
+do_readdir_many(V9fsPDU *pdu, V9fsFidState *fidp, struct V9fsDirEnt **entries,
324
-qemu-img: TEST_DIR/t.qcow2: Invalid compatibility level: 'foobar'
47
+ off_t offset, int32_t maxsize, bool dostat)
325
+qemu-img: TEST_DIR/t.qcow2: Invalid parameter 'foobar'
48
{
326
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=foobar cluster_size=65536 lazy_refcounts=off refcount_bits=16
49
V9fsState *s = pdu->s;
327
50
V9fsString name;
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
--
51
--
364
2.13.6
52
2.40.0
365
366
diff view generated by jsdifflib
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
QED's bdrv_invalidate_cache implementation would like to reuse functions
3
do_sgio can suspend via the coroutine function thread_pool_submit_co, so it
4
that acquire/release the metadata locks. Call it from coroutine context
4
has to be coroutine_fn as well---and the same is true of all its direct and
5
to simplify the logic.
5
indirect callers.
6
6
7
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
7
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
8
Message-Id: <1516279431-30424-6-git-send-email-pbonzini@redhat.com>
8
Message-Id: <20230309084456.304669-7-pbonzini@redhat.com>
9
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
11
---
12
include/block/block_int.h | 3 ++-
12
scsi/qemu-pr-helper.c | 22 +++++++++++-----------
13
block.c | 41 +++++++++++++++++++++++++++++++++++++----
13
1 file changed, 11 insertions(+), 11 deletions(-)
14
block/iscsi.c | 6 +++---
15
block/nfs.c | 6 +++---
16
block/qcow2.c | 7 +++++--
17
block/qed.c | 13 +++++--------
18
block/rbd.c | 6 +++---
19
7 files changed, 58 insertions(+), 24 deletions(-)
20
14
21
diff --git a/include/block/block_int.h b/include/block/block_int.h
15
diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c
22
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
23
--- a/include/block/block_int.h
17
--- a/scsi/qemu-pr-helper.c
24
+++ b/include/block/block_int.h
18
+++ b/scsi/qemu-pr-helper.c
25
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
19
@@ -XXX,XX +XXX,XX @@ static int do_sgio_worker(void *opaque)
26
/*
20
return status;
27
* Invalidate any cached meta-data.
28
*/
29
- void (*bdrv_invalidate_cache)(BlockDriverState *bs, Error **errp);
30
+ void coroutine_fn (*bdrv_co_invalidate_cache)(BlockDriverState *bs,
31
+ Error **errp);
32
int (*bdrv_inactivate)(BlockDriverState *bs);
33
34
/*
35
diff --git a/block.c b/block.c
36
index XXXXXXX..XXXXXXX 100644
37
--- a/block.c
38
+++ b/block.c
39
@@ -XXX,XX +XXX,XX @@ void bdrv_init_with_whitelist(void)
40
bdrv_init();
41
}
21
}
42
22
43
-void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
23
-static int do_sgio(int fd, const uint8_t *cdb, uint8_t *sense,
44
+static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs,
24
- uint8_t *buf, int *sz, int dir)
45
+ Error **errp)
25
+static int coroutine_fn do_sgio(int fd, const uint8_t *cdb, uint8_t *sense,
26
+ uint8_t *buf, int *sz, int dir)
46
{
27
{
47
BdrvChild *child, *parent;
28
int r;
48
uint64_t perm, shared_perm;
29
49
@@ -XXX,XX +XXX,XX @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
30
@@ -XXX,XX +XXX,XX @@ static SCSISense mpath_generic_sense(int r)
50
}
51
52
QLIST_FOREACH(child, &bs->children, next) {
53
- bdrv_invalidate_cache(child->bs, &local_err);
54
+ bdrv_co_invalidate_cache(child->bs, &local_err);
55
if (local_err) {
56
error_propagate(errp, local_err);
57
return;
58
@@ -XXX,XX +XXX,XX @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
59
}
60
bdrv_set_perm(bs, perm, shared_perm);
61
62
- if (bs->drv->bdrv_invalidate_cache) {
63
- bs->drv->bdrv_invalidate_cache(bs, &local_err);
64
+ if (bs->drv->bdrv_co_invalidate_cache) {
65
+ bs->drv->bdrv_co_invalidate_cache(bs, &local_err);
66
if (local_err) {
67
bs->open_flags |= BDRV_O_INACTIVE;
68
error_propagate(errp, local_err);
69
@@ -XXX,XX +XXX,XX @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
70
}
31
}
71
}
32
}
72
33
73
+typedef struct InvalidateCacheCo {
34
-static int mpath_reconstruct_sense(int fd, int r, uint8_t *sense)
74
+ BlockDriverState *bs;
35
+static int coroutine_fn mpath_reconstruct_sense(int fd, int r, uint8_t *sense)
75
+ Error **errp;
76
+ bool done;
77
+} InvalidateCacheCo;
78
+
79
+static void coroutine_fn bdrv_invalidate_cache_co_entry(void *opaque)
80
+{
81
+ InvalidateCacheCo *ico = opaque;
82
+ bdrv_co_invalidate_cache(ico->bs, ico->errp);
83
+ ico->done = true;
84
+}
85
+
86
+void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
87
+{
88
+ Coroutine *co;
89
+ InvalidateCacheCo ico = {
90
+ .bs = bs,
91
+ .done = false,
92
+ .errp = errp
93
+ };
94
+
95
+ if (qemu_in_coroutine()) {
96
+ /* Fast-path if already in coroutine context */
97
+ bdrv_invalidate_cache_co_entry(&ico);
98
+ } else {
99
+ co = qemu_coroutine_create(bdrv_invalidate_cache_co_entry, &ico);
100
+ qemu_coroutine_enter(co);
101
+ BDRV_POLL_WHILE(bs, !ico.done);
102
+ }
103
+}
104
+
105
void bdrv_invalidate_cache_all(Error **errp)
106
{
36
{
107
BlockDriverState *bs;
37
switch (r) {
108
diff --git a/block/iscsi.c b/block/iscsi.c
38
case MPATH_PR_SUCCESS:
109
index XXXXXXX..XXXXXXX 100644
39
@@ -XXX,XX +XXX,XX @@ static int mpath_reconstruct_sense(int fd, int r, uint8_t *sense)
110
--- a/block/iscsi.c
40
}
111
+++ b/block/iscsi.c
112
@@ -XXX,XX +XXX,XX @@ static int iscsi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
113
return 0;
114
}
41
}
115
42
116
-static void iscsi_invalidate_cache(BlockDriverState *bs,
43
-static int multipath_pr_in(int fd, const uint8_t *cdb, uint8_t *sense,
117
- Error **errp)
44
- uint8_t *data, int sz)
118
+static void coroutine_fn iscsi_co_invalidate_cache(BlockDriverState *bs,
45
+static int coroutine_fn multipath_pr_in(int fd, const uint8_t *cdb, uint8_t *sense,
119
+ Error **errp)
46
+ uint8_t *data, int sz)
120
{
47
{
121
IscsiLun *iscsilun = bs->opaque;
48
int rq_servact = cdb[1];
122
iscsi_allocmap_invalidate(iscsilun);
49
struct prin_resp resp;
123
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_iscsi = {
50
@@ -XXX,XX +XXX,XX @@ static int multipath_pr_in(int fd, const uint8_t *cdb, uint8_t *sense,
124
.create_opts = &iscsi_create_opts,
51
return mpath_reconstruct_sense(fd, r, sense);
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
}
52
}
138
53
139
#ifdef LIBNFS_FEATURE_PAGECACHE
54
-static int multipath_pr_out(int fd, const uint8_t *cdb, uint8_t *sense,
140
-static void nfs_invalidate_cache(BlockDriverState *bs,
55
- const uint8_t *param, int sz)
141
- Error **errp)
56
+static int coroutine_fn multipath_pr_out(int fd, const uint8_t *cdb, uint8_t *sense,
142
+static void coroutine_fn nfs_co_invalidate_cache(BlockDriverState *bs,
57
+ const uint8_t *param, int sz)
143
+ Error **errp)
144
{
58
{
145
NFSClient *client = bs->opaque;
59
int rq_servact = cdb[1];
146
nfs_pagecache_invalidate(client->context, client->fh);
60
int rq_scope = cdb[2] >> 4;
147
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_nfs = {
61
@@ -XXX,XX +XXX,XX @@ static int multipath_pr_out(int fd, const uint8_t *cdb, uint8_t *sense,
148
.bdrv_refresh_filename = nfs_refresh_filename,
62
}
149
150
#ifdef LIBNFS_FEATURE_PAGECACHE
151
- .bdrv_invalidate_cache = nfs_invalidate_cache,
152
+ .bdrv_co_invalidate_cache = nfs_co_invalidate_cache,
153
#endif
63
#endif
154
};
64
155
65
-static int do_pr_in(int fd, const uint8_t *cdb, uint8_t *sense,
156
diff --git a/block/qcow2.c b/block/qcow2.c
66
- uint8_t *data, int *resp_sz)
157
index XXXXXXX..XXXXXXX 100644
67
+static int coroutine_fn do_pr_in(int fd, const uint8_t *cdb, uint8_t *sense,
158
--- a/block/qcow2.c
68
+ uint8_t *data, int *resp_sz)
159
+++ b/block/qcow2.c
69
{
160
@@ -XXX,XX +XXX,XX @@ static void qcow2_close(BlockDriverState *bs)
70
#ifdef CONFIG_MPATH
161
qcow2_free_snapshots(bs);
71
if (is_mpath(fd)) {
72
@@ -XXX,XX +XXX,XX @@ static int do_pr_in(int fd, const uint8_t *cdb, uint8_t *sense,
73
SG_DXFER_FROM_DEV);
162
}
74
}
163
75
164
-static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp)
76
-static int do_pr_out(int fd, const uint8_t *cdb, uint8_t *sense,
165
+static void coroutine_fn qcow2_co_invalidate_cache(BlockDriverState *bs,
77
- const uint8_t *param, int sz)
166
+ Error **errp)
78
+static int coroutine_fn do_pr_out(int fd, const uint8_t *cdb, uint8_t *sense,
79
+ const uint8_t *param, int sz)
167
{
80
{
168
BDRVQcow2State *s = bs->opaque;
81
int resp_sz;
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
229
index XXXXXXX..XXXXXXX 100644
230
--- a/block/rbd.c
231
+++ b/block/rbd.c
232
@@ -XXX,XX +XXX,XX @@ static BlockAIOCB *qemu_rbd_aio_pdiscard(BlockDriverState *bs,
233
#endif
234
235
#ifdef LIBRBD_SUPPORTS_INVALIDATE
236
-static void qemu_rbd_invalidate_cache(BlockDriverState *bs,
237
- Error **errp)
238
+static void coroutine_fn qemu_rbd_co_invalidate_cache(BlockDriverState *bs,
239
+ Error **errp)
240
{
241
BDRVRBDState *s = bs->opaque;
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
82
252
--
83
--
253
2.13.6
84
2.40.0
254
255
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
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>
3
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
8
Message-Id: <1516279431-30424-4-git-send-email-pbonzini@redhat.com>
4
Message-Id: <20230309084456.304669-8-pbonzini@redhat.com>
9
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
5
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
7
---
12
block/qcow2.c | 46 +++++++++++++++++++++++++++++++++++++++++-----
8
tests/unit/test-thread-pool.c | 2 +-
13
1 file changed, 41 insertions(+), 5 deletions(-)
9
1 file changed, 1 insertion(+), 1 deletion(-)
14
10
15
diff --git a/block/qcow2.c b/block/qcow2.c
11
diff --git a/tests/unit/test-thread-pool.c b/tests/unit/test-thread-pool.c
16
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
17
--- a/block/qcow2.c
13
--- a/tests/unit/test-thread-pool.c
18
+++ b/block/qcow2.c
14
+++ b/tests/unit/test-thread-pool.c
19
@@ -XXX,XX +XXX,XX @@ static int qcow2_update_options(BlockDriverState *bs, QDict *options,
15
@@ -XXX,XX +XXX,XX @@ static void test_submit_aio(void)
20
return ret;
16
g_assert_cmpint(data.ret, ==, 0);
21
}
17
}
22
18
23
-static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
19
-static void co_test_cb(void *opaque)
24
- Error **errp)
20
+static void coroutine_fn co_test_cb(void *opaque)
25
+/* Called with s->lock held. */
26
+static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
27
+ int flags, Error **errp)
28
{
21
{
29
BDRVQcow2State *s = bs->opaque;
22
WorkerTestData *data = opaque;
30
unsigned int len, i;
23
31
@@ -XXX,XX +XXX,XX @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
32
}
33
}
34
35
- /* Initialise locks */
36
- qemu_co_mutex_init(&s->lock);
37
bs->supported_zero_flags = header.version >= 3 ? BDRV_REQ_MAY_UNMAP : 0;
38
39
/* Repair image if dirty */
40
@@ -XXX,XX +XXX,XX @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
41
return ret;
42
}
43
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
}
79
80
- return qcow2_do_open(bs, options, flags, errp);
81
+ /* Initialise locks */
82
+ qemu_co_mutex_init(&s->lock);
83
+
84
+ if (qemu_in_coroutine()) {
85
+ /* From bdrv_co_create. */
86
+ qcow2_open_entry(&qoc);
87
+ } else {
88
+ qemu_coroutine_enter(qemu_coroutine_create(qcow2_open_entry, &qoc));
89
+ BDRV_POLL_WHILE(bs, qoc.ret == -EINPROGRESS);
90
+ }
91
+ return qoc.ret;
92
}
93
94
static void qcow2_refresh_limits(BlockDriverState *bs, Error **errp)
95
--
24
--
96
2.13.6
25
2.40.0
97
98
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
Functions that can do I/O (including calling bdrv_is_allocated
4
bdrv_open or bdrv_check.
4
and bdrv_block_status functions) are prime candidates for being
5
coroutine_fns. Make the change for those that are themselves called
6
only from coroutine_fns. Also annotate that they are called with the
7
graph rdlock taken, thus allowing them to call bdrv_co_*() functions
8
for I/O.
5
9
6
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
10
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
7
Message-Id: <1516279431-30424-7-git-send-email-pbonzini@redhat.com>
11
Message-Id: <20230309084456.304669-9-pbonzini@redhat.com>
8
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
14
---
11
block/qcow2.h | 2 ++
15
block/qcow2.h | 15 ++++++++-------
12
block/qcow2-refcount.c | 28 ++++++++++++++++++++++++++++
16
block/qcow2-bitmap.c | 2 +-
13
block/qcow2.c | 20 ++++----------------
17
block/qcow2-cluster.c | 21 +++++++++++++--------
14
3 files changed, 34 insertions(+), 16 deletions(-)
18
block/qcow2-refcount.c | 8 ++++----
19
block/qcow2-snapshot.c | 25 +++++++++++++------------
20
block/qcow2.c | 27 ++++++++++++++-------------
21
6 files changed, 53 insertions(+), 45 deletions(-)
15
22
16
diff --git a/block/qcow2.h b/block/qcow2.h
23
diff --git a/block/qcow2.h b/block/qcow2.h
17
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
18
--- a/block/qcow2.h
25
--- a/block/qcow2.h
19
+++ b/block/qcow2.h
26
+++ b/block/qcow2.h
20
@@ -XXX,XX +XXX,XX @@ void qcow2_free_any_clusters(BlockDriverState *bs, uint64_t l2_entry,
27
@@ -XXX,XX +XXX,XX @@ int64_t qcow2_refcount_area(BlockDriverState *bs, uint64_t offset,
21
int qcow2_update_snapshot_refcount(BlockDriverState *bs,
28
uint64_t new_refblock_offset);
22
int64_t l1_table_offset, int l1_size, int addend);
29
23
30
int64_t qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size);
24
+int coroutine_fn qcow2_flush_caches(BlockDriverState *bs);
31
-int64_t qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
25
+int coroutine_fn qcow2_write_caches(BlockDriverState *bs);
32
- int64_t nb_clusters);
26
int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
33
-int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size);
27
BdrvCheckMode fix);
34
+int64_t coroutine_fn qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
28
35
+ int64_t nb_clusters);
36
+int64_t coroutine_fn qcow2_alloc_bytes(BlockDriverState *bs, int size);
37
void qcow2_free_clusters(BlockDriverState *bs,
38
int64_t offset, int64_t size,
39
enum qcow2_discard_type type);
40
@@ -XXX,XX +XXX,XX @@ int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order,
41
BlockDriverAmendStatusCB *status_cb,
42
void *cb_opaque, Error **errp);
43
int coroutine_fn GRAPH_RDLOCK qcow2_shrink_reftable(BlockDriverState *bs);
44
-int64_t qcow2_get_last_cluster(BlockDriverState *bs, int64_t size);
45
+int64_t coroutine_fn qcow2_get_last_cluster(BlockDriverState *bs, int64_t size);
46
int coroutine_fn qcow2_detect_metadata_preallocation(BlockDriverState *bs);
47
48
/* qcow2-cluster.c functions */
49
@@ -XXX,XX +XXX,XX @@ void qcow2_parse_compressed_l2_entry(BlockDriverState *bs, uint64_t l2_entry,
50
int coroutine_fn GRAPH_RDLOCK
51
qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m);
52
53
-void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m);
54
+void coroutine_fn qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m);
55
int qcow2_cluster_discard(BlockDriverState *bs, uint64_t offset,
56
uint64_t bytes, enum qcow2_discard_type type,
57
bool full_discard);
58
@@ -XXX,XX +XXX,XX @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs,
59
Error **errp);
60
61
void qcow2_free_snapshots(BlockDriverState *bs);
62
-int qcow2_read_snapshots(BlockDriverState *bs, Error **errp);
63
+int coroutine_fn GRAPH_RDLOCK
64
+qcow2_read_snapshots(BlockDriverState *bs, Error **errp);
65
int qcow2_write_snapshots(BlockDriverState *bs);
66
67
int coroutine_fn GRAPH_RDLOCK
68
@@ -XXX,XX +XXX,XX @@ bool coroutine_fn qcow2_load_dirty_bitmaps(BlockDriverState *bs,
69
bool qcow2_get_bitmap_info_list(BlockDriverState *bs,
70
Qcow2BitmapInfoList **info_list, Error **errp);
71
int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp);
72
-int qcow2_truncate_bitmaps_check(BlockDriverState *bs, Error **errp);
73
+int coroutine_fn qcow2_truncate_bitmaps_check(BlockDriverState *bs, Error **errp);
74
bool qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs,
75
bool release_stored, Error **errp);
76
int qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp);
77
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
78
index XXXXXXX..XXXXXXX 100644
79
--- a/block/qcow2-bitmap.c
80
+++ b/block/qcow2-bitmap.c
81
@@ -XXX,XX +XXX,XX @@ out:
82
}
83
84
/* Checks to see if it's safe to resize bitmaps */
85
-int qcow2_truncate_bitmaps_check(BlockDriverState *bs, Error **errp)
86
+int coroutine_fn qcow2_truncate_bitmaps_check(BlockDriverState *bs, Error **errp)
87
{
88
BDRVQcow2State *s = bs->opaque;
89
Qcow2BitmapList *bm_list;
90
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
91
index XXXXXXX..XXXXXXX 100644
92
--- a/block/qcow2-cluster.c
93
+++ b/block/qcow2-cluster.c
94
@@ -XXX,XX +XXX,XX @@ err:
95
* Frees the allocated clusters because the request failed and they won't
96
* actually be linked.
97
*/
98
-void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m)
99
+void coroutine_fn qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m)
100
{
101
BDRVQcow2State *s = bs->opaque;
102
if (!has_data_file(bs) && !m->keep_old_clusters) {
103
@@ -XXX,XX +XXX,XX @@ void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m)
104
*
105
* Returns 0 on success, -errno on failure.
106
*/
107
-static int calculate_l2_meta(BlockDriverState *bs, uint64_t host_cluster_offset,
108
- uint64_t guest_offset, unsigned bytes,
109
- uint64_t *l2_slice, QCowL2Meta **m, bool keep_old)
110
+static int coroutine_fn calculate_l2_meta(BlockDriverState *bs,
111
+ uint64_t host_cluster_offset,
112
+ uint64_t guest_offset, unsigned bytes,
113
+ uint64_t *l2_slice, QCowL2Meta **m,
114
+ bool keep_old)
115
{
116
BDRVQcow2State *s = bs->opaque;
117
int sc_index, l2_index = offset_to_l2_slice_index(s, guest_offset);
118
@@ -XXX,XX +XXX,XX @@ out:
119
* function has been waiting for another request and the allocation must be
120
* restarted, but the whole request should not be failed.
121
*/
122
-static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset,
123
- uint64_t *host_offset, uint64_t *nb_clusters)
124
+static int coroutine_fn do_alloc_cluster_offset(BlockDriverState *bs,
125
+ uint64_t guest_offset,
126
+ uint64_t *host_offset,
127
+ uint64_t *nb_clusters)
128
{
129
BDRVQcow2State *s = bs->opaque;
130
131
@@ -XXX,XX +XXX,XX @@ static int zero_in_l2_slice(BlockDriverState *bs, uint64_t offset,
132
return nb_clusters;
133
}
134
135
-static int zero_l2_subclusters(BlockDriverState *bs, uint64_t offset,
136
- unsigned nb_subclusters)
137
+static int coroutine_fn
138
+zero_l2_subclusters(BlockDriverState *bs, uint64_t offset,
139
+ unsigned nb_subclusters)
140
{
141
BDRVQcow2State *s = bs->opaque;
142
uint64_t *l2_slice;
29
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
143
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
30
index XXXXXXX..XXXXXXX 100644
144
index XXXXXXX..XXXXXXX 100644
31
--- a/block/qcow2-refcount.c
145
--- a/block/qcow2-refcount.c
32
+++ b/block/qcow2-refcount.c
146
+++ b/block/qcow2-refcount.c
33
@@ -XXX,XX +XXX,XX @@ void qcow2_free_any_clusters(BlockDriverState *bs, uint64_t l2_entry,
147
@@ -XXX,XX +XXX,XX @@ int64_t qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size)
34
}
148
return offset;
35
}
149
}
36
150
37
+int coroutine_fn qcow2_write_caches(BlockDriverState *bs)
151
-int64_t qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
38
+{
152
- int64_t nb_clusters)
39
+ BDRVQcow2State *s = bs->opaque;
153
+int64_t coroutine_fn qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
40
+ int ret;
154
+ int64_t nb_clusters)
41
155
{
42
+ ret = qcow2_cache_write(bs, s->l2_table_cache);
156
BDRVQcow2State *s = bs->opaque;
43
+ if (ret < 0) {
157
uint64_t cluster_index, refcount;
44
+ return ret;
158
@@ -XXX,XX +XXX,XX @@ int64_t qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
45
+ }
159
46
+
160
/* only used to allocate compressed sectors. We try to allocate
47
+ if (qcow2_need_accurate_refcounts(s)) {
161
contiguous sectors. size must be <= cluster_size */
48
+ ret = qcow2_cache_write(bs, s->refcount_block_cache);
162
-int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
49
+ if (ret < 0) {
163
+int64_t coroutine_fn qcow2_alloc_bytes(BlockDriverState *bs, int size)
50
+ return ret;
164
{
51
+ }
165
BDRVQcow2State *s = bs->opaque;
52
+ }
166
int64_t offset;
53
+
167
@@ -XXX,XX +XXX,XX @@ out:
54
+ return 0;
168
return ret;
55
+}
169
}
56
+
170
57
+int coroutine_fn qcow2_flush_caches(BlockDriverState *bs)
171
-int64_t qcow2_get_last_cluster(BlockDriverState *bs, int64_t size)
58
+{
172
+int64_t coroutine_fn qcow2_get_last_cluster(BlockDriverState *bs, int64_t size)
59
+ int ret = qcow2_write_caches(bs);
173
{
60
+ if (ret < 0) {
174
BDRVQcow2State *s = bs->opaque;
61
+ return ret;
175
int64_t i;
62
+ }
176
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
63
+
177
index XXXXXXX..XXXXXXX 100644
64
+ return bdrv_flush(bs->file->bs);
178
--- a/block/qcow2-snapshot.c
65
+}
179
+++ b/block/qcow2-snapshot.c
66
180
@@ -XXX,XX +XXX,XX @@ void qcow2_free_snapshots(BlockDriverState *bs)
67
/*********************************************************/
181
* qcow2_check_refcounts() does not do anything with snapshots'
68
/* snapshots and image creation */
182
* extra data.)
183
*/
184
-static int qcow2_do_read_snapshots(BlockDriverState *bs, bool repair,
185
- int *nb_clusters_reduced,
186
- int *extra_data_dropped,
187
- Error **errp)
188
+static coroutine_fn GRAPH_RDLOCK
189
+int qcow2_do_read_snapshots(BlockDriverState *bs, bool repair,
190
+ int *nb_clusters_reduced,
191
+ int *extra_data_dropped,
192
+ Error **errp)
193
{
194
BDRVQcow2State *s = bs->opaque;
195
QCowSnapshotHeader h;
196
@@ -XXX,XX +XXX,XX @@ static int qcow2_do_read_snapshots(BlockDriverState *bs, bool repair,
197
198
/* Read statically sized part of the snapshot header */
199
offset = ROUND_UP(offset, 8);
200
- ret = bdrv_pread(bs->file, offset, sizeof(h), &h, 0);
201
+ ret = bdrv_co_pread(bs->file, offset, sizeof(h), &h, 0);
202
if (ret < 0) {
203
error_setg_errno(errp, -ret, "Failed to read snapshot table");
204
goto fail;
205
@@ -XXX,XX +XXX,XX @@ static int qcow2_do_read_snapshots(BlockDriverState *bs, bool repair,
206
}
207
208
/* Read known extra data */
209
- ret = bdrv_pread(bs->file, offset,
210
- MIN(sizeof(extra), sn->extra_data_size), &extra, 0);
211
+ ret = bdrv_co_pread(bs->file, offset,
212
+ MIN(sizeof(extra), sn->extra_data_size), &extra, 0);
213
if (ret < 0) {
214
error_setg_errno(errp, -ret, "Failed to read snapshot table");
215
goto fail;
216
@@ -XXX,XX +XXX,XX @@ static int qcow2_do_read_snapshots(BlockDriverState *bs, bool repair,
217
/* Store unknown extra data */
218
unknown_extra_data_size = sn->extra_data_size - sizeof(extra);
219
sn->unknown_extra_data = g_malloc(unknown_extra_data_size);
220
- ret = bdrv_pread(bs->file, offset, unknown_extra_data_size,
221
- sn->unknown_extra_data, 0);
222
+ ret = bdrv_co_pread(bs->file, offset, unknown_extra_data_size,
223
+ sn->unknown_extra_data, 0);
224
if (ret < 0) {
225
error_setg_errno(errp, -ret,
226
"Failed to read snapshot table");
227
@@ -XXX,XX +XXX,XX @@ static int qcow2_do_read_snapshots(BlockDriverState *bs, bool repair,
228
229
/* Read snapshot ID */
230
sn->id_str = g_malloc(id_str_size + 1);
231
- ret = bdrv_pread(bs->file, offset, id_str_size, sn->id_str, 0);
232
+ ret = bdrv_co_pread(bs->file, offset, id_str_size, sn->id_str, 0);
233
if (ret < 0) {
234
error_setg_errno(errp, -ret, "Failed to read snapshot table");
235
goto fail;
236
@@ -XXX,XX +XXX,XX @@ static int qcow2_do_read_snapshots(BlockDriverState *bs, bool repair,
237
238
/* Read snapshot name */
239
sn->name = g_malloc(name_size + 1);
240
- ret = bdrv_pread(bs->file, offset, name_size, sn->name, 0);
241
+ ret = bdrv_co_pread(bs->file, offset, name_size, sn->name, 0);
242
if (ret < 0) {
243
error_setg_errno(errp, -ret, "Failed to read snapshot table");
244
goto fail;
245
@@ -XXX,XX +XXX,XX @@ fail:
246
return ret;
247
}
248
249
-int qcow2_read_snapshots(BlockDriverState *bs, Error **errp)
250
+int coroutine_fn qcow2_read_snapshots(BlockDriverState *bs, Error **errp)
251
{
252
return qcow2_do_read_snapshots(bs, false, NULL, NULL, errp);
253
}
69
diff --git a/block/qcow2.c b/block/qcow2.c
254
diff --git a/block/qcow2.c b/block/qcow2.c
70
index XXXXXXX..XXXXXXX 100644
255
index XXXXXXX..XXXXXXX 100644
71
--- a/block/qcow2.c
256
--- a/block/qcow2.c
72
+++ b/block/qcow2.c
257
+++ b/block/qcow2.c
73
@@ -XXX,XX +XXX,XX @@ static int qcow2_mark_clean(BlockDriverState *bs)
258
@@ -XXX,XX +XXX,XX @@ qcow2_extract_crypto_opts(QemuOpts *opts, const char *fmt, Error **errp)
74
259
* unknown magic is skipped (future extension this version knows nothing about)
75
s->incompatible_features &= ~QCOW2_INCOMPAT_DIRTY;
260
* return 0 upon success, non-0 otherwise
76
261
*/
77
- ret = bdrv_flush(bs);
262
-static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
78
+ ret = qcow2_flush_caches(bs);
263
- uint64_t end_offset, void **p_feature_table,
79
if (ret < 0) {
264
- int flags, bool *need_update_header,
80
return ret;
265
- Error **errp)
81
}
266
+static int coroutine_fn GRAPH_RDLOCK
82
@@ -XXX,XX +XXX,XX @@ int qcow2_mark_consistent(BlockDriverState *bs)
267
+qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
83
BDRVQcow2State *s = bs->opaque;
268
+ uint64_t end_offset, void **p_feature_table,
84
269
+ int flags, bool *need_update_header, Error **errp)
85
if (s->incompatible_features & QCOW2_INCOMPAT_CORRUPT) {
270
{
86
- int ret = bdrv_flush(bs);
271
BDRVQcow2State *s = bs->opaque;
87
+ int ret = qcow2_flush_caches(bs);
272
QCowExtension ext;
88
if (ret < 0) {
273
@@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
89
return ret;
274
printf("attempting to read extended header in offset %lu\n", offset);
90
}
275
#endif
91
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_flush_to_os(BlockDriverState *bs)
276
277
- ret = bdrv_pread(bs->file, offset, sizeof(ext), &ext, 0);
278
+ ret = bdrv_co_pread(bs->file, offset, sizeof(ext), &ext, 0);
279
if (ret < 0) {
280
error_setg_errno(errp, -ret, "qcow2_read_extension: ERROR: "
281
"pread fail from offset %" PRIu64, offset);
282
@@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
283
sizeof(bs->backing_format));
284
return 2;
285
}
286
- ret = bdrv_pread(bs->file, offset, ext.len, bs->backing_format, 0);
287
+ ret = bdrv_co_pread(bs->file, offset, ext.len, bs->backing_format, 0);
288
if (ret < 0) {
289
error_setg_errno(errp, -ret, "ERROR: ext_backing_format: "
290
"Could not read format name");
291
@@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
292
case QCOW2_EXT_MAGIC_FEATURE_TABLE:
293
if (p_feature_table != NULL) {
294
void *feature_table = g_malloc0(ext.len + 2 * sizeof(Qcow2Feature));
295
- ret = bdrv_pread(bs->file, offset, ext.len, feature_table, 0);
296
+ ret = bdrv_co_pread(bs->file, offset, ext.len, feature_table, 0);
297
if (ret < 0) {
298
error_setg_errno(errp, -ret, "ERROR: ext_feature_table: "
299
"Could not read table");
300
@@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
301
return -EINVAL;
302
}
303
304
- ret = bdrv_pread(bs->file, offset, ext.len, &s->crypto_header, 0);
305
+ ret = bdrv_co_pread(bs->file, offset, ext.len, &s->crypto_header, 0);
306
if (ret < 0) {
307
error_setg_errno(errp, -ret,
308
"Unable to read CRYPTO header extension");
309
@@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
310
break;
311
}
312
313
- ret = bdrv_pread(bs->file, offset, ext.len, &bitmaps_ext, 0);
314
+ ret = bdrv_co_pread(bs->file, offset, ext.len, &bitmaps_ext, 0);
315
if (ret < 0) {
316
error_setg_errno(errp, -ret, "bitmaps_ext: "
317
"Could not read ext header");
318
@@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
319
case QCOW2_EXT_MAGIC_DATA_FILE:
320
{
321
s->image_data_file = g_malloc0(ext.len + 1);
322
- ret = bdrv_pread(bs->file, offset, ext.len, s->image_data_file, 0);
323
+ ret = bdrv_co_pread(bs->file, offset, ext.len, s->image_data_file, 0);
324
if (ret < 0) {
325
error_setg_errno(errp, -ret,
326
"ERROR: Could not read data file name");
327
@@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
328
uext->len = ext.len;
329
QLIST_INSERT_HEAD(&s->unknown_header_ext, uext, next);
330
331
- ret = bdrv_pread(bs->file, offset, uext->len, uext->data, 0);
332
+ ret = bdrv_co_pread(bs->file, offset, uext->len, uext->data, 0);
333
if (ret < 0) {
334
error_setg_errno(errp, -ret, "ERROR: unknown extension: "
335
"Could not read data");
336
@@ -XXX,XX +XXX,XX @@ static void qcow2_update_options_abort(BlockDriverState *bs,
337
qapi_free_QCryptoBlockOpenOptions(r->crypto_opts);
338
}
339
340
-static int qcow2_update_options(BlockDriverState *bs, QDict *options,
341
- int flags, Error **errp)
342
+static int coroutine_fn
343
+qcow2_update_options(BlockDriverState *bs, QDict *options, int flags,
344
+ Error **errp)
345
{
346
Qcow2ReopenState r = {};
92
int ret;
347
int ret;
93
94
qemu_co_mutex_lock(&s->lock);
95
- ret = qcow2_cache_write(bs, s->l2_table_cache);
96
- if (ret < 0) {
97
- qemu_co_mutex_unlock(&s->lock);
98
- return ret;
99
- }
100
-
101
- if (qcow2_need_accurate_refcounts(s)) {
102
- ret = qcow2_cache_write(bs, s->refcount_block_cache);
103
- if (ret < 0) {
104
- qemu_co_mutex_unlock(&s->lock);
105
- return ret;
106
- }
107
- }
108
+ ret = qcow2_write_caches(bs);
109
qemu_co_mutex_unlock(&s->lock);
110
111
- return 0;
112
+ return ret;
113
}
114
115
static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
116
--
348
--
117
2.13.6
349
2.40.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
Suggested-by: Kevin Wolf <kwolf@redhat.com>
3
Functions that can do I/O are prime candidates for being coroutine_fns. Make the
4
change for the one that is itself called only from coroutine_fns. Unfortunately
5
vmdk does not use a coroutine_fn for the bulk of the open (like qcow2 does) so
6
vmdk_read_cid cannot have the same treatment.
7
4
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
8
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
5
Message-Id: <1516279431-30424-8-git-send-email-pbonzini@redhat.com>
9
Message-Id: <20230309084456.304669-10-pbonzini@redhat.com>
6
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
10
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
12
---
9
include/block/block_int.h | 5 +++--
13
block/vmdk.c | 2 +-
10
block.c | 43 ++++++++++++++++++++++++++++++++++++++++---
14
1 file changed, 1 insertion(+), 1 deletion(-)
11
block/parallels.c | 17 +++++++++++------
12
block/qcow2.c | 23 +++++++++++++++++++----
13
block/qed-check.c | 1 +
14
block/qed-table.c | 26 +++++++++-----------------
15
block/qed.c | 13 +++++++++----
16
block/vdi.c | 6 +++---
17
block/vhdx.c | 7 ++++---
18
block/vmdk.c | 7 ++++---
19
10 files changed, 103 insertions(+), 45 deletions(-)
20
15
21
diff --git a/include/block/block_int.h b/include/block/block_int.h
22
index XXXXXXX..XXXXXXX 100644
23
--- a/include/block/block_int.h
24
+++ b/include/block/block_int.h
25
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
26
* Returns 0 for completed check, -errno for internal errors.
27
* The check results are stored in result.
28
*/
29
- int (*bdrv_check)(BlockDriverState *bs, BdrvCheckResult *result,
30
- BdrvCheckMode fix);
31
+ int coroutine_fn (*bdrv_co_check)(BlockDriverState *bs,
32
+ BdrvCheckResult *result,
33
+ BdrvCheckMode fix);
34
35
int (*bdrv_amend_options)(BlockDriverState *bs, QemuOpts *opts,
36
BlockDriverAmendStatusCB *status_cb,
37
diff --git a/block.c b/block.c
38
index XXXXXXX..XXXXXXX 100644
39
--- a/block.c
40
+++ b/block.c
41
@@ -XXX,XX +XXX,XX @@ static void bdrv_delete(BlockDriverState *bs)
42
* free of errors) or -errno when an internal error occurred. The results of the
43
* check are stored in res.
44
*/
45
-int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix)
46
+static int coroutine_fn bdrv_co_check(BlockDriverState *bs,
47
+ BdrvCheckResult *res, BdrvCheckMode fix)
48
{
49
if (bs->drv == NULL) {
50
return -ENOMEDIUM;
51
}
52
- if (bs->drv->bdrv_check == NULL) {
53
+ if (bs->drv->bdrv_co_check == NULL) {
54
return -ENOTSUP;
55
}
56
57
memset(res, 0, sizeof(*res));
58
- return bs->drv->bdrv_check(bs, res, fix);
59
+ return bs->drv->bdrv_co_check(bs, res, fix);
60
+}
61
+
62
+typedef struct CheckCo {
63
+ BlockDriverState *bs;
64
+ BdrvCheckResult *res;
65
+ BdrvCheckMode fix;
66
+ int ret;
67
+} CheckCo;
68
+
69
+static void bdrv_check_co_entry(void *opaque)
70
+{
71
+ CheckCo *cco = opaque;
72
+ cco->ret = bdrv_co_check(cco->bs, cco->res, cco->fix);
73
+}
74
+
75
+int bdrv_check(BlockDriverState *bs,
76
+ BdrvCheckResult *res, BdrvCheckMode fix)
77
+{
78
+ Coroutine *co;
79
+ CheckCo cco = {
80
+ .bs = bs,
81
+ .res = res,
82
+ .ret = -EINPROGRESS,
83
+ .fix = fix,
84
+ };
85
+
86
+ if (qemu_in_coroutine()) {
87
+ /* Fast-path if already in coroutine context */
88
+ bdrv_check_co_entry(&cco);
89
+ } else {
90
+ co = qemu_coroutine_create(bdrv_check_co_entry, &cco);
91
+ qemu_coroutine_enter(co);
92
+ BDRV_POLL_WHILE(bs, cco.ret == -EINPROGRESS);
93
+ }
94
+
95
+ return cco.ret;
96
}
97
98
/*
99
diff --git a/block/parallels.c b/block/parallels.c
100
index XXXXXXX..XXXXXXX 100644
101
--- a/block/parallels.c
102
+++ b/block/parallels.c
103
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int parallels_co_readv(BlockDriverState *bs,
104
}
105
106
107
-static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
108
- BdrvCheckMode fix)
109
+static int coroutine_fn parallels_co_check(BlockDriverState *bs,
110
+ BdrvCheckResult *res,
111
+ BdrvCheckMode fix)
112
{
113
BDRVParallelsState *s = bs->opaque;
114
int64_t size, prev_off, high_off;
115
@@ -XXX,XX +XXX,XX @@ static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
116
return size;
117
}
118
119
+ qemu_co_mutex_lock(&s->lock);
120
if (s->header_unclean) {
121
fprintf(stderr, "%s image was not closed correctly\n",
122
fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR");
123
@@ -XXX,XX +XXX,XX @@ static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
124
prev_off = off;
125
}
126
127
+ ret = 0;
128
if (flush_bat) {
129
ret = bdrv_pwrite_sync(bs->file, 0, s->header, s->header_size);
130
if (ret < 0) {
131
res->check_errors++;
132
- return ret;
133
+ goto out;
134
}
135
}
136
137
@@ -XXX,XX +XXX,XX @@ static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
138
if (ret < 0) {
139
error_report_err(local_err);
140
res->check_errors++;
141
- return ret;
142
+ goto out;
143
}
144
res->leaks_fixed += count;
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
164
diff --git a/block/qcow2.c b/block/qcow2.c
165
index XXXXXXX..XXXXXXX 100644
166
--- a/block/qcow2.c
167
+++ b/block/qcow2.c
168
@@ -XXX,XX +XXX,XX @@ int qcow2_mark_consistent(BlockDriverState *bs)
169
return 0;
170
}
171
172
-static int qcow2_check(BlockDriverState *bs, BdrvCheckResult *result,
173
- BdrvCheckMode fix)
174
+static int coroutine_fn qcow2_co_check_locked(BlockDriverState *bs,
175
+ BdrvCheckResult *result,
176
+ BdrvCheckMode fix)
177
{
178
int ret = qcow2_check_refcounts(bs, result, fix);
179
if (ret < 0) {
180
@@ -XXX,XX +XXX,XX @@ static int qcow2_check(BlockDriverState *bs, BdrvCheckResult *result,
181
return ret;
182
}
183
184
+static int coroutine_fn qcow2_co_check(BlockDriverState *bs,
185
+ BdrvCheckResult *result,
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
{
200
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
201
(s->incompatible_features & QCOW2_INCOMPAT_DIRTY)) {
202
BdrvCheckResult result = {0};
203
204
- ret = qcow2_check(bs, &result, BDRV_FIX_ERRORS | BDRV_FIX_LEAKS);
205
+ ret = qcow2_co_check_locked(bs, &result,
206
+ BDRV_FIX_ERRORS | BDRV_FIX_LEAKS);
207
if (ret < 0 || result.check_errors) {
208
if (ret >= 0) {
209
ret = -EIO;
210
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_qcow2 = {
211
.bdrv_inactivate = qcow2_inactivate,
212
213
.create_opts = &qcow2_create_opts,
214
- .bdrv_check = qcow2_check,
215
+ .bdrv_co_check = qcow2_co_check,
216
.bdrv_amend_options = qcow2_amend_options,
217
218
.bdrv_detach_aio_context = qcow2_detach_aio_context,
219
diff --git a/block/qed-check.c b/block/qed-check.c
220
index XXXXXXX..XXXXXXX 100644
221
--- a/block/qed-check.c
222
+++ b/block/qed-check.c
223
@@ -XXX,XX +XXX,XX @@ static void qed_check_mark_clean(BDRVQEDState *s, BdrvCheckResult *result)
224
qed_write_header_sync(s);
225
}
226
227
+/* Called with table_lock held. */
228
int qed_check(BDRVQEDState *s, BdrvCheckResult *result, bool fix)
229
{
230
QEDCheck check = {
231
diff --git a/block/qed-table.c b/block/qed-table.c
232
index XXXXXXX..XXXXXXX 100644
233
--- a/block/qed-table.c
234
+++ b/block/qed-table.c
235
@@ -XXX,XX +XXX,XX @@
236
#include "qed.h"
237
#include "qemu/bswap.h"
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
347
index XXXXXXX..XXXXXXX 100644
348
--- a/block/vdi.c
349
+++ b/block/vdi.c
350
@@ -XXX,XX +XXX,XX @@ static void vdi_header_print(VdiHeader *header)
351
}
352
#endif
353
354
-static int vdi_check(BlockDriverState *bs, BdrvCheckResult *res,
355
- BdrvCheckMode fix)
356
+static int coroutine_fn vdi_co_check(BlockDriverState *bs, BdrvCheckResult *res,
357
+ BdrvCheckMode fix)
358
{
359
/* TODO: additional checks possible. */
360
BDRVVdiState *s = (BDRVVdiState *)bs->opaque;
361
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_vdi = {
362
.bdrv_get_info = vdi_get_info,
363
364
.create_opts = &vdi_create_opts,
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
16
diff --git a/block/vmdk.c b/block/vmdk.c
396
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
397
--- a/block/vmdk.c
18
--- a/block/vmdk.c
398
+++ b/block/vmdk.c
19
+++ b/block/vmdk.c
399
@@ -XXX,XX +XXX,XX @@ static ImageInfo *vmdk_get_extent_info(VmdkExtent *extent)
20
@@ -XXX,XX +XXX,XX @@ out:
400
return info;
21
return ret;
401
}
22
}
402
23
403
-static int vmdk_check(BlockDriverState *bs, BdrvCheckResult *result,
24
-static int vmdk_is_cid_valid(BlockDriverState *bs)
404
- BdrvCheckMode fix)
25
+static int coroutine_fn vmdk_is_cid_valid(BlockDriverState *bs)
405
+static int coroutine_fn vmdk_co_check(BlockDriverState *bs,
406
+ BdrvCheckResult *result,
407
+ BdrvCheckMode fix)
408
{
26
{
409
BDRVVmdkState *s = bs->opaque;
27
BDRVVmdkState *s = bs->opaque;
410
VmdkExtent *extent = NULL;
28
uint32_t cur_pcid;
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
--
29
--
421
2.13.6
30
2.40.0
422
423
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
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
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
All of the simple options are now passed to qcow2_co_create() in a
2
BlockdevCreateOptions object. Still missing: node-name and the
3
encryption options.
4
1
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/qcow2.c | 189 ++++++++++++++++++++++++++++++++++++++++++++++------------
10
1 file changed, 151 insertions(+), 38 deletions(-)
11
12
diff --git a/block/qcow2.c b/block/qcow2.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/block/qcow2.c
15
+++ b/block/qcow2.c
16
@@ -XXX,XX +XXX,XX @@ static int64_t qcow2_calc_prealloc_size(int64_t total_size,
17
return meta_size + aligned_total_size;
18
}
19
20
-static size_t qcow2_opt_get_cluster_size_del(QemuOpts *opts, Error **errp)
21
+static bool validate_cluster_size(size_t cluster_size, Error **errp)
22
{
23
- size_t cluster_size;
24
- int cluster_bits;
25
-
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
}
52
53
static int coroutine_fn
54
-qcow2_co_create(BlockDriverState *bs, int64_t total_size,
55
- const char *backing_file, const char *backing_format,
56
- int flags, size_t cluster_size, PreallocMode prealloc,
57
- QemuOpts *opts, int version, int refcount_order,
58
- const char *encryptfmt, Error **errp)
59
+qcow2_co_create(BlockDriverState *bs, BlockdevCreateOptions *create_options,
60
+ QemuOpts *opts, const char *encryptfmt, Error **errp)
61
{
62
+ BlockdevCreateOptionsQcow2 *qcow2_opts;
63
QDict *options;
64
65
/*
66
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockDriverState *bs, int64_t total_size,
67
*/
68
BlockBackend *blk;
69
QCowHeader *header;
70
+ size_t cluster_size;
71
+ int version;
72
+ int refcount_order;
73
uint64_t* refcount_table;
74
Error *local_err = NULL;
75
int ret;
76
77
+ /* Validate options and set default values */
78
+ assert(create_options->driver == BLOCKDEV_DRIVER_QCOW2);
79
+ qcow2_opts = &create_options->u.qcow2;
80
+
81
+ if (!QEMU_IS_ALIGNED(qcow2_opts->size, BDRV_SECTOR_SIZE)) {
82
+ error_setg(errp, "Image size must be a multiple of 512 bytes");
83
+ ret = -EINVAL;
84
+ goto out;
85
+ }
86
+
87
+ if (qcow2_opts->has_version) {
88
+ switch (qcow2_opts->version) {
89
+ case BLOCKDEV_QCOW2_VERSION_V2:
90
+ version = 2;
91
+ break;
92
+ case BLOCKDEV_QCOW2_VERSION_V3:
93
+ version = 3;
94
+ break;
95
+ default:
96
+ g_assert_not_reached();
97
+ }
98
+ } else {
99
+ version = 3;
100
+ }
101
+
102
+ if (qcow2_opts->has_cluster_size) {
103
+ cluster_size = qcow2_opts->cluster_size;
104
+ } else {
105
+ cluster_size = DEFAULT_CLUSTER_SIZE;
106
+ }
107
+
108
+ if (!validate_cluster_size(cluster_size, errp)) {
109
+ return -EINVAL;
110
+ }
111
+
112
+ if (!qcow2_opts->has_preallocation) {
113
+ qcow2_opts->preallocation = PREALLOC_MODE_OFF;
114
+ }
115
+ if (qcow2_opts->has_backing_file &&
116
+ qcow2_opts->preallocation != PREALLOC_MODE_OFF)
117
+ {
118
+ error_setg(errp, "Backing file and preallocation cannot be used at "
119
+ "the same time");
120
+ return -EINVAL;
121
+ }
122
+ if (qcow2_opts->has_backing_fmt && !qcow2_opts->has_backing_file) {
123
+ error_setg(errp, "Backing format cannot be used without backing file");
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) {
192
error_setg_errno(errp, -ret, "Could not assign backing file '%s' "
193
- "with format '%s'", backing_file, backing_format);
194
+ "with format '%s'", qcow2_opts->backing_file,
195
+ backing_format);
196
goto out;
197
}
198
}
199
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockDriverState *bs, int64_t total_size,
200
}
201
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
--
314
2.13.6
315
316
diff view generated by jsdifflib
Deleted patch
1
Instead of passing a separate BlockDriverState* into qcow2_co_create(),
2
make use of the BlockdevRef that is included in BlockdevCreateOptions.
3
1
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Eric Blake <eblake@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
---
8
include/block/block.h | 1 +
9
block.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
10
block/qcow2.c | 39 +++++++++++++++++++++++++--------------
11
3 files changed, 73 insertions(+), 14 deletions(-)
12
13
diff --git a/include/block/block.h b/include/block/block.h
14
index XXXXXXX..XXXXXXX 100644
15
--- a/include/block/block.h
16
+++ b/include/block/block.h
17
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_open_child(const char *filename,
18
BlockDriverState* parent,
19
const BdrvChildRole *child_role,
20
bool allow_none, Error **errp);
21
+BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp);
22
void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
23
Error **errp);
24
int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
25
diff --git a/block.c b/block.c
26
index XXXXXXX..XXXXXXX 100644
27
--- a/block.c
28
+++ b/block.c
29
@@ -XXX,XX +XXX,XX @@
30
#include "qapi/qmp/qdict.h"
31
#include "qapi/qmp/qjson.h"
32
#include "qapi/qmp/qstring.h"
33
+#include "qapi/qobject-output-visitor.h"
34
+#include "qapi/qapi-visit-block-core.h"
35
#include "sysemu/block-backend.h"
36
#include "sysemu/sysemu.h"
37
#include "qemu/notify.h"
38
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_open_child(const char *filename,
39
return c;
40
}
41
42
+/* TODO Future callers may need to specify parent/child_role in order for
43
+ * option inheritance to work. Existing callers use it for the root node. */
44
+BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp)
45
+{
46
+ BlockDriverState *bs = NULL;
47
+ Error *local_err = NULL;
48
+ QObject *obj = NULL;
49
+ QDict *qdict = NULL;
50
+ const char *reference = NULL;
51
+ Visitor *v = NULL;
52
+
53
+ if (ref->type == QTYPE_QSTRING) {
54
+ reference = ref->u.reference;
55
+ } else {
56
+ BlockdevOptions *options = &ref->u.definition;
57
+ assert(ref->type == QTYPE_QDICT);
58
+
59
+ v = qobject_output_visitor_new(&obj);
60
+ visit_type_BlockdevOptions(v, NULL, &options, &local_err);
61
+ if (local_err) {
62
+ error_propagate(errp, local_err);
63
+ goto fail;
64
+ }
65
+ visit_complete(v, &obj);
66
+
67
+ qdict = qobject_to_qdict(obj);
68
+ qdict_flatten(qdict);
69
+
70
+ /* bdrv_open_inherit() defaults to the values in bdrv_flags (for
71
+ * compatibility with other callers) rather than what we want as the
72
+ * real defaults. Apply the defaults here instead. */
73
+ qdict_set_default_str(qdict, BDRV_OPT_CACHE_DIRECT, "off");
74
+ qdict_set_default_str(qdict, BDRV_OPT_CACHE_NO_FLUSH, "off");
75
+ qdict_set_default_str(qdict, BDRV_OPT_READ_ONLY, "off");
76
+ }
77
+
78
+ bs = bdrv_open_inherit(NULL, reference, qdict, 0, NULL, NULL, errp);
79
+ obj = NULL;
80
+
81
+fail:
82
+ qobject_decref(obj);
83
+ visit_free(v);
84
+ return bs;
85
+}
86
+
87
static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs,
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
*/
109
- BlockBackend *blk;
110
+ BlockBackend *blk = NULL;
111
+ BlockDriverState *bs = NULL;
112
QCowHeader *header;
113
size_t cluster_size;
114
int version;
115
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockDriverState *bs, BlockdevCreateOptions *create_options,
116
Error *local_err = NULL;
117
int ret;
118
119
- /* Validate options and set default values */
120
assert(create_options->driver == BLOCKDEV_DRIVER_QCOW2);
121
qcow2_opts = &create_options->u.qcow2;
122
123
+ bs = bdrv_open_blockdev_ref(qcow2_opts->file, errp);
124
+ if (bs == NULL) {
125
+ return -EIO;
126
+ }
127
+
128
+ /* Validate options and set default values */
129
if (!QEMU_IS_ALIGNED(qcow2_opts->size, BDRV_SECTOR_SIZE)) {
130
error_setg(errp, "Image size must be a multiple of 512 bytes");
131
ret = -EINVAL;
132
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockDriverState *bs, BlockdevCreateOptions *create_options,
133
}
134
135
if (!validate_cluster_size(cluster_size, errp)) {
136
- return -EINVAL;
137
+ ret = -EINVAL;
138
+ goto out;
139
}
140
141
if (!qcow2_opts->has_preallocation) {
142
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockDriverState *bs, BlockdevCreateOptions *create_options,
143
{
144
error_setg(errp, "Backing file and preallocation cannot be used at "
145
"the same time");
146
- return -EINVAL;
147
+ ret = -EINVAL;
148
+ goto out;
149
}
150
if (qcow2_opts->has_backing_fmt && !qcow2_opts->has_backing_file) {
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
--
208
2.13.6
209
210
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
We'll use a separate source file for image creation, and we need to
2
check there whether the requested driver is whitelisted.
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/block/block.h | 1 +
9
block.c | 2 +-
10
2 files changed, 2 insertions(+), 1 deletion(-)
11
12
diff --git a/include/block/block.h b/include/block/block.h
13
index XXXXXXX..XXXXXXX 100644
14
--- a/include/block/block.h
15
+++ b/include/block/block.h
16
@@ -XXX,XX +XXX,XX @@ char *bdrv_perm_names(uint64_t perm);
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);
24
diff --git a/block.c b/block.c
25
index XXXXXXX..XXXXXXX 100644
26
--- a/block.c
27
+++ b/block.c
28
@@ -XXX,XX +XXX,XX @@ BlockDriver *bdrv_find_format(const char *format_name)
29
return bdrv_do_find_format(format_name);
30
}
31
32
-static int bdrv_is_whitelisted(BlockDriver *drv, bool read_only)
33
+int bdrv_is_whitelisted(BlockDriver *drv, bool read_only)
34
{
35
static const char *whitelist_rw[] = {
36
CONFIG_BDRV_RW_WHITELIST
37
--
38
2.13.6
39
40
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 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
Deleted patch
1
Instead of the QemuOpts in qemu_rbd_connect(), we want to use QAPI
2
objects. As a preparation, fetch those options directly from the QDict
3
that .bdrv_open() supports in the rbd driver and that are not in the
4
schema.
5
1
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
---
9
block/rbd.c | 55 ++++++++++++++++++++++++-------------------------------
10
1 file changed, 24 insertions(+), 31 deletions(-)
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 QemuOptsList runtime_opts = {
17
/*
18
* server.* extracted manually, see qemu_rbd_mon_host()
19
*/
20
- {
21
- .name = "password-secret",
22
- .type = QEMU_OPT_STRING,
23
- .help = "ID of secret providing the password",
24
- },
25
-
26
- /*
27
- * Keys for qemu_rbd_parse_filename(), not in the QAPI schema
28
- */
29
- {
30
- /*
31
- * HACK: name starts with '=' so that qemu_opts_parse()
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
{
54
QemuOpts *opts;
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
+
101
+ secretid = g_strdup(qdict_get_try_str(options, "password-secret"));
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
}
134
135
--
136
2.13.6
137
138
diff view generated by jsdifflib
Deleted patch
1
With the conversion to a QAPI options object, the function is now
2
prepared to be used in a .bdrv_co_create implementation.
3
1
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
---
7
block/rbd.c | 115 +++++++++++++++++++++++++++++-------------------------------
8
1 file changed, 55 insertions(+), 60 deletions(-)
9
10
diff --git a/block/rbd.c b/block/rbd.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/block/rbd.c
13
+++ b/block/rbd.c
14
@@ -XXX,XX +XXX,XX @@
15
#include "qapi/qmp/qdict.h"
16
#include "qapi/qmp/qjson.h"
17
#include "qapi/qmp/qlist.h"
18
+#include "qapi/qobject-input-visitor.h"
19
+#include "qapi/qapi-visit-block-core.h"
20
21
/*
22
* When specifying the image filename use:
23
@@ -XXX,XX +XXX,XX @@ static void qemu_rbd_complete_aio(RADOSCB *rcb)
24
qemu_aio_unref(acb);
25
}
26
27
-static char *qemu_rbd_mon_host(QDict *options, Error **errp)
28
+static char *qemu_rbd_mon_host(BlockdevOptionsRbd *opts, Error **errp)
29
{
30
- const char **vals = g_new(const char *, qdict_size(options) + 1);
31
- char keybuf[32];
32
+ const char **vals;
33
const char *host, *port;
34
char *rados_str;
35
- int i;
36
-
37
- for (i = 0;; i++) {
38
- sprintf(keybuf, "server.%d.host", i);
39
- host = qdict_get_try_str(options, keybuf);
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
+
55
+ if (!opts->has_server) {
56
+ return NULL;
57
+ }
58
+
59
+ for (cnt = 0, p = opts->server; p; p = p->next) {
60
+ cnt++;
61
+ }
62
+
63
+ vals = g_new(const char *, cnt + 1);
64
+
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
--
221
2.13.6
222
223
diff view generated by jsdifflib
Deleted patch
1
Now that the options are already available in qemu_rbd_open() and not
2
only parsed in qemu_rbd_connect(), we can assign s->snap and
3
s->image_name there instead of passing the fields by reference to
4
qemu_rbd_connect().
5
1
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
---
9
block/rbd.c | 14 +++++---------
10
1 file changed, 5 insertions(+), 9 deletions(-)
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 char *qemu_rbd_mon_host(BlockdevOptionsRbd *opts, Error **errp)
17
}
18
19
static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
20
- char **s_snap, char **s_image_name,
21
BlockdevOptionsRbd *opts, bool cache,
22
const char *keypairs, const char *secretid,
23
Error **errp)
24
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
25
goto failed_opts;
26
}
27
28
- *s_snap = g_strdup(opts->snapshot);
29
- *s_image_name = g_strdup(opts->image);
30
-
31
/* try default location when conf=NULL, but ignore failure */
32
r = rados_conf_read_file(*cluster, opts->conf);
33
if (opts->has_conf && r < 0) {
34
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
35
36
failed_shutdown:
37
rados_shutdown(*cluster);
38
- g_free(*s_snap);
39
- g_free(*s_image_name);
40
failed_opts:
41
g_free(mon_host);
42
return r;
43
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
44
goto out;
45
}
46
47
- r = qemu_rbd_connect(&s->cluster, &s->io_ctx, &s->snap, &s->image_name,
48
- opts, !(flags & BDRV_O_NOCACHE), keypairs, secretid,
49
- errp);
50
+ r = qemu_rbd_connect(&s->cluster, &s->io_ctx, opts,
51
+ !(flags & BDRV_O_NOCACHE), keypairs, secretid, errp);
52
if (r < 0) {
53
goto out;
54
}
55
56
+ s->snap = g_strdup(opts->snapshot);
57
+ s->image_name = g_strdup(opts->image);
58
+
59
/* rbd_open is always r/w */
60
r = rbd_open(s->io_ctx, s->image_name, &s->image, s->snap);
61
if (r < 0) {
62
--
63
2.13.6
64
65
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
Deleted patch
1
Using the QAPI visitor to turn all options into QAPI BlockdevOptionsNfs
2
simplifies the code a lot. It will also be useful for implementing the
3
QAPI based .bdrv_co_create callback.
4
1
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
---
8
block/nfs.c | 176 ++++++++++++++++++------------------------------------------
9
1 file changed, 53 insertions(+), 123 deletions(-)
10
11
diff --git a/block/nfs.c b/block/nfs.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/block/nfs.c
14
+++ b/block/nfs.c
15
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn nfs_co_flush(BlockDriverState *bs)
16
return task.ret;
17
}
18
19
-static QemuOptsList runtime_opts = {
20
- .name = "nfs",
21
- .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
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
{
64
NFSClient *client = bs->opaque;
65
@@ -XXX,XX +XXX,XX @@ static void nfs_file_close(BlockDriverState *bs)
66
nfs_client_close(client);
67
}
68
69
-static NFSServer *nfs_config(QDict *options, Error **errp)
70
-{
71
- NFSServer *server = NULL;
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
{
114
int64_t ret = -EINVAL;
115
- QemuOpts *opts = NULL;
116
- Error *local_err = NULL;
117
struct stat st;
118
char *file = NULL, *strp = NULL;
119
120
qemu_mutex_init(&client->mutex);
121
- opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
122
- qemu_opts_absorb_qdict(opts, options, &local_err);
123
- if (local_err) {
124
- error_propagate(errp, local_err);
125
- ret = -EINVAL;
126
- goto fail;
127
- }
128
129
- client->path = g_strdup(qemu_opt_get(opts, "path"));
130
- if (!client->path) {
131
- ret = -EINVAL;
132
- error_setg(errp, "No path was specified");
133
- goto fail;
134
- }
135
+ client->path = g_strdup(opts->path);
136
137
strp = strrchr(client->path, '/');
138
if (strp == NULL) {
139
@@ -XXX,XX +XXX,XX @@ static int64_t nfs_client_open(NFSClient *client, QDict *options,
140
file = g_strdup(strp);
141
*strp = 0;
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
}
159
160
- if (qemu_opt_get(opts, "user")) {
161
- client->uid = qemu_opt_get_number(opts, "user", 0);
162
+ if (opts->has_user) {
163
+ client->uid = opts->user;
164
nfs_set_uid(client->context, client->uid);
165
}
166
167
- if (qemu_opt_get(opts, "group")) {
168
- client->gid = qemu_opt_get_number(opts, "group", 0);
169
+ if (opts->has_group) {
170
+ client->gid = opts->group;
171
nfs_set_gid(client->context, client->gid);
172
}
173
174
- if (qemu_opt_get(opts, "tcp-syn-count")) {
175
- client->tcp_syncnt = qemu_opt_get_number(opts, "tcp-syn-count", 0);
176
+ if (opts->has_tcp_syn_count) {
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
+
239
+ crumpled = qdict_crumple(options, errp);
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;
276
}
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
--
287
2.13.6
288
289
diff view generated by jsdifflib
1
The "redundancy" option for Sheepdog image creation is currently a
1
From: Wang Liang <wangliangzz@inspur.com>
2
string that can encode one or two integers depending on its format,
3
which at the same time implicitly selects a mode.
4
2
5
This patch turns it into a QAPI union and converts the string into such
3
hmp_commit() calls blk_is_available() from a non-coroutine context (and in
6
a QAPI object before interpreting the values.
4
the main loop). blk_is_available() is a co_wrapper_mixed_bdrv_rdlock
5
function, and in the non-coroutine context it calls AIO_WAIT_WHILE(),
6
which crashes if the aio_context lock is not taken before.
7
7
8
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1615
9
Signed-off-by: Wang Liang <wangliangzz@inspur.com>
10
Message-Id: <20230424103902.45265-1-wangliangzz@126.com>
11
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
---
14
---
11
qapi/block-core.json | 45 +++++++++++++++++++++++++
15
block/monitor/block-hmp-cmds.c | 10 ++++++----
12
block/sheepdog.c | 94 +++++++++++++++++++++++++++++++++++++---------------
16
1 file changed, 6 insertions(+), 4 deletions(-)
13
2 files changed, 112 insertions(+), 27 deletions(-)
14
17
15
diff --git a/qapi/block-core.json b/qapi/block-core.json
18
diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c
16
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
17
--- a/qapi/block-core.json
20
--- a/block/monitor/block-hmp-cmds.c
18
+++ b/qapi/block-core.json
21
+++ b/block/monitor/block-hmp-cmds.c
19
@@ -XXX,XX +XXX,XX @@
22
@@ -XXX,XX +XXX,XX @@ void hmp_commit(Monitor *mon, const QDict *qdict)
20
'*cluster-size' : 'size' } }
23
error_report("Device '%s' not found", device);
21
24
return;
22
##
25
}
23
+# @SheepdogRedundancyType:
26
- if (!blk_is_available(blk)) {
24
+#
27
- error_report("Device '%s' has no medium", device);
25
+# @full Create a fully replicated vdi with x copies
28
- return;
26
+# @erasure-coded Create an erasure coded vdi with x data strips and
29
- }
27
+# y parity strips
30
28
+#
31
bs = bdrv_skip_implicit_filters(blk_bs(blk));
29
+# Since: 2.12
32
aio_context = bdrv_get_aio_context(bs);
30
+##
33
aio_context_acquire(aio_context);
31
+{ 'enum': 'SheepdogRedundancyType',
34
32
+ 'data': [ 'full', 'erasure-coded' ] }
35
+ if (!blk_is_available(blk)) {
33
+
36
+ error_report("Device '%s' has no medium", device);
34
+##
37
+ aio_context_release(aio_context);
35
+# @SheepdogRedundancyFull:
38
+ return;
36
+#
37
+# @copies Number of copies to use (between 1 and 31)
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
73
--- a/block/sheepdog.c
74
+++ b/block/sheepdog.c
75
@@ -XXX,XX +XXX,XX @@ out_with_err_set:
76
return ret;
77
}
78
79
+static int parse_redundancy(BDRVSheepdogState *s, SheepdogRedundancy *opt)
80
+{
81
+ struct SheepdogInode *inode = &s->inode;
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
+ }
39
+ }
100
+
40
+
101
+ if (parity >= SD_EC_MAX_STRIP || parity < 1) {
41
ret = bdrv_commit(bs);
102
+ return -EINVAL;
42
103
+ }
43
aio_context_release(aio_context);
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
{
131
- struct SheepdogInode *inode = &s->inode;
132
+ struct SheepdogRedundancy redundancy;
133
const char *n1, *n2;
134
long copy, parity;
135
char p[10];
136
+ int ret;
137
138
pstrcpy(p, sizeof(p), opt);
139
n1 = strtok(p, ":");
140
@@ -XXX,XX +XXX,XX @@ static int parse_redundancy(BDRVSheepdogState *s, const char *opt)
141
return -EINVAL;
142
}
143
144
- copy = strtol(n1, NULL, 10);
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
--
44
--
207
2.13.6
45
2.40.0
208
209
diff view generated by jsdifflib
Deleted patch
1
Create a BlockdevOptionsSsh object in connect_to_ssh() and take the
2
options from there. 'host_key_check' is still processed separately
3
because it's not in the schema yet.
4
1
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
---
8
block/ssh.c | 137 +++++++++++++++++++++++++++---------------------------------
9
1 file changed, 62 insertions(+), 75 deletions(-)
10
11
diff --git a/block/ssh.c b/block/ssh.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/block/ssh.c
14
+++ b/block/ssh.c
15
@@ -XXX,XX +XXX,XX @@
16
#include "qemu/sockets.h"
17
#include "qemu/uri.h"
18
#include "qapi/qapi-visit-sockets.h"
19
+#include "qapi/qapi-visit-block-core.h"
20
#include "qapi/qmp/qdict.h"
21
#include "qapi/qmp/qstring.h"
22
#include "qapi/qobject-input-visitor.h"
23
@@ -XXX,XX +XXX,XX @@ static QemuOptsList ssh_runtime_opts = {
24
.type = QEMU_OPT_NUMBER,
25
.help = "Port to connect to",
26
},
27
- {
28
- .name = "path",
29
- .type = QEMU_OPT_STRING,
30
- .help = "Path of the image on the host",
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
}
48
49
-static InetSocketAddress *ssh_config(QDict *options, Error **errp)
50
+static BlockdevOptionsSsh *ssh_parse_options(QDict *options, Error **errp)
51
{
52
- InetSocketAddress *inet = NULL;
53
- QDict *addr = NULL;
54
- QObject *crumpled_addr = NULL;
55
- Visitor *iv = NULL;
56
- Error *local_error = NULL;
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
90
/*
91
@@ -XXX,XX +XXX,XX @@ static InetSocketAddress *ssh_config(QDict *options, Error **errp)
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
--
225
2.13.6
226
227
diff view generated by jsdifflib
Deleted patch
1
This adds the .bdrv_co_create driver callback to ssh, 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 | 16 +++++++++-
8
block/ssh.c | 83 ++++++++++++++++++++++++++++++----------------------
9
2 files changed, 63 insertions(+), 36 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
'*object-size': 'size' } }
17
18
##
19
+# @BlockdevCreateOptionsSsh:
20
+#
21
+# Driver specific image creation options for SSH.
22
+#
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
+
32
+##
33
# @BlockdevCreateNotSupported:
34
#
35
# This is used for all drivers that don't support creating images.
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
47
--- a/block/ssh.c
48
+++ b/block/ssh.c
49
@@ -XXX,XX +XXX,XX @@ static QemuOptsList ssh_create_opts = {
50
}
51
};
52
53
+static int ssh_co_create(BlockdevCreateOptions *options, Error **errp)
54
+{
55
+ BlockdevCreateOptionsSsh *opts = &options->u.ssh;
56
+ BDRVSSHState s;
57
+ int ret;
58
+
59
+ assert(options->driver == BLOCKDEV_DRIVER_SSH);
60
+
61
+ ssh_state_init(&s);
62
+
63
+ ret = connect_to_ssh(&s, opts->location,
64
+ LIBSSH2_FXF_READ|LIBSSH2_FXF_WRITE|
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;
154
}
155
156
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_ssh = {
157
.instance_size = sizeof(BDRVSSHState),
158
.bdrv_parse_filename = ssh_parse_filename,
159
.bdrv_file_open = ssh_file_open,
160
+ .bdrv_co_create = ssh_co_create,
161
.bdrv_co_create_opts = ssh_co_create_opts,
162
.bdrv_close = ssh_close,
163
.bdrv_has_zero_init = ssh_has_zero_init,
164
--
165
2.13.6
166
167
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