1
The following changes since commit 9514f2648ca05b38e852b490a12b8cd98d5808c1:
1
The following changes since commit b98a66201dbc7cf3b962f4bb260f66100cc75578:
2
2
3
Merge remote-tracking branch 'remotes/gkurz/tags/for-upstream' into staging (2017-02-28 17:39:49 +0000)
3
Merge remote-tracking branch 'remotes/palmer/tags/riscv-for-master-4.0-rc0-2' into staging (2019-03-19 12:55:02 +0000)
4
4
5
are available in the git repository at:
5
are available in the Git repository at:
6
7
6
8
git://repo.or.cz/qemu/kevin.git tags/for-upstream
7
git://repo.or.cz/qemu/kevin.git tags/for-upstream
9
8
10
for you to fetch changes up to b2c2832c6140cfe3ddc0de2d77eeb0b77dea8fd3:
9
for you to fetch changes up to 59fba0aaee7438002d9803a86c888f21a1070cc8:
11
10
12
block: Add Error parameter to bdrv_append() (2017-02-28 20:47:51 +0100)
11
qemu-iotests: Treat custom TEST_DIR in 051 (2019-03-19 15:51:31 +0100)
13
12
14
----------------------------------------------------------------
13
----------------------------------------------------------------
15
Block layer patches
14
Block layer patches:
15
16
- mirror: Fix early return from drain (could cause deadlocks)
17
- vmdk: Fixed probing for version 3 images
18
- vl: Fix to create migration object before block backends again (fixes
19
segfault for block drivers that set migration blockers)
20
- Several minor fixes, documentation and test case improvements
16
21
17
----------------------------------------------------------------
22
----------------------------------------------------------------
18
Kevin Wolf (44):
23
Alberto Garcia (1):
19
block: Add op blocker permission constants
24
block: Make bdrv_{copy_on_read,crypto_luks,replication} static
20
block: Add Error argument to bdrv_attach_child()
25
21
block: Let callers request permissions when attaching a child node
26
Kevin Wolf (3):
22
block: Involve block drivers in permission granting
27
qcow2: Fix data file error condition in qcow2_co_create()
23
block: Default .bdrv_child_perm() for filter drivers
28
block: Silence Coverity in bdrv_drop_intermediate()
24
block: Request child permissions in filter drivers
29
qemu-iotests: Fix 232 for non-qcow2
25
block: Default .bdrv_child_perm() for format drivers
30
26
block: Request child permissions in format drivers
31
Lukáš Doktor (1):
27
vvfat: Implement .bdrv_child_perm()
32
qemu-iotests: Treat custom TEST_DIR in 051
28
block: Require .bdrv_child_perm() with child nodes
29
block: Request real permissions in bdrv_attach_child()
30
block: Add permissions to BlockBackend
31
block: Add permissions to blk_new()
32
block: Add error parameter to blk_insert_bs()
33
block: Add BDRV_O_RESIZE for blk_new_open()
34
block: Request real permissions in blk_new_open()
35
block: Allow error return in BlockDevOps.change_media_cb()
36
hw/block: Request permissions
37
hw/block: Introduce share-rw qdev property
38
blockjob: Add permissions to block_job_create()
39
block: Add BdrvChildRole.get_parent_desc()
40
block: Include details on permission errors in message
41
block: Add BdrvChildRole.stay_at_node
42
blockjob: Add permissions to block_job_add_bdrv()
43
commit: Use real permissions in commit block job
44
commit: Use real permissions for HMP 'commit'
45
backup: Use real permissions in backup block job
46
block: Fix pending requests check in bdrv_append()
47
block: BdrvChildRole.attach/detach() callbacks
48
block: Allow backing file links in change_parent_backing_link()
49
blockjob: Factor out block_job_remove_all_bdrv()
50
mirror: Use real permissions in mirror/active commit block job
51
stream: Use real permissions in streaming block job
52
mirror: Add filter-node-name to blockdev-mirror
53
commit: Add filter-node-name to block-commit
54
hmp: Request permissions in qemu-io
55
migration/block: Use real permissions
56
nbd/server: Use real permissions for NBD exports
57
tests: Remove FIXME comments
58
block: Pass BdrvChild to bdrv_aligned_preadv/pwritev and copy-on-read
59
block: Assertions for write permissions
60
block: Assertions for resize permission
61
block: Add Error parameter to bdrv_set_backing_hd()
62
block: Add Error parameter to bdrv_append()
63
33
64
Markus Armbruster (1):
34
Markus Armbruster (1):
65
option: Tweak invalid size error message and unbreak iotest 049
35
vl: Fix to create migration object before block backends again
66
36
67
Peter Lieven (1):
37
Max Reitz (1):
68
qemu-img: make convert async
38
blockdev: Check @replaces in blockdev_mirror_common
69
39
70
block.c | 583 ++++++++++++++++++++++++++++++++++-----
40
Sam Eiderman (1):
71
block/backup.c | 22 +-
41
vmdk: Support version=3 in VMDK descriptor files
72
block/blkdebug.c | 2 +
73
block/blkreplay.c | 1 +
74
block/blkverify.c | 1 +
75
block/block-backend.c | 116 +++++++-
76
block/bochs.c | 1 +
77
block/cloop.c | 1 +
78
block/commit.c | 176 ++++++++++--
79
block/crypto.c | 1 +
80
block/dmg.c | 1 +
81
block/io.c | 41 +--
82
block/mirror.c | 237 ++++++++++++++--
83
block/parallels.c | 4 +-
84
block/qcow.c | 4 +-
85
block/qcow2.c | 19 +-
86
block/qed.c | 4 +-
87
block/quorum.c | 11 +-
88
block/raw-format.c | 1 +
89
block/replication.c | 3 +-
90
block/sheepdog.c | 2 +-
91
block/stream.c | 47 +++-
92
block/vdi.c | 4 +-
93
block/vhdx.c | 4 +-
94
block/vmdk.c | 7 +-
95
block/vpc.c | 4 +-
96
block/vvfat.c | 24 +-
97
blockdev.c | 74 ++++-
98
blockjob.c | 62 ++++-
99
hmp.c | 33 ++-
100
hw/block/block.c | 24 +-
101
hw/block/fdc.c | 28 +-
102
hw/block/m25p80.c | 8 +
103
hw/block/nand.c | 7 +
104
hw/block/nvme.c | 8 +-
105
hw/block/onenand.c | 7 +
106
hw/block/pflash_cfi01.c | 18 +-
107
hw/block/pflash_cfi02.c | 19 +-
108
hw/block/virtio-blk.c | 8 +-
109
hw/core/qdev-properties-system.c | 9 +-
110
hw/ide/core.c | 2 +-
111
hw/ide/qdev.c | 9 +-
112
hw/nvram/spapr_nvram.c | 8 +
113
hw/scsi/scsi-disk.c | 12 +-
114
hw/sd/sd.c | 8 +-
115
hw/usb/dev-storage.c | 6 +-
116
include/block/block.h | 46 ++-
117
include/block/block_int.h | 126 ++++++++-
118
include/block/blockjob.h | 14 +-
119
include/block/blockjob_int.h | 4 +-
120
include/hw/block/block.h | 8 +-
121
include/qemu-io.h | 1 +
122
include/sysemu/block-backend.h | 9 +-
123
migration/block.c | 21 +-
124
nbd/server.c | 16 +-
125
qapi/block-core.json | 16 +-
126
qemu-img-cmds.hx | 4 +-
127
qemu-img.c | 334 +++++++++++++++-------
128
qemu-img.texi | 16 +-
129
qemu-io-cmds.c | 28 ++
130
tests/qemu-iotests/049.out | 14 +-
131
tests/qemu-iotests/051.pc.out | 6 +-
132
tests/qemu-iotests/055 | 11 +-
133
tests/qemu-iotests/085.out | 2 +-
134
tests/qemu-iotests/141 | 2 +-
135
tests/qemu-iotests/141.out | 4 +-
136
tests/qemu-iotests/172.out | 53 ++++
137
tests/test-blockjob-txn.c | 6 +-
138
tests/test-blockjob.c | 10 +-
139
tests/test-throttle.c | 7 +-
140
util/qemu-option.c | 2 +-
141
71 files changed, 2039 insertions(+), 392 deletions(-)
142
42
43
Sergio Lopez (2):
44
mirror: Confirm we're quiesced only if the job is paused or cancelled
45
iotests: 153: Wait for an answer to QMP commands
46
47
Vladimir Sementsov-Ogievskiy (2):
48
qapi: fix block-latency-histogram-set description and examples
49
blockjob: fix user pause in block_job_error_action
50
51
qapi/block-core.json | 10 +++---
52
block.c | 7 ++--
53
block/copy-on-read.c | 2 +-
54
block/crypto.c | 2 +-
55
block/mirror.c | 16 ++++++++++
56
block/qcow2.c | 2 +-
57
block/replication.c | 2 +-
58
block/vmdk.c | 6 ++--
59
blockdev.c | 55 +++++++++++++++++++-------------
60
blockjob.c | 8 +++--
61
vl.c | 15 +++++----
62
tests/qemu-iotests/051 | 2 +-
63
tests/qemu-iotests/153 | 12 +++----
64
tests/qemu-iotests/153.out | 6 ++++
65
tests/qemu-iotests/232 | 30 ------------------
66
tests/qemu-iotests/232.out | 20 ------------
67
tests/qemu-iotests/247 | 79 ++++++++++++++++++++++++++++++++++++++++++++++
68
tests/qemu-iotests/247.out | 22 +++++++++++++
69
tests/qemu-iotests/group | 1 +
70
19 files changed, 193 insertions(+), 104 deletions(-)
71
create mode 100755 tests/qemu-iotests/247
72
create mode 100644 tests/qemu-iotests/247.out
73
diff view generated by jsdifflib
1
The mirror block job is mainly used for two different scenarios:
1
From: Sergio Lopez <slp@redhat.com>
2
Mirroring to an otherwise unused, independent target node, or for active
3
commit where the target node is part of the backing chain of the source.
4
2
5
Similarly to the commit block job patch, we need to insert a new filter
3
While child_job_drained_begin() calls to job_pause(), the job doesn't
6
node to keep the permissions correct during active commit.
4
actually transition between states until it runs again and reaches a
5
pause point. This means bdrv_drained_begin() may return with some jobs
6
using the node still having 'busy == true'.
7
7
8
Note that one change this implies is that job->blk points to
8
As a consequence, block_job_detach_aio_context() may get into a
9
mirror_top_bs as its root now, and mirror_top_bs (rather than the actual
9
deadlock, waiting for the job to be actually paused, while the coroutine
10
source node) contains the bs->job pointer. This requires qemu-img commit
10
servicing the job is yielding and doesn't get the opportunity to get
11
to get the job by name now rather than just taking bs->job.
11
scheduled again. This situation can be reproduced by issuing a
12
'block-commit' immediately followed by a 'device_del'.
12
13
14
To ensure bdrv_drained_begin() only returns when the jobs have been
15
paused, we change mirror_drained_poll() to only confirm it's quiesced
16
when job->paused == true and there aren't any in-flight requests, except
17
if we reached that point by a drained section initiated by the
18
mirror/commit job itself.
19
20
The other block jobs shouldn't need any changes, as the default
21
drained_poll() behavior is to only confirm it's quiesced if the job is
22
not busy or completed.
23
24
Signed-off-by: Sergio Lopez <slp@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
25
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Acked-by: Fam Zheng <famz@redhat.com>
15
Acked-by: Max Reitz <mreitz@redhat.com>
16
---
26
---
17
block/mirror.c | 216 ++++++++++++++++++++++++++++++++++++++-------
27
block/mirror.c | 16 ++++++++++++++++
18
qemu-img.c | 6 +-
28
1 file changed, 16 insertions(+)
19
tests/qemu-iotests/141 | 2 +-
20
tests/qemu-iotests/141.out | 4 +-
21
4 files changed, 190 insertions(+), 38 deletions(-)
22
29
23
diff --git a/block/mirror.c b/block/mirror.c
30
diff --git a/block/mirror.c b/block/mirror.c
24
index XXXXXXX..XXXXXXX 100644
31
index XXXXXXX..XXXXXXX 100644
25
--- a/block/mirror.c
32
--- a/block/mirror.c
26
+++ b/block/mirror.c
33
+++ b/block/mirror.c
27
@@ -XXX,XX +XXX,XX @@ typedef struct MirrorBlockJob {
34
@@ -XXX,XX +XXX,XX @@ typedef struct MirrorBlockJob {
28
BlockJob common;
35
bool initial_zeroing_ongoing;
29
RateLimit limit;
36
int in_active_write_counter;
30
BlockBackend *target;
37
bool prepared;
31
+ BlockDriverState *mirror_top_bs;
38
+ bool in_drain;
32
+ BlockDriverState *source;
39
} MirrorBlockJob;
33
BlockDriverState *base;
40
34
+
41
typedef struct MirrorBDSOpaque {
35
/* The name of the graph node to replace */
42
@@ -XXX,XX +XXX,XX @@ static int mirror_exit_common(Job *job)
36
char *replaces;
43
37
/* The BDS to replace */
44
/* The mirror job has no requests in flight any more, but we need to
38
@@ -XXX,XX +XXX,XX @@ static void mirror_do_zero_or_discard(MirrorBlockJob *s,
45
* drain potential other users of the BDS before changing the graph. */
39
46
+ assert(s->in_drain);
40
static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
41
{
42
- BlockDriverState *source = blk_bs(s->common.blk);
43
+ BlockDriverState *source = s->source;
44
int64_t sector_num, first_chunk;
45
uint64_t delay_ns = 0;
46
/* At least the first dirty chunk is mirrored in one iteration. */
47
@@ -XXX,XX +XXX,XX @@ static void mirror_exit(BlockJob *job, void *opaque)
48
MirrorBlockJob *s = container_of(job, MirrorBlockJob, common);
49
MirrorExitData *data = opaque;
50
AioContext *replace_aio_context = NULL;
51
- BlockDriverState *src = blk_bs(s->common.blk);
52
+ BlockDriverState *src = s->source;
53
BlockDriverState *target_bs = blk_bs(s->target);
54
+ BlockDriverState *mirror_top_bs = s->mirror_top_bs;
55
56
/* Make sure that the source BDS doesn't go away before we called
57
* block_job_completed(). */
58
bdrv_ref(src);
59
+ bdrv_ref(mirror_top_bs);
60
+
61
+ /* We don't access the source any more. Dropping any WRITE/RESIZE is
62
+ * required before it could become a backing file of target_bs. */
63
+ bdrv_child_try_set_perm(mirror_top_bs->backing, 0, BLK_PERM_ALL,
64
+ &error_abort);
65
+ if (s->backing_mode == MIRROR_SOURCE_BACKING_CHAIN) {
66
+ BlockDriverState *backing = s->is_none_mode ? src : s->base;
67
+ if (backing_bs(target_bs) != backing) {
68
+ bdrv_set_backing_hd(target_bs, backing);
69
+ }
70
+ }
71
72
if (s->to_replace) {
73
replace_aio_context = bdrv_get_aio_context(s->to_replace);
74
@@ -XXX,XX +XXX,XX @@ static void mirror_exit(BlockJob *job, void *opaque)
75
bdrv_drained_begin(target_bs);
47
bdrv_drained_begin(target_bs);
76
bdrv_replace_in_backing_chain(to_replace, target_bs);
48
bdrv_replace_node(to_replace, target_bs, &local_err);
77
bdrv_drained_end(target_bs);
49
bdrv_drained_end(target_bs);
78
-
50
@@ -XXX,XX +XXX,XX @@ static int mirror_exit_common(Job *job)
79
- /* We just changed the BDS the job BB refers to, so switch the BB back
51
bs_opaque->job = NULL;
80
- * so the cleanup does the right thing. We don't need any permissions
52
81
- * any more now. */
53
bdrv_drained_end(src);
82
- blk_remove_bs(job->blk);
54
+ s->in_drain = false;
83
- blk_set_perm(job->blk, 0, BLK_PERM_ALL, &error_abort);
55
bdrv_unref(mirror_top_bs);
84
- blk_insert_bs(job->blk, src, &error_abort);
56
bdrv_unref(src);
57
58
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
59
*/
60
trace_mirror_before_drain(s, cnt);
61
62
+ s->in_drain = true;
63
bdrv_drained_begin(bs);
64
cnt = bdrv_get_dirty_count(s->dirty_bitmap);
65
if (cnt > 0 || mirror_flush(s) < 0) {
66
bdrv_drained_end(bs);
67
+ s->in_drain = false;
68
continue;
69
}
70
71
@@ -XXX,XX +XXX,XX @@ immediate_exit:
72
bdrv_dirty_iter_free(s->dbi);
73
74
if (need_drain) {
75
+ s->in_drain = true;
76
bdrv_drained_begin(bs);
85
}
77
}
86
if (s->to_replace) {
78
87
bdrv_op_unblock_all(s->to_replace, s->replace_blocker);
79
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn mirror_pause(Job *job)
88
@@ -XXX,XX +XXX,XX @@ static void mirror_exit(BlockJob *job, void *opaque)
80
static bool mirror_drained_poll(BlockJob *job)
89
g_free(s->replaces);
90
blk_unref(s->target);
91
s->target = NULL;
92
+
93
+ /* Remove the mirror filter driver from the graph. Before this, get rid of
94
+ * the blockers on the intermediate nodes so that the resulting state is
95
+ * valid. */
96
+ block_job_remove_all_bdrv(job);
97
+ bdrv_replace_in_backing_chain(mirror_top_bs, backing_bs(mirror_top_bs));
98
+
99
+ /* We just changed the BDS the job BB refers to (with either or both of the
100
+ * bdrv_replace_in_backing_chain() calls), so switch the BB back so the
101
+ * cleanup does the right thing. We don't need any permissions any more
102
+ * now. */
103
+ blk_remove_bs(job->blk);
104
+ blk_set_perm(job->blk, 0, BLK_PERM_ALL, &error_abort);
105
+ blk_insert_bs(job->blk, mirror_top_bs, &error_abort);
106
+
107
block_job_completed(&s->common, data->ret);
108
+
109
g_free(data);
110
bdrv_drained_end(src);
111
+ bdrv_unref(mirror_top_bs);
112
bdrv_unref(src);
113
}
114
115
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s)
116
{
117
int64_t sector_num, end;
118
BlockDriverState *base = s->base;
119
- BlockDriverState *bs = blk_bs(s->common.blk);
120
+ BlockDriverState *bs = s->source;
121
BlockDriverState *target_bs = blk_bs(s->target);
122
int ret, n;
123
124
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn mirror_run(void *opaque)
125
{
126
MirrorBlockJob *s = opaque;
127
MirrorExitData *data;
128
- BlockDriverState *bs = blk_bs(s->common.blk);
129
+ BlockDriverState *bs = s->source;
130
BlockDriverState *target_bs = blk_bs(s->target);
131
bool need_drain = true;
132
int64_t length;
133
@@ -XXX,XX +XXX,XX @@ static void mirror_set_speed(BlockJob *job, int64_t speed, Error **errp)
134
static void mirror_complete(BlockJob *job, Error **errp)
135
{
81
{
136
MirrorBlockJob *s = container_of(job, MirrorBlockJob, common);
82
MirrorBlockJob *s = container_of(job, MirrorBlockJob, common);
137
- BlockDriverState *src, *target;
138
+ BlockDriverState *target;
139
140
- src = blk_bs(job->blk);
141
target = blk_bs(s->target);
142
143
if (!s->synced) {
144
@@ -XXX,XX +XXX,XX @@ static void mirror_complete(BlockJob *job, Error **errp)
145
replace_aio_context = bdrv_get_aio_context(s->to_replace);
146
aio_context_acquire(replace_aio_context);
147
148
+ /* TODO Translate this into permission system. Current definition of
149
+ * GRAPH_MOD would require to request it for the parents; they might
150
+ * not even be BlockDriverStates, however, so a BdrvChild can't address
151
+ * them. May need redefinition of GRAPH_MOD. */
152
error_setg(&s->replace_blocker,
153
"block device is in use by block-job-complete");
154
bdrv_op_block_all(s->to_replace, s->replace_blocker);
155
@@ -XXX,XX +XXX,XX @@ static void mirror_complete(BlockJob *job, Error **errp)
156
aio_context_release(replace_aio_context);
157
}
158
159
- if (s->backing_mode == MIRROR_SOURCE_BACKING_CHAIN) {
160
- BlockDriverState *backing = s->is_none_mode ? src : s->base;
161
- if (backing_bs(target) != backing) {
162
- bdrv_set_backing_hd(target, backing);
163
- }
164
- }
165
-
166
s->should_complete = true;
167
block_job_enter(&s->common);
168
}
169
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver commit_active_job_driver = {
170
.drain = mirror_drain,
171
};
172
173
+static int coroutine_fn bdrv_mirror_top_preadv(BlockDriverState *bs,
174
+ uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags)
175
+{
176
+ return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags);
177
+}
178
+
83
+
179
+static int coroutine_fn bdrv_mirror_top_pwritev(BlockDriverState *bs,
84
+ /* If the job isn't paused nor cancelled, we can't be sure that it won't
180
+ uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags)
85
+ * issue more requests. We make an exception if we've reached this point
181
+{
86
+ * from one of our own drain sections, to avoid a deadlock waiting for
182
+ return bdrv_co_pwritev(bs->backing, offset, bytes, qiov, flags);
87
+ * ourselves.
183
+}
88
+ */
184
+
89
+ if (!s->common.job.paused && !s->common.job.cancelled && !s->in_drain) {
185
+static int coroutine_fn bdrv_mirror_top_flush(BlockDriverState *bs)
90
+ return true;
186
+{
187
+ return bdrv_co_flush(bs->backing->bs);
188
+}
189
+
190
+static int64_t coroutine_fn bdrv_mirror_top_get_block_status(
191
+ BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum,
192
+ BlockDriverState **file)
193
+{
194
+ *pnum = nb_sectors;
195
+ *file = bs->backing->bs;
196
+ return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID | BDRV_BLOCK_DATA |
197
+ (sector_num << BDRV_SECTOR_BITS);
198
+}
199
+
200
+static int coroutine_fn bdrv_mirror_top_pwrite_zeroes(BlockDriverState *bs,
201
+ int64_t offset, int count, BdrvRequestFlags flags)
202
+{
203
+ return bdrv_co_pwrite_zeroes(bs->backing, offset, count, flags);
204
+}
205
+
206
+static int coroutine_fn bdrv_mirror_top_pdiscard(BlockDriverState *bs,
207
+ int64_t offset, int count)
208
+{
209
+ return bdrv_co_pdiscard(bs->backing->bs, offset, count);
210
+}
211
+
212
+static void bdrv_mirror_top_close(BlockDriverState *bs)
213
+{
214
+}
215
+
216
+static void bdrv_mirror_top_child_perm(BlockDriverState *bs, BdrvChild *c,
217
+ const BdrvChildRole *role,
218
+ uint64_t perm, uint64_t shared,
219
+ uint64_t *nperm, uint64_t *nshared)
220
+{
221
+ /* Must be able to forward guest writes to the real image */
222
+ *nperm = 0;
223
+ if (perm & BLK_PERM_WRITE) {
224
+ *nperm |= BLK_PERM_WRITE;
225
+ }
91
+ }
226
+
92
+
227
+ *nshared = BLK_PERM_ALL;
93
return !!s->in_flight;
228
+}
229
+
230
+/* Dummy node that provides consistent read to its users without requiring it
231
+ * from its backing file and that allows writes on the backing file chain. */
232
+static BlockDriver bdrv_mirror_top = {
233
+ .format_name = "mirror_top",
234
+ .bdrv_co_preadv = bdrv_mirror_top_preadv,
235
+ .bdrv_co_pwritev = bdrv_mirror_top_pwritev,
236
+ .bdrv_co_pwrite_zeroes = bdrv_mirror_top_pwrite_zeroes,
237
+ .bdrv_co_pdiscard = bdrv_mirror_top_pdiscard,
238
+ .bdrv_co_flush = bdrv_mirror_top_flush,
239
+ .bdrv_co_get_block_status = bdrv_mirror_top_get_block_status,
240
+ .bdrv_close = bdrv_mirror_top_close,
241
+ .bdrv_child_perm = bdrv_mirror_top_child_perm,
242
+};
243
+
244
static void mirror_start_job(const char *job_id, BlockDriverState *bs,
245
int creation_flags, BlockDriverState *target,
246
const char *replaces, int64_t speed,
247
@@ -XXX,XX +XXX,XX @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
248
bool auto_complete)
249
{
250
MirrorBlockJob *s;
251
+ BlockDriverState *mirror_top_bs;
252
+ bool target_graph_mod;
253
+ bool target_is_backing;
254
int ret;
255
256
if (granularity == 0) {
257
@@ -XXX,XX +XXX,XX @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
258
buf_size = DEFAULT_MIRROR_BUF_SIZE;
259
}
260
261
- /* FIXME Use real permissions */
262
- s = block_job_create(job_id, driver, bs, 0, BLK_PERM_ALL, speed,
263
+ /* In the case of active commit, add dummy driver to provide consistent
264
+ * reads on the top, while disabling it in the intermediate nodes, and make
265
+ * the backing chain writable. */
266
+ mirror_top_bs = bdrv_new_open_driver(&bdrv_mirror_top, NULL, BDRV_O_RDWR,
267
+ errp);
268
+ if (mirror_top_bs == NULL) {
269
+ return;
270
+ }
271
+ mirror_top_bs->total_sectors = bs->total_sectors;
272
+
273
+ /* bdrv_append takes ownership of the mirror_top_bs reference, need to keep
274
+ * it alive until block_job_create() even if bs has no parent. */
275
+ bdrv_ref(mirror_top_bs);
276
+ bdrv_drained_begin(bs);
277
+ bdrv_append(mirror_top_bs, bs);
278
+ bdrv_drained_end(bs);
279
+
280
+ /* Make sure that the source is not resized while the job is running */
281
+ s = block_job_create(job_id, driver, mirror_top_bs,
282
+ BLK_PERM_CONSISTENT_READ,
283
+ BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED |
284
+ BLK_PERM_WRITE | BLK_PERM_GRAPH_MOD, speed,
285
creation_flags, cb, opaque, errp);
286
+ bdrv_unref(mirror_top_bs);
287
if (!s) {
288
- return;
289
+ goto fail;
290
}
291
-
292
- /* FIXME Use real permissions */
293
- s->target = blk_new(0, BLK_PERM_ALL);
294
+ s->source = bs;
295
+ s->mirror_top_bs = mirror_top_bs;
296
+
297
+ /* No resize for the target either; while the mirror is still running, a
298
+ * consistent read isn't necessarily possible. We could possibly allow
299
+ * writes and graph modifications, though it would likely defeat the
300
+ * purpose of a mirror, so leave them blocked for now.
301
+ *
302
+ * In the case of active commit, things look a bit different, though,
303
+ * because the target is an already populated backing file in active use.
304
+ * We can allow anything except resize there.*/
305
+ target_is_backing = bdrv_chain_contains(bs, target);
306
+ target_graph_mod = (backing_mode != MIRROR_LEAVE_BACKING_CHAIN);
307
+ s->target = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE |
308
+ (target_graph_mod ? BLK_PERM_GRAPH_MOD : 0),
309
+ BLK_PERM_WRITE_UNCHANGED |
310
+ (target_is_backing ? BLK_PERM_CONSISTENT_READ |
311
+ BLK_PERM_WRITE |
312
+ BLK_PERM_GRAPH_MOD : 0));
313
ret = blk_insert_bs(s->target, target, errp);
314
if (ret < 0) {
315
- blk_unref(s->target);
316
- block_job_unref(&s->common);
317
- return;
318
+ goto fail;
319
}
320
321
s->replaces = g_strdup(replaces);
322
@@ -XXX,XX +XXX,XX @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
323
return;
324
}
325
326
- /* FIXME Use real permissions */
327
+ /* Required permissions are already taken with blk_new() */
328
block_job_add_bdrv(&s->common, "target", target, 0, BLK_PERM_ALL,
329
&error_abort);
330
331
/* In commit_active_start() all intermediate nodes disappear, so
332
* any jobs in them must be blocked */
333
- if (bdrv_chain_contains(bs, target)) {
334
+ if (target_is_backing) {
335
BlockDriverState *iter;
336
for (iter = backing_bs(bs); iter != target; iter = backing_bs(iter)) {
337
- /* FIXME Use real permissions */
338
- block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
339
- BLK_PERM_ALL, &error_abort);
340
+ /* XXX BLK_PERM_WRITE needs to be allowed so we don't block
341
+ * ourselves at s->base (if writes are blocked for a node, they are
342
+ * also blocked for its backing file). The other options would be a
343
+ * second filter driver above s->base (== target). */
344
+ ret = block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
345
+ BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE,
346
+ errp);
347
+ if (ret < 0) {
348
+ goto fail;
349
+ }
350
}
351
}
352
353
trace_mirror_start(bs, s, opaque);
354
block_job_start(&s->common);
355
+ return;
356
+
357
+fail:
358
+ if (s) {
359
+ g_free(s->replaces);
360
+ blk_unref(s->target);
361
+ block_job_unref(&s->common);
362
+ }
363
+
364
+ bdrv_replace_in_backing_chain(mirror_top_bs, backing_bs(mirror_top_bs));
365
}
94
}
366
95
367
void mirror_start(const char *job_id, BlockDriverState *bs,
368
diff --git a/qemu-img.c b/qemu-img.c
369
index XXXXXXX..XXXXXXX 100644
370
--- a/qemu-img.c
371
+++ b/qemu-img.c
372
@@ -XXX,XX +XXX,XX @@ static void run_block_job(BlockJob *job, Error **errp)
373
{
374
AioContext *aio_context = blk_get_aio_context(job->blk);
375
376
+ /* FIXME In error cases, the job simply goes away and we access a dangling
377
+ * pointer below. */
378
aio_context_acquire(aio_context);
379
do {
380
aio_poll(aio_context, true);
381
@@ -XXX,XX +XXX,XX @@ static int img_commit(int argc, char **argv)
382
const char *filename, *fmt, *cache, *base;
383
BlockBackend *blk;
384
BlockDriverState *bs, *base_bs;
385
+ BlockJob *job;
386
bool progress = false, quiet = false, drop = false;
387
bool writethrough;
388
Error *local_err = NULL;
389
@@ -XXX,XX +XXX,XX @@ static int img_commit(int argc, char **argv)
390
bdrv_ref(bs);
391
}
392
393
- run_block_job(bs->job, &local_err);
394
+ job = block_job_get("commit");
395
+ run_block_job(job, &local_err);
396
if (local_err) {
397
goto unref_backing;
398
}
399
diff --git a/tests/qemu-iotests/141 b/tests/qemu-iotests/141
400
index XXXXXXX..XXXXXXX 100755
401
--- a/tests/qemu-iotests/141
402
+++ b/tests/qemu-iotests/141
403
@@ -XXX,XX +XXX,XX @@ test_blockjob()
404
_send_qemu_cmd $QEMU_HANDLE \
405
"{'execute': 'x-blockdev-del',
406
'arguments': {'node-name': 'drv0'}}" \
407
- 'error'
408
+ 'error' | _filter_generated_node_ids
409
410
_send_qemu_cmd $QEMU_HANDLE \
411
"{'execute': 'block-job-cancel',
412
diff --git a/tests/qemu-iotests/141.out b/tests/qemu-iotests/141.out
413
index XXXXXXX..XXXXXXX 100644
414
--- a/tests/qemu-iotests/141.out
415
+++ b/tests/qemu-iotests/141.out
416
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.
417
Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT
418
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "mirror"}}
419
{"return": {}}
420
-{"error": {"class": "GenericError", "desc": "Node drv0 is in use"}}
421
+{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: node is used as backing hd of 'NODE_NAME'"}}
422
{"return": {}}
423
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "mirror"}}
424
{"return": {}}
425
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.
426
{"return": {}}
427
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}}
428
{"return": {}}
429
-{"error": {"class": "GenericError", "desc": "Node drv0 is in use"}}
430
+{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: node is used as backing hd of 'NODE_NAME'"}}
431
{"return": {}}
432
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}}
433
{"return": {}}
434
--
96
--
435
1.8.3.1
97
2.20.1
436
98
437
99
diff view generated by jsdifflib
1
We want every user to be specific about the permissions it needs, so
1
We were trying to check whether bdrv_open_blockdev_ref() returned
2
we'll pass the initial permissions as parameters to blk_new(). A user
2
success, but accidentally checked the wrong variable. Spotted by
3
only needs to call blk_set_perm() if it wants to change the permissions
3
Coverity (CID 1399703).
4
after the fact.
5
6
The permissions are stored in the BlockBackend and applied whenever a
7
BlockDriverState should be attached in blk_insert_bs().
8
9
This does not include actually choosing the right set of permissions
10
everywhere yet. Instead, the usual FIXME comment is added to each place
11
and will be addressed in individual patches.
12
4
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
15
Acked-by: Fam Zheng <famz@redhat.com>
7
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
16
---
8
---
17
block.c | 2 +-
9
block/qcow2.c | 2 +-
18
block/backup.c | 3 ++-
10
1 file changed, 1 insertion(+), 1 deletion(-)
19
block/block-backend.c | 21 ++++++++++++++-------
20
block/commit.c | 12 ++++++++----
21
block/mirror.c | 3 ++-
22
block/qcow2.c | 2 +-
23
blockdev.c | 4 ++--
24
blockjob.c | 3 ++-
25
hmp.c | 3 ++-
26
hw/block/fdc.c | 3 ++-
27
hw/core/qdev-properties-system.c | 3 ++-
28
hw/ide/qdev.c | 3 ++-
29
hw/scsi/scsi-disk.c | 3 ++-
30
include/sysemu/block-backend.h | 2 +-
31
migration/block.c | 3 ++-
32
nbd/server.c | 3 ++-
33
tests/test-blockjob.c | 3 ++-
34
tests/test-throttle.c | 7 ++++---
35
18 files changed, 53 insertions(+), 30 deletions(-)
36
11
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 BlockDriverState *bdrv_open_inherit(const char *filename,
42
goto fail;
43
}
44
if (file_bs != NULL) {
45
- file = blk_new();
46
+ file = blk_new(BLK_PERM_CONSISTENT_READ, BLK_PERM_ALL);
47
blk_insert_bs(file, file_bs);
48
bdrv_unref(file_bs);
49
50
diff --git a/block/backup.c b/block/backup.c
51
index XXXXXXX..XXXXXXX 100644
52
--- a/block/backup.c
53
+++ b/block/backup.c
54
@@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
55
goto error;
56
}
57
58
- job->target = blk_new();
59
+ /* FIXME Use real permissions */
60
+ job->target = blk_new(0, BLK_PERM_ALL);
61
blk_insert_bs(job->target, target);
62
63
job->on_source_error = on_source_error;
64
diff --git a/block/block-backend.c b/block/block-backend.c
65
index XXXXXXX..XXXXXXX 100644
66
--- a/block/block-backend.c
67
+++ b/block/block-backend.c
68
@@ -XXX,XX +XXX,XX @@ static const BdrvChildRole child_root = {
69
70
/*
71
* Create a new BlockBackend with a reference count of one.
72
- * Store an error through @errp on failure, unless it's null.
73
+ *
74
+ * @perm is a bitmasks of BLK_PERM_* constants which describes the permissions
75
+ * to request for a block driver node that is attached to this BlockBackend.
76
+ * @shared_perm is a bitmask which describes which permissions may be granted
77
+ * to other users of the attached node.
78
+ * Both sets of permissions can be changed later using blk_set_perm().
79
+ *
80
* Return the new BlockBackend on success, null on failure.
81
*/
82
-BlockBackend *blk_new(void)
83
+BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm)
84
{
85
BlockBackend *blk;
86
87
blk = g_new0(BlockBackend, 1);
88
blk->refcnt = 1;
89
- blk->perm = 0;
90
- blk->shared_perm = BLK_PERM_ALL;
91
+ blk->perm = perm;
92
+ blk->shared_perm = shared_perm;
93
blk_set_enable_write_cache(blk, true);
94
95
qemu_co_queue_init(&blk->public.throttled_reqs[0]);
96
@@ -XXX,XX +XXX,XX @@ BlockBackend *blk_new_open(const char *filename, const char *reference,
97
BlockBackend *blk;
98
BlockDriverState *bs;
99
100
- blk = blk_new();
101
+ blk = blk_new(0, BLK_PERM_ALL);
102
bs = bdrv_open(filename, reference, options, flags, errp);
103
if (!bs) {
104
blk_unref(blk);
105
@@ -XXX,XX +XXX,XX @@ void blk_remove_bs(BlockBackend *blk)
106
void blk_insert_bs(BlockBackend *blk, BlockDriverState *bs)
107
{
108
bdrv_ref(bs);
109
- /* FIXME Use real permissions */
110
+ /* FIXME Error handling */
111
blk->root = bdrv_root_attach_child(bs, "root", &child_root,
112
- 0, BLK_PERM_ALL, blk, &error_abort);
113
+ blk->perm, blk->shared_perm, blk,
114
+ &error_abort);
115
116
notifier_list_notify(&blk->insert_bs_notifiers, blk);
117
if (blk->public.throttle_state) {
118
diff --git a/block/commit.c b/block/commit.c
119
index XXXXXXX..XXXXXXX 100644
120
--- a/block/commit.c
121
+++ b/block/commit.c
122
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
123
block_job_add_bdrv(&s->common, overlay_bs);
124
}
125
126
- s->base = blk_new();
127
+ /* FIXME Use real permissions */
128
+ s->base = blk_new(0, BLK_PERM_ALL);
129
blk_insert_bs(s->base, base);
130
131
- s->top = blk_new();
132
+ /* FIXME Use real permissions */
133
+ s->top = blk_new(0, BLK_PERM_ALL);
134
blk_insert_bs(s->top, top);
135
136
s->active = bs;
137
@@ -XXX,XX +XXX,XX @@ int bdrv_commit(BlockDriverState *bs)
138
}
139
}
140
141
- src = blk_new();
142
+ /* FIXME Use real permissions */
143
+ src = blk_new(0, BLK_PERM_ALL);
144
blk_insert_bs(src, bs);
145
146
- backing = blk_new();
147
+ /* FIXME Use real permissions */
148
+ backing = blk_new(0, BLK_PERM_ALL);
149
blk_insert_bs(backing, bs->backing->bs);
150
151
length = blk_getlength(src);
152
diff --git a/block/mirror.c b/block/mirror.c
153
index XXXXXXX..XXXXXXX 100644
154
--- a/block/mirror.c
155
+++ b/block/mirror.c
156
@@ -XXX,XX +XXX,XX @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
157
return;
158
}
159
160
- s->target = blk_new();
161
+ /* FIXME Use real permissions */
162
+ s->target = blk_new(0, BLK_PERM_ALL);
163
blk_insert_bs(s->target, target);
164
165
s->replaces = g_strdup(replaces);
166
diff --git a/block/qcow2.c b/block/qcow2.c
12
diff --git a/block/qcow2.c b/block/qcow2.c
167
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
168
--- a/block/qcow2.c
14
--- a/block/qcow2.c
169
+++ b/block/qcow2.c
15
+++ b/block/qcow2.c
170
@@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
16
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
171
}
17
goto out;
172
173
if (new_size) {
174
- BlockBackend *blk = blk_new();
175
+ BlockBackend *blk = blk_new(BLK_PERM_RESIZE, BLK_PERM_ALL);
176
blk_insert_bs(blk, bs);
177
ret = blk_truncate(blk, new_size);
178
blk_unref(blk);
179
diff --git a/blockdev.c b/blockdev.c
180
index XXXXXXX..XXXXXXX 100644
181
--- a/blockdev.c
182
+++ b/blockdev.c
183
@@ -XXX,XX +XXX,XX @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
184
if ((!file || !*file) && !qdict_size(bs_opts)) {
185
BlockBackendRootState *blk_rs;
186
187
- blk = blk_new();
188
+ blk = blk_new(0, BLK_PERM_ALL);
189
blk_rs = blk_get_root_state(blk);
190
blk_rs->open_flags = bdrv_flags;
191
blk_rs->read_only = read_only;
192
@@ -XXX,XX +XXX,XX @@ void qmp_block_resize(bool has_device, const char *device,
193
goto out;
194
}
195
196
- blk = blk_new();
197
+ blk = blk_new(BLK_PERM_RESIZE, BLK_PERM_ALL);
198
blk_insert_bs(blk, bs);
199
200
/* complete all in-flight operations before resizing the device */
201
diff --git a/blockjob.c b/blockjob.c
202
index XXXXXXX..XXXXXXX 100644
203
--- a/blockjob.c
204
+++ b/blockjob.c
205
@@ -XXX,XX +XXX,XX @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
206
}
18
}
207
}
19
data_bs = bdrv_open_blockdev_ref(qcow2_opts->data_file, errp);
208
20
- if (bs == NULL) {
209
- blk = blk_new();
21
+ if (data_bs == NULL) {
210
+ /* FIXME Use real permissions */
22
ret = -EIO;
211
+ blk = blk_new(0, BLK_PERM_ALL);
23
goto out;
212
blk_insert_bs(blk, bs);
213
214
job = g_malloc0(driver->instance_size);
215
diff --git a/hmp.c b/hmp.c
216
index XXXXXXX..XXXXXXX 100644
217
--- a/hmp.c
218
+++ b/hmp.c
219
@@ -XXX,XX +XXX,XX @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict)
220
if (!blk) {
221
BlockDriverState *bs = bdrv_lookup_bs(NULL, device, &err);
222
if (bs) {
223
- blk = local_blk = blk_new();
224
+ /* FIXME Use real permissions */
225
+ blk = local_blk = blk_new(0, BLK_PERM_ALL);
226
blk_insert_bs(blk, bs);
227
} else {
228
goto fail;
229
diff --git a/hw/block/fdc.c b/hw/block/fdc.c
230
index XXXXXXX..XXXXXXX 100644
231
--- a/hw/block/fdc.c
232
+++ b/hw/block/fdc.c
233
@@ -XXX,XX +XXX,XX @@ static int floppy_drive_init(DeviceState *qdev)
234
235
if (!dev->conf.blk) {
236
/* Anonymous BlockBackend for an empty drive */
237
- dev->conf.blk = blk_new();
238
+ /* FIXME Use real permissions */
239
+ dev->conf.blk = blk_new(0, BLK_PERM_ALL);
240
ret = blk_attach_dev(dev->conf.blk, qdev);
241
assert(ret == 0);
242
}
243
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
244
index XXXXXXX..XXXXXXX 100644
245
--- a/hw/core/qdev-properties-system.c
246
+++ b/hw/core/qdev-properties-system.c
247
@@ -XXX,XX +XXX,XX @@ static void parse_drive(DeviceState *dev, const char *str, void **ptr,
248
if (!blk) {
249
BlockDriverState *bs = bdrv_lookup_bs(NULL, str, NULL);
250
if (bs) {
251
- blk = blk_new();
252
+ /* FIXME Use real permissions */
253
+ blk = blk_new(0, BLK_PERM_ALL);
254
blk_insert_bs(blk, bs);
255
blk_created = true;
256
}
24
}
257
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
258
index XXXXXXX..XXXXXXX 100644
259
--- a/hw/ide/qdev.c
260
+++ b/hw/ide/qdev.c
261
@@ -XXX,XX +XXX,XX @@ static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind)
262
return -1;
263
} else {
264
/* Anonymous BlockBackend for an empty drive */
265
- dev->conf.blk = blk_new();
266
+ /* FIXME Use real permissions */
267
+ dev->conf.blk = blk_new(0, BLK_PERM_ALL);
268
}
269
}
270
271
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
272
index XXXXXXX..XXXXXXX 100644
273
--- a/hw/scsi/scsi-disk.c
274
+++ b/hw/scsi/scsi-disk.c
275
@@ -XXX,XX +XXX,XX @@ static void scsi_cd_realize(SCSIDevice *dev, Error **errp)
276
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
277
278
if (!dev->conf.blk) {
279
- dev->conf.blk = blk_new();
280
+ /* FIXME Use real permissions */
281
+ dev->conf.blk = blk_new(0, BLK_PERM_ALL);
282
}
283
284
s->qdev.blocksize = 2048;
285
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
286
index XXXXXXX..XXXXXXX 100644
287
--- a/include/sysemu/block-backend.h
288
+++ b/include/sysemu/block-backend.h
289
@@ -XXX,XX +XXX,XX @@ typedef struct BlockBackendPublic {
290
QLIST_ENTRY(BlockBackendPublic) round_robin;
291
} BlockBackendPublic;
292
293
-BlockBackend *blk_new(void);
294
+BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm);
295
BlockBackend *blk_new_open(const char *filename, const char *reference,
296
QDict *options, int flags, Error **errp);
297
int blk_get_refcnt(BlockBackend *blk);
298
diff --git a/migration/block.c b/migration/block.c
299
index XXXXXXX..XXXXXXX 100644
300
--- a/migration/block.c
301
+++ b/migration/block.c
302
@@ -XXX,XX +XXX,XX @@ static void init_blk_migration(QEMUFile *f)
303
}
304
305
bmds = g_new0(BlkMigDevState, 1);
306
- bmds->blk = blk_new();
307
+ /* FIXME Use real permissions */
308
+ bmds->blk = blk_new(0, BLK_PERM_ALL);
309
bmds->blk_name = g_strdup(bdrv_get_device_name(bs));
310
bmds->bulk_completed = 0;
311
bmds->total_sectors = sectors;
312
diff --git a/nbd/server.c b/nbd/server.c
313
index XXXXXXX..XXXXXXX 100644
314
--- a/nbd/server.c
315
+++ b/nbd/server.c
316
@@ -XXX,XX +XXX,XX @@ NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, off_t size,
317
BlockBackend *blk;
318
NBDExport *exp = g_malloc0(sizeof(NBDExport));
319
320
- blk = blk_new();
321
+ /* FIXME Use real permissions */
322
+ blk = blk_new(0, BLK_PERM_ALL);
323
blk_insert_bs(blk, bs);
324
blk_set_enable_write_cache(blk, !writethrough);
325
326
diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c
327
index XXXXXXX..XXXXXXX 100644
328
--- a/tests/test-blockjob.c
329
+++ b/tests/test-blockjob.c
330
@@ -XXX,XX +XXX,XX @@ static BlockJob *do_test_id(BlockBackend *blk, const char *id,
331
* BlockDriverState inserted. */
332
static BlockBackend *create_blk(const char *name)
333
{
334
- BlockBackend *blk = blk_new();
335
+ /* FIXME Use real permissions */
336
+ BlockBackend *blk = blk_new(0, BLK_PERM_ALL);
337
BlockDriverState *bs;
338
339
bs = bdrv_open("null-co://", NULL, NULL, 0, &error_abort);
340
diff --git a/tests/test-throttle.c b/tests/test-throttle.c
341
index XXXXXXX..XXXXXXX 100644
342
--- a/tests/test-throttle.c
343
+++ b/tests/test-throttle.c
344
@@ -XXX,XX +XXX,XX @@ static void test_groups(void)
345
BlockBackend *blk1, *blk2, *blk3;
346
BlockBackendPublic *blkp1, *blkp2, *blkp3;
347
348
- blk1 = blk_new();
349
- blk2 = blk_new();
350
- blk3 = blk_new();
351
+ /* FIXME Use real permissions */
352
+ blk1 = blk_new(0, BLK_PERM_ALL);
353
+ blk2 = blk_new(0, BLK_PERM_ALL);
354
+ blk3 = blk_new(0, BLK_PERM_ALL);
355
356
blkp1 = blk_get_public(blk1);
357
blkp2 = blk_get_public(blk2);
358
--
25
--
359
1.8.3.1
26
2.20.1
360
27
361
28
diff view generated by jsdifflib
1
Management tools need to be able to know about every node in the graph
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
and need a way to address them. Changing the graph structure was okay
3
because libvirt doesn't really manage the node level yet, but future
4
libvirt versions need to deal with both new and old version of qemu.
5
2
6
This new option to blockdev-commit allows the client to set a node-name
3
There no @device parameter, only the @id one.
7
for the automatically inserted filter driver, and at the same time
8
serves as a witness for a future libvirt that this version of qemu does
9
automatically insert a filter driver.
10
4
5
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Acked-by: Fam Zheng <famz@redhat.com>
13
Reviewed-by: Max Reitz <mreitz@redhat.com>
14
---
8
---
15
block/commit.c | 5 +++--
9
qapi/block-core.json | 10 +++++-----
16
block/mirror.c | 3 ++-
10
1 file changed, 5 insertions(+), 5 deletions(-)
17
block/replication.c | 2 +-
18
blockdev.c | 10 +++++++---
19
include/block/block_int.h | 13 ++++++++++---
20
qapi/block-core.json | 8 +++++++-
21
qemu-img.c | 4 ++--
22
7 files changed, 32 insertions(+), 13 deletions(-)
23
11
24
diff --git a/block/commit.c b/block/commit.c
25
index XXXXXXX..XXXXXXX 100644
26
--- a/block/commit.c
27
+++ b/block/commit.c
28
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_commit_top = {
29
void commit_start(const char *job_id, BlockDriverState *bs,
30
BlockDriverState *base, BlockDriverState *top, int64_t speed,
31
BlockdevOnError on_error, const char *backing_file_str,
32
- Error **errp)
33
+ const char *filter_node_name, Error **errp)
34
{
35
CommitBlockJob *s;
36
BlockReopenQueue *reopen_queue = NULL;
37
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
38
39
/* Insert commit_top block node above top, so we can block consistent read
40
* on the backing chain below it */
41
- commit_top_bs = bdrv_new_open_driver(&bdrv_commit_top, NULL, 0, errp);
42
+ commit_top_bs = bdrv_new_open_driver(&bdrv_commit_top, filter_node_name, 0,
43
+ errp);
44
if (commit_top_bs == NULL) {
45
goto fail;
46
}
47
diff --git a/block/mirror.c b/block/mirror.c
48
index XXXXXXX..XXXXXXX 100644
49
--- a/block/mirror.c
50
+++ b/block/mirror.c
51
@@ -XXX,XX +XXX,XX @@ void mirror_start(const char *job_id, BlockDriverState *bs,
52
void commit_active_start(const char *job_id, BlockDriverState *bs,
53
BlockDriverState *base, int creation_flags,
54
int64_t speed, BlockdevOnError on_error,
55
+ const char *filter_node_name,
56
BlockCompletionFunc *cb, void *opaque, Error **errp,
57
bool auto_complete)
58
{
59
@@ -XXX,XX +XXX,XX @@ void commit_active_start(const char *job_id, BlockDriverState *bs,
60
MIRROR_LEAVE_BACKING_CHAIN,
61
on_error, on_error, true, cb, opaque, &local_err,
62
&commit_active_job_driver, false, base, auto_complete,
63
- NULL);
64
+ filter_node_name);
65
if (local_err) {
66
error_propagate(errp, local_err);
67
goto error_restore_flags;
68
diff --git a/block/replication.c b/block/replication.c
69
index XXXXXXX..XXXXXXX 100644
70
--- a/block/replication.c
71
+++ b/block/replication.c
72
@@ -XXX,XX +XXX,XX @@ static void replication_stop(ReplicationState *rs, bool failover, Error **errp)
73
s->replication_state = BLOCK_REPLICATION_FAILOVER;
74
commit_active_start(NULL, s->active_disk->bs, s->secondary_disk->bs,
75
BLOCK_JOB_INTERNAL, 0, BLOCKDEV_ON_ERROR_REPORT,
76
- replication_done, bs, errp, true);
77
+ NULL, replication_done, bs, errp, true);
78
break;
79
default:
80
aio_context_release(aio_context);
81
diff --git a/blockdev.c b/blockdev.c
82
index XXXXXXX..XXXXXXX 100644
83
--- a/blockdev.c
84
+++ b/blockdev.c
85
@@ -XXX,XX +XXX,XX @@ void qmp_block_commit(bool has_job_id, const char *job_id, const char *device,
86
bool has_top, const char *top,
87
bool has_backing_file, const char *backing_file,
88
bool has_speed, int64_t speed,
89
+ bool has_filter_node_name, const char *filter_node_name,
90
Error **errp)
91
{
92
BlockDriverState *bs;
93
@@ -XXX,XX +XXX,XX @@ void qmp_block_commit(bool has_job_id, const char *job_id, const char *device,
94
if (!has_speed) {
95
speed = 0;
96
}
97
+ if (!has_filter_node_name) {
98
+ filter_node_name = NULL;
99
+ }
100
101
/* Important Note:
102
* libvirt relies on the DeviceNotFound error class in order to probe for
103
@@ -XXX,XX +XXX,XX @@ void qmp_block_commit(bool has_job_id, const char *job_id, const char *device,
104
goto out;
105
}
106
commit_active_start(has_job_id ? job_id : NULL, bs, base_bs,
107
- BLOCK_JOB_DEFAULT, speed, on_error, NULL, NULL,
108
- &local_err, false);
109
+ BLOCK_JOB_DEFAULT, speed, on_error,
110
+ filter_node_name, NULL, NULL, &local_err, false);
111
} else {
112
BlockDriverState *overlay_bs = bdrv_find_overlay(bs, top_bs);
113
if (bdrv_op_is_blocked(overlay_bs, BLOCK_OP_TYPE_COMMIT_TARGET, errp)) {
114
@@ -XXX,XX +XXX,XX @@ void qmp_block_commit(bool has_job_id, const char *job_id, const char *device,
115
}
116
commit_start(has_job_id ? job_id : NULL, bs, base_bs, top_bs, speed,
117
on_error, has_backing_file ? backing_file : NULL,
118
- &local_err);
119
+ filter_node_name, &local_err);
120
}
121
if (local_err != NULL) {
122
error_propagate(errp, local_err);
123
diff --git a/include/block/block_int.h b/include/block/block_int.h
124
index XXXXXXX..XXXXXXX 100644
125
--- a/include/block/block_int.h
126
+++ b/include/block/block_int.h
127
@@ -XXX,XX +XXX,XX @@ void stream_start(const char *job_id, BlockDriverState *bs,
128
* @speed: The maximum speed, in bytes per second, or 0 for unlimited.
129
* @on_error: The action to take upon error.
130
* @backing_file_str: String to use as the backing file in @top's overlay
131
+ * @filter_node_name: The node name that should be assigned to the filter
132
+ * driver that the commit job inserts into the graph above @top. NULL means
133
+ * that a node name should be autogenerated.
134
* @errp: Error object.
135
*
136
*/
137
void commit_start(const char *job_id, BlockDriverState *bs,
138
BlockDriverState *base, BlockDriverState *top, int64_t speed,
139
BlockdevOnError on_error, const char *backing_file_str,
140
- Error **errp);
141
+ const char *filter_node_name, Error **errp);
142
/**
143
* commit_active_start:
144
* @job_id: The id of the newly-created job, or %NULL to use the
145
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
146
* See @BlockJobCreateFlags
147
* @speed: The maximum speed, in bytes per second, or 0 for unlimited.
148
* @on_error: The action to take upon error.
149
+ * @filter_node_name: The node name that should be assigned to the filter
150
+ * driver that the commit job inserts into the graph above @bs. NULL means that
151
+ * a node name should be autogenerated.
152
* @cb: Completion function for the job.
153
* @opaque: Opaque pointer value passed to @cb.
154
* @errp: Error object.
155
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
156
void commit_active_start(const char *job_id, BlockDriverState *bs,
157
BlockDriverState *base, int creation_flags,
158
int64_t speed, BlockdevOnError on_error,
159
- BlockCompletionFunc *cb,
160
- void *opaque, Error **errp, bool auto_complete);
161
+ const char *filter_node_name,
162
+ BlockCompletionFunc *cb, void *opaque, Error **errp,
163
+ bool auto_complete);
164
/*
165
* mirror_start:
166
* @job_id: The id of the newly-created job, or %NULL to use the
167
diff --git a/qapi/block-core.json b/qapi/block-core.json
12
diff --git a/qapi/block-core.json b/qapi/block-core.json
168
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
169
--- a/qapi/block-core.json
14
--- a/qapi/block-core.json
170
+++ b/qapi/block-core.json
15
+++ b/qapi/block-core.json
171
@@ -XXX,XX +XXX,XX @@
16
@@ -XXX,XX +XXX,XX @@
172
#
17
#
173
# @speed: #optional the maximum speed, in bytes per second
18
# Manage read, write and flush latency histograms for the device.
174
#
19
#
175
+# @filter-node-name: #optional the node name that should be assigned to the
20
-# If only @device parameter is specified, remove all present latency histograms
176
+# filter driver that the commit job inserts into the graph
21
+# If only @id parameter is specified, remove all present latency histograms
177
+# above @top. If this option is not given, a node name is
22
# for the device. Otherwise, add/reset some of (or all) latency histograms.
178
+# autogenerated. (Since: 2.9)
23
#
179
+#
24
# @id: The name or QOM path of the guest device.
180
# Returns: Nothing on success
181
# If commit or stream is already active on this device, DeviceInUse
182
# If @device does not exist, DeviceNotFound
183
@@ -XXX,XX +XXX,XX @@
25
@@ -XXX,XX +XXX,XX @@
26
# [0, 10), [10, 50), [50, 100), [100, +inf):
27
#
28
# -> { "execute": "block-latency-histogram-set",
29
-# "arguments": { "device": "drive0",
30
+# "arguments": { "id": "drive0",
31
# "boundaries": [10, 50, 100] } }
32
# <- { "return": {} }
33
#
34
@@ -XXX,XX +XXX,XX @@
35
# not changed (or not created):
36
#
37
# -> { "execute": "block-latency-histogram-set",
38
-# "arguments": { "device": "drive0",
39
+# "arguments": { "id": "drive0",
40
# "boundaries-write": [10, 50, 100] } }
41
# <- { "return": {} }
42
#
43
@@ -XXX,XX +XXX,XX @@
44
# write: [0, 1000), [1000, 5000), [5000, +inf)
45
#
46
# -> { "execute": "block-latency-histogram-set",
47
-# "arguments": { "device": "drive0",
48
+# "arguments": { "id": "drive0",
49
# "boundaries": [10, 50, 100],
50
# "boundaries-write": [1000, 5000] } }
51
# <- { "return": {} }
52
@@ -XXX,XX +XXX,XX @@
53
# Example: remove all latency histograms:
54
#
55
# -> { "execute": "block-latency-histogram-set",
56
-# "arguments": { "device": "drive0" } }
57
+# "arguments": { "id": "drive0" } }
58
# <- { "return": {} }
184
##
59
##
185
{ 'command': 'block-commit',
60
{ 'command': 'block-latency-histogram-set',
186
'data': { '*job-id': 'str', 'device': 'str', '*base': 'str', '*top': 'str',
187
- '*backing-file': 'str', '*speed': 'int' } }
188
+ '*backing-file': 'str', '*speed': 'int',
189
+ '*filter-node-name': 'str' } }
190
191
##
192
# @drive-backup:
193
diff --git a/qemu-img.c b/qemu-img.c
194
index XXXXXXX..XXXXXXX 100644
195
--- a/qemu-img.c
196
+++ b/qemu-img.c
197
@@ -XXX,XX +XXX,XX @@ static int img_commit(int argc, char **argv)
198
aio_context = bdrv_get_aio_context(bs);
199
aio_context_acquire(aio_context);
200
commit_active_start("commit", bs, base_bs, BLOCK_JOB_DEFAULT, 0,
201
- BLOCKDEV_ON_ERROR_REPORT, common_block_job_cb, &cbi,
202
- &local_err, false);
203
+ BLOCKDEV_ON_ERROR_REPORT, NULL, common_block_job_cb,
204
+ &cbi, &local_err, false);
205
aio_context_release(aio_context);
206
if (local_err) {
207
goto done;
208
--
61
--
209
1.8.3.1
62
2.20.1
210
63
211
64
diff view generated by jsdifflib
1
This makes use of the .bdrv_child_perm() implementation for formats that
1
From: Sam Eiderman <shmuel.eiderman@oracle.com>
2
we just added. All format drivers expose the permissions they actually
3
need nows, so that they can be set accordingly and updated when parents
4
are attached or detached.
5
2
6
The only format not included here is raw, which was already converted
3
Commit 509d39aa22909c0ed1aabf896865f19c81fb38a1 added support for read
7
with the other filter drivers.
4
only VMDKs of version 3.
8
5
6
This commit fixes the probe function to correctly handle descriptors of
7
version 3.
8
9
This commit has two effects:
10
1. We no longer need to supply '-f vmdk' when pointing to descriptor
11
files of version 3 in qemu/qemu-img command line arguments.
12
2. This fixes the scenario where a VMDK points to a parent version 3
13
descriptor file which is being probed as "raw" instead of "vmdk".
14
15
Reviewed-by: Arbel Moshe <arbel.moshe@oracle.com>
16
Reviewed-by: Mark Kanda <mark.kanda@oracle.com>
17
Signed-off-by: Shmuel Eiderman <shmuel.eiderman@oracle.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Reviewed-by: Max Reitz <mreitz@redhat.com>
11
Acked-by: Fam Zheng <famz@redhat.com>
12
---
19
---
13
block/bochs.c | 1 +
20
block/vmdk.c | 6 ++++--
14
block/cloop.c | 1 +
21
1 file changed, 4 insertions(+), 2 deletions(-)
15
block/crypto.c | 1 +
16
block/dmg.c | 1 +
17
block/parallels.c | 1 +
18
block/qcow.c | 1 +
19
block/qcow2.c | 1 +
20
block/qed.c | 1 +
21
block/vdi.c | 1 +
22
block/vhdx.c | 1 +
23
block/vmdk.c | 1 +
24
block/vpc.c | 1 +
25
12 files changed, 12 insertions(+)
26
22
27
diff --git a/block/bochs.c b/block/bochs.c
28
index XXXXXXX..XXXXXXX 100644
29
--- a/block/bochs.c
30
+++ b/block/bochs.c
31
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_bochs = {
32
.instance_size    = sizeof(BDRVBochsState),
33
.bdrv_probe        = bochs_probe,
34
.bdrv_open        = bochs_open,
35
+ .bdrv_child_perm = bdrv_format_default_perms,
36
.bdrv_refresh_limits = bochs_refresh_limits,
37
.bdrv_co_preadv = bochs_co_preadv,
38
.bdrv_close        = bochs_close,
39
diff --git a/block/cloop.c b/block/cloop.c
40
index XXXXXXX..XXXXXXX 100644
41
--- a/block/cloop.c
42
+++ b/block/cloop.c
43
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_cloop = {
44
.instance_size = sizeof(BDRVCloopState),
45
.bdrv_probe = cloop_probe,
46
.bdrv_open = cloop_open,
47
+ .bdrv_child_perm = bdrv_format_default_perms,
48
.bdrv_refresh_limits = cloop_refresh_limits,
49
.bdrv_co_preadv = cloop_co_preadv,
50
.bdrv_close = cloop_close,
51
diff --git a/block/crypto.c b/block/crypto.c
52
index XXXXXXX..XXXXXXX 100644
53
--- a/block/crypto.c
54
+++ b/block/crypto.c
55
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_crypto_luks = {
56
.bdrv_probe = block_crypto_probe_luks,
57
.bdrv_open = block_crypto_open_luks,
58
.bdrv_close = block_crypto_close,
59
+ .bdrv_child_perm = bdrv_format_default_perms,
60
.bdrv_create = block_crypto_create_luks,
61
.bdrv_truncate = block_crypto_truncate,
62
.create_opts = &block_crypto_create_opts_luks,
63
diff --git a/block/dmg.c b/block/dmg.c
64
index XXXXXXX..XXXXXXX 100644
65
--- a/block/dmg.c
66
+++ b/block/dmg.c
67
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_dmg = {
68
.bdrv_probe = dmg_probe,
69
.bdrv_open = dmg_open,
70
.bdrv_refresh_limits = dmg_refresh_limits,
71
+ .bdrv_child_perm = bdrv_format_default_perms,
72
.bdrv_co_preadv = dmg_co_preadv,
73
.bdrv_close = dmg_close,
74
};
75
diff --git a/block/parallels.c b/block/parallels.c
76
index XXXXXXX..XXXXXXX 100644
77
--- a/block/parallels.c
78
+++ b/block/parallels.c
79
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_parallels = {
80
.bdrv_probe        = parallels_probe,
81
.bdrv_open        = parallels_open,
82
.bdrv_close        = parallels_close,
83
+ .bdrv_child_perm = bdrv_format_default_perms,
84
.bdrv_co_get_block_status = parallels_co_get_block_status,
85
.bdrv_has_zero_init = bdrv_has_zero_init_1,
86
.bdrv_co_flush_to_os = parallels_co_flush_to_os,
87
diff --git a/block/qcow.c b/block/qcow.c
88
index XXXXXXX..XXXXXXX 100644
89
--- a/block/qcow.c
90
+++ b/block/qcow.c
91
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_qcow = {
92
.bdrv_probe        = qcow_probe,
93
.bdrv_open        = qcow_open,
94
.bdrv_close        = qcow_close,
95
+ .bdrv_child_perm = bdrv_format_default_perms,
96
.bdrv_reopen_prepare = qcow_reopen_prepare,
97
.bdrv_create = qcow_create,
98
.bdrv_has_zero_init = bdrv_has_zero_init_1,
99
diff --git a/block/qcow2.c b/block/qcow2.c
100
index XXXXXXX..XXXXXXX 100644
101
--- a/block/qcow2.c
102
+++ b/block/qcow2.c
103
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_qcow2 = {
104
.bdrv_reopen_commit = qcow2_reopen_commit,
105
.bdrv_reopen_abort = qcow2_reopen_abort,
106
.bdrv_join_options = qcow2_join_options,
107
+ .bdrv_child_perm = bdrv_format_default_perms,
108
.bdrv_create = qcow2_create,
109
.bdrv_has_zero_init = bdrv_has_zero_init_1,
110
.bdrv_co_get_block_status = qcow2_co_get_block_status,
111
diff --git a/block/qed.c b/block/qed.c
112
index XXXXXXX..XXXXXXX 100644
113
--- a/block/qed.c
114
+++ b/block/qed.c
115
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_qed = {
116
.bdrv_open = bdrv_qed_open,
117
.bdrv_close = bdrv_qed_close,
118
.bdrv_reopen_prepare = bdrv_qed_reopen_prepare,
119
+ .bdrv_child_perm = bdrv_format_default_perms,
120
.bdrv_create = bdrv_qed_create,
121
.bdrv_has_zero_init = bdrv_has_zero_init_1,
122
.bdrv_co_get_block_status = bdrv_qed_co_get_block_status,
123
diff --git a/block/vdi.c b/block/vdi.c
124
index XXXXXXX..XXXXXXX 100644
125
--- a/block/vdi.c
126
+++ b/block/vdi.c
127
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_vdi = {
128
.bdrv_open = vdi_open,
129
.bdrv_close = vdi_close,
130
.bdrv_reopen_prepare = vdi_reopen_prepare,
131
+ .bdrv_child_perm = bdrv_format_default_perms,
132
.bdrv_create = vdi_create,
133
.bdrv_has_zero_init = bdrv_has_zero_init_1,
134
.bdrv_co_get_block_status = vdi_co_get_block_status,
135
diff --git a/block/vhdx.c b/block/vhdx.c
136
index XXXXXXX..XXXXXXX 100644
137
--- a/block/vhdx.c
138
+++ b/block/vhdx.c
139
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_vhdx = {
140
.bdrv_open = vhdx_open,
141
.bdrv_close = vhdx_close,
142
.bdrv_reopen_prepare = vhdx_reopen_prepare,
143
+ .bdrv_child_perm = bdrv_format_default_perms,
144
.bdrv_co_readv = vhdx_co_readv,
145
.bdrv_co_writev = vhdx_co_writev,
146
.bdrv_create = vhdx_create,
147
diff --git a/block/vmdk.c b/block/vmdk.c
23
diff --git a/block/vmdk.c b/block/vmdk.c
148
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
149
--- a/block/vmdk.c
25
--- a/block/vmdk.c
150
+++ b/block/vmdk.c
26
+++ b/block/vmdk.c
151
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_vmdk = {
27
@@ -XXX,XX +XXX,XX @@ static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename)
152
.bdrv_open = vmdk_open,
28
}
153
.bdrv_check = vmdk_check,
29
if (end - p >= strlen("version=X\n")) {
154
.bdrv_reopen_prepare = vmdk_reopen_prepare,
30
if (strncmp("version=1\n", p, strlen("version=1\n")) == 0 ||
155
+ .bdrv_child_perm = bdrv_format_default_perms,
31
- strncmp("version=2\n", p, strlen("version=2\n")) == 0) {
156
.bdrv_co_preadv = vmdk_co_preadv,
32
+ strncmp("version=2\n", p, strlen("version=2\n")) == 0 ||
157
.bdrv_co_pwritev = vmdk_co_pwritev,
33
+ strncmp("version=3\n", p, strlen("version=3\n")) == 0) {
158
.bdrv_co_pwritev_compressed = vmdk_co_pwritev_compressed,
34
return 100;
159
diff --git a/block/vpc.c b/block/vpc.c
35
}
160
index XXXXXXX..XXXXXXX 100644
36
}
161
--- a/block/vpc.c
37
if (end - p >= strlen("version=X\r\n")) {
162
+++ b/block/vpc.c
38
if (strncmp("version=1\r\n", p, strlen("version=1\r\n")) == 0 ||
163
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_vpc = {
39
- strncmp("version=2\r\n", p, strlen("version=2\r\n")) == 0) {
164
.bdrv_open = vpc_open,
40
+ strncmp("version=2\r\n", p, strlen("version=2\r\n")) == 0 ||
165
.bdrv_close = vpc_close,
41
+ strncmp("version=3\r\n", p, strlen("version=3\r\n")) == 0) {
166
.bdrv_reopen_prepare = vpc_reopen_prepare,
42
return 100;
167
+ .bdrv_child_perm = bdrv_format_default_perms,
43
}
168
.bdrv_create = vpc_create,
44
}
169
170
.bdrv_co_preadv = vpc_co_preadv,
171
--
45
--
172
1.8.3.1
46
2.20.1
173
47
174
48
diff view generated by jsdifflib
1
Now that the backing file child role implements .attach/.detach
1
Coverity doesn't like that the return value of bdrv_check_update_perm()
2
callbacks, nothing prevents us from modifying the graph even if that
2
stays unused only in this place (CID 1399710).
3
involves changing backing file links.
3
4
Even if checking local_err should be equivalent to checking ret < 0,
5
let's switch to using the return value to be more consistent (and in
6
case of a bug somewhere down the call chain, forgetting to assign errp
7
is more likely than returning 0 for an error case).
4
8
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Reviewed-by: Alberto Garcia <berto@igalia.com>
7
Acked-by: Fam Zheng <famz@redhat.com>
11
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
12
Reviewed-by: Markus Armbruster <armbru@redhat.com>
8
---
13
---
9
block.c | 7 +++----
14
block.c | 7 +++----
10
1 file changed, 3 insertions(+), 4 deletions(-)
15
1 file changed, 3 insertions(+), 4 deletions(-)
11
16
12
diff --git a/block.c b/block.c
17
diff --git a/block.c b/block.c
13
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
14
--- a/block.c
19
--- a/block.c
15
+++ b/block.c
20
+++ b/block.c
16
@@ -XXX,XX +XXX,XX @@ static void change_parent_backing_link(BlockDriverState *from,
21
@@ -XXX,XX +XXX,XX @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
17
continue;
22
QLIST_FOREACH_SAFE(c, &top->parents, next_parent, next) {
23
/* Check whether we are allowed to switch c from top to base */
24
GSList *ignore_children = g_slist_prepend(NULL, c);
25
- bdrv_check_update_perm(base, NULL, c->perm, c->shared_perm,
26
- ignore_children, &local_err);
27
+ ret = bdrv_check_update_perm(base, NULL, c->perm, c->shared_perm,
28
+ ignore_children, &local_err);
29
g_slist_free(ignore_children);
30
- if (local_err) {
31
- ret = -EPERM;
32
+ if (ret < 0) {
33
error_report_err(local_err);
34
goto exit;
18
}
35
}
19
if (c->role == &child_backing) {
20
- /* @from is generally not allowed to be a backing file, except for
21
- * when @to is the overlay. In that case, @from may not be replaced
22
- * by @to as @to's backing node. */
23
+ /* If @from is a backing file of @to, ignore the child to avoid
24
+ * creating a loop. We only want to change the pointer of other
25
+ * parents. */
26
QLIST_FOREACH(to_c, &to->children, next) {
27
if (to_c == c) {
28
break;
29
@@ -XXX,XX +XXX,XX @@ static void change_parent_backing_link(BlockDriverState *from,
30
}
31
}
32
33
- assert(c->role != &child_backing);
34
bdrv_ref(to);
35
/* FIXME Are we sure that bdrv_replace_child() can't run into
36
* &error_abort because of permissions? */
37
--
36
--
38
1.8.3.1
37
2.20.1
39
38
40
39
diff view generated by jsdifflib
1
Aborting on error in bdrv_append() isn't correct. This patch fixes it
1
From: Sergio Lopez <slp@redhat.com>
2
and lets the callers handle failures.
3
2
4
Test case 085 needs a reference output update. This is caused by the
3
There are various actions in this test that must be executed
5
reversed order of bdrv_set_backing_hd() and change_parent_backing_link()
4
sequentially, as the result of it depends on the state triggered by the
6
in bdrv_append(): When the backing file of the new node is set, the
5
previous one.
7
parent nodes are still pointing to the old top, so the backing blocker
8
is now initialised with the node name rather than the BlockBackend name.
9
6
7
If the last argument of _send_qemu_cmd() is an empty string, it just
8
sends the QMP commands without waiting for an answer. While unlikely, it
9
may happen that the next action in the test gets invoked before QEMU
10
processes the QMP request.
11
12
This issue seems to be easier to reproduce on servers with limited
13
resources or highly loaded.
14
15
With this change, we wait for an answer on all _send_qemu_cmd() calls.
16
17
Signed-off-by: Sergio Lopez <slp@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Acked-by: Fam Zheng <famz@redhat.com>
12
Reviewed-by: Max Reitz <mreitz@redhat.com>
13
---
19
---
14
block.c | 23 +++++++++++++++++------
20
tests/qemu-iotests/153 | 12 ++++++------
15
block/mirror.c | 9 ++++++++-
21
tests/qemu-iotests/153.out | 6 ++++++
16
blockdev.c | 18 +++++++++++++++---
22
2 files changed, 12 insertions(+), 6 deletions(-)
17
include/block/block.h | 3 ++-
18
tests/qemu-iotests/085.out | 2 +-
19
5 files changed, 43 insertions(+), 12 deletions(-)
20
23
21
diff --git a/block.c b/block.c
24
diff --git a/tests/qemu-iotests/153 b/tests/qemu-iotests/153
25
index XXXXXXX..XXXXXXX 100755
26
--- a/tests/qemu-iotests/153
27
+++ b/tests/qemu-iotests/153
28
@@ -XXX,XX +XXX,XX @@ for opts1 in "" "read-only=on" "read-only=on,force-share=on"; do
29
_img_info -U | grep 'file format'
30
fi
31
done
32
- _send_qemu_cmd $h "{ 'execute': 'quit', }" ""
33
+ _send_qemu_cmd $h "{ 'execute': 'quit' }" ''
34
echo
35
echo "Round done"
36
_cleanup_qemu
37
@@ -XXX,XX +XXX,XX @@ echo "Adding drive"
38
_send_qemu_cmd $QEMU_HANDLE \
39
"{ 'execute': 'human-monitor-command',
40
'arguments': { 'command-line': 'drive_add 0 if=none,id=d0,file=${TEST_IMG}' } }" \
41
- ""
42
+ 'return'
43
44
_run_cmd $QEMU_IO "${TEST_IMG}" -c 'write 0 512'
45
46
@@ -XXX,XX +XXX,XX @@ echo "== Closing an image should unlock it =="
47
_send_qemu_cmd $QEMU_HANDLE \
48
"{ 'execute': 'human-monitor-command',
49
'arguments': { 'command-line': 'drive_del d0' } }" \
50
- ""
51
+ 'return'
52
53
_run_cmd $QEMU_IO "${TEST_IMG}" -c 'write 0 512'
54
55
@@ -XXX,XX +XXX,XX @@ for d in d0 d1; do
56
_send_qemu_cmd $QEMU_HANDLE \
57
"{ 'execute': 'human-monitor-command',
58
'arguments': { 'command-line': 'drive_add 0 if=none,id=$d,file=${TEST_IMG},readonly=on' } }" \
59
- ""
60
+ 'return'
61
done
62
63
_run_cmd $QEMU_IMG info "${TEST_IMG}"
64
@@ -XXX,XX +XXX,XX @@ _run_cmd $QEMU_IMG info "${TEST_IMG}"
65
_send_qemu_cmd $QEMU_HANDLE \
66
"{ 'execute': 'human-monitor-command',
67
'arguments': { 'command-line': 'drive_del d0' } }" \
68
- ""
69
+ 'return'
70
71
_run_cmd $QEMU_IO "${TEST_IMG}" -c 'write 0 512'
72
73
@@ -XXX,XX +XXX,XX @@ echo "Closing the other"
74
_send_qemu_cmd $QEMU_HANDLE \
75
"{ 'execute': 'human-monitor-command',
76
'arguments': { 'command-line': 'drive_del d1' } }" \
77
- ""
78
+ 'return'
79
80
_run_cmd $QEMU_IO "${TEST_IMG}" -c 'write 0 512'
81
82
diff --git a/tests/qemu-iotests/153.out b/tests/qemu-iotests/153.out
22
index XXXXXXX..XXXXXXX 100644
83
index XXXXXXX..XXXXXXX 100644
23
--- a/block.c
84
--- a/tests/qemu-iotests/153.out
24
+++ b/block.c
85
+++ b/tests/qemu-iotests/153.out
25
@@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs,
86
@@ -XXX,XX +XXX,XX @@ Is another process using the image [TEST_DIR/t.qcow2]?
26
int64_t total_size;
87
_qemu_img_wrapper commit -b TEST_DIR/t.qcow2.b TEST_DIR/t.qcow2.c
27
QemuOpts *opts = NULL;
88
{"return": {}}
28
BlockDriverState *bs_snapshot;
89
Adding drive
29
+ Error *local_err = NULL;
90
+{"return": "OKrn"}
30
int ret;
91
31
92
_qemu_io_wrapper TEST_DIR/t.qcow2 -c write 0 512
32
/* if snapshot, we create a temporary backing file and open it
93
can't open device TEST_DIR/t.qcow2: Failed to get "write" lock
33
@@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs,
94
@@ -XXX,XX +XXX,XX @@ Creating overlay with qemu-img when the guest is running should be allowed
34
* call bdrv_unref() on it), so in order to be able to return one, we have
95
35
* to increase bs_snapshot's refcount here */
96
_qemu_img_wrapper create -f qcow2 -b TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.overlay
36
bdrv_ref(bs_snapshot);
97
== Closing an image should unlock it ==
37
- bdrv_append(bs_snapshot, bs);
98
+{"return": ""}
38
+ bdrv_append(bs_snapshot, bs, &local_err);
99
39
+ if (local_err) {
100
_qemu_io_wrapper TEST_DIR/t.qcow2 -c write 0 512
40
+ error_propagate(errp, local_err);
101
Adding two and closing one
41
+ ret = -EINVAL;
102
+{"return": "OKrn"}
42
+ goto out;
103
+{"return": "OKrn"}
43
+ }
104
44
105
_qemu_img_wrapper info TEST_DIR/t.qcow2
45
g_free(tmp_filename);
106
+{"return": ""}
46
return bs_snapshot;
107
47
@@ -XXX,XX +XXX,XX @@ static void change_parent_backing_link(BlockDriverState *from,
108
_qemu_io_wrapper TEST_DIR/t.qcow2 -c write 0 512
48
* parents of bs_top after bdrv_append() returns. If the caller needs to keep a
109
can't open device TEST_DIR/t.qcow2: Failed to get "write" lock
49
* reference of its own, it must call bdrv_ref().
110
Is another process using the image [TEST_DIR/t.qcow2]?
50
*/
111
Closing the other
51
-void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top)
112
+{"return": ""}
52
+void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
113
53
+ Error **errp)
114
_qemu_io_wrapper TEST_DIR/t.qcow2 -c write 0 512
54
{
55
+ Error *local_err = NULL;
56
+
57
assert(!atomic_read(&bs_top->in_flight));
58
assert(!atomic_read(&bs_new->in_flight));
59
60
- bdrv_ref(bs_top);
61
+ bdrv_set_backing_hd(bs_new, bs_top, &local_err);
62
+ if (local_err) {
63
+ error_propagate(errp, local_err);
64
+ goto out;
65
+ }
66
67
change_parent_backing_link(bs_top, bs_new);
68
- /* FIXME Error handling */
69
- bdrv_set_backing_hd(bs_new, bs_top, &error_abort);
70
- bdrv_unref(bs_top);
71
72
/* bs_new is now referenced by its new parents, we don't need the
73
* additional reference any more. */
74
+out:
75
bdrv_unref(bs_new);
76
}
77
78
diff --git a/block/mirror.c b/block/mirror.c
79
index XXXXXXX..XXXXXXX 100644
80
--- a/block/mirror.c
81
+++ b/block/mirror.c
82
@@ -XXX,XX +XXX,XX @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
83
BlockDriverState *mirror_top_bs;
84
bool target_graph_mod;
85
bool target_is_backing;
86
+ Error *local_err = NULL;
87
int ret;
88
89
if (granularity == 0) {
90
@@ -XXX,XX +XXX,XX @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
91
* it alive until block_job_create() even if bs has no parent. */
92
bdrv_ref(mirror_top_bs);
93
bdrv_drained_begin(bs);
94
- bdrv_append(mirror_top_bs, bs);
95
+ bdrv_append(mirror_top_bs, bs, &local_err);
96
bdrv_drained_end(bs);
97
98
+ if (local_err) {
99
+ bdrv_unref(mirror_top_bs);
100
+ error_propagate(errp, local_err);
101
+ return;
102
+ }
103
+
104
/* Make sure that the source is not resized while the job is running */
105
s = block_job_create(job_id, driver, mirror_top_bs,
106
BLK_PERM_CONSISTENT_READ,
107
diff --git a/blockdev.c b/blockdev.c
108
index XXXXXXX..XXXXXXX 100644
109
--- a/blockdev.c
110
+++ b/blockdev.c
111
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_prepare(BlkActionState *common,
112
113
if (!state->new_bs->drv->supports_backing) {
114
error_setg(errp, "The snapshot does not support backing images");
115
+ return;
116
+ }
117
+
118
+ /* This removes our old bs and adds the new bs. This is an operation that
119
+ * can fail, so we need to do it in .prepare; undoing it for abort is
120
+ * always possible. */
121
+ bdrv_ref(state->new_bs);
122
+ bdrv_append(state->new_bs, state->old_bs, &local_err);
123
+ if (local_err) {
124
+ error_propagate(errp, local_err);
125
+ return;
126
}
127
}
128
129
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_commit(BlkActionState *common)
130
131
bdrv_set_aio_context(state->new_bs, state->aio_context);
132
133
- /* This removes our old bs and adds the new bs */
134
- bdrv_append(state->new_bs, state->old_bs);
135
/* We don't need (or want) to use the transactional
136
* bdrv_reopen_multiple() across all the entries at once, because we
137
* don't want to abort all of them if one of them fails the reopen */
138
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_abort(BlkActionState *common)
139
ExternalSnapshotState *state =
140
DO_UPCAST(ExternalSnapshotState, common, common);
141
if (state->new_bs) {
142
- bdrv_unref(state->new_bs);
143
+ if (state->new_bs->backing) {
144
+ bdrv_replace_in_backing_chain(state->new_bs, state->old_bs);
145
+ }
146
}
147
}
148
149
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_clean(BlkActionState *common)
150
if (state->aio_context) {
151
bdrv_drained_end(state->old_bs);
152
aio_context_release(state->aio_context);
153
+ bdrv_unref(state->new_bs);
154
}
155
}
156
157
diff --git a/include/block/block.h b/include/block/block.h
158
index XXXXXXX..XXXXXXX 100644
159
--- a/include/block/block.h
160
+++ b/include/block/block.h
161
@@ -XXX,XX +XXX,XX @@ int bdrv_create(BlockDriver *drv, const char* filename,
162
QemuOpts *opts, Error **errp);
163
int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp);
164
BlockDriverState *bdrv_new(void);
165
-void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top);
166
+void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
167
+ Error **errp);
168
void bdrv_replace_in_backing_chain(BlockDriverState *old,
169
BlockDriverState *new);
170
171
diff --git a/tests/qemu-iotests/085.out b/tests/qemu-iotests/085.out
172
index XXXXXXX..XXXXXXX 100644
173
--- a/tests/qemu-iotests/085.out
174
+++ b/tests/qemu-iotests/085.out
175
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/
176
177
=== Invalid command - snapshot node used as backing hd ===
178
179
-{"error": {"class": "GenericError", "desc": "Node 'snap_11' is busy: node is used as backing hd of 'virtio0'"}}
180
+{"error": {"class": "GenericError", "desc": "Node 'snap_11' is busy: node is used as backing hd of 'snap_12'"}}
181
182
=== Invalid command - snapshot node has a backing image ===
183
115
184
--
116
--
185
1.8.3.1
117
2.20.1
186
118
187
119
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
From: Markus Armbruster <armbru@redhat.com>
2
2
3
Commit 75cdcd1 neglected to update tests/qemu-iotests/049.out, and
3
Recent commit cda4aa9a5a0 moved block backend creation before machine
4
made the error message for negative size worse. Fix that.
4
property evaluation. This broke qemu-iotests 055. Turns out we need
5
to create the migration object before block backends, so block
6
backends can add migration blockers. Fix by calling
7
migration_object_init() earlier, right before configure_blockdev().
5
8
6
Reported-by: Thomas Huth <thuth@redhat.com>
9
Fixes: cda4aa9a5a08777cf13e164c0543bd4888b8adce
10
Reported-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Markus Armbruster <armbru@redhat.com>
11
Signed-off-by: Markus Armbruster <armbru@redhat.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Reviewed-by: Thomas Huth <thuth@redhat.com>
10
Tested-by: Christian Borntraeger <borntraeger@de.ibm.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
13
---
13
tests/qemu-iotests/049.out | 14 +++++++++-----
14
vl.c | 15 ++++++++-------
14
util/qemu-option.c | 2 +-
15
1 file changed, 8 insertions(+), 7 deletions(-)
15
2 files changed, 10 insertions(+), 6 deletions(-)
16
16
17
diff --git a/tests/qemu-iotests/049.out b/tests/qemu-iotests/049.out
17
diff --git a/vl.c b/vl.c
18
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
19
--- a/tests/qemu-iotests/049.out
19
--- a/vl.c
20
+++ b/tests/qemu-iotests/049.out
20
+++ b/vl.c
21
@@ -XXX,XX +XXX,XX @@ qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- -1024
21
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp)
22
qemu-img: Image size must be less than 8 EiB!
22
exit(0);
23
23
}
24
qemu-img create -f qcow2 -o size=-1024 TEST_DIR/t.qcow2
24
25
-qemu-img: Parameter 'size' expects a non-negative number below 2^64
25
+ /*
26
+qemu-img: Value '-1024' is out of range for parameter 'size'
26
+ * Migration object can only be created after global properties
27
qemu-img: TEST_DIR/t.qcow2: Invalid options for file format 'qcow2'
27
+ * are applied correctly.
28
28
+ */
29
qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- -1k
29
+ migration_object_init();
30
qemu-img: Image size must be less than 8 EiB!
30
+
31
31
/*
32
qemu-img create -f qcow2 -o size=-1k TEST_DIR/t.qcow2
32
* Note: we need to create block backends before
33
-qemu-img: Parameter 'size' expects a non-negative number below 2^64
33
* machine_set_property(), so machine properties can refer to
34
+qemu-img: Value '-1k' is out of range for parameter 'size'
34
- * them.
35
qemu-img: TEST_DIR/t.qcow2: Invalid options for file format 'qcow2'
35
+ * them, and after migration_object_init(), so we can create
36
36
+ * migration blockers.
37
qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- 1kilobyte
37
*/
38
@@ -XXX,XX +XXX,XX @@ qemu-img: Invalid image size specified! You may use k, M, G, T, P or E suffixes
38
configure_blockdev(&bdo_queue, machine_class, snapshot);
39
qemu-img: kilobytes, megabytes, gigabytes, terabytes, petabytes and exabytes.
39
40
40
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp)
41
qemu-img create -f qcow2 -o size=1kilobyte TEST_DIR/t.qcow2
41
machine_class->name, machine_class->deprecation_reason);
42
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
42
}
43
+qemu-img: Parameter 'size' expects a non-negative number below 2^64
43
44
+Optional suffix k, M, G, T, P or E means kilo-, mega-, giga-, tera-, peta-
44
- /*
45
+and exabytes, respectively.
45
- * Migration object can only be created after global properties
46
+qemu-img: TEST_DIR/t.qcow2: Invalid options for file format 'qcow2'
46
- * are applied correctly.
47
47
- */
48
qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- foobar
48
- migration_object_init();
49
qemu-img: Invalid image size specified! You may use k, M, G, T, P or E suffixes for
49
-
50
qemu-img: kilobytes, megabytes, gigabytes, terabytes, petabytes and exabytes.
50
if (qtest_chrdev) {
51
51
qtest_init(qtest_chrdev, qtest_log, &error_fatal);
52
qemu-img create -f qcow2 -o size=foobar TEST_DIR/t.qcow2
53
-qemu-img: Parameter 'size' expects a size
54
-You may use k, M, G or T suffixes for kilobytes, megabytes, gigabytes and terabytes.
55
+qemu-img: Parameter 'size' expects a non-negative number below 2^64
56
+Optional suffix k, M, G, T, P or E means kilo-, mega-, giga-, tera-, peta-
57
+and exabytes, respectively.
58
qemu-img: TEST_DIR/t.qcow2: Invalid options for file format 'qcow2'
59
60
== Check correct interpretation of suffixes for cluster size ==
61
diff --git a/util/qemu-option.c b/util/qemu-option.c
62
index XXXXXXX..XXXXXXX 100644
63
--- a/util/qemu-option.c
64
+++ b/util/qemu-option.c
65
@@ -XXX,XX +XXX,XX @@ void parse_option_size(const char *name, const char *value,
66
67
err = qemu_strtosz(value, NULL, &size);
68
if (err == -ERANGE) {
69
- error_setg(errp, "Value '%s' is too large for parameter '%s'",
70
+ error_setg(errp, "Value '%s' is out of range for parameter '%s'",
71
value, name);
72
return;
73
}
52
}
74
--
53
--
75
1.8.3.1
54
2.20.1
76
55
77
56
diff view generated by jsdifflib
1
This adds an assertion that ensures that the necessary resize permission
1
232 is marked as generic, but commit 12efe428c9e added code that assumes
2
has been granted before bdrv_truncate() is called.
2
qcow2. What the new test really needs is backing files and support for
3
updating the backing file link (.bdrv_change_backing_file).
4
5
Split the non-generic code into a new test case 247 and make it work
6
with qed, too.
3
7
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Acked-by: Fam Zheng <famz@redhat.com>
7
---
9
---
8
block.c | 3 +++
10
tests/qemu-iotests/232 | 30 ---------------
9
block/io.c | 1 +
11
tests/qemu-iotests/232.out | 20 ----------
10
2 files changed, 4 insertions(+)
12
tests/qemu-iotests/247 | 79 ++++++++++++++++++++++++++++++++++++++
11
13
tests/qemu-iotests/247.out | 22 +++++++++++
12
diff --git a/block.c b/block.c
14
tests/qemu-iotests/group | 1 +
15
5 files changed, 102 insertions(+), 50 deletions(-)
16
create mode 100755 tests/qemu-iotests/247
17
create mode 100644 tests/qemu-iotests/247.out
18
19
diff --git a/tests/qemu-iotests/232 b/tests/qemu-iotests/232
20
index XXXXXXX..XXXXXXX 100755
21
--- a/tests/qemu-iotests/232
22
+++ b/tests/qemu-iotests/232
23
@@ -XXX,XX +XXX,XX @@ run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,a
24
run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,auto-read-only=on
25
run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0
26
27
-echo
28
-echo "=== Try commit to backing file with auto-read-only ==="
29
-echo
30
-
31
-TEST_IMG="$TEST_IMG.0" _make_test_img $size
32
-TEST_IMG="$TEST_IMG.1" _make_test_img $size
33
-TEST_IMG="$TEST_IMG.2" _make_test_img $size
34
-TEST_IMG="$TEST_IMG.3" _make_test_img $size
35
-TEST_IMG="$TEST_IMG.4" _make_test_img $size
36
-
37
-(cat <<EOF
38
-{"execute":"qmp_capabilities"}
39
-{"execute":"block-commit",
40
- "arguments":{"device":"format-4", "top-node": "format-2", "base-node":"format-0", "job-id":"job0"}}
41
-EOF
42
-sleep 1
43
-echo '{"execute":"quit"}'
44
-) | $QEMU -qmp stdio -nographic -nodefaults \
45
- -blockdev file,node-name=file-0,filename=$TEST_IMG.0,auto-read-only=on \
46
- -blockdev qcow2,node-name=format-0,file=file-0,read-only=on \
47
- -blockdev file,node-name=file-1,filename=$TEST_IMG.1,auto-read-only=on \
48
- -blockdev qcow2,node-name=format-1,file=file-1,read-only=on,backing=format-0 \
49
- -blockdev file,node-name=file-2,filename=$TEST_IMG.2,auto-read-only=on \
50
- -blockdev qcow2,node-name=format-2,file=file-2,read-only=on,backing=format-1 \
51
- -blockdev file,node-name=file-3,filename=$TEST_IMG.3,auto-read-only=on \
52
- -blockdev qcow2,node-name=format-3,file=file-3,read-only=on,backing=format-2 \
53
- -blockdev file,node-name=file-4,filename=$TEST_IMG.4,auto-read-only=on \
54
- -blockdev qcow2,node-name=format-4,file=file-4,read-only=on,backing=format-3 |
55
- _filter_qmp
56
-
57
# success, all done
58
echo "*** done"
59
rm -f $seq.full
60
diff --git a/tests/qemu-iotests/232.out b/tests/qemu-iotests/232.out
13
index XXXXXXX..XXXXXXX 100644
61
index XXXXXXX..XXXXXXX 100644
14
--- a/block.c
62
--- a/tests/qemu-iotests/232.out
15
+++ b/block.c
63
+++ b/tests/qemu-iotests/232.out
16
@@ -XXX,XX +XXX,XX @@ int bdrv_truncate(BdrvChild *child, int64_t offset)
64
@@ -XXX,XX +XXX,XX @@ QEMU_PROG: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0,read
17
BlockDriverState *bs = child->bs;
65
QEMU_PROG: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0,auto-read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
18
BlockDriver *drv = bs->drv;
66
node0: TEST_DIR/t.IMGFMT (file)
19
int ret;
67
QEMU_PROG: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
20
+
68
-
21
+ assert(child->perm & BLK_PERM_RESIZE);
69
-=== Try commit to backing file with auto-read-only ===
22
+
70
-
23
if (!drv)
71
-Formatting 'TEST_DIR/t.IMGFMT.0', fmt=IMGFMT size=134217728
24
return -ENOMEDIUM;
72
-Formatting 'TEST_DIR/t.IMGFMT.1', fmt=IMGFMT size=134217728
25
if (!drv->bdrv_truncate)
73
-Formatting 'TEST_DIR/t.IMGFMT.2', fmt=IMGFMT size=134217728
26
diff --git a/block/io.c b/block/io.c
74
-Formatting 'TEST_DIR/t.IMGFMT.3', fmt=IMGFMT size=134217728
75
-Formatting 'TEST_DIR/t.IMGFMT.4', fmt=IMGFMT size=134217728
76
-QMP_VERSION
77
-{"return": {}}
78
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}}
79
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}}
80
-{"return": {}}
81
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job0"}}
82
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job0"}}
83
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job0", "len": 134217728, "offset": 134217728, "speed": 0, "type": "commit"}}
84
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job0"}}
85
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job0"}}
86
-{"return": {}}
87
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
88
*** done
89
diff --git a/tests/qemu-iotests/247 b/tests/qemu-iotests/247
90
new file mode 100755
91
index XXXXXXX..XXXXXXX
92
--- /dev/null
93
+++ b/tests/qemu-iotests/247
94
@@ -XXX,XX +XXX,XX @@
95
+#!/usr/bin/env bash
96
+#
97
+# Test for auto-read-only with commit block job
98
+#
99
+# Copyright (C) 2019 Red Hat, Inc.
100
+#
101
+# This program is free software; you can redistribute it and/or modify
102
+# it under the terms of the GNU General Public License as published by
103
+# the Free Software Foundation; either version 2 of the License, or
104
+# (at your option) any later version.
105
+#
106
+# This program is distributed in the hope that it will be useful,
107
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
108
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
109
+# GNU General Public License for more details.
110
+#
111
+# You should have received a copy of the GNU General Public License
112
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
113
+#
114
+
115
+# creator
116
+owner=kwolf@redhat.com
117
+
118
+seq=`basename $0`
119
+echo "QA output created by $seq"
120
+
121
+status=1    # failure is the default!
122
+
123
+_cleanup()
124
+{
125
+ _cleanup_test_img
126
+ rm -f $TEST_IMG.[01234]
127
+}
128
+trap "_cleanup; exit \$status" 0 1 2 3 15
129
+
130
+# get standard environment, filters and checks
131
+. ./common.rc
132
+. ./common.filter
133
+
134
+# Requires backing files and .bdrv_change_backing_file support
135
+_supported_fmt qcow2 qed
136
+_supported_proto file
137
+_supported_os Linux
138
+
139
+size=128M
140
+
141
+echo
142
+echo "=== Try commit to backing file with auto-read-only ==="
143
+echo
144
+TEST_IMG="$TEST_IMG.0" _make_test_img $size
145
+TEST_IMG="$TEST_IMG.1" _make_test_img $size
146
+TEST_IMG="$TEST_IMG.2" _make_test_img $size
147
+TEST_IMG="$TEST_IMG.3" _make_test_img $size
148
+TEST_IMG="$TEST_IMG.4" _make_test_img $size
149
+
150
+(cat <<EOF
151
+{"execute":"qmp_capabilities"}
152
+{"execute":"block-commit",
153
+ "arguments":{"device":"format-4", "top-node": "format-2", "base-node":"format-0", "job-id":"job0"}}
154
+EOF
155
+sleep 1
156
+echo '{"execute":"quit"}'
157
+) | $QEMU -qmp stdio -nographic -nodefaults \
158
+ -blockdev file,node-name=file-0,filename=$TEST_IMG.0,auto-read-only=on \
159
+ -blockdev $IMGFMT,node-name=format-0,file=file-0,read-only=on \
160
+ -blockdev file,node-name=file-1,filename=$TEST_IMG.1,auto-read-only=on \
161
+ -blockdev $IMGFMT,node-name=format-1,file=file-1,read-only=on,backing=format-0 \
162
+ -blockdev file,node-name=file-2,filename=$TEST_IMG.2,auto-read-only=on \
163
+ -blockdev $IMGFMT,node-name=format-2,file=file-2,read-only=on,backing=format-1 \
164
+ -blockdev file,node-name=file-3,filename=$TEST_IMG.3,auto-read-only=on \
165
+ -blockdev $IMGFMT,node-name=format-3,file=file-3,read-only=on,backing=format-2 \
166
+ -blockdev file,node-name=file-4,filename=$TEST_IMG.4,auto-read-only=on \
167
+ -blockdev $IMGFMT,node-name=format-4,file=file-4,read-only=on,backing=format-3 |
168
+ _filter_qmp
169
+
170
+# success, all done
171
+echo "*** done"
172
+rm -f $seq.full
173
+status=0
174
diff --git a/tests/qemu-iotests/247.out b/tests/qemu-iotests/247.out
175
new file mode 100644
176
index XXXXXXX..XXXXXXX
177
--- /dev/null
178
+++ b/tests/qemu-iotests/247.out
179
@@ -XXX,XX +XXX,XX @@
180
+QA output created by 247
181
+
182
+=== Try commit to backing file with auto-read-only ===
183
+
184
+Formatting 'TEST_DIR/t.IMGFMT.0', fmt=IMGFMT size=134217728
185
+Formatting 'TEST_DIR/t.IMGFMT.1', fmt=IMGFMT size=134217728
186
+Formatting 'TEST_DIR/t.IMGFMT.2', fmt=IMGFMT size=134217728
187
+Formatting 'TEST_DIR/t.IMGFMT.3', fmt=IMGFMT size=134217728
188
+Formatting 'TEST_DIR/t.IMGFMT.4', fmt=IMGFMT size=134217728
189
+QMP_VERSION
190
+{"return": {}}
191
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}}
192
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}}
193
+{"return": {}}
194
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job0"}}
195
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job0"}}
196
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job0", "len": 134217728, "offset": 134217728, "speed": 0, "type": "commit"}}
197
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job0"}}
198
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job0"}}
199
+{"return": {}}
200
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
201
+*** done
202
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
27
index XXXXXXX..XXXXXXX 100644
203
index XXXXXXX..XXXXXXX 100644
28
--- a/block/io.c
204
--- a/tests/qemu-iotests/group
29
+++ b/block/io.c
205
+++ b/tests/qemu-iotests/group
30
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
206
@@ -XXX,XX +XXX,XX @@
31
assert(req->overlap_offset <= offset);
207
244 rw auto quick
32
assert(offset + bytes <= req->overlap_offset + req->overlap_bytes);
208
245 rw auto
33
assert(child->perm & BLK_PERM_WRITE);
209
246 rw auto quick
34
+ assert(end_sector <= bs->total_sectors || child->perm & BLK_PERM_RESIZE);
210
+247 rw auto quick
35
36
ret = notifier_with_return_list_notify(&bs->before_write_notifiers, req);
37
38
--
211
--
39
1.8.3.1
212
2.20.1
40
213
41
214
diff view generated by jsdifflib
1
In some cases, we want to remove op blockers on intermediate nodes
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
before the whole block job transaction has completed (because they block
3
restoring the final graph state during completion). Provide a function
4
for this.
5
2
6
The whole block job lifecycle is a bit messed up and it's hard to
3
Job (especially mirror) may call block_job_error_action several
7
actually do all things in the right order, but I'll leave simplifying
4
times before actual pause if it has several in-flight requests.
8
this for another day.
9
5
6
block_job_error_action will call job_pause more than once in this case,
7
which lead to following block-job-resume qmp command can't actually
8
resume the job.
9
10
Fix it by do not increase pause level in block_job_error_action if
11
user_paused already set.
12
13
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Acked-by: Fam Zheng <famz@redhat.com>
12
Reviewed-by: Max Reitz <mreitz@redhat.com>
13
---
15
---
14
blockjob.c | 20 +++++++++++++-------
16
blockjob.c | 8 +++++---
15
include/block/blockjob.h | 9 +++++++++
17
1 file changed, 5 insertions(+), 3 deletions(-)
16
2 files changed, 22 insertions(+), 7 deletions(-)
17
18
18
diff --git a/blockjob.c b/blockjob.c
19
diff --git a/blockjob.c b/blockjob.c
19
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
20
--- a/blockjob.c
21
--- a/blockjob.c
21
+++ b/blockjob.c
22
+++ b/blockjob.c
22
@@ -XXX,XX +XXX,XX @@ static void block_job_detach_aio_context(void *opaque)
23
@@ -XXX,XX +XXX,XX @@ BlockErrorAction block_job_error_action(BlockJob *job, BlockdevOnError on_err,
23
block_job_unref(job);
24
action);
24
}
25
}
25
26
if (action == BLOCK_ERROR_ACTION_STOP) {
26
+void block_job_remove_all_bdrv(BlockJob *job)
27
- job_pause(&job->job);
27
+{
28
- /* make the pause user visible, which will be resumed from QMP. */
28
+ GSList *l;
29
- job->job.user_paused = true;
29
+ for (l = job->nodes; l; l = l->next) {
30
+ if (!job->job.user_paused) {
30
+ BdrvChild *c = l->data;
31
+ job_pause(&job->job);
31
+ bdrv_op_unblock_all(c->bs, job->blocker);
32
+ /* make the pause user visible, which will be resumed from QMP. */
32
+ bdrv_root_unref_child(c);
33
+ job->job.user_paused = true;
33
+ }
34
+ }
34
+ g_slist_free(job->nodes);
35
block_job_iostatus_set_err(job, error);
35
+ job->nodes = NULL;
36
}
36
+}
37
return action;
37
+
38
int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs,
39
uint64_t perm, uint64_t shared_perm, Error **errp)
40
{
41
@@ -XXX,XX +XXX,XX @@ void block_job_ref(BlockJob *job)
42
void block_job_unref(BlockJob *job)
43
{
44
if (--job->refcnt == 0) {
45
- GSList *l;
46
BlockDriverState *bs = blk_bs(job->blk);
47
bs->job = NULL;
48
- for (l = job->nodes; l; l = l->next) {
49
- BdrvChild *c = l->data;
50
- bdrv_op_unblock_all(c->bs, job->blocker);
51
- bdrv_root_unref_child(c);
52
- }
53
- g_slist_free(job->nodes);
54
+ block_job_remove_all_bdrv(job);
55
blk_remove_aio_context_notifier(job->blk,
56
block_job_attached_aio_context,
57
block_job_detach_aio_context, job);
58
diff --git a/include/block/blockjob.h b/include/block/blockjob.h
59
index XXXXXXX..XXXXXXX 100644
60
--- a/include/block/blockjob.h
61
+++ b/include/block/blockjob.h
62
@@ -XXX,XX +XXX,XX @@ int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs,
63
uint64_t perm, uint64_t shared_perm, Error **errp);
64
65
/**
66
+ * block_job_remove_all_bdrv:
67
+ * @job: The block job
68
+ *
69
+ * Remove all BlockDriverStates from the list of nodes that are involved in the
70
+ * job. This removes the blockers added with block_job_add_bdrv().
71
+ */
72
+void block_job_remove_all_bdrv(BlockJob *job);
73
+
74
+/**
75
* block_job_set_speed:
76
* @job: The job to set the speed for.
77
* @speed: The new value
78
--
38
--
79
1.8.3.1
39
2.20.1
80
40
81
41
diff view generated by jsdifflib
1
All callers will have to request permissions for all of their child
1
From: Alberto Garcia <berto@igalia.com>
2
nodes. Block drivers that act as simply filters can use the default
3
implementation of .bdrv_child_perm().
4
2
3
Signed-off-by: Alberto Garcia <berto@igalia.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
Acked-by: Fam Zheng <famz@redhat.com>
8
---
5
---
9
block/blkdebug.c | 2 ++
6
block/copy-on-read.c | 2 +-
10
block/blkreplay.c | 1 +
7
block/crypto.c | 2 +-
11
block/blkverify.c | 1 +
8
block/replication.c | 2 +-
12
block/quorum.c | 2 ++
9
3 files changed, 3 insertions(+), 3 deletions(-)
13
block/raw-format.c | 1 +
14
block/replication.c | 1 +
15
6 files changed, 8 insertions(+)
16
10
17
diff --git a/block/blkdebug.c b/block/blkdebug.c
11
diff --git a/block/copy-on-read.c b/block/copy-on-read.c
18
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
19
--- a/block/blkdebug.c
13
--- a/block/copy-on-read.c
20
+++ b/block/blkdebug.c
14
+++ b/block/copy-on-read.c
21
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_blkdebug = {
15
@@ -XXX,XX +XXX,XX @@ static bool cor_recurse_is_first_non_filter(BlockDriverState *bs,
22
.bdrv_file_open = blkdebug_open,
16
}
23
.bdrv_close = blkdebug_close,
17
24
.bdrv_reopen_prepare = blkdebug_reopen_prepare,
18
25
+ .bdrv_child_perm = bdrv_filter_default_perms,
19
-BlockDriver bdrv_copy_on_read = {
26
+
20
+static BlockDriver bdrv_copy_on_read = {
27
.bdrv_getlength = blkdebug_getlength,
21
.format_name = "copy-on-read",
28
.bdrv_truncate = blkdebug_truncate,
22
29
.bdrv_refresh_filename = blkdebug_refresh_filename,
23
.bdrv_open = cor_open,
30
diff --git a/block/blkreplay.c b/block/blkreplay.c
24
diff --git a/block/crypto.c b/block/crypto.c
31
index XXXXXXX..XXXXXXX 100755
32
--- a/block/blkreplay.c
33
+++ b/block/blkreplay.c
34
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_blkreplay = {
35
36
.bdrv_file_open = blkreplay_open,
37
.bdrv_close = blkreplay_close,
38
+ .bdrv_child_perm = bdrv_filter_default_perms,
39
.bdrv_getlength = blkreplay_getlength,
40
41
.bdrv_co_preadv = blkreplay_co_preadv,
42
diff --git a/block/blkverify.c b/block/blkverify.c
43
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
44
--- a/block/blkverify.c
26
--- a/block/crypto.c
45
+++ b/block/blkverify.c
27
+++ b/block/crypto.c
46
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_blkverify = {
28
@@ -XXX,XX +XXX,XX @@ static const char *const block_crypto_strong_runtime_opts[] = {
47
.bdrv_parse_filename = blkverify_parse_filename,
29
NULL
48
.bdrv_file_open = blkverify_open,
49
.bdrv_close = blkverify_close,
50
+ .bdrv_child_perm = bdrv_filter_default_perms,
51
.bdrv_getlength = blkverify_getlength,
52
.bdrv_refresh_filename = blkverify_refresh_filename,
53
54
diff --git a/block/quorum.c b/block/quorum.c
55
index XXXXXXX..XXXXXXX 100644
56
--- a/block/quorum.c
57
+++ b/block/quorum.c
58
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_quorum = {
59
.bdrv_add_child = quorum_add_child,
60
.bdrv_del_child = quorum_del_child,
61
62
+ .bdrv_child_perm = bdrv_filter_default_perms,
63
+
64
.is_filter = true,
65
.bdrv_recurse_is_first_non_filter = quorum_recurse_is_first_non_filter,
66
};
30
};
67
diff --git a/block/raw-format.c b/block/raw-format.c
31
68
index XXXXXXX..XXXXXXX 100644
32
-BlockDriver bdrv_crypto_luks = {
69
--- a/block/raw-format.c
33
+static BlockDriver bdrv_crypto_luks = {
70
+++ b/block/raw-format.c
34
.format_name = "luks",
71
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_raw = {
35
.instance_size = sizeof(BlockCrypto),
72
.bdrv_reopen_abort = &raw_reopen_abort,
36
.bdrv_probe = block_crypto_probe_luks,
73
.bdrv_open = &raw_open,
74
.bdrv_close = &raw_close,
75
+ .bdrv_child_perm = bdrv_filter_default_perms,
76
.bdrv_create = &raw_create,
77
.bdrv_co_preadv = &raw_co_preadv,
78
.bdrv_co_pwritev = &raw_co_pwritev,
79
diff --git a/block/replication.c b/block/replication.c
37
diff --git a/block/replication.c b/block/replication.c
80
index XXXXXXX..XXXXXXX 100644
38
index XXXXXXX..XXXXXXX 100644
81
--- a/block/replication.c
39
--- a/block/replication.c
82
+++ b/block/replication.c
40
+++ b/block/replication.c
83
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_replication = {
41
@@ -XXX,XX +XXX,XX @@ static const char *const replication_strong_runtime_opts[] = {
84
42
NULL
85
.bdrv_open = replication_open,
43
};
86
.bdrv_close = replication_close,
44
87
+ .bdrv_child_perm = bdrv_filter_default_perms,
45
-BlockDriver bdrv_replication = {
88
46
+static BlockDriver bdrv_replication = {
89
.bdrv_getlength = replication_getlength,
47
.format_name = "replication",
90
.bdrv_co_readv = replication_co_readv,
48
.instance_size = sizeof(BDRVReplicationState),
49
91
--
50
--
92
1.8.3.1
51
2.20.1
93
52
94
53
diff view generated by jsdifflib
1
From: Peter Lieven <pl@kamp.de>
1
From: Max Reitz <mreitz@redhat.com>
2
2
3
the convert process is currently completely implemented with sync operations.
3
There is no reason why the constraints we put on @replaces should be
4
That means it reads one buffer and then writes it. No parallelism and each sync
4
limited to drive-mirror. Therefore, move the sanity checks from
5
request takes as long as it takes until it is completed.
5
qmp_drive_mirror() to blockdev_mirror_common() so they apply to
6
blockdev-mirror as well.
6
7
7
This can be a big performance hit when the convert process reads and writes
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
to devices which do not benefit from kernel readahead or pagecache.
9
Reviewed-by: Eric Blake <eblake@redhat.com>
9
In our environment we heavily have the following two use cases when using
10
Reviewed-by: Alberto Garcia <berto@igalia.com>
10
qemu-img convert.
11
12
a) reading from NFS and writing to iSCSI for deploying templates
13
b) reading from iSCSI and writing to NFS for backups
14
15
In both processes we use libiscsi and libnfs so we have no kernel cache.
16
17
This patch changes the convert process to work with parallel running coroutines
18
which can significantly improve performance for network storage devices:
19
20
qemu-img (master)
21
nfs -> iscsi 22.8 secs
22
nfs -> ram 11.7 secs
23
ram -> iscsi 12.3 secs
24
25
qemu-img-async (8 coroutines, in-order write disabled)
26
nfs -> iscsi 11.0 secs
27
nfs -> ram 10.4 secs
28
ram -> iscsi 9.0 secs
29
30
This patches introduces 2 new cmdline parameters. The -m parameter to specify
31
the number of coroutines running in parallel (defaults to 8). And the -W parameter to
32
allow qemu-img to write to the target out of order rather than sequential. This improves
33
performance as the writes do not have to wait for each other to complete.
34
35
Signed-off-by: Peter Lieven <pl@kamp.de>
36
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
37
---
12
---
38
qemu-img-cmds.hx | 4 +-
13
blockdev.c | 55 ++++++++++++++++++++++++++++++++----------------------
39
qemu-img.c | 322 ++++++++++++++++++++++++++++++++++++++-----------------
14
1 file changed, 33 insertions(+), 22 deletions(-)
40
qemu-img.texi | 16 ++-
41
3 files changed, 243 insertions(+), 99 deletions(-)
42
15
43
diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx
16
diff --git a/blockdev.c b/blockdev.c
44
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
45
--- a/qemu-img-cmds.hx
18
--- a/blockdev.c
46
+++ b/qemu-img-cmds.hx
19
+++ b/blockdev.c
47
@@ -XXX,XX +XXX,XX @@ STEXI
20
@@ -XXX,XX +XXX,XX @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs,
48
ETEXI
21
sync = MIRROR_SYNC_MODE_FULL;
49
22
}
50
DEF("convert", img_convert,
23
51
- "convert [--object objectdef] [--image-opts] [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-o options] [-s snapshot_id_or_name] [-l snapshot_param] [-S sparse_size] filename [filename2 [...]] output_filename")
24
+ if (has_replaces) {
52
+ "convert [--object objectdef] [--image-opts] [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-o options] [-s snapshot_id_or_name] [-l snapshot_param] [-S sparse_size] [-m num_coroutines] [-W] filename [filename2 [...]] output_filename")
25
+ BlockDriverState *to_replace_bs;
53
STEXI
26
+ AioContext *replace_aio_context;
54
-@item convert [--object @var{objectdef}] [--image-opts] [-c] [-p] [-q] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_id_or_name}] [-l @var{snapshot_param}] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename}
27
+ int64_t bs_size, replace_size;
55
+@item convert [--object @var{objectdef}] [--image-opts] [-c] [-p] [-q] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_id_or_name}] [-l @var{snapshot_param}] [-S @var{sparse_size}] [-m @var{num_coroutines}] [-W] @var{filename} [@var{filename2} [...]] @var{output_filename}
56
ETEXI
57
58
DEF("dd", img_dd,
59
diff --git a/qemu-img.c b/qemu-img.c
60
index XXXXXXX..XXXXXXX 100644
61
--- a/qemu-img.c
62
+++ b/qemu-img.c
63
@@ -XXX,XX +XXX,XX @@ static void QEMU_NORETURN help(void)
64
" kinds of errors, with a higher risk of choosing the wrong fix or\n"
65
" hiding corruption that has already occurred.\n"
66
"\n"
67
+ "Parameters to convert subcommand:\n"
68
+ " '-m' specifies how many coroutines work in parallel during the convert\n"
69
+ " process (defaults to 8)\n"
70
+ " '-W' allow to write to the target out of order rather than sequential\n"
71
+ "\n"
72
"Parameters to snapshot subcommand:\n"
73
" 'snapshot' is the name of the snapshot to create, apply or delete\n"
74
" '-a' applies a snapshot (revert disk to saved state)\n"
75
@@ -XXX,XX +XXX,XX @@ enum ImgConvertBlockStatus {
76
BLK_BACKING_FILE,
77
};
78
79
+#define MAX_COROUTINES 16
80
+
28
+
81
typedef struct ImgConvertState {
29
+ bs_size = bdrv_getlength(bs);
82
BlockBackend **src;
30
+ if (bs_size < 0) {
83
int64_t *src_sectors;
31
+ error_setg_errno(errp, -bs_size, "Failed to query device's size");
84
- int src_cur, src_num;
32
+ return;
85
- int64_t src_cur_offset;
86
+ int src_num;
87
int64_t total_sectors;
88
int64_t allocated_sectors;
89
+ int64_t allocated_done;
90
+ int64_t sector_num;
91
+ int64_t wr_offs;
92
enum ImgConvertBlockStatus status;
93
int64_t sector_next_status;
94
BlockBackend *target;
95
bool has_zero_init;
96
bool compressed;
97
bool target_has_backing;
98
+ bool wr_in_order;
99
int min_sparse;
100
size_t cluster_sectors;
101
size_t buf_sectors;
102
+ int num_coroutines;
103
+ int running_coroutines;
104
+ Coroutine *co[MAX_COROUTINES];
105
+ int64_t wait_sector_num[MAX_COROUTINES];
106
+ CoMutex lock;
107
+ int ret;
108
} ImgConvertState;
109
110
-static void convert_select_part(ImgConvertState *s, int64_t sector_num)
111
+static void convert_select_part(ImgConvertState *s, int64_t sector_num,
112
+ int *src_cur, int64_t *src_cur_offset)
113
{
114
- assert(sector_num >= s->src_cur_offset);
115
- while (sector_num - s->src_cur_offset >= s->src_sectors[s->src_cur]) {
116
- s->src_cur_offset += s->src_sectors[s->src_cur];
117
- s->src_cur++;
118
- assert(s->src_cur < s->src_num);
119
+ *src_cur = 0;
120
+ *src_cur_offset = 0;
121
+ while (sector_num - *src_cur_offset >= s->src_sectors[*src_cur]) {
122
+ *src_cur_offset += s->src_sectors[*src_cur];
123
+ (*src_cur)++;
124
+ assert(*src_cur < s->src_num);
125
}
126
}
127
128
static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num)
129
{
130
- int64_t ret;
131
- int n;
132
+ int64_t ret, src_cur_offset;
133
+ int n, src_cur;
134
135
- convert_select_part(s, sector_num);
136
+ convert_select_part(s, sector_num, &src_cur, &src_cur_offset);
137
138
assert(s->total_sectors > sector_num);
139
n = MIN(s->total_sectors - sector_num, BDRV_REQUEST_MAX_SECTORS);
140
141
if (s->sector_next_status <= sector_num) {
142
BlockDriverState *file;
143
- ret = bdrv_get_block_status(blk_bs(s->src[s->src_cur]),
144
- sector_num - s->src_cur_offset,
145
+ ret = bdrv_get_block_status(blk_bs(s->src[src_cur]),
146
+ sector_num - src_cur_offset,
147
n, &n, &file);
148
if (ret < 0) {
149
return ret;
150
@@ -XXX,XX +XXX,XX @@ static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num)
151
/* Check block status of the backing file chain to avoid
152
* needlessly reading zeroes and limiting the iteration to the
153
* buffer size */
154
- ret = bdrv_get_block_status_above(blk_bs(s->src[s->src_cur]), NULL,
155
- sector_num - s->src_cur_offset,
156
+ ret = bdrv_get_block_status_above(blk_bs(s->src[src_cur]), NULL,
157
+ sector_num - src_cur_offset,
158
n, &n, &file);
159
if (ret < 0) {
160
return ret;
161
@@ -XXX,XX +XXX,XX @@ static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num)
162
return n;
163
}
164
165
-static int convert_read(ImgConvertState *s, int64_t sector_num, int nb_sectors,
166
- uint8_t *buf)
167
+static int coroutine_fn convert_co_read(ImgConvertState *s, int64_t sector_num,
168
+ int nb_sectors, uint8_t *buf)
169
{
170
- int n;
171
- int ret;
172
+ int n, ret;
173
+ QEMUIOVector qiov;
174
+ struct iovec iov;
175
176
assert(nb_sectors <= s->buf_sectors);
177
while (nb_sectors > 0) {
178
BlockBackend *blk;
179
- int64_t bs_sectors;
180
+ int src_cur;
181
+ int64_t bs_sectors, src_cur_offset;
182
183
/* In the case of compression with multiple source files, we can get a
184
* nb_sectors that spreads into the next part. So we must be able to
185
* read across multiple BDSes for one convert_read() call. */
186
- convert_select_part(s, sector_num);
187
- blk = s->src[s->src_cur];
188
- bs_sectors = s->src_sectors[s->src_cur];
189
-
190
- n = MIN(nb_sectors, bs_sectors - (sector_num - s->src_cur_offset));
191
- ret = blk_pread(blk,
192
- (sector_num - s->src_cur_offset) << BDRV_SECTOR_BITS,
193
- buf, n << BDRV_SECTOR_BITS);
194
+ convert_select_part(s, sector_num, &src_cur, &src_cur_offset);
195
+ blk = s->src[src_cur];
196
+ bs_sectors = s->src_sectors[src_cur];
197
+
198
+ n = MIN(nb_sectors, bs_sectors - (sector_num - src_cur_offset));
199
+ iov.iov_base = buf;
200
+ iov.iov_len = n << BDRV_SECTOR_BITS;
201
+ qemu_iovec_init_external(&qiov, &iov, 1);
202
+
203
+ ret = blk_co_preadv(
204
+ blk, (sector_num - src_cur_offset) << BDRV_SECTOR_BITS,
205
+ n << BDRV_SECTOR_BITS, &qiov, 0);
206
if (ret < 0) {
207
return ret;
208
}
209
@@ -XXX,XX +XXX,XX @@ static int convert_read(ImgConvertState *s, int64_t sector_num, int nb_sectors,
210
return 0;
211
}
212
213
-static int convert_write(ImgConvertState *s, int64_t sector_num, int nb_sectors,
214
- const uint8_t *buf)
215
+
216
+static int coroutine_fn convert_co_write(ImgConvertState *s, int64_t sector_num,
217
+ int nb_sectors, uint8_t *buf,
218
+ enum ImgConvertBlockStatus status)
219
{
220
int ret;
221
+ QEMUIOVector qiov;
222
+ struct iovec iov;
223
224
while (nb_sectors > 0) {
225
int n = nb_sectors;
226
-
227
- switch (s->status) {
228
+ switch (status) {
229
case BLK_BACKING_FILE:
230
/* If we have a backing file, leave clusters unallocated that are
231
* unallocated in the source image, so that the backing file is
232
@@ -XXX,XX +XXX,XX @@ static int convert_write(ImgConvertState *s, int64_t sector_num, int nb_sectors,
233
break;
234
}
235
236
- ret = blk_pwrite_compressed(s->target,
237
- sector_num << BDRV_SECTOR_BITS,
238
- buf, n << BDRV_SECTOR_BITS);
239
+ iov.iov_base = buf;
240
+ iov.iov_len = n << BDRV_SECTOR_BITS;
241
+ qemu_iovec_init_external(&qiov, &iov, 1);
242
+
243
+ ret = blk_co_pwritev(s->target, sector_num << BDRV_SECTOR_BITS,
244
+ n << BDRV_SECTOR_BITS, &qiov,
245
+ BDRV_REQ_WRITE_COMPRESSED);
246
if (ret < 0) {
247
return ret;
248
}
249
@@ -XXX,XX +XXX,XX @@ static int convert_write(ImgConvertState *s, int64_t sector_num, int nb_sectors,
250
if (!s->min_sparse ||
251
is_allocated_sectors_min(buf, n, &n, s->min_sparse))
252
{
253
- ret = blk_pwrite(s->target, sector_num << BDRV_SECTOR_BITS,
254
- buf, n << BDRV_SECTOR_BITS, 0);
255
+ iov.iov_base = buf;
256
+ iov.iov_len = n << BDRV_SECTOR_BITS;
257
+ qemu_iovec_init_external(&qiov, &iov, 1);
258
+
259
+ ret = blk_co_pwritev(s->target, sector_num << BDRV_SECTOR_BITS,
260
+ n << BDRV_SECTOR_BITS, &qiov, 0);
261
if (ret < 0) {
262
return ret;
263
}
264
@@ -XXX,XX +XXX,XX @@ static int convert_write(ImgConvertState *s, int64_t sector_num, int nb_sectors,
265
if (s->has_zero_init) {
266
break;
267
}
268
- ret = blk_pwrite_zeroes(s->target, sector_num << BDRV_SECTOR_BITS,
269
- n << BDRV_SECTOR_BITS, 0);
270
+ ret = blk_co_pwrite_zeroes(s->target,
271
+ sector_num << BDRV_SECTOR_BITS,
272
+ n << BDRV_SECTOR_BITS, 0);
273
if (ret < 0) {
274
return ret;
275
}
276
@@ -XXX,XX +XXX,XX @@ static int convert_write(ImgConvertState *s, int64_t sector_num, int nb_sectors,
277
return 0;
278
}
279
280
-static int convert_do_copy(ImgConvertState *s)
281
+static void coroutine_fn convert_co_do_copy(void *opaque)
282
{
283
+ ImgConvertState *s = opaque;
284
uint8_t *buf = NULL;
285
- int64_t sector_num, allocated_done;
286
- int ret;
287
- int n;
288
+ int ret, i;
289
+ int index = -1;
290
+
291
+ for (i = 0; i < s->num_coroutines; i++) {
292
+ if (s->co[i] == qemu_coroutine_self()) {
293
+ index = i;
294
+ break;
295
+ }
296
+ }
297
+ assert(index >= 0);
298
+
299
+ s->running_coroutines++;
300
+ buf = blk_blockalign(s->target, s->buf_sectors * BDRV_SECTOR_SIZE);
301
+
302
+ while (1) {
303
+ int n;
304
+ int64_t sector_num;
305
+ enum ImgConvertBlockStatus status;
306
+
307
+ qemu_co_mutex_lock(&s->lock);
308
+ if (s->ret != -EINPROGRESS || s->sector_num >= s->total_sectors) {
309
+ qemu_co_mutex_unlock(&s->lock);
310
+ goto out;
311
+ }
312
+ n = convert_iteration_sectors(s, s->sector_num);
313
+ if (n < 0) {
314
+ qemu_co_mutex_unlock(&s->lock);
315
+ s->ret = n;
316
+ goto out;
317
+ }
318
+ /* save current sector and allocation status to local variables */
319
+ sector_num = s->sector_num;
320
+ status = s->status;
321
+ if (!s->min_sparse && s->status == BLK_ZERO) {
322
+ n = MIN(n, s->buf_sectors);
323
+ }
324
+ /* increment global sector counter so that other coroutines can
325
+ * already continue reading beyond this request */
326
+ s->sector_num += n;
327
+ qemu_co_mutex_unlock(&s->lock);
328
+
329
+ if (status == BLK_DATA || (!s->min_sparse && status == BLK_ZERO)) {
330
+ s->allocated_done += n;
331
+ qemu_progress_print(100.0 * s->allocated_done /
332
+ s->allocated_sectors, 0);
333
+ }
33
+ }
334
+
34
+
335
+ if (status == BLK_DATA) {
35
+ to_replace_bs = check_to_replace_node(bs, replaces, errp);
336
+ ret = convert_co_read(s, sector_num, n, buf);
36
+ if (!to_replace_bs) {
337
+ if (ret < 0) {
37
+ return;
338
+ error_report("error while reading sector %" PRId64
339
+ ": %s", sector_num, strerror(-ret));
340
+ s->ret = ret;
341
+ goto out;
342
+ }
343
+ } else if (!s->min_sparse && status == BLK_ZERO) {
344
+ status = BLK_DATA;
345
+ memset(buf, 0x00, n * BDRV_SECTOR_SIZE);
346
+ }
38
+ }
347
+
39
+
348
+ if (s->wr_in_order) {
40
+ replace_aio_context = bdrv_get_aio_context(to_replace_bs);
349
+ /* keep writes in order */
41
+ aio_context_acquire(replace_aio_context);
350
+ while (s->wr_offs != sector_num) {
42
+ replace_size = bdrv_getlength(to_replace_bs);
351
+ if (s->ret != -EINPROGRESS) {
43
+ aio_context_release(replace_aio_context);
352
+ goto out;
44
+
353
+ }
45
+ if (replace_size < 0) {
354
+ s->wait_sector_num[index] = sector_num;
46
+ error_setg_errno(errp, -replace_size,
355
+ qemu_coroutine_yield();
47
+ "Failed to query the replacement node's size");
356
+ }
48
+ return;
357
+ s->wait_sector_num[index] = -1;
358
+ }
49
+ }
359
+
50
+ if (bs_size != replace_size) {
360
+ ret = convert_co_write(s, sector_num, n, buf, status);
51
+ error_setg(errp, "cannot replace image with a mirror image of "
361
+ if (ret < 0) {
52
+ "different size");
362
+ error_report("error while writing sector %" PRId64
53
+ return;
363
+ ": %s", sector_num, strerror(-ret));
364
+ s->ret = ret;
365
+ goto out;
366
+ }
367
+
368
+ if (s->wr_in_order) {
369
+ /* reenter the coroutine that might have waited
370
+ * for this write to complete */
371
+ s->wr_offs = sector_num + n;
372
+ for (i = 0; i < s->num_coroutines; i++) {
373
+ if (s->co[i] && s->wait_sector_num[i] == s->wr_offs) {
374
+ /*
375
+ * A -> B -> A cannot occur because A has
376
+ * s->wait_sector_num[i] == -1 during A -> B. Therefore
377
+ * B will never enter A during this time window.
378
+ */
379
+ qemu_coroutine_enter(s->co[i]);
380
+ break;
381
+ }
382
+ }
383
+ }
54
+ }
384
+ }
55
+ }
385
+
56
+
386
+out:
57
/* pass the node name to replace to mirror start since it's loose coupling
387
+ qemu_vfree(buf);
58
* and will allow to check whether the node still exist at mirror completion
388
+ s->co[index] = NULL;
59
*/
389
+ s->running_coroutines--;
60
@@ -XXX,XX +XXX,XX @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
390
+ if (!s->running_coroutines && s->ret == -EINPROGRESS) {
61
}
391
+ /* the convert job finished successfully */
62
392
+ s->ret = 0;
63
if (arg->has_replaces) {
393
+ }
64
- BlockDriverState *to_replace_bs;
394
+}
65
- AioContext *replace_aio_context;
395
+
66
- int64_t replace_size;
396
+static int convert_do_copy(ImgConvertState *s)
67
-
397
+{
68
if (!arg->has_node_name) {
398
+ int ret, i, n;
69
error_setg(errp, "a node-name must be provided when replacing a"
399
+ int64_t sector_num = 0;
70
" named node of the graph");
400
71
goto out;
401
/* Check whether we have zero initialisation or can get it efficiently */
402
s->has_zero_init = s->min_sparse && !s->target_has_backing
403
@@ -XXX,XX +XXX,XX @@ static int convert_do_copy(ImgConvertState *s)
404
if (s->compressed) {
405
if (s->cluster_sectors <= 0 || s->cluster_sectors > s->buf_sectors) {
406
error_report("invalid cluster size");
407
- ret = -EINVAL;
408
- goto fail;
409
+ return -EINVAL;
410
}
72
}
411
s->buf_sectors = s->cluster_sectors;
412
}
413
- buf = blk_blockalign(s->target, s->buf_sectors * BDRV_SECTOR_SIZE);
414
415
- /* Calculate allocated sectors for progress */
416
- s->allocated_sectors = 0;
417
- sector_num = 0;
418
while (sector_num < s->total_sectors) {
419
n = convert_iteration_sectors(s, sector_num);
420
if (n < 0) {
421
- ret = n;
422
- goto fail;
423
+ return n;
424
}
425
if (s->status == BLK_DATA || (!s->min_sparse && s->status == BLK_ZERO))
426
{
427
@@ -XXX,XX +XXX,XX @@ static int convert_do_copy(ImgConvertState *s)
428
}
429
430
/* Do the copy */
431
- s->src_cur = 0;
432
- s->src_cur_offset = 0;
433
s->sector_next_status = 0;
434
+ s->ret = -EINPROGRESS;
435
436
- sector_num = 0;
437
- allocated_done = 0;
438
-
73
-
439
- while (sector_num < s->total_sectors) {
74
- to_replace_bs = check_to_replace_node(bs, arg->replaces, &local_err);
440
- n = convert_iteration_sectors(s, sector_num);
75
-
441
- if (n < 0) {
76
- if (!to_replace_bs) {
442
- ret = n;
77
- error_propagate(errp, local_err);
443
- goto fail;
78
- goto out;
444
- }
445
- if (s->status == BLK_DATA || (!s->min_sparse && s->status == BLK_ZERO))
446
- {
447
- allocated_done += n;
448
- qemu_progress_print(100.0 * allocated_done / s->allocated_sectors,
449
- 0);
450
- }
79
- }
451
-
80
-
452
- if (s->status == BLK_DATA) {
81
- replace_aio_context = bdrv_get_aio_context(to_replace_bs);
453
- ret = convert_read(s, sector_num, n, buf);
82
- aio_context_acquire(replace_aio_context);
454
- if (ret < 0) {
83
- replace_size = bdrv_getlength(to_replace_bs);
455
- error_report("error while reading sector %" PRId64
84
- aio_context_release(replace_aio_context);
456
- ": %s", sector_num, strerror(-ret));
85
-
457
- goto fail;
86
- if (size != replace_size) {
458
- }
87
- error_setg(errp, "cannot replace image with a mirror image of "
459
- } else if (!s->min_sparse && s->status == BLK_ZERO) {
88
- "different size");
460
- n = MIN(n, s->buf_sectors);
89
- goto out;
461
- memset(buf, 0, n * BDRV_SECTOR_SIZE);
462
- s->status = BLK_DATA;
463
- }
90
- }
464
-
465
- ret = convert_write(s, sector_num, n, buf);
466
- if (ret < 0) {
467
- error_report("error while writing sector %" PRId64
468
- ": %s", sector_num, strerror(-ret));
469
- goto fail;
470
- }
471
+ qemu_co_mutex_init(&s->lock);
472
+ for (i = 0; i < s->num_coroutines; i++) {
473
+ s->co[i] = qemu_coroutine_create(convert_co_do_copy, s);
474
+ s->wait_sector_num[i] = -1;
475
+ qemu_coroutine_enter(s->co[i]);
476
+ }
477
478
- sector_num += n;
479
+ while (s->ret == -EINPROGRESS) {
480
+ main_loop_wait(false);
481
}
91
}
482
92
483
- if (s->compressed) {
93
if (arg->mode == NEW_IMAGE_MODE_ABSOLUTE_PATHS) {
484
+ if (s->compressed && !s->ret) {
485
/* signal EOF to align */
486
ret = blk_pwrite_compressed(s->target, 0, NULL, 0);
487
if (ret < 0) {
488
- goto fail;
489
+ return ret;
490
}
491
}
492
493
- ret = 0;
494
-fail:
495
- qemu_vfree(buf);
496
- return ret;
497
+ return s->ret;
498
}
499
500
static int img_convert(int argc, char **argv)
501
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
502
QemuOpts *sn_opts = NULL;
503
ImgConvertState state;
504
bool image_opts = false;
505
+ bool wr_in_order = true;
506
+ long num_coroutines = 8;
507
508
fmt = NULL;
509
out_fmt = "raw";
510
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
511
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
512
{0, 0, 0, 0}
513
};
514
- c = getopt_long(argc, argv, "hf:O:B:ce6o:s:l:S:pt:T:qn",
515
+ c = getopt_long(argc, argv, "hf:O:B:ce6o:s:l:S:pt:T:qnm:W",
516
long_options, NULL);
517
if (c == -1) {
518
break;
519
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
520
case 'n':
521
skip_create = 1;
522
break;
523
+ case 'm':
524
+ if (qemu_strtol(optarg, NULL, 0, &num_coroutines) ||
525
+ num_coroutines < 1 || num_coroutines > MAX_COROUTINES) {
526
+ error_report("Invalid number of coroutines. Allowed number of"
527
+ " coroutines is between 1 and %d", MAX_COROUTINES);
528
+ ret = -1;
529
+ goto fail_getopt;
530
+ }
531
+ break;
532
+ case 'W':
533
+ wr_in_order = false;
534
+ break;
535
case OPTION_OBJECT:
536
opts = qemu_opts_parse_noisily(&qemu_object_opts,
537
optarg, true);
538
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
539
goto fail_getopt;
540
}
541
542
+ if (!wr_in_order && compress) {
543
+ error_report("Out of order write and compress are mutually exclusive");
544
+ ret = -1;
545
+ goto fail_getopt;
546
+ }
547
+
548
/* Initialize before goto out */
549
if (quiet) {
550
progress = 0;
551
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
552
.min_sparse = min_sparse,
553
.cluster_sectors = cluster_sectors,
554
.buf_sectors = bufsectors,
555
+ .wr_in_order = wr_in_order,
556
+ .num_coroutines = num_coroutines,
557
};
558
ret = convert_do_copy(&state);
559
560
diff --git a/qemu-img.texi b/qemu-img.texi
561
index XXXXXXX..XXXXXXX 100644
562
--- a/qemu-img.texi
563
+++ b/qemu-img.texi
564
@@ -XXX,XX +XXX,XX @@ Parameters to convert subcommand:
565
566
@item -n
567
Skip the creation of the target volume
568
+@item -m
569
+Number of parallel coroutines for the convert process
570
+@item -W
571
+Allow out-of-order writes to the destination. This option improves performance,
572
+but is only recommended for preallocated devices like host devices or other
573
+raw block devices.
574
@end table
575
576
Parameters to dd subcommand:
577
@@ -XXX,XX +XXX,XX @@ Error on reading data
578
579
@end table
580
581
-@item convert [-c] [-p] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_id_or_name}] [-l @var{snapshot_param}] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename}
582
+@item convert [-c] [-p] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_id_or_name}] [-l @var{snapshot_param}] [-m @var{num_coroutines}] [-W] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename}
583
584
Convert the disk image @var{filename} or a snapshot @var{snapshot_param}(@var{snapshot_id_or_name} is deprecated)
585
to disk image @var{output_filename} using format @var{output_fmt}. It can be optionally compressed (@code{-c}
586
@@ -XXX,XX +XXX,XX @@ skipped. This is useful for formats such as @code{rbd} if the target
587
volume has already been created with site specific options that cannot
588
be supplied through qemu-img.
589
590
+Out of order writes can be enabled with @code{-W} to improve performance.
591
+This is only recommended for preallocated devices like host devices or other
592
+raw block devices. Out of order write does not work in combination with
593
+creating compressed images.
594
+
595
+@var{num_coroutines} specifies how many coroutines work in parallel during
596
+the convert process (defaults to 8).
597
+
598
@item dd [-f @var{fmt}] [-O @var{output_fmt}] [bs=@var{block_size}] [count=@var{blocks}] [skip=@var{blocks}] if=@var{input} of=@var{output}
599
600
Dd copies from @var{input} file to @var{output} file converting it from
601
--
94
--
602
1.8.3.1
95
2.20.1
603
96
604
97
diff view generated by jsdifflib
Deleted patch
1
This patch defines the permission categories that will be used by the
2
new op blocker system.
3
1
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Acked-by: Fam Zheng <famz@redhat.com>
7
---
8
include/block/block.h | 36 ++++++++++++++++++++++++++++++++++++
9
1 file changed, 36 insertions(+)
10
11
diff --git a/include/block/block.h b/include/block/block.h
12
index XXXXXXX..XXXXXXX 100644
13
--- a/include/block/block.h
14
+++ b/include/block/block.h
15
@@ -XXX,XX +XXX,XX @@ typedef enum BlockOpType {
16
BLOCK_OP_TYPE_MAX,
17
} BlockOpType;
18
19
+/* Block node permission constants */
20
+enum {
21
+ /**
22
+ * A user that has the "permission" of consistent reads is guaranteed that
23
+ * their view of the contents of the block device is complete and
24
+ * self-consistent, representing the contents of a disk at a specific
25
+ * point.
26
+ *
27
+ * For most block devices (including their backing files) this is true, but
28
+ * the property cannot be maintained in a few situations like for
29
+ * intermediate nodes of a commit block job.
30
+ */
31
+ BLK_PERM_CONSISTENT_READ = 0x01,
32
+
33
+ /** This permission is required to change the visible disk contents. */
34
+ BLK_PERM_WRITE = 0x02,
35
+
36
+ /**
37
+ * This permission (which is weaker than BLK_PERM_WRITE) is both enough and
38
+ * required for writes to the block node when the caller promises that
39
+ * the visible disk content doesn't change.
40
+ */
41
+ BLK_PERM_WRITE_UNCHANGED = 0x04,
42
+
43
+ /** This permission is required to change the size of a block node. */
44
+ BLK_PERM_RESIZE = 0x08,
45
+
46
+ /**
47
+ * This permission is required to change the node that this BdrvChild
48
+ * points to.
49
+ */
50
+ BLK_PERM_GRAPH_MOD = 0x10,
51
+
52
+ BLK_PERM_ALL = 0x1f,
53
+};
54
+
55
/* disk I/O throttling */
56
void bdrv_init(void);
57
void bdrv_init_with_whitelist(void);
58
--
59
1.8.3.1
60
61
diff view generated by jsdifflib
Deleted patch
1
It will have to return an error soon, so prepare the callers for it.
2
1
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Reviewed-by: Max Reitz <mreitz@redhat.com>
5
Acked-by: Fam Zheng <famz@redhat.com>
6
---
7
block.c | 16 +++++++++++++---
8
block/quorum.c | 9 ++++++++-
9
include/block/block.h | 3 ++-
10
3 files changed, 23 insertions(+), 5 deletions(-)
11
12
diff --git a/block.c b/block.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/block.c
15
+++ b/block.c
16
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
17
BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
18
BlockDriverState *child_bs,
19
const char *child_name,
20
- const BdrvChildRole *child_role)
21
+ const BdrvChildRole *child_role,
22
+ Error **errp)
23
{
24
BdrvChild *child = bdrv_root_attach_child(child_bs, child_name, child_role,
25
parent_bs);
26
@@ -XXX,XX +XXX,XX @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd)
27
bs->backing = NULL;
28
goto out;
29
}
30
- bs->backing = bdrv_attach_child(bs, backing_hd, "backing", &child_backing);
31
+ /* FIXME Error handling */
32
+ bs->backing = bdrv_attach_child(bs, backing_hd, "backing", &child_backing,
33
+ &error_abort);
34
bs->open_flags &= ~BDRV_O_NO_BACKING;
35
pstrcpy(bs->backing_file, sizeof(bs->backing_file), backing_hd->filename);
36
pstrcpy(bs->backing_format, sizeof(bs->backing_format),
37
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_open_child(const char *filename,
38
const BdrvChildRole *child_role,
39
bool allow_none, Error **errp)
40
{
41
+ BdrvChild *c;
42
BlockDriverState *bs;
43
44
bs = bdrv_open_child_bs(filename, options, bdref_key, parent, child_role,
45
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_open_child(const char *filename,
46
return NULL;
47
}
48
49
- return bdrv_attach_child(parent, bs, bdref_key, child_role);
50
+ c = bdrv_attach_child(parent, bs, bdref_key, child_role, errp);
51
+ if (!c) {
52
+ bdrv_unref(bs);
53
+ return NULL;
54
+ }
55
+
56
+ return c;
57
}
58
59
static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs,
60
diff --git a/block/quorum.c b/block/quorum.c
61
index XXXXXXX..XXXXXXX 100644
62
--- a/block/quorum.c
63
+++ b/block/quorum.c
64
@@ -XXX,XX +XXX,XX @@ static void quorum_add_child(BlockDriverState *bs, BlockDriverState *child_bs,
65
66
/* We can safely add the child now */
67
bdrv_ref(child_bs);
68
- child = bdrv_attach_child(bs, child_bs, indexstr, &child_format);
69
+
70
+ child = bdrv_attach_child(bs, child_bs, indexstr, &child_format, errp);
71
+ if (child == NULL) {
72
+ s->next_child_index--;
73
+ bdrv_unref(child_bs);
74
+ goto out;
75
+ }
76
s->children = g_renew(BdrvChild *, s->children, s->num_children + 1);
77
s->children[s->num_children++] = child;
78
79
+out:
80
bdrv_drained_end(bs);
81
}
82
83
diff --git a/include/block/block.h b/include/block/block.h
84
index XXXXXXX..XXXXXXX 100644
85
--- a/include/block/block.h
86
+++ b/include/block/block.h
87
@@ -XXX,XX +XXX,XX @@ void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child);
88
BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
89
BlockDriverState *child_bs,
90
const char *child_name,
91
- const BdrvChildRole *child_role);
92
+ const BdrvChildRole *child_role,
93
+ Error **errp);
94
95
bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp);
96
void bdrv_op_block(BlockDriverState *bs, BlockOpType op, Error *reason);
97
--
98
1.8.3.1
99
100
diff view generated by jsdifflib
Deleted patch
1
When attaching a node as a child to a new parent, the required and
2
shared permissions for this parent are checked against all other parents
3
of the node now, and an error is returned if there is a conflict.
4
1
5
This allows error returns to a function that previously always
6
succeeded, and the same is true for quite a few callers and their
7
callers. Converting all of them within the same patch would be too much,
8
so for now everyone tells that they don't need any permissions and allow
9
everyone else to do anything. This way we can use &error_abort initially
10
and convert caller by caller to pass actual permission requirements and
11
implement error handling.
12
13
All these places are marked with FIXME comments and it will be the job
14
of the next patches to clean them up again.
15
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Reviewed-by: Max Reitz <mreitz@redhat.com>
18
Acked-by: Fam Zheng <famz@redhat.com>
19
---
20
block.c | 66 +++++++++++++++++++++++++++++++++++++++++------
21
block/block-backend.c | 8 ++++--
22
include/block/block_int.h | 15 ++++++++++-
23
3 files changed, 78 insertions(+), 11 deletions(-)
24
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 @@ static int bdrv_fill_options(QDict **options, const char *filename,
30
return 0;
31
}
32
33
+static int bdrv_check_update_perm(BlockDriverState *bs, uint64_t new_used_perm,
34
+ uint64_t new_shared_perm,
35
+ BdrvChild *ignore_child, Error **errp)
36
+{
37
+ BdrvChild *c;
38
+
39
+ /* There is no reason why anyone couldn't tolerate write_unchanged */
40
+ assert(new_shared_perm & BLK_PERM_WRITE_UNCHANGED);
41
+
42
+ QLIST_FOREACH(c, &bs->parents, next_parent) {
43
+ if (c == ignore_child) {
44
+ continue;
45
+ }
46
+
47
+ if ((new_used_perm & c->shared_perm) != new_used_perm ||
48
+ (c->perm & new_shared_perm) != c->perm)
49
+ {
50
+ const char *user = NULL;
51
+ if (c->role->get_name) {
52
+ user = c->role->get_name(c);
53
+ if (user && !*user) {
54
+ user = NULL;
55
+ }
56
+ }
57
+ error_setg(errp, "Conflicts with %s", user ?: "another operation");
58
+ return -EPERM;
59
+ }
60
+ }
61
+
62
+ return 0;
63
+}
64
+
65
static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs)
66
{
67
BlockDriverState *old_bs = child->bs;
68
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs)
69
BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
70
const char *child_name,
71
const BdrvChildRole *child_role,
72
- void *opaque)
73
+ uint64_t perm, uint64_t shared_perm,
74
+ void *opaque, Error **errp)
75
{
76
- BdrvChild *child = g_new(BdrvChild, 1);
77
+ BdrvChild *child;
78
+ int ret;
79
+
80
+ ret = bdrv_check_update_perm(child_bs, perm, shared_perm, NULL, errp);
81
+ if (ret < 0) {
82
+ return NULL;
83
+ }
84
+
85
+ child = g_new(BdrvChild, 1);
86
*child = (BdrvChild) {
87
- .bs = NULL,
88
- .name = g_strdup(child_name),
89
- .role = child_role,
90
- .opaque = opaque,
91
+ .bs = NULL,
92
+ .name = g_strdup(child_name),
93
+ .role = child_role,
94
+ .perm = perm,
95
+ .shared_perm = shared_perm,
96
+ .opaque = opaque,
97
};
98
99
bdrv_replace_child(child, child_bs);
100
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
101
const BdrvChildRole *child_role,
102
Error **errp)
103
{
104
- BdrvChild *child = bdrv_root_attach_child(child_bs, child_name, child_role,
105
- parent_bs);
106
+ BdrvChild *child;
107
+
108
+ /* FIXME Use real permissions */
109
+ child = bdrv_root_attach_child(child_bs, child_name, child_role,
110
+ 0, BLK_PERM_ALL, parent_bs, errp);
111
+ if (child == NULL) {
112
+ return NULL;
113
+ }
114
+
115
QLIST_INSERT_HEAD(&parent_bs->children, child, next);
116
return child;
117
}
118
diff --git a/block/block-backend.c b/block/block-backend.c
119
index XXXXXXX..XXXXXXX 100644
120
--- a/block/block-backend.c
121
+++ b/block/block-backend.c
122
@@ -XXX,XX +XXX,XX @@ BlockBackend *blk_new_open(const char *filename, const char *reference,
123
return NULL;
124
}
125
126
- blk->root = bdrv_root_attach_child(bs, "root", &child_root, blk);
127
+ /* FIXME Use real permissions */
128
+ blk->root = bdrv_root_attach_child(bs, "root", &child_root,
129
+ 0, BLK_PERM_ALL, blk, &error_abort);
130
131
return blk;
132
}
133
@@ -XXX,XX +XXX,XX @@ void blk_remove_bs(BlockBackend *blk)
134
void blk_insert_bs(BlockBackend *blk, BlockDriverState *bs)
135
{
136
bdrv_ref(bs);
137
- blk->root = bdrv_root_attach_child(bs, "root", &child_root, blk);
138
+ /* FIXME Use real permissions */
139
+ blk->root = bdrv_root_attach_child(bs, "root", &child_root,
140
+ 0, BLK_PERM_ALL, blk, &error_abort);
141
142
notifier_list_notify(&blk->insert_bs_notifiers, blk);
143
if (blk->public.throttle_state) {
144
diff --git a/include/block/block_int.h b/include/block/block_int.h
145
index XXXXXXX..XXXXXXX 100644
146
--- a/include/block/block_int.h
147
+++ b/include/block/block_int.h
148
@@ -XXX,XX +XXX,XX @@ struct BdrvChild {
149
char *name;
150
const BdrvChildRole *role;
151
void *opaque;
152
+
153
+ /**
154
+ * Granted permissions for operating on this BdrvChild (BLK_PERM_* bitmask)
155
+ */
156
+ uint64_t perm;
157
+
158
+ /**
159
+ * Permissions that can still be granted to other users of @bs while this
160
+ * BdrvChild is still attached to it. (BLK_PERM_* bitmask)
161
+ */
162
+ uint64_t shared_perm;
163
+
164
QLIST_ENTRY(BdrvChild) next;
165
QLIST_ENTRY(BdrvChild) next_parent;
166
};
167
@@ -XXX,XX +XXX,XX @@ void hmp_drive_add_node(Monitor *mon, const char *optstr);
168
BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
169
const char *child_name,
170
const BdrvChildRole *child_role,
171
- void *opaque);
172
+ uint64_t perm, uint64_t shared_perm,
173
+ void *opaque, Error **errp);
174
void bdrv_root_unref_child(BdrvChild *child);
175
176
const char *bdrv_get_parent_name(const BlockDriverState *bs);
177
--
178
1.8.3.1
179
180
diff view generated by jsdifflib
Deleted patch
1
In many cases, the required permissions of one node on its children
2
depend on what its parents require from it. For example, the raw format
3
or most filter drivers only need to request consistent reads if that's
4
something that one of their parents wants.
5
1
6
In order to achieve this, this patch introduces two new BlockDriver
7
callbacks. The first one lets drivers first check (recursively) whether
8
the requested permissions can be set; the second one actually sets the
9
new permission bitmask.
10
11
Also add helper functions that drivers can use in their implementation
12
of the callbacks to update their permissions on a specific child.
13
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
Acked-by: Fam Zheng <famz@redhat.com>
16
Reviewed-by: Max Reitz <mreitz@redhat.com>
17
---
18
block.c | 206 +++++++++++++++++++++++++++++++++++++++++++++-
19
include/block/block_int.h | 61 ++++++++++++++
20
2 files changed, 263 insertions(+), 4 deletions(-)
21
22
diff --git a/block.c b/block.c
23
index XXXXXXX..XXXXXXX 100644
24
--- a/block.c
25
+++ b/block.c
26
@@ -XXX,XX +XXX,XX @@ static int bdrv_fill_options(QDict **options, const char *filename,
27
return 0;
28
}
29
30
+/*
31
+ * Check whether permissions on this node can be changed in a way that
32
+ * @cumulative_perms and @cumulative_shared_perms are the new cumulative
33
+ * permissions of all its parents. This involves checking whether all necessary
34
+ * permission changes to child nodes can be performed.
35
+ *
36
+ * A call to this function must always be followed by a call to bdrv_set_perm()
37
+ * or bdrv_abort_perm_update().
38
+ */
39
+static int bdrv_check_perm(BlockDriverState *bs, uint64_t cumulative_perms,
40
+ uint64_t cumulative_shared_perms, Error **errp)
41
+{
42
+ BlockDriver *drv = bs->drv;
43
+ BdrvChild *c;
44
+ int ret;
45
+
46
+ /* Write permissions never work with read-only images */
47
+ if ((cumulative_perms & (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED)) &&
48
+ bdrv_is_read_only(bs))
49
+ {
50
+ error_setg(errp, "Block node is read-only");
51
+ return -EPERM;
52
+ }
53
+
54
+ /* Check this node */
55
+ if (!drv) {
56
+ return 0;
57
+ }
58
+
59
+ if (drv->bdrv_check_perm) {
60
+ return drv->bdrv_check_perm(bs, cumulative_perms,
61
+ cumulative_shared_perms, errp);
62
+ }
63
+
64
+ /* Drivers may not have .bdrv_child_perm() */
65
+ if (!drv->bdrv_child_perm) {
66
+ return 0;
67
+ }
68
+
69
+ /* Check all children */
70
+ QLIST_FOREACH(c, &bs->children, next) {
71
+ uint64_t cur_perm, cur_shared;
72
+ drv->bdrv_child_perm(bs, c, c->role,
73
+ cumulative_perms, cumulative_shared_perms,
74
+ &cur_perm, &cur_shared);
75
+ ret = bdrv_child_check_perm(c, cur_perm, cur_shared, errp);
76
+ if (ret < 0) {
77
+ return ret;
78
+ }
79
+ }
80
+
81
+ return 0;
82
+}
83
+
84
+/*
85
+ * Notifies drivers that after a previous bdrv_check_perm() call, the
86
+ * permission update is not performed and any preparations made for it (e.g.
87
+ * taken file locks) need to be undone.
88
+ *
89
+ * This function recursively notifies all child nodes.
90
+ */
91
+static void bdrv_abort_perm_update(BlockDriverState *bs)
92
+{
93
+ BlockDriver *drv = bs->drv;
94
+ BdrvChild *c;
95
+
96
+ if (!drv) {
97
+ return;
98
+ }
99
+
100
+ if (drv->bdrv_abort_perm_update) {
101
+ drv->bdrv_abort_perm_update(bs);
102
+ }
103
+
104
+ QLIST_FOREACH(c, &bs->children, next) {
105
+ bdrv_child_abort_perm_update(c);
106
+ }
107
+}
108
+
109
+static void bdrv_set_perm(BlockDriverState *bs, uint64_t cumulative_perms,
110
+ uint64_t cumulative_shared_perms)
111
+{
112
+ BlockDriver *drv = bs->drv;
113
+ BdrvChild *c;
114
+
115
+ if (!drv) {
116
+ return;
117
+ }
118
+
119
+ /* Update this node */
120
+ if (drv->bdrv_set_perm) {
121
+ drv->bdrv_set_perm(bs, cumulative_perms, cumulative_shared_perms);
122
+ }
123
+
124
+ /* Drivers may not have .bdrv_child_perm() */
125
+ if (!drv->bdrv_child_perm) {
126
+ return;
127
+ }
128
+
129
+ /* Update all children */
130
+ QLIST_FOREACH(c, &bs->children, next) {
131
+ uint64_t cur_perm, cur_shared;
132
+ drv->bdrv_child_perm(bs, c, c->role,
133
+ cumulative_perms, cumulative_shared_perms,
134
+ &cur_perm, &cur_shared);
135
+ bdrv_child_set_perm(c, cur_perm, cur_shared);
136
+ }
137
+}
138
+
139
+static void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm,
140
+ uint64_t *shared_perm)
141
+{
142
+ BdrvChild *c;
143
+ uint64_t cumulative_perms = 0;
144
+ uint64_t cumulative_shared_perms = BLK_PERM_ALL;
145
+
146
+ QLIST_FOREACH(c, &bs->parents, next_parent) {
147
+ cumulative_perms |= c->perm;
148
+ cumulative_shared_perms &= c->shared_perm;
149
+ }
150
+
151
+ *perm = cumulative_perms;
152
+ *shared_perm = cumulative_shared_perms;
153
+}
154
+
155
+/*
156
+ * Checks whether a new reference to @bs can be added if the new user requires
157
+ * @new_used_perm/@new_shared_perm as its permissions. If @ignore_child is set,
158
+ * this old reference is ignored in the calculations; this allows checking
159
+ * permission updates for an existing reference.
160
+ *
161
+ * Needs to be followed by a call to either bdrv_set_perm() or
162
+ * bdrv_abort_perm_update(). */
163
static int bdrv_check_update_perm(BlockDriverState *bs, uint64_t new_used_perm,
164
uint64_t new_shared_perm,
165
BdrvChild *ignore_child, Error **errp)
166
{
167
BdrvChild *c;
168
+ uint64_t cumulative_perms = new_used_perm;
169
+ uint64_t cumulative_shared_perms = new_shared_perm;
170
171
/* There is no reason why anyone couldn't tolerate write_unchanged */
172
assert(new_shared_perm & BLK_PERM_WRITE_UNCHANGED);
173
@@ -XXX,XX +XXX,XX @@ static int bdrv_check_update_perm(BlockDriverState *bs, uint64_t new_used_perm,
174
error_setg(errp, "Conflicts with %s", user ?: "another operation");
175
return -EPERM;
176
}
177
+
178
+ cumulative_perms |= c->perm;
179
+ cumulative_shared_perms &= c->shared_perm;
180
}
181
182
+ return bdrv_check_perm(bs, cumulative_perms, cumulative_shared_perms, errp);
183
+}
184
+
185
+/* Needs to be followed by a call to either bdrv_child_set_perm() or
186
+ * bdrv_child_abort_perm_update(). */
187
+int bdrv_child_check_perm(BdrvChild *c, uint64_t perm, uint64_t shared,
188
+ Error **errp)
189
+{
190
+ return bdrv_check_update_perm(c->bs, perm, shared, c, errp);
191
+}
192
+
193
+void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared)
194
+{
195
+ uint64_t cumulative_perms, cumulative_shared_perms;
196
+
197
+ c->perm = perm;
198
+ c->shared_perm = shared;
199
+
200
+ bdrv_get_cumulative_perm(c->bs, &cumulative_perms,
201
+ &cumulative_shared_perms);
202
+ bdrv_set_perm(c->bs, cumulative_perms, cumulative_shared_perms);
203
+}
204
+
205
+void bdrv_child_abort_perm_update(BdrvChild *c)
206
+{
207
+ bdrv_abort_perm_update(c->bs);
208
+}
209
+
210
+int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared,
211
+ Error **errp)
212
+{
213
+ int ret;
214
+
215
+ ret = bdrv_child_check_perm(c, perm, shared, errp);
216
+ if (ret < 0) {
217
+ bdrv_child_abort_perm_update(c);
218
+ return ret;
219
+ }
220
+
221
+ bdrv_child_set_perm(c, perm, shared);
222
+
223
return 0;
224
}
225
226
-static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs)
227
+static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs,
228
+ bool check_new_perm)
229
{
230
BlockDriverState *old_bs = child->bs;
231
+ uint64_t perm, shared_perm;
232
233
if (old_bs) {
234
if (old_bs->quiesce_counter && child->role->drained_end) {
235
child->role->drained_end(child);
236
}
237
QLIST_REMOVE(child, next_parent);
238
+
239
+ /* Update permissions for old node. This is guaranteed to succeed
240
+ * because we're just taking a parent away, so we're loosening
241
+ * restrictions. */
242
+ bdrv_get_cumulative_perm(old_bs, &perm, &shared_perm);
243
+ bdrv_check_perm(old_bs, perm, shared_perm, &error_abort);
244
+ bdrv_set_perm(old_bs, perm, shared_perm);
245
}
246
247
child->bs = new_bs;
248
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs)
249
if (new_bs->quiesce_counter && child->role->drained_begin) {
250
child->role->drained_begin(child);
251
}
252
+
253
+ bdrv_get_cumulative_perm(new_bs, &perm, &shared_perm);
254
+ if (check_new_perm) {
255
+ bdrv_check_perm(new_bs, perm, shared_perm, &error_abort);
256
+ }
257
+ bdrv_set_perm(new_bs, perm, shared_perm);
258
}
259
}
260
261
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
262
263
ret = bdrv_check_update_perm(child_bs, perm, shared_perm, NULL, errp);
264
if (ret < 0) {
265
+ bdrv_abort_perm_update(child_bs);
266
return NULL;
267
}
268
269
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
270
.opaque = opaque,
271
};
272
273
- bdrv_replace_child(child, child_bs);
274
+ /* This performs the matching bdrv_set_perm() for the above check. */
275
+ bdrv_replace_child(child, child_bs, false);
276
277
return child;
278
}
279
@@ -XXX,XX +XXX,XX @@ static void bdrv_detach_child(BdrvChild *child)
280
child->next.le_prev = NULL;
281
}
282
283
- bdrv_replace_child(child, NULL);
284
+ bdrv_replace_child(child, NULL, false);
285
286
g_free(child->name);
287
g_free(child);
288
@@ -XXX,XX +XXX,XX @@ static void change_parent_backing_link(BlockDriverState *from,
289
290
assert(c->role != &child_backing);
291
bdrv_ref(to);
292
- bdrv_replace_child(c, to);
293
+ /* FIXME Are we sure that bdrv_replace_child() can't run into
294
+ * &error_abort because of permissions? */
295
+ bdrv_replace_child(c, to, true);
296
bdrv_unref(from);
297
}
298
}
299
diff --git a/include/block/block_int.h b/include/block/block_int.h
300
index XXXXXXX..XXXXXXX 100644
301
--- a/include/block/block_int.h
302
+++ b/include/block/block_int.h
303
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
304
void (*bdrv_del_child)(BlockDriverState *parent, BdrvChild *child,
305
Error **errp);
306
307
+ /**
308
+ * Informs the block driver that a permission change is intended. The
309
+ * driver checks whether the change is permissible and may take other
310
+ * preparations for the change (e.g. get file system locks). This operation
311
+ * is always followed either by a call to either .bdrv_set_perm or
312
+ * .bdrv_abort_perm_update.
313
+ *
314
+ * Checks whether the requested set of cumulative permissions in @perm
315
+ * can be granted for accessing @bs and whether no other users are using
316
+ * permissions other than those given in @shared (both arguments take
317
+ * BLK_PERM_* bitmasks).
318
+ *
319
+ * If both conditions are met, 0 is returned. Otherwise, -errno is returned
320
+ * and errp is set to an error describing the conflict.
321
+ */
322
+ int (*bdrv_check_perm)(BlockDriverState *bs, uint64_t perm,
323
+ uint64_t shared, Error **errp);
324
+
325
+ /**
326
+ * Called to inform the driver that the set of cumulative set of used
327
+ * permissions for @bs has changed to @perm, and the set of sharable
328
+ * permission to @shared. The driver can use this to propagate changes to
329
+ * its children (i.e. request permissions only if a parent actually needs
330
+ * them).
331
+ *
332
+ * This function is only invoked after bdrv_check_perm(), so block drivers
333
+ * may rely on preparations made in their .bdrv_check_perm implementation.
334
+ */
335
+ void (*bdrv_set_perm)(BlockDriverState *bs, uint64_t perm, uint64_t shared);
336
+
337
+ /*
338
+ * Called to inform the driver that after a previous bdrv_check_perm()
339
+ * call, the permission update is not performed and any preparations made
340
+ * for it (e.g. taken file locks) need to be undone.
341
+ *
342
+ * This function can be called even for nodes that never saw a
343
+ * bdrv_check_perm() call. It is a no-op then.
344
+ */
345
+ void (*bdrv_abort_perm_update)(BlockDriverState *bs);
346
+
347
+ /**
348
+ * Returns in @nperm and @nshared the permissions that the driver for @bs
349
+ * needs on its child @c, based on the cumulative permissions requested by
350
+ * the parents in @parent_perm and @parent_shared.
351
+ *
352
+ * If @c is NULL, return the permissions for attaching a new child for the
353
+ * given @role.
354
+ */
355
+ void (*bdrv_child_perm)(BlockDriverState *bs, BdrvChild *c,
356
+ const BdrvChildRole *role,
357
+ uint64_t parent_perm, uint64_t parent_shared,
358
+ uint64_t *nperm, uint64_t *nshared);
359
+
360
QLIST_ENTRY(BlockDriver) list;
361
};
362
363
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
364
void *opaque, Error **errp);
365
void bdrv_root_unref_child(BdrvChild *child);
366
367
+int bdrv_child_check_perm(BdrvChild *c, uint64_t perm, uint64_t shared,
368
+ Error **errp);
369
+void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared);
370
+void bdrv_child_abort_perm_update(BdrvChild *c);
371
+int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared,
372
+ Error **errp);
373
+
374
+
375
const char *bdrv_get_parent_name(const BlockDriverState *bs);
376
void blk_dev_change_media_cb(BlockBackend *blk, bool load);
377
bool blk_dev_has_removable_media(BlockBackend *blk);
378
--
379
1.8.3.1
380
381
diff view generated by jsdifflib
Deleted patch
1
Most filters need permissions related to read and write for their
2
children, but only if the node has a parent that wants to use the same
3
operation on the filter. The same is true for resize.
4
1
5
This adds a default implementation that simply forwards all necessary
6
permissions to all children of the node and leaves the other permissions
7
unchanged.
8
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Acked-by: Fam Zheng <famz@redhat.com>
11
Reviewed-by: Max Reitz <mreitz@redhat.com>
12
---
13
block.c | 23 +++++++++++++++++++++++
14
include/block/block_int.h | 8 ++++++++
15
2 files changed, 31 insertions(+)
16
17
diff --git a/block.c b/block.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/block.c
20
+++ b/block.c
21
@@ -XXX,XX +XXX,XX @@ int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared,
22
return 0;
23
}
24
25
+#define DEFAULT_PERM_PASSTHROUGH (BLK_PERM_CONSISTENT_READ \
26
+ | BLK_PERM_WRITE \
27
+ | BLK_PERM_WRITE_UNCHANGED \
28
+ | BLK_PERM_RESIZE)
29
+#define DEFAULT_PERM_UNCHANGED (BLK_PERM_ALL & ~DEFAULT_PERM_PASSTHROUGH)
30
+
31
+void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c,
32
+ const BdrvChildRole *role,
33
+ uint64_t perm, uint64_t shared,
34
+ uint64_t *nperm, uint64_t *nshared)
35
+{
36
+ if (c == NULL) {
37
+ *nperm = perm & DEFAULT_PERM_PASSTHROUGH;
38
+ *nshared = (shared & DEFAULT_PERM_PASSTHROUGH) | DEFAULT_PERM_UNCHANGED;
39
+ return;
40
+ }
41
+
42
+ *nperm = (perm & DEFAULT_PERM_PASSTHROUGH) |
43
+ (c->perm & DEFAULT_PERM_UNCHANGED);
44
+ *nshared = (shared & DEFAULT_PERM_PASSTHROUGH) |
45
+ (c->shared_perm & DEFAULT_PERM_UNCHANGED);
46
+}
47
+
48
static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs,
49
bool check_new_perm)
50
{
51
diff --git a/include/block/block_int.h b/include/block/block_int.h
52
index XXXXXXX..XXXXXXX 100644
53
--- a/include/block/block_int.h
54
+++ b/include/block/block_int.h
55
@@ -XXX,XX +XXX,XX @@ void bdrv_child_abort_perm_update(BdrvChild *c);
56
int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared,
57
Error **errp);
58
59
+/* Default implementation for BlockDriver.bdrv_child_perm() that can be used by
60
+ * block filters: Forward CONSISTENT_READ, WRITE, WRITE_UNCHANGED and RESIZE to
61
+ * all children */
62
+void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c,
63
+ const BdrvChildRole *role,
64
+ uint64_t perm, uint64_t shared,
65
+ uint64_t *nperm, uint64_t *nshared);
66
+
67
68
const char *bdrv_get_parent_name(const BlockDriverState *bs);
69
void blk_dev_change_media_cb(BlockBackend *blk, bool load);
70
--
71
1.8.3.1
72
73
diff view generated by jsdifflib
Deleted patch
1
Almost all format drivers have the same characteristics as far as
2
permissions are concerned: They have one or more children for storing
3
their own data and, more importantly, metadata (can be written to and
4
grow even without external write requests, must be protected against
5
other writers and present consistent data) and optionally a backing file
6
(this is just data, so like for a filter, it only depends on what the
7
parent nodes need).
8
1
9
This provides a default implementation that can be shared by most of
10
our format drivers.
11
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Acked-by: Fam Zheng <famz@redhat.com>
14
Reviewed-by: Max Reitz <mreitz@redhat.com>
15
---
16
block.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
17
include/block/block_int.h | 8 ++++++++
18
2 files changed, 52 insertions(+)
19
20
diff --git a/block.c b/block.c
21
index XXXXXXX..XXXXXXX 100644
22
--- a/block.c
23
+++ b/block.c
24
@@ -XXX,XX +XXX,XX @@ void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c,
25
(c->shared_perm & DEFAULT_PERM_UNCHANGED);
26
}
27
28
+void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
29
+ const BdrvChildRole *role,
30
+ uint64_t perm, uint64_t shared,
31
+ uint64_t *nperm, uint64_t *nshared)
32
+{
33
+ bool backing = (role == &child_backing);
34
+ assert(role == &child_backing || role == &child_file);
35
+
36
+ if (!backing) {
37
+ /* Apart from the modifications below, the same permissions are
38
+ * forwarded and left alone as for filters */
39
+ bdrv_filter_default_perms(bs, c, role, perm, shared, &perm, &shared);
40
+
41
+ /* Format drivers may touch metadata even if the guest doesn't write */
42
+ if (!bdrv_is_read_only(bs)) {
43
+ perm |= BLK_PERM_WRITE | BLK_PERM_RESIZE;
44
+ }
45
+
46
+ /* bs->file always needs to be consistent because of the metadata. We
47
+ * can never allow other users to resize or write to it. */
48
+ perm |= BLK_PERM_CONSISTENT_READ;
49
+ shared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE);
50
+ } else {
51
+ /* We want consistent read from backing files if the parent needs it.
52
+ * No other operations are performed on backing files. */
53
+ perm &= BLK_PERM_CONSISTENT_READ;
54
+
55
+ /* If the parent can deal with changing data, we're okay with a
56
+ * writable and resizable backing file. */
57
+ /* TODO Require !(perm & BLK_PERM_CONSISTENT_READ), too? */
58
+ if (shared & BLK_PERM_WRITE) {
59
+ shared = BLK_PERM_WRITE | BLK_PERM_RESIZE;
60
+ } else {
61
+ shared = 0;
62
+ }
63
+
64
+ shared |= BLK_PERM_CONSISTENT_READ | BLK_PERM_GRAPH_MOD |
65
+ BLK_PERM_WRITE_UNCHANGED;
66
+ }
67
+
68
+ *nperm = perm;
69
+ *nshared = shared;
70
+}
71
+
72
static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs,
73
bool check_new_perm)
74
{
75
diff --git a/include/block/block_int.h b/include/block/block_int.h
76
index XXXXXXX..XXXXXXX 100644
77
--- a/include/block/block_int.h
78
+++ b/include/block/block_int.h
79
@@ -XXX,XX +XXX,XX @@ void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c,
80
uint64_t perm, uint64_t shared,
81
uint64_t *nperm, uint64_t *nshared);
82
83
+/* Default implementation for BlockDriver.bdrv_child_perm() that can be used by
84
+ * (non-raw) image formats: Like above for bs->backing, but for bs->file it
85
+ * requires WRITE | RESIZE for read-write images, always requires
86
+ * CONSISTENT_READ and doesn't share WRITE. */
87
+void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
88
+ const BdrvChildRole *role,
89
+ uint64_t perm, uint64_t shared,
90
+ uint64_t *nperm, uint64_t *nshared);
91
92
const char *bdrv_get_parent_name(const BlockDriverState *bs);
93
void blk_dev_change_media_cb(BlockBackend *blk, bool load);
94
--
95
1.8.3.1
96
97
diff view generated by jsdifflib
Deleted patch
1
vvfat is the last remaining driver that can have children, but doesn't
2
implement .bdrv_child_perm() yet. The default handlers aren't suitable
3
here, so let's implement a very simple driver-specific one that protects
4
the internal child from being used by other users as good as our
5
permissions permit.
6
1
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Acked-by: Fam Zheng <famz@redhat.com>
10
---
11
block.c | 2 +-
12
block/vvfat.c | 22 ++++++++++++++++++++++
13
include/block/block_int.h | 1 +
14
3 files changed, 24 insertions(+), 1 deletion(-)
15
16
diff --git a/block.c b/block.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/block.c
19
+++ b/block.c
20
@@ -XXX,XX +XXX,XX @@ static void bdrv_backing_options(int *child_flags, QDict *child_options,
21
*child_flags = flags;
22
}
23
24
-static const BdrvChildRole child_backing = {
25
+const BdrvChildRole child_backing = {
26
.inherit_options = bdrv_backing_options,
27
.drained_begin = bdrv_child_cb_drained_begin,
28
.drained_end = bdrv_child_cb_drained_end,
29
diff --git a/block/vvfat.c b/block/vvfat.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/block/vvfat.c
32
+++ b/block/vvfat.c
33
@@ -XXX,XX +XXX,XX @@ err:
34
return ret;
35
}
36
37
+static void vvfat_child_perm(BlockDriverState *bs, BdrvChild *c,
38
+ const BdrvChildRole *role,
39
+ uint64_t perm, uint64_t shared,
40
+ uint64_t *nperm, uint64_t *nshared)
41
+{
42
+ BDRVVVFATState *s = bs->opaque;
43
+
44
+ assert(c == s->qcow || role == &child_backing);
45
+
46
+ if (c == s->qcow) {
47
+ /* This is a private node, nobody should try to attach to it */
48
+ *nperm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE;
49
+ *nshared = BLK_PERM_WRITE_UNCHANGED;
50
+ } else {
51
+ /* The backing file is there so 'commit' can use it. vvfat doesn't
52
+ * access it in any way. */
53
+ *nperm = 0;
54
+ *nshared = BLK_PERM_ALL;
55
+ }
56
+}
57
+
58
static void vvfat_close(BlockDriverState *bs)
59
{
60
BDRVVVFATState *s = bs->opaque;
61
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_vvfat = {
62
.bdrv_file_open = vvfat_open,
63
.bdrv_refresh_limits = vvfat_refresh_limits,
64
.bdrv_close = vvfat_close,
65
+ .bdrv_child_perm = vvfat_child_perm,
66
67
.bdrv_co_preadv = vvfat_co_preadv,
68
.bdrv_co_pwritev = vvfat_co_pwritev,
69
diff --git a/include/block/block_int.h b/include/block/block_int.h
70
index XXXXXXX..XXXXXXX 100644
71
--- a/include/block/block_int.h
72
+++ b/include/block/block_int.h
73
@@ -XXX,XX +XXX,XX @@ struct BdrvChildRole {
74
75
extern const BdrvChildRole child_file;
76
extern const BdrvChildRole child_format;
77
+extern const BdrvChildRole child_backing;
78
79
struct BdrvChild {
80
BlockDriverState *bs;
81
--
82
1.8.3.1
83
84
diff view generated by jsdifflib
Deleted patch
1
All block drivers that can have child nodes implement .bdrv_child_perm()
2
now. Make this officially a requirement by asserting that only drivers
3
without children can omit .bdrv_child_perm().
4
1
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
Acked-by: Fam Zheng <famz@redhat.com>
8
---
9
block.c | 6 ++++--
10
1 file changed, 4 insertions(+), 2 deletions(-)
11
12
diff --git a/block.c b/block.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/block.c
15
+++ b/block.c
16
@@ -XXX,XX +XXX,XX @@ static int bdrv_check_perm(BlockDriverState *bs, uint64_t cumulative_perms,
17
cumulative_shared_perms, errp);
18
}
19
20
- /* Drivers may not have .bdrv_child_perm() */
21
+ /* Drivers that never have children can omit .bdrv_child_perm() */
22
if (!drv->bdrv_child_perm) {
23
+ assert(QLIST_EMPTY(&bs->children));
24
return 0;
25
}
26
27
@@ -XXX,XX +XXX,XX @@ static void bdrv_set_perm(BlockDriverState *bs, uint64_t cumulative_perms,
28
drv->bdrv_set_perm(bs, cumulative_perms, cumulative_shared_perms);
29
}
30
31
- /* Drivers may not have .bdrv_child_perm() */
32
+ /* Drivers that never have children can omit .bdrv_child_perm() */
33
if (!drv->bdrv_child_perm) {
34
+ assert(QLIST_EMPTY(&bs->children));
35
return;
36
}
37
38
--
39
1.8.3.1
40
41
diff view generated by jsdifflib
Deleted patch
1
Now that all block drivers with children tell us what permissions they
2
need from each of their children, bdrv_attach_child() can use this
3
information and make the right requirements while trying to attach new
4
children.
5
1
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Acked-by: Fam Zheng <famz@redhat.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
---
10
block.c | 10 ++++++++--
11
1 file changed, 8 insertions(+), 2 deletions(-)
12
13
diff --git a/block.c b/block.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/block.c
16
+++ b/block.c
17
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
18
Error **errp)
19
{
20
BdrvChild *child;
21
+ uint64_t perm, shared_perm;
22
+
23
+ bdrv_get_cumulative_perm(parent_bs, &perm, &shared_perm);
24
+
25
+ assert(parent_bs->drv);
26
+ parent_bs->drv->bdrv_child_perm(parent_bs, NULL, child_role,
27
+ perm, shared_perm, &perm, &shared_perm);
28
29
- /* FIXME Use real permissions */
30
child = bdrv_root_attach_child(child_bs, child_name, child_role,
31
- 0, BLK_PERM_ALL, parent_bs, errp);
32
+ perm, shared_perm, parent_bs, errp);
33
if (child == NULL) {
34
return NULL;
35
}
36
--
37
1.8.3.1
38
39
diff view generated by jsdifflib
Deleted patch
1
The BlockBackend can now store the permissions that its user requires.
2
This is necessary because nodes can be ejected from or inserted into a
3
BlockBackend and all of these operations must make sure that the user
4
still gets what it requested initially.
5
1
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Acked-by: Fam Zheng <famz@redhat.com>
9
---
10
block/block-backend.c | 27 +++++++++++++++++++++++++++
11
include/sysemu/block-backend.h | 2 ++
12
2 files changed, 29 insertions(+)
13
14
diff --git a/block/block-backend.c b/block/block-backend.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/block/block-backend.c
17
+++ b/block/block-backend.c
18
@@ -XXX,XX +XXX,XX @@ struct BlockBackend {
19
bool iostatus_enabled;
20
BlockDeviceIoStatus iostatus;
21
22
+ uint64_t perm;
23
+ uint64_t shared_perm;
24
+
25
bool allow_write_beyond_eof;
26
27
NotifierList remove_bs_notifiers, insert_bs_notifiers;
28
@@ -XXX,XX +XXX,XX @@ BlockBackend *blk_new(void)
29
30
blk = g_new0(BlockBackend, 1);
31
blk->refcnt = 1;
32
+ blk->perm = 0;
33
+ blk->shared_perm = BLK_PERM_ALL;
34
blk_set_enable_write_cache(blk, true);
35
36
qemu_co_queue_init(&blk->public.throttled_reqs[0]);
37
@@ -XXX,XX +XXX,XX @@ void blk_insert_bs(BlockBackend *blk, BlockDriverState *bs)
38
}
39
}
40
41
+/*
42
+ * Sets the permission bitmasks that the user of the BlockBackend needs.
43
+ */
44
+int blk_set_perm(BlockBackend *blk, uint64_t perm, uint64_t shared_perm,
45
+ Error **errp)
46
+{
47
+ int ret;
48
+
49
+ if (blk->root) {
50
+ ret = bdrv_child_try_set_perm(blk->root, perm, shared_perm, errp);
51
+ if (ret < 0) {
52
+ return ret;
53
+ }
54
+ }
55
+
56
+ blk->perm = perm;
57
+ blk->shared_perm = shared_perm;
58
+
59
+ return 0;
60
+}
61
+
62
static int blk_do_attach_dev(BlockBackend *blk, void *dev)
63
{
64
if (blk->dev) {
65
@@ -XXX,XX +XXX,XX @@ void blk_detach_dev(BlockBackend *blk, void *dev)
66
blk->dev_ops = NULL;
67
blk->dev_opaque = NULL;
68
blk->guest_block_size = 512;
69
+ blk_set_perm(blk, 0, BLK_PERM_ALL, &error_abort);
70
blk_unref(blk);
71
}
72
73
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
74
index XXXXXXX..XXXXXXX 100644
75
--- a/include/sysemu/block-backend.h
76
+++ b/include/sysemu/block-backend.h
77
@@ -XXX,XX +XXX,XX @@ void blk_remove_bs(BlockBackend *blk);
78
void blk_insert_bs(BlockBackend *blk, BlockDriverState *bs);
79
bool bdrv_has_blk(BlockDriverState *bs);
80
bool bdrv_is_root_node(BlockDriverState *bs);
81
+int blk_set_perm(BlockBackend *blk, uint64_t perm, uint64_t shared_perm,
82
+ Error **errp);
83
84
void blk_set_allow_write_beyond_eof(BlockBackend *blk, bool allow);
85
void blk_iostatus_enable(BlockBackend *blk);
86
--
87
1.8.3.1
88
89
diff view generated by jsdifflib
Deleted patch
1
Now that blk_insert_bs() requests the BlockBackend permissions for the
2
node it attaches to, it can fail. Instead of aborting, pass the errors
3
to the callers.
4
1
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
Acked-by: Fam Zheng <famz@redhat.com>
8
---
9
block.c | 5 ++++-
10
block/backup.c | 5 ++++-
11
block/block-backend.c | 13 ++++++++-----
12
block/commit.c | 38 ++++++++++++++++++++++++++++++--------
13
block/mirror.c | 15 ++++++++++++---
14
block/qcow2.c | 10 ++++++++--
15
blockdev.c | 11 +++++++++--
16
blockjob.c | 7 ++++++-
17
hmp.c | 6 +++++-
18
hw/core/qdev-properties-system.c | 7 ++++++-
19
include/sysemu/block-backend.h | 2 +-
20
migration/block.c | 2 +-
21
nbd/server.c | 6 +++++-
22
tests/test-blockjob.c | 2 +-
23
14 files changed, 100 insertions(+), 29 deletions(-)
24
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 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
30
}
31
if (file_bs != NULL) {
32
file = blk_new(BLK_PERM_CONSISTENT_READ, BLK_PERM_ALL);
33
- blk_insert_bs(file, file_bs);
34
+ blk_insert_bs(file, file_bs, &local_err);
35
bdrv_unref(file_bs);
36
+ if (local_err) {
37
+ goto fail;
38
+ }
39
40
qdict_put(options, "file",
41
qstring_from_str(bdrv_get_node_name(file_bs)));
42
diff --git a/block/backup.c b/block/backup.c
43
index XXXXXXX..XXXXXXX 100644
44
--- a/block/backup.c
45
+++ b/block/backup.c
46
@@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
47
48
/* FIXME Use real permissions */
49
job->target = blk_new(0, BLK_PERM_ALL);
50
- blk_insert_bs(job->target, target);
51
+ ret = blk_insert_bs(job->target, target, errp);
52
+ if (ret < 0) {
53
+ goto error;
54
+ }
55
56
job->on_source_error = on_source_error;
57
job->on_target_error = on_target_error;
58
diff --git a/block/block-backend.c b/block/block-backend.c
59
index XXXXXXX..XXXXXXX 100644
60
--- a/block/block-backend.c
61
+++ b/block/block-backend.c
62
@@ -XXX,XX +XXX,XX @@ void blk_remove_bs(BlockBackend *blk)
63
/*
64
* Associates a new BlockDriverState with @blk.
65
*/
66
-void blk_insert_bs(BlockBackend *blk, BlockDriverState *bs)
67
+int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp)
68
{
69
- bdrv_ref(bs);
70
- /* FIXME Error handling */
71
blk->root = bdrv_root_attach_child(bs, "root", &child_root,
72
- blk->perm, blk->shared_perm, blk,
73
- &error_abort);
74
+ blk->perm, blk->shared_perm, blk, errp);
75
+ if (blk->root == NULL) {
76
+ return -EPERM;
77
+ }
78
+ bdrv_ref(bs);
79
80
notifier_list_notify(&blk->insert_bs_notifiers, blk);
81
if (blk->public.throttle_state) {
82
throttle_timers_attach_aio_context(
83
&blk->public.throttle_timers, bdrv_get_aio_context(bs));
84
}
85
+
86
+ return 0;
87
}
88
89
/*
90
diff --git a/block/commit.c b/block/commit.c
91
index XXXXXXX..XXXXXXX 100644
92
--- a/block/commit.c
93
+++ b/block/commit.c
94
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
95
BlockDriverState *iter;
96
BlockDriverState *overlay_bs;
97
Error *local_err = NULL;
98
+ int ret;
99
100
assert(top != bs);
101
if (top == base) {
102
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
103
bdrv_reopen_multiple(bdrv_get_aio_context(bs), reopen_queue, &local_err);
104
if (local_err != NULL) {
105
error_propagate(errp, local_err);
106
- block_job_unref(&s->common);
107
- return;
108
+ goto fail;
109
}
110
}
111
112
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
113
114
/* FIXME Use real permissions */
115
s->base = blk_new(0, BLK_PERM_ALL);
116
- blk_insert_bs(s->base, base);
117
+ ret = blk_insert_bs(s->base, base, errp);
118
+ if (ret < 0) {
119
+ goto fail;
120
+ }
121
122
/* FIXME Use real permissions */
123
s->top = blk_new(0, BLK_PERM_ALL);
124
- blk_insert_bs(s->top, top);
125
+ ret = blk_insert_bs(s->top, top, errp);
126
+ if (ret < 0) {
127
+ goto fail;
128
+ }
129
130
s->active = bs;
131
132
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
133
134
trace_commit_start(bs, base, top, s);
135
block_job_start(&s->common);
136
+ return;
137
+
138
+fail:
139
+ if (s->base) {
140
+ blk_unref(s->base);
141
+ }
142
+ if (s->top) {
143
+ blk_unref(s->top);
144
+ }
145
+ block_job_unref(&s->common);
146
}
147
148
149
@@ -XXX,XX +XXX,XX @@ int bdrv_commit(BlockDriverState *bs)
150
151
/* FIXME Use real permissions */
152
src = blk_new(0, BLK_PERM_ALL);
153
- blk_insert_bs(src, bs);
154
-
155
- /* FIXME Use real permissions */
156
backing = blk_new(0, BLK_PERM_ALL);
157
- blk_insert_bs(backing, bs->backing->bs);
158
+
159
+ ret = blk_insert_bs(src, bs, NULL);
160
+ if (ret < 0) {
161
+ goto ro_cleanup;
162
+ }
163
+
164
+ ret = blk_insert_bs(backing, bs->backing->bs, NULL);
165
+ if (ret < 0) {
166
+ goto ro_cleanup;
167
+ }
168
169
length = blk_getlength(src);
170
if (length < 0) {
171
diff --git a/block/mirror.c b/block/mirror.c
172
index XXXXXXX..XXXXXXX 100644
173
--- a/block/mirror.c
174
+++ b/block/mirror.c
175
@@ -XXX,XX +XXX,XX @@ static void mirror_exit(BlockJob *job, void *opaque)
176
bdrv_replace_in_backing_chain(to_replace, target_bs);
177
bdrv_drained_end(target_bs);
178
179
- /* We just changed the BDS the job BB refers to */
180
+ /* We just changed the BDS the job BB refers to, so switch the BB back
181
+ * so the cleanup does the right thing. We don't need any permissions
182
+ * any more now. */
183
blk_remove_bs(job->blk);
184
- blk_insert_bs(job->blk, src);
185
+ blk_set_perm(job->blk, 0, BLK_PERM_ALL, &error_abort);
186
+ blk_insert_bs(job->blk, src, &error_abort);
187
}
188
if (s->to_replace) {
189
bdrv_op_unblock_all(s->to_replace, s->replace_blocker);
190
@@ -XXX,XX +XXX,XX @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
191
bool auto_complete)
192
{
193
MirrorBlockJob *s;
194
+ int ret;
195
196
if (granularity == 0) {
197
granularity = bdrv_get_default_bitmap_granularity(target);
198
@@ -XXX,XX +XXX,XX @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
199
200
/* FIXME Use real permissions */
201
s->target = blk_new(0, BLK_PERM_ALL);
202
- blk_insert_bs(s->target, target);
203
+ ret = blk_insert_bs(s->target, target, errp);
204
+ if (ret < 0) {
205
+ blk_unref(s->target);
206
+ block_job_unref(&s->common);
207
+ return;
208
+ }
209
210
s->replaces = g_strdup(replaces);
211
s->on_source_error = on_source_error;
212
diff --git a/block/qcow2.c b/block/qcow2.c
213
index XXXXXXX..XXXXXXX 100644
214
--- a/block/qcow2.c
215
+++ b/block/qcow2.c
216
@@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
217
uint64_t cluster_size = s->cluster_size;
218
bool encrypt;
219
int refcount_bits = s->refcount_bits;
220
+ Error *local_err = NULL;
221
int ret;
222
QemuOptDesc *desc = opts->list->desc;
223
Qcow2AmendHelperCBInfo helper_cb_info;
224
@@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
225
226
if (new_size) {
227
BlockBackend *blk = blk_new(BLK_PERM_RESIZE, BLK_PERM_ALL);
228
- blk_insert_bs(blk, bs);
229
+ ret = blk_insert_bs(blk, bs, &local_err);
230
+ if (ret < 0) {
231
+ error_report_err(local_err);
232
+ blk_unref(blk);
233
+ return ret;
234
+ }
235
+
236
ret = blk_truncate(blk, new_size);
237
blk_unref(blk);
238
-
239
if (ret < 0) {
240
return ret;
241
}
242
diff --git a/blockdev.c b/blockdev.c
243
index XXXXXXX..XXXXXXX 100644
244
--- a/blockdev.c
245
+++ b/blockdev.c
246
@@ -XXX,XX +XXX,XX @@ static void qmp_blockdev_insert_anon_medium(BlockBackend *blk,
247
BlockDriverState *bs, Error **errp)
248
{
249
bool has_device;
250
+ int ret;
251
252
/* For BBs without a device, we can exchange the BDS tree at will */
253
has_device = blk_get_attached_dev(blk);
254
@@ -XXX,XX +XXX,XX @@ static void qmp_blockdev_insert_anon_medium(BlockBackend *blk,
255
return;
256
}
257
258
- blk_insert_bs(blk, bs);
259
+ ret = blk_insert_bs(blk, bs, errp);
260
+ if (ret < 0) {
261
+ return;
262
+ }
263
264
if (!blk_dev_has_tray(blk)) {
265
/* For tray-less devices, blockdev-close-tray is a no-op (or may not be
266
@@ -XXX,XX +XXX,XX @@ void qmp_block_resize(bool has_device, const char *device,
267
}
268
269
blk = blk_new(BLK_PERM_RESIZE, BLK_PERM_ALL);
270
- blk_insert_bs(blk, bs);
271
+ ret = blk_insert_bs(blk, bs, errp);
272
+ if (ret < 0) {
273
+ goto out;
274
+ }
275
276
/* complete all in-flight operations before resizing the device */
277
bdrv_drain_all();
278
diff --git a/blockjob.c b/blockjob.c
279
index XXXXXXX..XXXXXXX 100644
280
--- a/blockjob.c
281
+++ b/blockjob.c
282
@@ -XXX,XX +XXX,XX @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
283
{
284
BlockBackend *blk;
285
BlockJob *job;
286
+ int ret;
287
288
if (bs->job) {
289
error_setg(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(bs));
290
@@ -XXX,XX +XXX,XX @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
291
292
/* FIXME Use real permissions */
293
blk = blk_new(0, BLK_PERM_ALL);
294
- blk_insert_bs(blk, bs);
295
+ ret = blk_insert_bs(blk, bs, errp);
296
+ if (ret < 0) {
297
+ blk_unref(blk);
298
+ return NULL;
299
+ }
300
301
job = g_malloc0(driver->instance_size);
302
error_setg(&job->blocker, "block device is in use by block job: %s",
303
diff --git a/hmp.c b/hmp.c
304
index XXXXXXX..XXXXXXX 100644
305
--- a/hmp.c
306
+++ b/hmp.c
307
@@ -XXX,XX +XXX,XX @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict)
308
const char* device = qdict_get_str(qdict, "device");
309
const char* command = qdict_get_str(qdict, "command");
310
Error *err = NULL;
311
+ int ret;
312
313
blk = blk_by_name(device);
314
if (!blk) {
315
@@ -XXX,XX +XXX,XX @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict)
316
if (bs) {
317
/* FIXME Use real permissions */
318
blk = local_blk = blk_new(0, BLK_PERM_ALL);
319
- blk_insert_bs(blk, bs);
320
+ ret = blk_insert_bs(blk, bs, &err);
321
+ if (ret < 0) {
322
+ goto fail;
323
+ }
324
} else {
325
goto fail;
326
}
327
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
328
index XXXXXXX..XXXXXXX 100644
329
--- a/hw/core/qdev-properties-system.c
330
+++ b/hw/core/qdev-properties-system.c
331
@@ -XXX,XX +XXX,XX @@ static void parse_drive(DeviceState *dev, const char *str, void **ptr,
332
{
333
BlockBackend *blk;
334
bool blk_created = false;
335
+ int ret;
336
337
blk = blk_by_name(str);
338
if (!blk) {
339
@@ -XXX,XX +XXX,XX @@ static void parse_drive(DeviceState *dev, const char *str, void **ptr,
340
if (bs) {
341
/* FIXME Use real permissions */
342
blk = blk_new(0, BLK_PERM_ALL);
343
- blk_insert_bs(blk, bs);
344
blk_created = true;
345
+
346
+ ret = blk_insert_bs(blk, bs, errp);
347
+ if (ret < 0) {
348
+ goto fail;
349
+ }
350
}
351
}
352
if (!blk) {
353
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
354
index XXXXXXX..XXXXXXX 100644
355
--- a/include/sysemu/block-backend.h
356
+++ b/include/sysemu/block-backend.h
357
@@ -XXX,XX +XXX,XX @@ BlockBackend *blk_by_public(BlockBackendPublic *public);
358
359
BlockDriverState *blk_bs(BlockBackend *blk);
360
void blk_remove_bs(BlockBackend *blk);
361
-void blk_insert_bs(BlockBackend *blk, BlockDriverState *bs);
362
+int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp);
363
bool bdrv_has_blk(BlockDriverState *bs);
364
bool bdrv_is_root_node(BlockDriverState *bs);
365
int blk_set_perm(BlockBackend *blk, uint64_t perm, uint64_t shared_perm,
366
diff --git a/migration/block.c b/migration/block.c
367
index XXXXXXX..XXXXXXX 100644
368
--- a/migration/block.c
369
+++ b/migration/block.c
370
@@ -XXX,XX +XXX,XX @@ static void init_blk_migration(QEMUFile *f)
371
BlockDriverState *bs = bmds_bs[i].bs;
372
373
if (bmds) {
374
- blk_insert_bs(bmds->blk, bs);
375
+ blk_insert_bs(bmds->blk, bs, &error_abort);
376
377
alloc_aio_bitmap(bmds);
378
error_setg(&bmds->blocker, "block device is in use by migration");
379
diff --git a/nbd/server.c b/nbd/server.c
380
index XXXXXXX..XXXXXXX 100644
381
--- a/nbd/server.c
382
+++ b/nbd/server.c
383
@@ -XXX,XX +XXX,XX @@ NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, off_t size,
384
{
385
BlockBackend *blk;
386
NBDExport *exp = g_malloc0(sizeof(NBDExport));
387
+ int ret;
388
389
/* FIXME Use real permissions */
390
blk = blk_new(0, BLK_PERM_ALL);
391
- blk_insert_bs(blk, bs);
392
+ ret = blk_insert_bs(blk, bs, errp);
393
+ if (ret < 0) {
394
+ goto fail;
395
+ }
396
blk_set_enable_write_cache(blk, !writethrough);
397
398
exp->refcount = 1;
399
diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c
400
index XXXXXXX..XXXXXXX 100644
401
--- a/tests/test-blockjob.c
402
+++ b/tests/test-blockjob.c
403
@@ -XXX,XX +XXX,XX @@ static BlockBackend *create_blk(const char *name)
404
bs = bdrv_open("null-co://", NULL, NULL, 0, &error_abort);
405
g_assert_nonnull(bs);
406
407
- blk_insert_bs(blk, bs);
408
+ blk_insert_bs(blk, bs, &error_abort);
409
bdrv_unref(bs);
410
411
if (name) {
412
--
413
1.8.3.1
414
415
diff view generated by jsdifflib
Deleted patch
1
blk_new_open() is a convenience function that processes flags rather
2
than QDict options as a simple way to just open an image file.
3
1
4
In order to keep it convenient in the future, it must automatically
5
request the necessary permissions. This can easily be inferred from the
6
flags for read and write, but we need another flag that tells us whether
7
to get the resize permission.
8
9
We can't just always request it because that means that no block jobs
10
can run on the resulting BlockBackend (which is something that e.g.
11
qemu-img commit wants to do), but we also can't request it never because
12
most of the .bdrv_create() implementations call blk_truncate().
13
14
The solution is to introduce another flag that is passed by all users
15
that want to resize the image.
16
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
Acked-by: Fam Zheng <famz@redhat.com>
19
Reviewed-by: Max Reitz <mreitz@redhat.com>
20
---
21
block/parallels.c | 3 ++-
22
block/qcow.c | 3 ++-
23
block/qcow2.c | 6 ++++--
24
block/qed.c | 3 ++-
25
block/sheepdog.c | 2 +-
26
block/vdi.c | 3 ++-
27
block/vhdx.c | 3 ++-
28
block/vmdk.c | 6 ++++--
29
block/vpc.c | 3 ++-
30
include/block/block.h | 1 +
31
qemu-img.c | 2 +-
32
11 files changed, 23 insertions(+), 12 deletions(-)
33
34
diff --git a/block/parallels.c b/block/parallels.c
35
index XXXXXXX..XXXXXXX 100644
36
--- a/block/parallels.c
37
+++ b/block/parallels.c
38
@@ -XXX,XX +XXX,XX @@ static int parallels_create(const char *filename, QemuOpts *opts, Error **errp)
39
}
40
41
file = blk_new_open(filename, NULL, NULL,
42
- BDRV_O_RDWR | BDRV_O_PROTOCOL, &local_err);
43
+ BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL,
44
+ &local_err);
45
if (file == NULL) {
46
error_propagate(errp, local_err);
47
return -EIO;
48
diff --git a/block/qcow.c b/block/qcow.c
49
index XXXXXXX..XXXXXXX 100644
50
--- a/block/qcow.c
51
+++ b/block/qcow.c
52
@@ -XXX,XX +XXX,XX @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp)
53
}
54
55
qcow_blk = blk_new_open(filename, NULL, NULL,
56
- BDRV_O_RDWR | BDRV_O_PROTOCOL, &local_err);
57
+ BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL,
58
+ &local_err);
59
if (qcow_blk == NULL) {
60
error_propagate(errp, local_err);
61
ret = -EIO;
62
diff --git a/block/qcow2.c b/block/qcow2.c
63
index XXXXXXX..XXXXXXX 100644
64
--- a/block/qcow2.c
65
+++ b/block/qcow2.c
66
@@ -XXX,XX +XXX,XX @@ static int qcow2_create2(const char *filename, int64_t total_size,
67
}
68
69
blk = blk_new_open(filename, NULL, NULL,
70
- BDRV_O_RDWR | BDRV_O_PROTOCOL, &local_err);
71
+ BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL,
72
+ &local_err);
73
if (blk == NULL) {
74
error_propagate(errp, local_err);
75
return -EIO;
76
@@ -XXX,XX +XXX,XX @@ static int qcow2_create2(const char *filename, int64_t total_size,
77
options = qdict_new();
78
qdict_put(options, "driver", qstring_from_str("qcow2"));
79
blk = blk_new_open(filename, NULL, options,
80
- BDRV_O_RDWR | BDRV_O_NO_FLUSH, &local_err);
81
+ BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_NO_FLUSH,
82
+ &local_err);
83
if (blk == NULL) {
84
error_propagate(errp, local_err);
85
ret = -EIO;
86
diff --git a/block/qed.c b/block/qed.c
87
index XXXXXXX..XXXXXXX 100644
88
--- a/block/qed.c
89
+++ b/block/qed.c
90
@@ -XXX,XX +XXX,XX @@ static int qed_create(const char *filename, uint32_t cluster_size,
91
}
92
93
blk = blk_new_open(filename, NULL, NULL,
94
- BDRV_O_RDWR | BDRV_O_PROTOCOL, &local_err);
95
+ BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL,
96
+ &local_err);
97
if (blk == NULL) {
98
error_propagate(errp, local_err);
99
return -EIO;
100
diff --git a/block/sheepdog.c b/block/sheepdog.c
101
index XXXXXXX..XXXXXXX 100644
102
--- a/block/sheepdog.c
103
+++ b/block/sheepdog.c
104
@@ -XXX,XX +XXX,XX @@ static int sd_prealloc(const char *filename, Error **errp)
105
int ret;
106
107
blk = blk_new_open(filename, NULL, NULL,
108
- BDRV_O_RDWR | BDRV_O_PROTOCOL, errp);
109
+ BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp);
110
if (blk == NULL) {
111
ret = -EIO;
112
goto out_with_err_set;
113
diff --git a/block/vdi.c b/block/vdi.c
114
index XXXXXXX..XXXXXXX 100644
115
--- a/block/vdi.c
116
+++ b/block/vdi.c
117
@@ -XXX,XX +XXX,XX @@ static int vdi_create(const char *filename, QemuOpts *opts, Error **errp)
118
}
119
120
blk = blk_new_open(filename, NULL, NULL,
121
- BDRV_O_RDWR | BDRV_O_PROTOCOL, &local_err);
122
+ BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL,
123
+ &local_err);
124
if (blk == NULL) {
125
error_propagate(errp, local_err);
126
ret = -EIO;
127
diff --git a/block/vhdx.c b/block/vhdx.c
128
index XXXXXXX..XXXXXXX 100644
129
--- a/block/vhdx.c
130
+++ b/block/vhdx.c
131
@@ -XXX,XX +XXX,XX @@ static int vhdx_create(const char *filename, QemuOpts *opts, Error **errp)
132
}
133
134
blk = blk_new_open(filename, NULL, NULL,
135
- BDRV_O_RDWR | BDRV_O_PROTOCOL, &local_err);
136
+ BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL,
137
+ &local_err);
138
if (blk == NULL) {
139
error_propagate(errp, local_err);
140
ret = -EIO;
141
diff --git a/block/vmdk.c b/block/vmdk.c
142
index XXXXXXX..XXXXXXX 100644
143
--- a/block/vmdk.c
144
+++ b/block/vmdk.c
145
@@ -XXX,XX +XXX,XX @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
146
}
147
148
blk = blk_new_open(filename, NULL, NULL,
149
- BDRV_O_RDWR | BDRV_O_PROTOCOL, &local_err);
150
+ BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL,
151
+ &local_err);
152
if (blk == NULL) {
153
error_propagate(errp, local_err);
154
ret = -EIO;
155
@@ -XXX,XX +XXX,XX @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp)
156
}
157
158
new_blk = blk_new_open(filename, NULL, NULL,
159
- BDRV_O_RDWR | BDRV_O_PROTOCOL, &local_err);
160
+ BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL,
161
+ &local_err);
162
if (new_blk == NULL) {
163
error_propagate(errp, local_err);
164
ret = -EIO;
165
diff --git a/block/vpc.c b/block/vpc.c
166
index XXXXXXX..XXXXXXX 100644
167
--- a/block/vpc.c
168
+++ b/block/vpc.c
169
@@ -XXX,XX +XXX,XX @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp)
170
}
171
172
blk = blk_new_open(filename, NULL, NULL,
173
- BDRV_O_RDWR | BDRV_O_PROTOCOL, &local_err);
174
+ BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL,
175
+ &local_err);
176
if (blk == NULL) {
177
error_propagate(errp, local_err);
178
ret = -EIO;
179
diff --git a/include/block/block.h b/include/block/block.h
180
index XXXXXXX..XXXXXXX 100644
181
--- a/include/block/block.h
182
+++ b/include/block/block.h
183
@@ -XXX,XX +XXX,XX @@ typedef struct HDGeometry {
184
} HDGeometry;
185
186
#define BDRV_O_RDWR 0x0002
187
+#define BDRV_O_RESIZE 0x0004 /* request permission for resizing the node */
188
#define BDRV_O_SNAPSHOT 0x0008 /* open the file read only and save writes in a snapshot */
189
#define BDRV_O_TEMPORARY 0x0010 /* delete the file after use */
190
#define BDRV_O_NOCACHE 0x0020 /* do not use the host page cache */
191
diff --git a/qemu-img.c b/qemu-img.c
192
index XXXXXXX..XXXXXXX 100644
193
--- a/qemu-img.c
194
+++ b/qemu-img.c
195
@@ -XXX,XX +XXX,XX @@ static int img_resize(int argc, char **argv)
196
qemu_opts_del(param);
197
198
blk = img_open(image_opts, filename, fmt,
199
- BDRV_O_RDWR, false, quiet);
200
+ BDRV_O_RDWR | BDRV_O_RESIZE, false, quiet);
201
if (!blk) {
202
ret = -1;
203
goto out;
204
--
205
1.8.3.1
206
207
diff view generated by jsdifflib
Deleted patch
1
We can figure out the necessary permissions from the flags that the
2
caller passed.
3
1
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Acked-by: Fam Zheng <famz@redhat.com>
7
---
8
block/block-backend.c | 22 +++++++++++++++++++---
9
1 file changed, 19 insertions(+), 3 deletions(-)
10
11
diff --git a/block/block-backend.c b/block/block-backend.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/block/block-backend.c
14
+++ b/block/block-backend.c
15
@@ -XXX,XX +XXX,XX @@ BlockBackend *blk_new_open(const char *filename, const char *reference,
16
{
17
BlockBackend *blk;
18
BlockDriverState *bs;
19
+ uint64_t perm;
20
+
21
+ /* blk_new_open() is mainly used in .bdrv_create implementations and the
22
+ * tools where sharing isn't a concern because the BDS stays private, so we
23
+ * just request permission according to the flags.
24
+ *
25
+ * The exceptions are xen_disk and blockdev_init(); in these cases, the
26
+ * caller of blk_new_open() doesn't make use of the permissions, but they
27
+ * shouldn't hurt either. We can still share everything here because the
28
+ * guest devices will add their own blockers if they can't share. */
29
+ perm = BLK_PERM_CONSISTENT_READ;
30
+ if (flags & BDRV_O_RDWR) {
31
+ perm |= BLK_PERM_WRITE;
32
+ }
33
+ if (flags & BDRV_O_RESIZE) {
34
+ perm |= BLK_PERM_RESIZE;
35
+ }
36
37
- blk = blk_new(0, BLK_PERM_ALL);
38
+ blk = blk_new(perm, BLK_PERM_ALL);
39
bs = bdrv_open(filename, reference, options, flags, errp);
40
if (!bs) {
41
blk_unref(blk);
42
return NULL;
43
}
44
45
- /* FIXME Use real permissions */
46
blk->root = bdrv_root_attach_child(bs, "root", &child_root,
47
- 0, BLK_PERM_ALL, blk, &error_abort);
48
+ perm, BLK_PERM_ALL, blk, &error_abort);
49
50
return blk;
51
}
52
--
53
1.8.3.1
54
55
diff view generated by jsdifflib
Deleted patch
1
Some devices allow a media change between read-only and read-write
2
media. They need to adapt the permissions in their .change_media_cb()
3
implementation, which can fail. So add an Error parameter to the
4
function.
5
1
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Acked-by: Fam Zheng <famz@redhat.com>
9
---
10
block/block-backend.c | 20 +++++++++++++++-----
11
blockdev.c | 19 +++++++++++++++----
12
hw/block/fdc.c | 2 +-
13
hw/ide/core.c | 2 +-
14
hw/scsi/scsi-disk.c | 2 +-
15
hw/sd/sd.c | 2 +-
16
include/block/block_int.h | 2 +-
17
include/sysemu/block-backend.h | 2 +-
18
8 files changed, 36 insertions(+), 15 deletions(-)
19
20
diff --git a/block/block-backend.c b/block/block-backend.c
21
index XXXXXXX..XXXXXXX 100644
22
--- a/block/block-backend.c
23
+++ b/block/block-backend.c
24
@@ -XXX,XX +XXX,XX @@ void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops,
25
26
/*
27
* Notify @blk's attached device model of media change.
28
- * If @load is true, notify of media load.
29
- * Else, notify of media eject.
30
+ *
31
+ * If @load is true, notify of media load. This action can fail, meaning that
32
+ * the medium cannot be loaded. @errp is set then.
33
+ *
34
+ * If @load is false, notify of media eject. This can never fail.
35
+ *
36
* Also send DEVICE_TRAY_MOVED events as appropriate.
37
*/
38
-void blk_dev_change_media_cb(BlockBackend *blk, bool load)
39
+void blk_dev_change_media_cb(BlockBackend *blk, bool load, Error **errp)
40
{
41
if (blk->dev_ops && blk->dev_ops->change_media_cb) {
42
bool tray_was_open, tray_is_open;
43
+ Error *local_err = NULL;
44
45
assert(!blk->legacy_dev);
46
47
tray_was_open = blk_dev_is_tray_open(blk);
48
- blk->dev_ops->change_media_cb(blk->dev_opaque, load);
49
+ blk->dev_ops->change_media_cb(blk->dev_opaque, load, &local_err);
50
+ if (local_err) {
51
+ assert(load == true);
52
+ error_propagate(errp, local_err);
53
+ return;
54
+ }
55
tray_is_open = blk_dev_is_tray_open(blk);
56
57
if (tray_was_open != tray_is_open) {
58
@@ -XXX,XX +XXX,XX @@ void blk_dev_change_media_cb(BlockBackend *blk, bool load)
59
60
static void blk_root_change_media(BdrvChild *child, bool load)
61
{
62
- blk_dev_change_media_cb(child->opaque, load);
63
+ blk_dev_change_media_cb(child->opaque, load, NULL);
64
}
65
66
/*
67
diff --git a/blockdev.c b/blockdev.c
68
index XXXXXXX..XXXXXXX 100644
69
--- a/blockdev.c
70
+++ b/blockdev.c
71
@@ -XXX,XX +XXX,XX @@ static int do_open_tray(const char *blk_name, const char *qdev_id,
72
}
73
74
if (!locked || force) {
75
- blk_dev_change_media_cb(blk, false);
76
+ blk_dev_change_media_cb(blk, false, &error_abort);
77
}
78
79
if (locked && !force) {
80
@@ -XXX,XX +XXX,XX @@ void qmp_blockdev_close_tray(bool has_device, const char *device,
81
Error **errp)
82
{
83
BlockBackend *blk;
84
+ Error *local_err = NULL;
85
86
device = has_device ? device : NULL;
87
id = has_id ? id : NULL;
88
@@ -XXX,XX +XXX,XX @@ void qmp_blockdev_close_tray(bool has_device, const char *device,
89
return;
90
}
91
92
- blk_dev_change_media_cb(blk, true);
93
+ blk_dev_change_media_cb(blk, true, &local_err);
94
+ if (local_err) {
95
+ error_propagate(errp, local_err);
96
+ return;
97
+ }
98
}
99
100
void qmp_x_blockdev_remove_medium(bool has_device, const char *device,
101
@@ -XXX,XX +XXX,XX @@ void qmp_x_blockdev_remove_medium(bool has_device, const char *device,
102
* called at all); therefore, the medium needs to be ejected here.
103
* Do it after blk_remove_bs() so blk_is_inserted(blk) returns the @load
104
* value passed here (i.e. false). */
105
- blk_dev_change_media_cb(blk, false);
106
+ blk_dev_change_media_cb(blk, false, &error_abort);
107
}
108
109
out:
110
@@ -XXX,XX +XXX,XX @@ out:
111
static void qmp_blockdev_insert_anon_medium(BlockBackend *blk,
112
BlockDriverState *bs, Error **errp)
113
{
114
+ Error *local_err = NULL;
115
bool has_device;
116
int ret;
117
118
@@ -XXX,XX +XXX,XX @@ static void qmp_blockdev_insert_anon_medium(BlockBackend *blk,
119
* slot here.
120
* Do it after blk_insert_bs() so blk_is_inserted(blk) returns the @load
121
* value passed here (i.e. true). */
122
- blk_dev_change_media_cb(blk, true);
123
+ blk_dev_change_media_cb(blk, true, &local_err);
124
+ if (local_err) {
125
+ error_propagate(errp, local_err);
126
+ blk_remove_bs(blk);
127
+ return;
128
+ }
129
}
130
}
131
132
diff --git a/hw/block/fdc.c b/hw/block/fdc.c
133
index XXXXXXX..XXXXXXX 100644
134
--- a/hw/block/fdc.c
135
+++ b/hw/block/fdc.c
136
@@ -XXX,XX +XXX,XX @@ static void fd_revalidate(FDrive *drv)
137
}
138
}
139
140
-static void fd_change_cb(void *opaque, bool load)
141
+static void fd_change_cb(void *opaque, bool load, Error **errp)
142
{
143
FDrive *drive = opaque;
144
145
diff --git a/hw/ide/core.c b/hw/ide/core.c
146
index XXXXXXX..XXXXXXX 100644
147
--- a/hw/ide/core.c
148
+++ b/hw/ide/core.c
149
@@ -XXX,XX +XXX,XX @@ static void ide_cfata_metadata_write(IDEState *s)
150
}
151
152
/* called when the inserted state of the media has changed */
153
-static void ide_cd_change_cb(void *opaque, bool load)
154
+static void ide_cd_change_cb(void *opaque, bool load, Error **errp)
155
{
156
IDEState *s = opaque;
157
uint64_t nb_sectors;
158
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
159
index XXXXXXX..XXXXXXX 100644
160
--- a/hw/scsi/scsi-disk.c
161
+++ b/hw/scsi/scsi-disk.c
162
@@ -XXX,XX +XXX,XX @@ static void scsi_disk_resize_cb(void *opaque)
163
}
164
}
165
166
-static void scsi_cd_change_media_cb(void *opaque, bool load)
167
+static void scsi_cd_change_media_cb(void *opaque, bool load, Error **errp)
168
{
169
SCSIDiskState *s = opaque;
170
171
diff --git a/hw/sd/sd.c b/hw/sd/sd.c
172
index XXXXXXX..XXXXXXX 100644
173
--- a/hw/sd/sd.c
174
+++ b/hw/sd/sd.c
175
@@ -XXX,XX +XXX,XX @@ static bool sd_get_readonly(SDState *sd)
176
return sd->wp_switch;
177
}
178
179
-static void sd_cardchange(void *opaque, bool load)
180
+static void sd_cardchange(void *opaque, bool load, Error **errp)
181
{
182
SDState *sd = opaque;
183
DeviceState *dev = DEVICE(sd);
184
diff --git a/include/block/block_int.h b/include/block/block_int.h
185
index XXXXXXX..XXXXXXX 100644
186
--- a/include/block/block_int.h
187
+++ b/include/block/block_int.h
188
@@ -XXX,XX +XXX,XX @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
189
uint64_t *nperm, uint64_t *nshared);
190
191
const char *bdrv_get_parent_name(const BlockDriverState *bs);
192
-void blk_dev_change_media_cb(BlockBackend *blk, bool load);
193
+void blk_dev_change_media_cb(BlockBackend *blk, bool load, Error **errp);
194
bool blk_dev_has_removable_media(BlockBackend *blk);
195
bool blk_dev_has_tray(BlockBackend *blk);
196
void blk_dev_eject_request(BlockBackend *blk, bool force);
197
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
198
index XXXXXXX..XXXXXXX 100644
199
--- a/include/sysemu/block-backend.h
200
+++ b/include/sysemu/block-backend.h
201
@@ -XXX,XX +XXX,XX @@ typedef struct BlockDevOps {
202
* changes. Sure would be useful if it did.
203
* Device models with removable media must implement this callback.
204
*/
205
- void (*change_media_cb)(void *opaque, bool load);
206
+ void (*change_media_cb)(void *opaque, bool load, Error **errp);
207
/*
208
* Runs when an eject request is issued from the monitor, the tray
209
* is closed, and the medium is locked.
210
--
211
1.8.3.1
212
213
diff view generated by jsdifflib
Deleted patch
1
This makes all device emulations with a qdev drive property request
2
permissions on their BlockBackend. The only thing we block at this point
3
is resizing images for some devices that can't support it.
4
1
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Acked-by: Fam Zheng <famz@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
---
9
hw/block/block.c | 22 +++++++++++++++++++++-
10
hw/block/fdc.c | 25 +++++++++++++++++++++++--
11
hw/block/m25p80.c | 8 ++++++++
12
hw/block/nand.c | 7 +++++++
13
hw/block/nvme.c | 8 +++++++-
14
hw/block/onenand.c | 7 +++++++
15
hw/block/pflash_cfi01.c | 18 ++++++++++++------
16
hw/block/pflash_cfi02.c | 19 +++++++++++++------
17
hw/block/virtio-blk.c | 8 +++++++-
18
hw/core/qdev-properties-system.c | 1 -
19
hw/ide/qdev.c | 8 ++++++--
20
hw/nvram/spapr_nvram.c | 8 ++++++++
21
hw/scsi/scsi-disk.c | 9 +++++++--
22
hw/sd/sd.c | 6 ++++++
23
hw/usb/dev-storage.c | 6 +++++-
24
include/hw/block/block.h | 3 ++-
25
tests/qemu-iotests/051.pc.out | 6 +++---
26
17 files changed, 142 insertions(+), 27 deletions(-)
27
28
diff --git a/hw/block/block.c b/hw/block/block.c
29
index XXXXXXX..XXXXXXX 100644
30
--- a/hw/block/block.c
31
+++ b/hw/block/block.c
32
@@ -XXX,XX +XXX,XX @@ void blkconf_blocksizes(BlockConf *conf)
33
}
34
}
35
36
-void blkconf_apply_backend_options(BlockConf *conf)
37
+void blkconf_apply_backend_options(BlockConf *conf, bool readonly,
38
+ bool resizable, Error **errp)
39
{
40
BlockBackend *blk = conf->blk;
41
BlockdevOnError rerror, werror;
42
+ uint64_t perm, shared_perm;
43
bool wce;
44
+ int ret;
45
+
46
+ perm = BLK_PERM_CONSISTENT_READ;
47
+ if (!readonly) {
48
+ perm |= BLK_PERM_WRITE;
49
+ }
50
+
51
+ /* TODO Remove BLK_PERM_WRITE unless explicitly configured so */
52
+ shared_perm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED |
53
+ BLK_PERM_GRAPH_MOD | BLK_PERM_WRITE;
54
+ if (resizable) {
55
+ shared_perm |= BLK_PERM_RESIZE;
56
+ }
57
+
58
+ ret = blk_set_perm(blk, perm, shared_perm, errp);
59
+ if (ret < 0) {
60
+ return;
61
+ }
62
63
switch (conf->wce) {
64
case ON_OFF_AUTO_ON: wce = true; break;
65
diff --git a/hw/block/fdc.c b/hw/block/fdc.c
66
index XXXXXXX..XXXXXXX 100644
67
--- a/hw/block/fdc.c
68
+++ b/hw/block/fdc.c
69
@@ -XXX,XX +XXX,XX @@ typedef enum FDiskFlags {
70
struct FDrive {
71
FDCtrl *fdctrl;
72
BlockBackend *blk;
73
+ BlockConf *conf;
74
/* Drive status */
75
FloppyDriveType drive; /* CMOS drive type */
76
uint8_t perpendicular; /* 2.88 MB access mode */
77
@@ -XXX,XX +XXX,XX @@ static void fd_revalidate(FDrive *drv)
78
static void fd_change_cb(void *opaque, bool load, Error **errp)
79
{
80
FDrive *drive = opaque;
81
+ Error *local_err = NULL;
82
+
83
+ if (!load) {
84
+ blk_set_perm(drive->blk, 0, BLK_PERM_ALL, &error_abort);
85
+ } else {
86
+ blkconf_apply_backend_options(drive->conf,
87
+ blk_is_read_only(drive->blk), false,
88
+ &local_err);
89
+ if (local_err) {
90
+ error_propagate(errp, local_err);
91
+ return;
92
+ }
93
+ }
94
95
drive->media_changed = 1;
96
drive->media_validated = false;
97
@@ -XXX,XX +XXX,XX @@ static int floppy_drive_init(DeviceState *qdev)
98
FloppyDrive *dev = FLOPPY_DRIVE(qdev);
99
FloppyBus *bus = FLOPPY_BUS(qdev->parent_bus);
100
FDrive *drive;
101
+ Error *local_err = NULL;
102
int ret;
103
104
if (dev->unit == -1) {
105
@@ -XXX,XX +XXX,XX @@ static int floppy_drive_init(DeviceState *qdev)
106
107
if (!dev->conf.blk) {
108
/* Anonymous BlockBackend for an empty drive */
109
- /* FIXME Use real permissions */
110
dev->conf.blk = blk_new(0, BLK_PERM_ALL);
111
ret = blk_attach_dev(dev->conf.blk, qdev);
112
assert(ret == 0);
113
@@ -XXX,XX +XXX,XX @@ static int floppy_drive_init(DeviceState *qdev)
114
* blkconf_apply_backend_options(). */
115
dev->conf.rerror = BLOCKDEV_ON_ERROR_AUTO;
116
dev->conf.werror = BLOCKDEV_ON_ERROR_AUTO;
117
- blkconf_apply_backend_options(&dev->conf);
118
+
119
+ blkconf_apply_backend_options(&dev->conf, blk_is_read_only(dev->conf.blk),
120
+ false, &local_err);
121
+ if (local_err) {
122
+ error_report_err(local_err);
123
+ return -1;
124
+ }
125
126
/* 'enospc' is the default for -drive, 'report' is what blk_new() gives us
127
* for empty drives. */
128
@@ -XXX,XX +XXX,XX @@ static int floppy_drive_init(DeviceState *qdev)
129
return -1;
130
}
131
132
+ drive->conf = &dev->conf;
133
drive->blk = dev->conf.blk;
134
drive->fdctrl = bus->fdc;
135
136
diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
137
index XXXXXXX..XXXXXXX 100644
138
--- a/hw/block/m25p80.c
139
+++ b/hw/block/m25p80.c
140
@@ -XXX,XX +XXX,XX @@ static void m25p80_realize(SSISlave *ss, Error **errp)
141
{
142
Flash *s = M25P80(ss);
143
M25P80Class *mc = M25P80_GET_CLASS(s);
144
+ int ret;
145
146
s->pi = mc->pi;
147
148
@@ -XXX,XX +XXX,XX @@ static void m25p80_realize(SSISlave *ss, Error **errp)
149
s->dirty_page = -1;
150
151
if (s->blk) {
152
+ uint64_t perm = BLK_PERM_CONSISTENT_READ |
153
+ (blk_is_read_only(s->blk) ? 0 : BLK_PERM_WRITE);
154
+ ret = blk_set_perm(s->blk, perm, BLK_PERM_ALL, errp);
155
+ if (ret < 0) {
156
+ return;
157
+ }
158
+
159
DB_PRINT_L(0, "Binding to IF_MTD drive\n");
160
s->storage = blk_blockalign(s->blk, s->size);
161
162
diff --git a/hw/block/nand.c b/hw/block/nand.c
163
index XXXXXXX..XXXXXXX 100644
164
--- a/hw/block/nand.c
165
+++ b/hw/block/nand.c
166
@@ -XXX,XX +XXX,XX @@ static void nand_realize(DeviceState *dev, Error **errp)
167
{
168
int pagesize;
169
NANDFlashState *s = NAND(dev);
170
+ int ret;
171
+
172
173
s->buswidth = nand_flash_ids[s->chip_id].width >> 3;
174
s->size = nand_flash_ids[s->chip_id].size << 20;
175
@@ -XXX,XX +XXX,XX @@ static void nand_realize(DeviceState *dev, Error **errp)
176
error_setg(errp, "Can't use a read-only drive");
177
return;
178
}
179
+ ret = blk_set_perm(s->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE,
180
+ BLK_PERM_ALL, errp);
181
+ if (ret < 0) {
182
+ return;
183
+ }
184
if (blk_getlength(s->blk) >=
185
(s->pages << s->page_shift) + (s->pages << s->oob_shift)) {
186
pagesize = 0;
187
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
188
index XXXXXXX..XXXXXXX 100644
189
--- a/hw/block/nvme.c
190
+++ b/hw/block/nvme.c
191
@@ -XXX,XX +XXX,XX @@ static int nvme_init(PCIDevice *pci_dev)
192
int i;
193
int64_t bs_size;
194
uint8_t *pci_conf;
195
+ Error *local_err = NULL;
196
197
if (!n->conf.blk) {
198
return -1;
199
@@ -XXX,XX +XXX,XX @@ static int nvme_init(PCIDevice *pci_dev)
200
return -1;
201
}
202
blkconf_blocksizes(&n->conf);
203
- blkconf_apply_backend_options(&n->conf);
204
+ blkconf_apply_backend_options(&n->conf, blk_is_read_only(n->conf.blk),
205
+ false, &local_err);
206
+ if (local_err) {
207
+ error_report_err(local_err);
208
+ return -1;
209
+ }
210
211
pci_conf = pci_dev->config;
212
pci_conf[PCI_INTERRUPT_PIN] = 1;
213
diff --git a/hw/block/onenand.c b/hw/block/onenand.c
214
index XXXXXXX..XXXXXXX 100644
215
--- a/hw/block/onenand.c
216
+++ b/hw/block/onenand.c
217
@@ -XXX,XX +XXX,XX @@ static int onenand_initfn(SysBusDevice *sbd)
218
OneNANDState *s = ONE_NAND(dev);
219
uint32_t size = 1 << (24 + ((s->id.dev >> 4) & 7));
220
void *ram;
221
+ Error *local_err = NULL;
222
223
s->base = (hwaddr)-1;
224
s->rdy = NULL;
225
@@ -XXX,XX +XXX,XX @@ static int onenand_initfn(SysBusDevice *sbd)
226
error_report("Can't use a read-only drive");
227
return -1;
228
}
229
+ blk_set_perm(s->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE,
230
+ BLK_PERM_ALL, &local_err);
231
+ if (local_err) {
232
+ error_report_err(local_err);
233
+ return -1;
234
+ }
235
s->blk_cur = s->blk;
236
}
237
s->otp = memset(g_malloc((64 + 2) << PAGE_SHIFT),
238
diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c
239
index XXXXXXX..XXXXXXX 100644
240
--- a/hw/block/pflash_cfi01.c
241
+++ b/hw/block/pflash_cfi01.c
242
@@ -XXX,XX +XXX,XX @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
243
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem);
244
245
if (pfl->blk) {
246
+ uint64_t perm;
247
+ pfl->ro = blk_is_read_only(pfl->blk);
248
+ perm = BLK_PERM_CONSISTENT_READ | (pfl->ro ? 0 : BLK_PERM_WRITE);
249
+ ret = blk_set_perm(pfl->blk, perm, BLK_PERM_ALL, errp);
250
+ if (ret < 0) {
251
+ return;
252
+ }
253
+ } else {
254
+ pfl->ro = 0;
255
+ }
256
+
257
+ if (pfl->blk) {
258
/* read the initial flash content */
259
ret = blk_pread(pfl->blk, 0, pfl->storage, total_len);
260
261
@@ -XXX,XX +XXX,XX @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
262
}
263
}
264
265
- if (pfl->blk) {
266
- pfl->ro = blk_is_read_only(pfl->blk);
267
- } else {
268
- pfl->ro = 0;
269
- }
270
-
271
/* Default to devices being used at their maximum device width. This was
272
* assumed before the device_width support was added.
273
*/
274
diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
275
index XXXXXXX..XXXXXXX 100644
276
--- a/hw/block/pflash_cfi02.c
277
+++ b/hw/block/pflash_cfi02.c
278
@@ -XXX,XX +XXX,XX @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
279
vmstate_register_ram(&pfl->orig_mem, DEVICE(pfl));
280
pfl->storage = memory_region_get_ram_ptr(&pfl->orig_mem);
281
pfl->chip_len = chip_len;
282
+
283
+ if (pfl->blk) {
284
+ uint64_t perm;
285
+ pfl->ro = blk_is_read_only(pfl->blk);
286
+ perm = BLK_PERM_CONSISTENT_READ | (pfl->ro ? 0 : BLK_PERM_WRITE);
287
+ ret = blk_set_perm(pfl->blk, perm, BLK_PERM_ALL, errp);
288
+ if (ret < 0) {
289
+ return;
290
+ }
291
+ } else {
292
+ pfl->ro = 0;
293
+ }
294
+
295
if (pfl->blk) {
296
/* read the initial flash content */
297
ret = blk_pread(pfl->blk, 0, pfl->storage, chip_len);
298
@@ -XXX,XX +XXX,XX @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
299
pfl->rom_mode = 1;
300
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem);
301
302
- if (pfl->blk) {
303
- pfl->ro = blk_is_read_only(pfl->blk);
304
- } else {
305
- pfl->ro = 0;
306
- }
307
-
308
pfl->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, pflash_timer, pfl);
309
pfl->wcycle = 0;
310
pfl->cmd = 0;
311
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
312
index XXXXXXX..XXXXXXX 100644
313
--- a/hw/block/virtio-blk.c
314
+++ b/hw/block/virtio-blk.c
315
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
316
}
317
318
blkconf_serial(&conf->conf, &conf->serial);
319
- blkconf_apply_backend_options(&conf->conf);
320
+ blkconf_apply_backend_options(&conf->conf,
321
+ blk_is_read_only(conf->conf.blk), true,
322
+ &err);
323
+ if (err) {
324
+ error_propagate(errp, err);
325
+ return;
326
+ }
327
s->original_wce = blk_enable_write_cache(conf->conf.blk);
328
blkconf_geometry(&conf->conf, NULL, 65535, 255, 255, &err);
329
if (err) {
330
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
331
index XXXXXXX..XXXXXXX 100644
332
--- a/hw/core/qdev-properties-system.c
333
+++ b/hw/core/qdev-properties-system.c
334
@@ -XXX,XX +XXX,XX @@ static void parse_drive(DeviceState *dev, const char *str, void **ptr,
335
if (!blk) {
336
BlockDriverState *bs = bdrv_lookup_bs(NULL, str, NULL);
337
if (bs) {
338
- /* FIXME Use real permissions */
339
blk = blk_new(0, BLK_PERM_ALL);
340
blk_created = true;
341
342
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
343
index XXXXXXX..XXXXXXX 100644
344
--- a/hw/ide/qdev.c
345
+++ b/hw/ide/qdev.c
346
@@ -XXX,XX +XXX,XX @@ static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind)
347
return -1;
348
} else {
349
/* Anonymous BlockBackend for an empty drive */
350
- /* FIXME Use real permissions */
351
dev->conf.blk = blk_new(0, BLK_PERM_ALL);
352
}
353
}
354
@@ -XXX,XX +XXX,XX @@ static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind)
355
return -1;
356
}
357
}
358
- blkconf_apply_backend_options(&dev->conf);
359
+ blkconf_apply_backend_options(&dev->conf, kind == IDE_CD, kind != IDE_CD,
360
+ &err);
361
+ if (err) {
362
+ error_report_err(err);
363
+ return -1;
364
+ }
365
366
if (ide_init_drive(s, dev->conf.blk, kind,
367
dev->version, dev->serial, dev->model, dev->wwn,
368
diff --git a/hw/nvram/spapr_nvram.c b/hw/nvram/spapr_nvram.c
369
index XXXXXXX..XXXXXXX 100644
370
--- a/hw/nvram/spapr_nvram.c
371
+++ b/hw/nvram/spapr_nvram.c
372
@@ -XXX,XX +XXX,XX @@ static void rtas_nvram_store(PowerPCCPU *cpu, sPAPRMachineState *spapr,
373
static void spapr_nvram_realize(VIOsPAPRDevice *dev, Error **errp)
374
{
375
sPAPRNVRAM *nvram = VIO_SPAPR_NVRAM(dev);
376
+ int ret;
377
378
if (nvram->blk) {
379
nvram->size = blk_getlength(nvram->blk);
380
+
381
+ ret = blk_set_perm(nvram->blk,
382
+ BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE,
383
+ BLK_PERM_ALL, errp);
384
+ if (ret < 0) {
385
+ return;
386
+ }
387
} else {
388
nvram->size = DEFAULT_NVRAM_SIZE;
389
}
390
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
391
index XXXXXXX..XXXXXXX 100644
392
--- a/hw/scsi/scsi-disk.c
393
+++ b/hw/scsi/scsi-disk.c
394
@@ -XXX,XX +XXX,XX @@ static void scsi_realize(SCSIDevice *dev, Error **errp)
395
return;
396
}
397
}
398
- blkconf_apply_backend_options(&dev->conf);
399
+ blkconf_apply_backend_options(&dev->conf,
400
+ blk_is_read_only(s->qdev.conf.blk),
401
+ dev->type == TYPE_DISK, &err);
402
+ if (err) {
403
+ error_propagate(errp, err);
404
+ return;
405
+ }
406
407
if (s->qdev.conf.discard_granularity == -1) {
408
s->qdev.conf.discard_granularity =
409
@@ -XXX,XX +XXX,XX @@ static void scsi_cd_realize(SCSIDevice *dev, Error **errp)
410
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
411
412
if (!dev->conf.blk) {
413
- /* FIXME Use real permissions */
414
dev->conf.blk = blk_new(0, BLK_PERM_ALL);
415
}
416
417
diff --git a/hw/sd/sd.c b/hw/sd/sd.c
418
index XXXXXXX..XXXXXXX 100644
419
--- a/hw/sd/sd.c
420
+++ b/hw/sd/sd.c
421
@@ -XXX,XX +XXX,XX @@ static void sd_instance_finalize(Object *obj)
422
static void sd_realize(DeviceState *dev, Error **errp)
423
{
424
SDState *sd = SD_CARD(dev);
425
+ int ret;
426
427
if (sd->blk && blk_is_read_only(sd->blk)) {
428
error_setg(errp, "Cannot use read-only drive as SD card");
429
@@ -XXX,XX +XXX,XX @@ static void sd_realize(DeviceState *dev, Error **errp)
430
}
431
432
if (sd->blk) {
433
+ ret = blk_set_perm(sd->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE,
434
+ BLK_PERM_ALL, errp);
435
+ if (ret < 0) {
436
+ return;
437
+ }
438
blk_set_dev_ops(sd->blk, &sd_block_ops, sd);
439
}
440
}
441
diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
442
index XXXXXXX..XXXXXXX 100644
443
--- a/hw/usb/dev-storage.c
444
+++ b/hw/usb/dev-storage.c
445
@@ -XXX,XX +XXX,XX @@ static void usb_msd_realize_storage(USBDevice *dev, Error **errp)
446
447
blkconf_serial(&s->conf, &dev->serial);
448
blkconf_blocksizes(&s->conf);
449
- blkconf_apply_backend_options(&s->conf);
450
+ blkconf_apply_backend_options(&s->conf, blk_is_read_only(blk), true, &err);
451
+ if (err) {
452
+ error_propagate(errp, err);
453
+ return;
454
+ }
455
456
/*
457
* Hack alert: this pretends to be a block device, but it's really
458
diff --git a/include/hw/block/block.h b/include/hw/block/block.h
459
index XXXXXXX..XXXXXXX 100644
460
--- a/include/hw/block/block.h
461
+++ b/include/hw/block/block.h
462
@@ -XXX,XX +XXX,XX @@ void blkconf_geometry(BlockConf *conf, int *trans,
463
unsigned cyls_max, unsigned heads_max, unsigned secs_max,
464
Error **errp);
465
void blkconf_blocksizes(BlockConf *conf);
466
-void blkconf_apply_backend_options(BlockConf *conf);
467
+void blkconf_apply_backend_options(BlockConf *conf, bool readonly,
468
+ bool resizable, Error **errp);
469
470
/* Hard disk geometry */
471
472
diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out
473
index XXXXXXX..XXXXXXX 100644
474
--- a/tests/qemu-iotests/051.pc.out
475
+++ b/tests/qemu-iotests/051.pc.out
476
@@ -XXX,XX +XXX,XX @@ qququiquit
477
478
Testing: -drive file=TEST_DIR/t.qcow2,if=ide,readonly=on
479
QEMU X.Y.Z monitor - type 'help' for more information
480
-(qemu) QEMU_PROG: Can't use a read-only drive
481
+(qemu) QEMU_PROG: Block node is read-only
482
QEMU_PROG: Initialization of device ide-hd failed: Device initialization failed.
483
484
Testing: -drive file=TEST_DIR/t.qcow2,if=scsi,readonly=on
485
@@ -XXX,XX +XXX,XX @@ QEMU X.Y.Z monitor - type 'help' for more information
486
487
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-drive,drive=disk
488
QEMU X.Y.Z monitor - type 'help' for more information
489
-(qemu) QEMU_PROG: -device ide-drive,drive=disk: Can't use a read-only drive
490
+(qemu) QEMU_PROG: -device ide-drive,drive=disk: Block node is read-only
491
QEMU_PROG: -device ide-drive,drive=disk: Device initialization failed.
492
493
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-hd,drive=disk
494
QEMU X.Y.Z monitor - type 'help' for more information
495
-(qemu) QEMU_PROG: -device ide-hd,drive=disk: Can't use a read-only drive
496
+(qemu) QEMU_PROG: -device ide-hd,drive=disk: Block node is read-only
497
QEMU_PROG: -device ide-hd,drive=disk: Device initialization failed.
498
499
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-disk,drive=disk
500
--
501
1.8.3.1
502
503
diff view generated by jsdifflib
Deleted patch
1
By default, don't allow another writer for block devices that are
2
attached to a guest device. For the cases where this setup is intended
3
(e.g. using a cluster filesystem on the disk), the new option can be
4
used to allow it.
5
1
6
This change affects only devices using DEFINE_BLOCK_PROPERTIES().
7
Devices directly using DEFINE_PROP_DRIVE() still accept writers
8
unconditionally.
9
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Reviewed-by: Max Reitz <mreitz@redhat.com>
12
Acked-by: Fam Zheng <famz@redhat.com>
13
---
14
hw/block/block.c | 6 ++++--
15
include/hw/block/block.h | 5 ++++-
16
tests/qemu-iotests/172.out | 53 ++++++++++++++++++++++++++++++++++++++++++++++
17
3 files changed, 61 insertions(+), 3 deletions(-)
18
19
diff --git a/hw/block/block.c b/hw/block/block.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/hw/block/block.c
22
+++ b/hw/block/block.c
23
@@ -XXX,XX +XXX,XX @@ void blkconf_apply_backend_options(BlockConf *conf, bool readonly,
24
perm |= BLK_PERM_WRITE;
25
}
26
27
- /* TODO Remove BLK_PERM_WRITE unless explicitly configured so */
28
shared_perm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED |
29
- BLK_PERM_GRAPH_MOD | BLK_PERM_WRITE;
30
+ BLK_PERM_GRAPH_MOD;
31
if (resizable) {
32
shared_perm |= BLK_PERM_RESIZE;
33
}
34
+ if (conf->share_rw) {
35
+ shared_perm |= BLK_PERM_WRITE;
36
+ }
37
38
ret = blk_set_perm(blk, perm, shared_perm, errp);
39
if (ret < 0) {
40
diff --git a/include/hw/block/block.h b/include/hw/block/block.h
41
index XXXXXXX..XXXXXXX 100644
42
--- a/include/hw/block/block.h
43
+++ b/include/hw/block/block.h
44
@@ -XXX,XX +XXX,XX @@ typedef struct BlockConf {
45
/* geometry, not all devices use this */
46
uint32_t cyls, heads, secs;
47
OnOffAuto wce;
48
+ bool share_rw;
49
BlockdevOnError rerror;
50
BlockdevOnError werror;
51
} BlockConf;
52
@@ -XXX,XX +XXX,XX @@ static inline unsigned int get_physical_block_exp(BlockConf *conf)
53
DEFINE_PROP_UINT32("opt_io_size", _state, _conf.opt_io_size, 0), \
54
DEFINE_PROP_UINT32("discard_granularity", _state, \
55
_conf.discard_granularity, -1), \
56
- DEFINE_PROP_ON_OFF_AUTO("write-cache", _state, _conf.wce, ON_OFF_AUTO_AUTO)
57
+ DEFINE_PROP_ON_OFF_AUTO("write-cache", _state, _conf.wce, \
58
+ ON_OFF_AUTO_AUTO), \
59
+ DEFINE_PROP_BOOL("share-rw", _state, _conf.share_rw, false)
60
61
#define DEFINE_BLOCK_CHS_PROPERTIES(_state, _conf) \
62
DEFINE_PROP_UINT32("cyls", _state, _conf.cyls, 0), \
63
diff --git a/tests/qemu-iotests/172.out b/tests/qemu-iotests/172.out
64
index XXXXXXX..XXXXXXX 100644
65
--- a/tests/qemu-iotests/172.out
66
+++ b/tests/qemu-iotests/172.out
67
@@ -XXX,XX +XXX,XX @@ Testing:
68
opt_io_size = 0 (0x0)
69
discard_granularity = 4294967295 (0xffffffff)
70
write-cache = "auto"
71
+ share-rw = false
72
drive-type = "288"
73
74
75
@@ -XXX,XX +XXX,XX @@ Testing: -fda TEST_DIR/t.qcow2
76
opt_io_size = 0 (0x0)
77
discard_granularity = 4294967295 (0xffffffff)
78
write-cache = "auto"
79
+ share-rw = false
80
drive-type = "144"
81
82
Testing: -fdb TEST_DIR/t.qcow2
83
@@ -XXX,XX +XXX,XX @@ Testing: -fdb TEST_DIR/t.qcow2
84
opt_io_size = 0 (0x0)
85
discard_granularity = 4294967295 (0xffffffff)
86
write-cache = "auto"
87
+ share-rw = false
88
drive-type = "144"
89
dev: floppy, id ""
90
unit = 0 (0x0)
91
@@ -XXX,XX +XXX,XX @@ Testing: -fdb TEST_DIR/t.qcow2
92
opt_io_size = 0 (0x0)
93
discard_granularity = 4294967295 (0xffffffff)
94
write-cache = "auto"
95
+ share-rw = false
96
drive-type = "288"
97
98
Testing: -fda TEST_DIR/t.qcow2 -fdb TEST_DIR/t.qcow2
99
@@ -XXX,XX +XXX,XX @@ Testing: -fda TEST_DIR/t.qcow2 -fdb TEST_DIR/t.qcow2
100
opt_io_size = 0 (0x0)
101
discard_granularity = 4294967295 (0xffffffff)
102
write-cache = "auto"
103
+ share-rw = false
104
drive-type = "144"
105
dev: floppy, id ""
106
unit = 0 (0x0)
107
@@ -XXX,XX +XXX,XX @@ Testing: -fda TEST_DIR/t.qcow2 -fdb TEST_DIR/t.qcow2
108
opt_io_size = 0 (0x0)
109
discard_granularity = 4294967295 (0xffffffff)
110
write-cache = "auto"
111
+ share-rw = false
112
drive-type = "144"
113
114
115
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2
116
opt_io_size = 0 (0x0)
117
discard_granularity = 4294967295 (0xffffffff)
118
write-cache = "auto"
119
+ share-rw = false
120
drive-type = "144"
121
122
Testing: -drive if=floppy,file=TEST_DIR/t.qcow2,index=1
123
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2,index=1
124
opt_io_size = 0 (0x0)
125
discard_granularity = 4294967295 (0xffffffff)
126
write-cache = "auto"
127
+ share-rw = false
128
drive-type = "144"
129
dev: floppy, id ""
130
unit = 0 (0x0)
131
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2,index=1
132
opt_io_size = 0 (0x0)
133
discard_granularity = 4294967295 (0xffffffff)
134
write-cache = "auto"
135
+ share-rw = false
136
drive-type = "288"
137
138
Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=floppy,file=TEST_DIR/t.qcow2,index=1
139
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=floppy,file=TEST_DIR/t
140
opt_io_size = 0 (0x0)
141
discard_granularity = 4294967295 (0xffffffff)
142
write-cache = "auto"
143
+ share-rw = false
144
drive-type = "144"
145
dev: floppy, id ""
146
unit = 0 (0x0)
147
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=floppy,file=TEST_DIR/t
148
opt_io_size = 0 (0x0)
149
discard_granularity = 4294967295 (0xffffffff)
150
write-cache = "auto"
151
+ share-rw = false
152
drive-type = "144"
153
154
155
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -global isa-fdc.driveA=none0
156
opt_io_size = 0 (0x0)
157
discard_granularity = 4294967295 (0xffffffff)
158
write-cache = "auto"
159
+ share-rw = false
160
drive-type = "144"
161
162
Testing: -drive if=none,file=TEST_DIR/t.qcow2 -global isa-fdc.driveB=none0
163
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -global isa-fdc.driveB=none0
164
opt_io_size = 0 (0x0)
165
discard_granularity = 4294967295 (0xffffffff)
166
write-cache = "auto"
167
+ share-rw = false
168
drive-type = "144"
169
170
Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2 -global isa-fdc.driveA=none0 -global isa-fdc.driveB=none1
171
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qco
172
opt_io_size = 0 (0x0)
173
discard_granularity = 4294967295 (0xffffffff)
174
write-cache = "auto"
175
+ share-rw = false
176
drive-type = "144"
177
dev: floppy, id ""
178
unit = 0 (0x0)
179
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qco
180
opt_io_size = 0 (0x0)
181
discard_granularity = 4294967295 (0xffffffff)
182
write-cache = "auto"
183
+ share-rw = false
184
drive-type = "144"
185
186
187
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0
188
opt_io_size = 0 (0x0)
189
discard_granularity = 4294967295 (0xffffffff)
190
write-cache = "auto"
191
+ share-rw = false
192
drive-type = "144"
193
194
Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,unit=1
195
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,unit=1
196
opt_io_size = 0 (0x0)
197
discard_granularity = 4294967295 (0xffffffff)
198
write-cache = "auto"
199
+ share-rw = false
200
drive-type = "144"
201
202
Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0 -device floppy,drive=none1,unit=1
203
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qco
204
opt_io_size = 0 (0x0)
205
discard_granularity = 4294967295 (0xffffffff)
206
write-cache = "auto"
207
+ share-rw = false
208
drive-type = "144"
209
dev: floppy, id ""
210
unit = 0 (0x0)
211
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qco
212
opt_io_size = 0 (0x0)
213
discard_granularity = 4294967295 (0xffffffff)
214
write-cache = "auto"
215
+ share-rw = false
216
drive-type = "144"
217
218
219
@@ -XXX,XX +XXX,XX @@ Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2 -global isa-
220
opt_io_size = 0 (0x0)
221
discard_granularity = 4294967295 (0xffffffff)
222
write-cache = "auto"
223
+ share-rw = false
224
drive-type = "144"
225
dev: floppy, id ""
226
unit = 0 (0x0)
227
@@ -XXX,XX +XXX,XX @@ Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2 -global isa-
228
opt_io_size = 0 (0x0)
229
discard_granularity = 4294967295 (0xffffffff)
230
write-cache = "auto"
231
+ share-rw = false
232
drive-type = "144"
233
234
Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2 -global isa-fdc.driveA=none0
235
@@ -XXX,XX +XXX,XX @@ Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2 -global isa-
236
opt_io_size = 0 (0x0)
237
discard_granularity = 4294967295 (0xffffffff)
238
write-cache = "auto"
239
+ share-rw = false
240
drive-type = "144"
241
dev: floppy, id ""
242
unit = 0 (0x0)
243
@@ -XXX,XX +XXX,XX @@ Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2 -global isa-
244
opt_io_size = 0 (0x0)
245
discard_granularity = 4294967295 (0xffffffff)
246
write-cache = "auto"
247
+ share-rw = false
248
drive-type = "144"
249
250
Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2 -global isa-fdc.driveA=none0
251
@@ -XXX,XX +XXX,XX @@ Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2 -global isa-
252
opt_io_size = 0 (0x0)
253
discard_granularity = 4294967295 (0xffffffff)
254
write-cache = "auto"
255
+ share-rw = false
256
drive-type = "144"
257
258
Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2 -global isa-fdc.driveB=none0
259
@@ -XXX,XX +XXX,XX @@ Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2 -global isa-
260
opt_io_size = 0 (0x0)
261
discard_granularity = 4294967295 (0xffffffff)
262
write-cache = "auto"
263
+ share-rw = false
264
drive-type = "144"
265
266
267
@@ -XXX,XX +XXX,XX @@ Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2 -device flop
268
opt_io_size = 0 (0x0)
269
discard_granularity = 4294967295 (0xffffffff)
270
write-cache = "auto"
271
+ share-rw = false
272
drive-type = "144"
273
dev: floppy, id ""
274
unit = 0 (0x0)
275
@@ -XXX,XX +XXX,XX @@ Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2 -device flop
276
opt_io_size = 0 (0x0)
277
discard_granularity = 4294967295 (0xffffffff)
278
write-cache = "auto"
279
+ share-rw = false
280
drive-type = "144"
281
282
Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,unit=1
283
@@ -XXX,XX +XXX,XX @@ Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2 -device flop
284
opt_io_size = 0 (0x0)
285
discard_granularity = 4294967295 (0xffffffff)
286
write-cache = "auto"
287
+ share-rw = false
288
drive-type = "144"
289
dev: floppy, id ""
290
unit = 0 (0x0)
291
@@ -XXX,XX +XXX,XX @@ Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2 -device flop
292
opt_io_size = 0 (0x0)
293
discard_granularity = 4294967295 (0xffffffff)
294
write-cache = "auto"
295
+ share-rw = false
296
drive-type = "144"
297
298
Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0
299
@@ -XXX,XX +XXX,XX @@ Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2 -device flop
300
opt_io_size = 0 (0x0)
301
discard_granularity = 4294967295 (0xffffffff)
302
write-cache = "auto"
303
+ share-rw = false
304
drive-type = "144"
305
dev: floppy, id ""
306
unit = 1 (0x1)
307
@@ -XXX,XX +XXX,XX @@ Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2 -device flop
308
opt_io_size = 0 (0x0)
309
discard_granularity = 4294967295 (0xffffffff)
310
write-cache = "auto"
311
+ share-rw = false
312
drive-type = "144"
313
314
Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,unit=0
315
@@ -XXX,XX +XXX,XX @@ Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2 -device flop
316
opt_io_size = 0 (0x0)
317
discard_granularity = 4294967295 (0xffffffff)
318
write-cache = "auto"
319
+ share-rw = false
320
drive-type = "144"
321
dev: floppy, id ""
322
unit = 1 (0x1)
323
@@ -XXX,XX +XXX,XX @@ Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2 -device flop
324
opt_io_size = 0 (0x0)
325
discard_granularity = 4294967295 (0xffffffff)
326
write-cache = "auto"
327
+ share-rw = false
328
drive-type = "144"
329
330
Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,unit=0
331
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.q
332
opt_io_size = 0 (0x0)
333
discard_granularity = 4294967295 (0xffffffff)
334
write-cache = "auto"
335
+ share-rw = false
336
drive-type = "144"
337
dev: floppy, id ""
338
unit = 0 (0x0)
339
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.q
340
opt_io_size = 0 (0x0)
341
discard_granularity = 4294967295 (0xffffffff)
342
write-cache = "auto"
343
+ share-rw = false
344
drive-type = "144"
345
346
Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,unit=1
347
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.q
348
opt_io_size = 0 (0x0)
349
discard_granularity = 4294967295 (0xffffffff)
350
write-cache = "auto"
351
+ share-rw = false
352
drive-type = "144"
353
dev: floppy, id ""
354
unit = 0 (0x0)
355
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.q
356
opt_io_size = 0 (0x0)
357
discard_granularity = 4294967295 (0xffffffff)
358
write-cache = "auto"
359
+ share-rw = false
360
drive-type = "144"
361
362
Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,unit=0
363
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qco
364
opt_io_size = 0 (0x0)
365
discard_granularity = 4294967295 (0xffffffff)
366
write-cache = "auto"
367
+ share-rw = false
368
drive-type = "144"
369
dev: floppy, id ""
370
unit = 0 (0x0)
371
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qco
372
opt_io_size = 0 (0x0)
373
discard_granularity = 4294967295 (0xffffffff)
374
write-cache = "auto"
375
+ share-rw = false
376
drive-type = "144"
377
378
Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2 -global isa-fdc.driveA=none0 -device floppy,drive=none1,unit=1
379
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qco
380
opt_io_size = 0 (0x0)
381
discard_granularity = 4294967295 (0xffffffff)
382
write-cache = "auto"
383
+ share-rw = false
384
drive-type = "144"
385
dev: floppy, id ""
386
unit = 0 (0x0)
387
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qco
388
opt_io_size = 0 (0x0)
389
discard_granularity = 4294967295 (0xffffffff)
390
write-cache = "auto"
391
+ share-rw = false
392
drive-type = "144"
393
394
Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2 -global isa-fdc.driveB=none0 -device floppy,drive=none1
395
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qco
396
opt_io_size = 0 (0x0)
397
discard_granularity = 4294967295 (0xffffffff)
398
write-cache = "auto"
399
+ share-rw = false
400
drive-type = "144"
401
dev: floppy, id ""
402
unit = 1 (0x1)
403
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qco
404
opt_io_size = 0 (0x0)
405
discard_granularity = 4294967295 (0xffffffff)
406
write-cache = "auto"
407
+ share-rw = false
408
drive-type = "144"
409
410
Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2 -global isa-fdc.driveB=none0 -device floppy,drive=none1,unit=0
411
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qco
412
opt_io_size = 0 (0x0)
413
discard_granularity = 4294967295 (0xffffffff)
414
write-cache = "auto"
415
+ share-rw = false
416
drive-type = "144"
417
dev: floppy, id ""
418
unit = 1 (0x1)
419
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qco
420
opt_io_size = 0 (0x0)
421
discard_granularity = 4294967295 (0xffffffff)
422
write-cache = "auto"
423
+ share-rw = false
424
drive-type = "144"
425
426
Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2 -global isa-fdc.driveA=none0 -device floppy,drive=none1,unit=0
427
@@ -XXX,XX +XXX,XX @@ Testing: -device floppy
428
opt_io_size = 0 (0x0)
429
discard_granularity = 4294967295 (0xffffffff)
430
write-cache = "auto"
431
+ share-rw = false
432
drive-type = "288"
433
434
Testing: -device floppy,drive-type=120
435
@@ -XXX,XX +XXX,XX @@ Testing: -device floppy,drive-type=120
436
opt_io_size = 0 (0x0)
437
discard_granularity = 4294967295 (0xffffffff)
438
write-cache = "auto"
439
+ share-rw = false
440
drive-type = "120"
441
442
Testing: -device floppy,drive-type=144
443
@@ -XXX,XX +XXX,XX @@ Testing: -device floppy,drive-type=144
444
opt_io_size = 0 (0x0)
445
discard_granularity = 4294967295 (0xffffffff)
446
write-cache = "auto"
447
+ share-rw = false
448
drive-type = "144"
449
450
Testing: -device floppy,drive-type=288
451
@@ -XXX,XX +XXX,XX @@ Testing: -device floppy,drive-type=288
452
opt_io_size = 0 (0x0)
453
discard_granularity = 4294967295 (0xffffffff)
454
write-cache = "auto"
455
+ share-rw = false
456
drive-type = "288"
457
458
459
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,drive-t
460
opt_io_size = 0 (0x0)
461
discard_granularity = 4294967295 (0xffffffff)
462
write-cache = "auto"
463
+ share-rw = false
464
drive-type = "120"
465
466
Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,drive-type=288
467
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,drive-t
468
opt_io_size = 0 (0x0)
469
discard_granularity = 4294967295 (0xffffffff)
470
write-cache = "auto"
471
+ share-rw = false
472
drive-type = "288"
473
474
475
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,logical
476
opt_io_size = 0 (0x0)
477
discard_granularity = 4294967295 (0xffffffff)
478
write-cache = "auto"
479
+ share-rw = false
480
drive-type = "144"
481
482
Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,physical_block_size=512
483
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,physica
484
opt_io_size = 0 (0x0)
485
discard_granularity = 4294967295 (0xffffffff)
486
write-cache = "auto"
487
+ share-rw = false
488
drive-type = "144"
489
490
Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,logical_block_size=4096
491
--
492
1.8.3.1
493
494
diff view generated by jsdifflib
Deleted patch
1
This functions creates a BlockBackend internally, so the block jobs need
2
to tell it what they want to do with the BB.
3
1
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Acked-by: Fam Zheng <famz@redhat.com>
7
---
8
block/backup.c | 5 +++--
9
block/commit.c | 5 +++--
10
block/mirror.c | 5 +++--
11
block/stream.c | 5 +++--
12
blockjob.c | 6 +++---
13
include/block/blockjob_int.h | 4 +++-
14
tests/test-blockjob-txn.c | 6 +++---
15
tests/test-blockjob.c | 5 +++--
16
8 files changed, 24 insertions(+), 17 deletions(-)
17
18
diff --git a/block/backup.c b/block/backup.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/block/backup.c
21
+++ b/block/backup.c
22
@@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
23
goto error;
24
}
25
26
- job = block_job_create(job_id, &backup_job_driver, bs, speed,
27
- creation_flags, cb, opaque, errp);
28
+ /* FIXME Use real permissions */
29
+ job = block_job_create(job_id, &backup_job_driver, bs, 0, BLK_PERM_ALL,
30
+ speed, creation_flags, cb, opaque, errp);
31
if (!job) {
32
goto error;
33
}
34
diff --git a/block/commit.c b/block/commit.c
35
index XXXXXXX..XXXXXXX 100644
36
--- a/block/commit.c
37
+++ b/block/commit.c
38
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
39
return;
40
}
41
42
- s = block_job_create(job_id, &commit_job_driver, bs, speed,
43
- BLOCK_JOB_DEFAULT, NULL, NULL, errp);
44
+ /* FIXME Use real permissions */
45
+ s = block_job_create(job_id, &commit_job_driver, bs, 0, BLK_PERM_ALL,
46
+ speed, BLOCK_JOB_DEFAULT, NULL, NULL, errp);
47
if (!s) {
48
return;
49
}
50
diff --git a/block/mirror.c b/block/mirror.c
51
index XXXXXXX..XXXXXXX 100644
52
--- a/block/mirror.c
53
+++ b/block/mirror.c
54
@@ -XXX,XX +XXX,XX @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
55
buf_size = DEFAULT_MIRROR_BUF_SIZE;
56
}
57
58
- s = block_job_create(job_id, driver, bs, speed, creation_flags,
59
- cb, opaque, errp);
60
+ /* FIXME Use real permissions */
61
+ s = block_job_create(job_id, driver, bs, 0, BLK_PERM_ALL, speed,
62
+ creation_flags, cb, opaque, errp);
63
if (!s) {
64
return;
65
}
66
diff --git a/block/stream.c b/block/stream.c
67
index XXXXXXX..XXXXXXX 100644
68
--- a/block/stream.c
69
+++ b/block/stream.c
70
@@ -XXX,XX +XXX,XX @@ void stream_start(const char *job_id, BlockDriverState *bs,
71
BlockDriverState *iter;
72
int orig_bs_flags;
73
74
- s = block_job_create(job_id, &stream_job_driver, bs, speed,
75
- BLOCK_JOB_DEFAULT, NULL, NULL, errp);
76
+ /* FIXME Use real permissions */
77
+ s = block_job_create(job_id, &stream_job_driver, bs, 0, BLK_PERM_ALL,
78
+ speed, BLOCK_JOB_DEFAULT, NULL, NULL, errp);
79
if (!s) {
80
return;
81
}
82
diff --git a/blockjob.c b/blockjob.c
83
index XXXXXXX..XXXXXXX 100644
84
--- a/blockjob.c
85
+++ b/blockjob.c
86
@@ -XXX,XX +XXX,XX @@ void block_job_add_bdrv(BlockJob *job, BlockDriverState *bs)
87
}
88
89
void *block_job_create(const char *job_id, const BlockJobDriver *driver,
90
- BlockDriverState *bs, int64_t speed, int flags,
91
+ BlockDriverState *bs, uint64_t perm,
92
+ uint64_t shared_perm, int64_t speed, int flags,
93
BlockCompletionFunc *cb, void *opaque, Error **errp)
94
{
95
BlockBackend *blk;
96
@@ -XXX,XX +XXX,XX @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
97
}
98
}
99
100
- /* FIXME Use real permissions */
101
- blk = blk_new(0, BLK_PERM_ALL);
102
+ blk = blk_new(perm, shared_perm);
103
ret = blk_insert_bs(blk, bs, errp);
104
if (ret < 0) {
105
blk_unref(blk);
106
diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h
107
index XXXXXXX..XXXXXXX 100644
108
--- a/include/block/blockjob_int.h
109
+++ b/include/block/blockjob_int.h
110
@@ -XXX,XX +XXX,XX @@ struct BlockJobDriver {
111
* generated automatically.
112
* @job_type: The class object for the newly-created job.
113
* @bs: The block
114
+ * @perm, @shared_perm: Permissions to request for @bs
115
* @speed: The maximum speed, in bytes per second, or 0 for unlimited.
116
* @cb: Completion function for the job.
117
* @opaque: Opaque pointer value passed to @cb.
118
@@ -XXX,XX +XXX,XX @@ struct BlockJobDriver {
119
* called from a wrapper that is specific to the job type.
120
*/
121
void *block_job_create(const char *job_id, const BlockJobDriver *driver,
122
- BlockDriverState *bs, int64_t speed, int flags,
123
+ BlockDriverState *bs, uint64_t perm,
124
+ uint64_t shared_perm, int64_t speed, int flags,
125
BlockCompletionFunc *cb, void *opaque, Error **errp);
126
127
/**
128
diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c
129
index XXXXXXX..XXXXXXX 100644
130
--- a/tests/test-blockjob-txn.c
131
+++ b/tests/test-blockjob-txn.c
132
@@ -XXX,XX +XXX,XX @@ static BlockJob *test_block_job_start(unsigned int iterations,
133
g_assert_nonnull(bs);
134
135
snprintf(job_id, sizeof(job_id), "job%u", counter++);
136
- s = block_job_create(job_id, &test_block_job_driver, bs, 0,
137
- BLOCK_JOB_DEFAULT, test_block_job_cb,
138
- data, &error_abort);
139
+ s = block_job_create(job_id, &test_block_job_driver, bs,
140
+ 0, BLK_PERM_ALL, 0, BLOCK_JOB_DEFAULT,
141
+ test_block_job_cb, data, &error_abort);
142
s->iterations = iterations;
143
s->use_timer = use_timer;
144
s->rc = rc;
145
diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c
146
index XXXXXXX..XXXXXXX 100644
147
--- a/tests/test-blockjob.c
148
+++ b/tests/test-blockjob.c
149
@@ -XXX,XX +XXX,XX @@ static BlockJob *do_test_id(BlockBackend *blk, const char *id,
150
BlockJob *job;
151
Error *errp = NULL;
152
153
- job = block_job_create(id, &test_block_job_driver, blk_bs(blk), 0,
154
- BLOCK_JOB_DEFAULT, block_job_cb, NULL, &errp);
155
+ job = block_job_create(id, &test_block_job_driver, blk_bs(blk),
156
+ 0, BLK_PERM_ALL, 0, BLOCK_JOB_DEFAULT, block_job_cb,
157
+ NULL, &errp);
158
if (should_succeed) {
159
g_assert_null(errp);
160
g_assert_nonnull(job);
161
--
162
1.8.3.1
163
164
diff view generated by jsdifflib
Deleted patch
1
For meaningful error messages in the permission system, we need to get
2
some human-readable description of the parent of a BdrvChild.
3
1
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Acked-by: Fam Zheng <famz@redhat.com>
7
---
8
block.c | 9 +++++++++
9
block/block-backend.c | 21 +++++++++++++++++++++
10
include/block/block_int.h | 6 ++++++
11
3 files changed, 36 insertions(+)
12
13
diff --git a/block.c b/block.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/block.c
16
+++ b/block.c
17
@@ -XXX,XX +XXX,XX @@ int bdrv_parse_cache_mode(const char *mode, int *flags, bool *writethrough)
18
return 0;
19
}
20
21
+static char *bdrv_child_get_parent_desc(BdrvChild *c)
22
+{
23
+ BlockDriverState *parent = c->opaque;
24
+ return g_strdup(bdrv_get_device_or_node_name(parent));
25
+}
26
+
27
static void bdrv_child_cb_drained_begin(BdrvChild *child)
28
{
29
BlockDriverState *bs = child->opaque;
30
@@ -XXX,XX +XXX,XX @@ static void bdrv_inherited_options(int *child_flags, QDict *child_options,
31
}
32
33
const BdrvChildRole child_file = {
34
+ .get_parent_desc = bdrv_child_get_parent_desc,
35
.inherit_options = bdrv_inherited_options,
36
.drained_begin = bdrv_child_cb_drained_begin,
37
.drained_end = bdrv_child_cb_drained_end,
38
@@ -XXX,XX +XXX,XX @@ static void bdrv_inherited_fmt_options(int *child_flags, QDict *child_options,
39
}
40
41
const BdrvChildRole child_format = {
42
+ .get_parent_desc = bdrv_child_get_parent_desc,
43
.inherit_options = bdrv_inherited_fmt_options,
44
.drained_begin = bdrv_child_cb_drained_begin,
45
.drained_end = bdrv_child_cb_drained_end,
46
@@ -XXX,XX +XXX,XX @@ static void bdrv_backing_options(int *child_flags, QDict *child_options,
47
}
48
49
const BdrvChildRole child_backing = {
50
+ .get_parent_desc = bdrv_child_get_parent_desc,
51
.inherit_options = bdrv_backing_options,
52
.drained_begin = bdrv_child_cb_drained_begin,
53
.drained_end = bdrv_child_cb_drained_end,
54
diff --git a/block/block-backend.c b/block/block-backend.c
55
index XXXXXXX..XXXXXXX 100644
56
--- a/block/block-backend.c
57
+++ b/block/block-backend.c
58
@@ -XXX,XX +XXX,XX @@ static const AIOCBInfo block_backend_aiocb_info = {
59
60
static void drive_info_del(DriveInfo *dinfo);
61
static BlockBackend *bdrv_first_blk(BlockDriverState *bs);
62
+static char *blk_get_attached_dev_id(BlockBackend *blk);
63
64
/* All BlockBackends */
65
static QTAILQ_HEAD(, BlockBackend) block_backends =
66
@@ -XXX,XX +XXX,XX @@ static void blk_root_drained_end(BdrvChild *child);
67
static void blk_root_change_media(BdrvChild *child, bool load);
68
static void blk_root_resize(BdrvChild *child);
69
70
+static char *blk_root_get_parent_desc(BdrvChild *child)
71
+{
72
+ BlockBackend *blk = child->opaque;
73
+ char *dev_id;
74
+
75
+ if (blk->name) {
76
+ return g_strdup(blk->name);
77
+ }
78
+
79
+ dev_id = blk_get_attached_dev_id(blk);
80
+ if (*dev_id) {
81
+ return dev_id;
82
+ } else {
83
+ /* TODO Callback into the BB owner for something more detailed */
84
+ g_free(dev_id);
85
+ return g_strdup("a block device");
86
+ }
87
+}
88
+
89
static const char *blk_root_get_name(BdrvChild *child)
90
{
91
return blk_name(child->opaque);
92
@@ -XXX,XX +XXX,XX @@ static const BdrvChildRole child_root = {
93
.change_media = blk_root_change_media,
94
.resize = blk_root_resize,
95
.get_name = blk_root_get_name,
96
+ .get_parent_desc = blk_root_get_parent_desc,
97
98
.drained_begin = blk_root_drained_begin,
99
.drained_end = blk_root_drained_end,
100
diff --git a/include/block/block_int.h b/include/block/block_int.h
101
index XXXXXXX..XXXXXXX 100644
102
--- a/include/block/block_int.h
103
+++ b/include/block/block_int.h
104
@@ -XXX,XX +XXX,XX @@ struct BdrvChildRole {
105
* name), or NULL if the parent can't provide a better name. */
106
const char* (*get_name)(BdrvChild *child);
107
108
+ /* Returns a malloced string that describes the parent of the child for a
109
+ * human reader. This could be a node-name, BlockBackend name, qdev ID or
110
+ * QOM path of the device owning the BlockBackend, job type and ID etc. The
111
+ * caller is responsible for freeing the memory. */
112
+ char* (*get_parent_desc)(BdrvChild *child);
113
+
114
/*
115
* If this pair of functions is implemented, the parent doesn't issue new
116
* requests after returning from .drained_begin() until .drained_end() is
117
--
118
1.8.3.1
119
120
diff view generated by jsdifflib
Deleted patch
1
Instead of just telling that there was some conflict, we can be specific
2
and tell which permissions were in conflict and which way the conflict
3
is.
4
1
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Acked-by: Fam Zheng <famz@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
---
9
block.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
10
1 file changed, 56 insertions(+), 11 deletions(-)
11
12
diff --git a/block.c b/block.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/block.c
15
+++ b/block.c
16
@@ -XXX,XX +XXX,XX @@ static void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm,
17
*shared_perm = cumulative_shared_perms;
18
}
19
20
+static char *bdrv_child_user_desc(BdrvChild *c)
21
+{
22
+ if (c->role->get_parent_desc) {
23
+ return c->role->get_parent_desc(c);
24
+ }
25
+
26
+ return g_strdup("another user");
27
+}
28
+
29
+static char *bdrv_perm_names(uint64_t perm)
30
+{
31
+ struct perm_name {
32
+ uint64_t perm;
33
+ const char *name;
34
+ } permissions[] = {
35
+ { BLK_PERM_CONSISTENT_READ, "consistent read" },
36
+ { BLK_PERM_WRITE, "write" },
37
+ { BLK_PERM_WRITE_UNCHANGED, "write unchanged" },
38
+ { BLK_PERM_RESIZE, "resize" },
39
+ { BLK_PERM_GRAPH_MOD, "change children" },
40
+ { 0, NULL }
41
+ };
42
+
43
+ char *result = g_strdup("");
44
+ struct perm_name *p;
45
+
46
+ for (p = permissions; p->name; p++) {
47
+ if (perm & p->perm) {
48
+ char *old = result;
49
+ result = g_strdup_printf("%s%s%s", old, *old ? ", " : "", p->name);
50
+ g_free(old);
51
+ }
52
+ }
53
+
54
+ return result;
55
+}
56
+
57
/*
58
* Checks whether a new reference to @bs can be added if the new user requires
59
* @new_used_perm/@new_shared_perm as its permissions. If @ignore_child is set,
60
@@ -XXX,XX +XXX,XX @@ static int bdrv_check_update_perm(BlockDriverState *bs, uint64_t new_used_perm,
61
continue;
62
}
63
64
- if ((new_used_perm & c->shared_perm) != new_used_perm ||
65
- (c->perm & new_shared_perm) != c->perm)
66
- {
67
- const char *user = NULL;
68
- if (c->role->get_name) {
69
- user = c->role->get_name(c);
70
- if (user && !*user) {
71
- user = NULL;
72
- }
73
- }
74
- error_setg(errp, "Conflicts with %s", user ?: "another operation");
75
+ if ((new_used_perm & c->shared_perm) != new_used_perm) {
76
+ char *user = bdrv_child_user_desc(c);
77
+ char *perm_names = bdrv_perm_names(new_used_perm & ~c->shared_perm);
78
+ error_setg(errp, "Conflicts with use by %s as '%s', which does not "
79
+ "allow '%s' on %s",
80
+ user, c->name, perm_names, bdrv_get_node_name(c->bs));
81
+ g_free(user);
82
+ g_free(perm_names);
83
+ return -EPERM;
84
+ }
85
+
86
+ if ((c->perm & new_shared_perm) != c->perm) {
87
+ char *user = bdrv_child_user_desc(c);
88
+ char *perm_names = bdrv_perm_names(c->perm & ~new_shared_perm);
89
+ error_setg(errp, "Conflicts with use by %s as '%s', which uses "
90
+ "'%s' on %s",
91
+ user, c->name, perm_names, bdrv_get_node_name(c->bs));
92
+ g_free(user);
93
+ g_free(perm_names);
94
return -EPERM;
95
}
96
97
--
98
1.8.3.1
99
100
diff view generated by jsdifflib
Deleted patch
1
When the parents' child links are updated in bdrv_append() or
2
bdrv_replace_in_backing_chain(), this should affect all child links of
3
BlockBackends or other nodes, but not on child links held for other
4
purposes (like for setting permissions). This patch allows to control
5
the behaviour per BdrvChildRole.
6
1
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Acked-by: Fam Zheng <famz@redhat.com>
10
---
11
block.c | 3 +++
12
include/block/block_int.h | 4 ++++
13
2 files changed, 7 insertions(+)
14
15
diff --git a/block.c b/block.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/block.c
18
+++ b/block.c
19
@@ -XXX,XX +XXX,XX @@ static void change_parent_backing_link(BlockDriverState *from,
20
BdrvChild *c, *next, *to_c;
21
22
QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) {
23
+ if (c->role->stay_at_node) {
24
+ continue;
25
+ }
26
if (c->role == &child_backing) {
27
/* @from is generally not allowed to be a backing file, except for
28
* when @to is the overlay. In that case, @from may not be replaced
29
diff --git a/include/block/block_int.h b/include/block/block_int.h
30
index XXXXXXX..XXXXXXX 100644
31
--- a/include/block/block_int.h
32
+++ b/include/block/block_int.h
33
@@ -XXX,XX +XXX,XX @@ typedef struct BdrvAioNotifier {
34
} BdrvAioNotifier;
35
36
struct BdrvChildRole {
37
+ /* If true, bdrv_replace_in_backing_chain() doesn't change the node this
38
+ * BdrvChild points to. */
39
+ bool stay_at_node;
40
+
41
void (*inherit_options)(int *child_flags, QDict *child_options,
42
int parent_flags, QDict *parent_options);
43
44
--
45
1.8.3.1
46
47
diff view generated by jsdifflib
Deleted patch
1
Block jobs don't actually do I/O through the the reference they create
2
with block_job_add_bdrv(), but they might want to use the permisssion
3
system to express what the block job does to intermediate nodes. This
4
adds permissions to block_job_add_bdrv() to provide the means to request
5
permissions.
6
1
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Acked-by: Fam Zheng <famz@redhat.com>
10
---
11
block/backup.c | 4 +++-
12
block/commit.c | 8 ++++++--
13
block/mirror.c | 9 +++++++--
14
block/stream.c | 4 +++-
15
blockjob.c | 36 ++++++++++++++++++++++++++++++------
16
include/block/blockjob.h | 5 ++++-
17
6 files changed, 53 insertions(+), 13 deletions(-)
18
19
diff --git a/block/backup.c b/block/backup.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/block/backup.c
22
+++ b/block/backup.c
23
@@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
24
job->cluster_size = MAX(BACKUP_CLUSTER_SIZE_DEFAULT, bdi.cluster_size);
25
}
26
27
- block_job_add_bdrv(&job->common, target);
28
+ /* FIXME Use real permissions */
29
+ block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL,
30
+ &error_abort);
31
job->common.len = len;
32
block_job_txn_add_job(txn, &job->common);
33
34
diff --git a/block/commit.c b/block/commit.c
35
index XXXXXXX..XXXXXXX 100644
36
--- a/block/commit.c
37
+++ b/block/commit.c
38
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
39
* disappear from the chain after this operation. */
40
assert(bdrv_chain_contains(top, base));
41
for (iter = top; iter != backing_bs(base); iter = backing_bs(iter)) {
42
- block_job_add_bdrv(&s->common, iter);
43
+ /* FIXME Use real permissions */
44
+ block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
45
+ BLK_PERM_ALL, &error_abort);
46
}
47
/* overlay_bs must be blocked because it needs to be modified to
48
* update the backing image string, but if it's the root node then
49
* don't block it again */
50
if (bs != overlay_bs) {
51
- block_job_add_bdrv(&s->common, overlay_bs);
52
+ /* FIXME Use real permissions */
53
+ block_job_add_bdrv(&s->common, "overlay of top", overlay_bs, 0,
54
+ BLK_PERM_ALL, &error_abort);
55
}
56
57
/* FIXME Use real permissions */
58
diff --git a/block/mirror.c b/block/mirror.c
59
index XXXXXXX..XXXXXXX 100644
60
--- a/block/mirror.c
61
+++ b/block/mirror.c
62
@@ -XXX,XX +XXX,XX @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
63
return;
64
}
65
66
- block_job_add_bdrv(&s->common, target);
67
+ /* FIXME Use real permissions */
68
+ block_job_add_bdrv(&s->common, "target", target, 0, BLK_PERM_ALL,
69
+ &error_abort);
70
+
71
/* In commit_active_start() all intermediate nodes disappear, so
72
* any jobs in them must be blocked */
73
if (bdrv_chain_contains(bs, target)) {
74
BlockDriverState *iter;
75
for (iter = backing_bs(bs); iter != target; iter = backing_bs(iter)) {
76
- block_job_add_bdrv(&s->common, iter);
77
+ /* FIXME Use real permissions */
78
+ block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
79
+ BLK_PERM_ALL, &error_abort);
80
}
81
}
82
83
diff --git a/block/stream.c b/block/stream.c
84
index XXXXXXX..XXXXXXX 100644
85
--- a/block/stream.c
86
+++ b/block/stream.c
87
@@ -XXX,XX +XXX,XX @@ void stream_start(const char *job_id, BlockDriverState *bs,
88
/* Block all intermediate nodes between bs and base, because they
89
* will disappear from the chain after this operation */
90
for (iter = backing_bs(bs); iter && iter != base; iter = backing_bs(iter)) {
91
- block_job_add_bdrv(&s->common, iter);
92
+ /* FIXME Use real permissions */
93
+ block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
94
+ BLK_PERM_ALL, &error_abort);
95
}
96
97
s->base = base;
98
diff --git a/blockjob.c b/blockjob.c
99
index XXXXXXX..XXXXXXX 100644
100
--- a/blockjob.c
101
+++ b/blockjob.c
102
@@ -XXX,XX +XXX,XX @@ struct BlockJobTxn {
103
104
static QLIST_HEAD(, BlockJob) block_jobs = QLIST_HEAD_INITIALIZER(block_jobs);
105
106
+static char *child_job_get_parent_desc(BdrvChild *c)
107
+{
108
+ BlockJob *job = c->opaque;
109
+ return g_strdup_printf("%s job '%s'",
110
+ BlockJobType_lookup[job->driver->job_type],
111
+ job->id);
112
+}
113
+
114
+static const BdrvChildRole child_job = {
115
+ .get_parent_desc = child_job_get_parent_desc,
116
+ .stay_at_node = true,
117
+};
118
+
119
BlockJob *block_job_next(BlockJob *job)
120
{
121
if (!job) {
122
@@ -XXX,XX +XXX,XX @@ static void block_job_detach_aio_context(void *opaque)
123
block_job_unref(job);
124
}
125
126
-void block_job_add_bdrv(BlockJob *job, BlockDriverState *bs)
127
+int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs,
128
+ uint64_t perm, uint64_t shared_perm, Error **errp)
129
{
130
- job->nodes = g_slist_prepend(job->nodes, bs);
131
+ BdrvChild *c;
132
+
133
+ c = bdrv_root_attach_child(bs, name, &child_job, perm, shared_perm,
134
+ job, errp);
135
+ if (c == NULL) {
136
+ return -EPERM;
137
+ }
138
+
139
+ job->nodes = g_slist_prepend(job->nodes, c);
140
bdrv_ref(bs);
141
bdrv_op_block_all(bs, job->blocker);
142
+
143
+ return 0;
144
}
145
146
void *block_job_create(const char *job_id, const BlockJobDriver *driver,
147
@@ -XXX,XX +XXX,XX @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
148
job = g_malloc0(driver->instance_size);
149
error_setg(&job->blocker, "block device is in use by block job: %s",
150
BlockJobType_lookup[driver->job_type]);
151
- block_job_add_bdrv(job, bs);
152
+ block_job_add_bdrv(job, "main node", bs, 0, BLK_PERM_ALL, &error_abort);
153
bdrv_op_unblock(bs, BLOCK_OP_TYPE_DATAPLANE, job->blocker);
154
155
job->driver = driver;
156
@@ -XXX,XX +XXX,XX @@ void block_job_unref(BlockJob *job)
157
BlockDriverState *bs = blk_bs(job->blk);
158
bs->job = NULL;
159
for (l = job->nodes; l; l = l->next) {
160
- bs = l->data;
161
- bdrv_op_unblock_all(bs, job->blocker);
162
- bdrv_unref(bs);
163
+ BdrvChild *c = l->data;
164
+ bdrv_op_unblock_all(c->bs, job->blocker);
165
+ bdrv_root_unref_child(c);
166
}
167
g_slist_free(job->nodes);
168
blk_remove_aio_context_notifier(job->blk,
169
diff --git a/include/block/blockjob.h b/include/block/blockjob.h
170
index XXXXXXX..XXXXXXX 100644
171
--- a/include/block/blockjob.h
172
+++ b/include/block/blockjob.h
173
@@ -XXX,XX +XXX,XX @@ BlockJob *block_job_get(const char *id);
174
/**
175
* block_job_add_bdrv:
176
* @job: A block job
177
+ * @name: The name to assign to the new BdrvChild
178
* @bs: A BlockDriverState that is involved in @job
179
+ * @perm, @shared_perm: Permissions to request on the node
180
*
181
* Add @bs to the list of BlockDriverState that are involved in
182
* @job. This means that all operations will be blocked on @bs while
183
* @job exists.
184
*/
185
-void block_job_add_bdrv(BlockJob *job, BlockDriverState *bs);
186
+int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs,
187
+ uint64_t perm, uint64_t shared_perm, Error **errp);
188
189
/**
190
* block_job_set_speed:
191
--
192
1.8.3.1
193
194
diff view generated by jsdifflib
Deleted patch
1
This is probably one of the most interesting conversions to the new
2
op blocker system because a commit block job intentionally leaves some
3
intermediate block nodes in the backing chain that aren't valid on their
4
own any more; only the whole chain together results in a valid view.
5
1
6
In order to provide the 'consistent read' permission to the parents of
7
the 'top' node of the commit job, a new filter block driver is inserted
8
above 'top' which doesn't require 'consistent read' on its backing
9
chain. Subsequently, the commit job can block 'consistent read' on all
10
intermediate nodes without causing a conflict.
11
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Acked-by: Fam Zheng <famz@redhat.com>
14
Reviewed-by: Max Reitz <mreitz@redhat.com>
15
---
16
block/commit.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++---------
17
1 file changed, 95 insertions(+), 18 deletions(-)
18
19
diff --git a/block/commit.c b/block/commit.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/block/commit.c
22
+++ b/block/commit.c
23
@@ -XXX,XX +XXX,XX @@ typedef struct CommitBlockJob {
24
BlockJob common;
25
RateLimit limit;
26
BlockDriverState *active;
27
+ BlockDriverState *commit_top_bs;
28
BlockBackend *top;
29
BlockBackend *base;
30
BlockdevOnError on_error;
31
@@ -XXX,XX +XXX,XX @@ static void commit_complete(BlockJob *job, void *opaque)
32
BlockDriverState *active = s->active;
33
BlockDriverState *top = blk_bs(s->top);
34
BlockDriverState *base = blk_bs(s->base);
35
- BlockDriverState *overlay_bs = bdrv_find_overlay(active, top);
36
+ BlockDriverState *overlay_bs = bdrv_find_overlay(active, s->commit_top_bs);
37
int ret = data->ret;
38
+ bool remove_commit_top_bs = false;
39
+
40
+ /* Remove base node parent that still uses BLK_PERM_WRITE/RESIZE before
41
+ * the normal backing chain can be restored. */
42
+ blk_unref(s->base);
43
44
if (!block_job_is_cancelled(&s->common) && ret == 0) {
45
/* success */
46
- ret = bdrv_drop_intermediate(active, top, base, s->backing_file_str);
47
+ ret = bdrv_drop_intermediate(active, s->commit_top_bs, base,
48
+ s->backing_file_str);
49
+ } else if (overlay_bs) {
50
+ /* XXX Can (or should) we somehow keep 'consistent read' blocked even
51
+ * after the failed/cancelled commit job is gone? If we already wrote
52
+ * something to base, the intermediate images aren't valid any more. */
53
+ remove_commit_top_bs = true;
54
}
55
56
/* restore base open flags here if appropriate (e.g., change the base back
57
@@ -XXX,XX +XXX,XX @@ static void commit_complete(BlockJob *job, void *opaque)
58
}
59
g_free(s->backing_file_str);
60
blk_unref(s->top);
61
- blk_unref(s->base);
62
block_job_completed(&s->common, ret);
63
g_free(data);
64
+
65
+ /* If bdrv_drop_intermediate() didn't already do that, remove the commit
66
+ * filter driver from the backing chain. Do this as the final step so that
67
+ * the 'consistent read' permission can be granted. */
68
+ if (remove_commit_top_bs) {
69
+ bdrv_set_backing_hd(overlay_bs, top);
70
+ }
71
}
72
73
static void coroutine_fn commit_run(void *opaque)
74
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver commit_job_driver = {
75
.start = commit_run,
76
};
77
78
+static int coroutine_fn bdrv_commit_top_preadv(BlockDriverState *bs,
79
+ uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags)
80
+{
81
+ return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags);
82
+}
83
+
84
+static void bdrv_commit_top_close(BlockDriverState *bs)
85
+{
86
+}
87
+
88
+static void bdrv_commit_top_child_perm(BlockDriverState *bs, BdrvChild *c,
89
+ const BdrvChildRole *role,
90
+ uint64_t perm, uint64_t shared,
91
+ uint64_t *nperm, uint64_t *nshared)
92
+{
93
+ *nperm = 0;
94
+ *nshared = BLK_PERM_ALL;
95
+}
96
+
97
+/* Dummy node that provides consistent read to its users without requiring it
98
+ * from its backing file and that allows writes on the backing file chain. */
99
+static BlockDriver bdrv_commit_top = {
100
+ .format_name = "commit_top",
101
+ .bdrv_co_preadv = bdrv_commit_top_preadv,
102
+ .bdrv_close = bdrv_commit_top_close,
103
+ .bdrv_child_perm = bdrv_commit_top_child_perm,
104
+};
105
+
106
void commit_start(const char *job_id, BlockDriverState *bs,
107
BlockDriverState *base, BlockDriverState *top, int64_t speed,
108
BlockdevOnError on_error, const char *backing_file_str,
109
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
110
int orig_base_flags;
111
BlockDriverState *iter;
112
BlockDriverState *overlay_bs;
113
+ BlockDriverState *commit_top_bs = NULL;
114
Error *local_err = NULL;
115
int ret;
116
117
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
118
return;
119
}
120
121
- /* FIXME Use real permissions */
122
s = block_job_create(job_id, &commit_job_driver, bs, 0, BLK_PERM_ALL,
123
speed, BLOCK_JOB_DEFAULT, NULL, NULL, errp);
124
if (!s) {
125
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
126
}
127
}
128
129
+ /* Insert commit_top block node above top, so we can block consistent read
130
+ * on the backing chain below it */
131
+ commit_top_bs = bdrv_new_open_driver(&bdrv_commit_top, NULL, 0, errp);
132
+ if (commit_top_bs == NULL) {
133
+ goto fail;
134
+ }
135
+
136
+ bdrv_set_backing_hd(commit_top_bs, top);
137
+ bdrv_set_backing_hd(overlay_bs, commit_top_bs);
138
+
139
+ s->commit_top_bs = commit_top_bs;
140
+ bdrv_unref(commit_top_bs);
141
142
/* Block all nodes between top and base, because they will
143
* disappear from the chain after this operation. */
144
assert(bdrv_chain_contains(top, base));
145
- for (iter = top; iter != backing_bs(base); iter = backing_bs(iter)) {
146
- /* FIXME Use real permissions */
147
- block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
148
- BLK_PERM_ALL, &error_abort);
149
+ for (iter = top; iter != base; iter = backing_bs(iter)) {
150
+ /* XXX BLK_PERM_WRITE needs to be allowed so we don't block ourselves
151
+ * at s->base (if writes are blocked for a node, they are also blocked
152
+ * for its backing file). The other options would be a second filter
153
+ * driver above s->base. */
154
+ ret = block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
155
+ BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE,
156
+ errp);
157
+ if (ret < 0) {
158
+ goto fail;
159
+ }
160
}
161
+
162
+ ret = block_job_add_bdrv(&s->common, "base", base, 0, BLK_PERM_ALL, errp);
163
+ if (ret < 0) {
164
+ goto fail;
165
+ }
166
+
167
/* overlay_bs must be blocked because it needs to be modified to
168
- * update the backing image string, but if it's the root node then
169
- * don't block it again */
170
- if (bs != overlay_bs) {
171
- /* FIXME Use real permissions */
172
- block_job_add_bdrv(&s->common, "overlay of top", overlay_bs, 0,
173
- BLK_PERM_ALL, &error_abort);
174
+ * update the backing image string. */
175
+ ret = block_job_add_bdrv(&s->common, "overlay of top", overlay_bs,
176
+ BLK_PERM_GRAPH_MOD, BLK_PERM_ALL, errp);
177
+ if (ret < 0) {
178
+ goto fail;
179
}
180
181
- /* FIXME Use real permissions */
182
- s->base = blk_new(0, BLK_PERM_ALL);
183
+ s->base = blk_new(BLK_PERM_CONSISTENT_READ
184
+ | BLK_PERM_WRITE
185
+ | BLK_PERM_RESIZE,
186
+ BLK_PERM_CONSISTENT_READ
187
+ | BLK_PERM_GRAPH_MOD
188
+ | BLK_PERM_WRITE_UNCHANGED);
189
ret = blk_insert_bs(s->base, base, errp);
190
if (ret < 0) {
191
goto fail;
192
}
193
194
- /* FIXME Use real permissions */
195
+ /* Required permissions are already taken with block_job_add_bdrv() */
196
s->top = blk_new(0, BLK_PERM_ALL);
197
- ret = blk_insert_bs(s->top, top, errp);
198
+ blk_insert_bs(s->top, top, errp);
199
if (ret < 0) {
200
goto fail;
201
}
202
@@ -XXX,XX +XXX,XX @@ fail:
203
if (s->top) {
204
blk_unref(s->top);
205
}
206
+ if (commit_top_bs) {
207
+ bdrv_set_backing_hd(overlay_bs, top);
208
+ }
209
block_job_unref(&s->common);
210
}
211
212
--
213
1.8.3.1
214
215
diff view generated by jsdifflib
Deleted patch
1
This is a little simpler than the commit block job because it's
2
synchronous and only commits into the immediate backing file, but
3
otherwise doing more or less the same.
4
1
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
Acked-by: Fam Zheng <famz@redhat.com>
8
---
9
block/commit.c | 33 +++++++++++++++++++++++++++------
10
1 file changed, 27 insertions(+), 6 deletions(-)
11
12
diff --git a/block/commit.c b/block/commit.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/block/commit.c
15
+++ b/block/commit.c
16
@@ -XXX,XX +XXX,XX @@ fail:
17
int bdrv_commit(BlockDriverState *bs)
18
{
19
BlockBackend *src, *backing;
20
+ BlockDriverState *backing_file_bs = NULL;
21
+ BlockDriverState *commit_top_bs = NULL;
22
BlockDriver *drv = bs->drv;
23
int64_t sector, total_sectors, length, backing_length;
24
int n, ro, open_flags;
25
int ret = 0;
26
uint8_t *buf = NULL;
27
+ Error *local_err = NULL;
28
29
if (!drv)
30
return -ENOMEDIUM;
31
@@ -XXX,XX +XXX,XX @@ int bdrv_commit(BlockDriverState *bs)
32
}
33
}
34
35
- /* FIXME Use real permissions */
36
- src = blk_new(0, BLK_PERM_ALL);
37
- backing = blk_new(0, BLK_PERM_ALL);
38
+ src = blk_new(BLK_PERM_CONSISTENT_READ, BLK_PERM_ALL);
39
+ backing = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
40
41
- ret = blk_insert_bs(src, bs, NULL);
42
+ ret = blk_insert_bs(src, bs, &local_err);
43
if (ret < 0) {
44
+ error_report_err(local_err);
45
+ goto ro_cleanup;
46
+ }
47
+
48
+ /* Insert commit_top block node above backing, so we can write to it */
49
+ backing_file_bs = backing_bs(bs);
50
+
51
+ commit_top_bs = bdrv_new_open_driver(&bdrv_commit_top, NULL, BDRV_O_RDWR,
52
+ &local_err);
53
+ if (commit_top_bs == NULL) {
54
+ error_report_err(local_err);
55
goto ro_cleanup;
56
}
57
58
- ret = blk_insert_bs(backing, bs->backing->bs, NULL);
59
+ bdrv_set_backing_hd(commit_top_bs, backing_file_bs);
60
+ bdrv_set_backing_hd(bs, commit_top_bs);
61
+
62
+ ret = blk_insert_bs(backing, backing_file_bs, &local_err);
63
if (ret < 0) {
64
+ error_report_err(local_err);
65
goto ro_cleanup;
66
}
67
68
@@ -XXX,XX +XXX,XX @@ int bdrv_commit(BlockDriverState *bs)
69
ro_cleanup:
70
qemu_vfree(buf);
71
72
- blk_unref(src);
73
blk_unref(backing);
74
+ if (backing_file_bs) {
75
+ bdrv_set_backing_hd(bs, backing_file_bs);
76
+ }
77
+ bdrv_unref(commit_top_bs);
78
+ blk_unref(src);
79
80
if (ro) {
81
/* ignoring error return here */
82
--
83
1.8.3.1
84
85
diff view generated by jsdifflib
Deleted patch
1
The backup block job doesn't have very complicated requirements: It
2
needs to read from the source and write to the target, but it's fine
3
with either side being changed. The only restriction is that we can't
4
resize the image because the job uses a cached value.
5
1
6
qemu-iotests 055 needs to be changed because it used a target which was
7
already attached to a virtio-blk device. The permission system correctly
8
forbids this (virtio-blk can't accept another writer with its default
9
share-rw=off).
10
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Reviewed-by: Max Reitz <mreitz@redhat.com>
13
Acked-by: Fam Zheng <famz@redhat.com>
14
---
15
block/backup.c | 15 ++++++++++-----
16
tests/qemu-iotests/055 | 11 +++++++----
17
2 files changed, 17 insertions(+), 9 deletions(-)
18
19
diff --git a/block/backup.c b/block/backup.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/block/backup.c
22
+++ b/block/backup.c
23
@@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
24
goto error;
25
}
26
27
- /* FIXME Use real permissions */
28
- job = block_job_create(job_id, &backup_job_driver, bs, 0, BLK_PERM_ALL,
29
+ /* job->common.len is fixed, so we can't allow resize */
30
+ job = block_job_create(job_id, &backup_job_driver, bs,
31
+ BLK_PERM_CONSISTENT_READ,
32
+ BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE |
33
+ BLK_PERM_WRITE_UNCHANGED | BLK_PERM_GRAPH_MOD,
34
speed, creation_flags, cb, opaque, errp);
35
if (!job) {
36
goto error;
37
}
38
39
- /* FIXME Use real permissions */
40
- job->target = blk_new(0, BLK_PERM_ALL);
41
+ /* The target must match the source in size, so no resize here either */
42
+ job->target = blk_new(BLK_PERM_WRITE,
43
+ BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE |
44
+ BLK_PERM_WRITE_UNCHANGED | BLK_PERM_GRAPH_MOD);
45
ret = blk_insert_bs(job->target, target, errp);
46
if (ret < 0) {
47
goto error;
48
@@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
49
job->cluster_size = MAX(BACKUP_CLUSTER_SIZE_DEFAULT, bdi.cluster_size);
50
}
51
52
- /* FIXME Use real permissions */
53
+ /* Required permissions are already taken with target's blk_new() */
54
block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL,
55
&error_abort);
56
job->common.len = len;
57
diff --git a/tests/qemu-iotests/055 b/tests/qemu-iotests/055
58
index XXXXXXX..XXXXXXX 100755
59
--- a/tests/qemu-iotests/055
60
+++ b/tests/qemu-iotests/055
61
@@ -XXX,XX +XXX,XX @@ class TestSingleDrive(iotests.QMPTestCase):
62
def setUp(self):
63
qemu_img('create', '-f', iotests.imgfmt, blockdev_target_img, str(image_len))
64
65
- self.vm = iotests.VM().add_drive(test_img).add_drive(blockdev_target_img)
66
+ self.vm = iotests.VM().add_drive(test_img)
67
+ self.vm.add_drive(blockdev_target_img, interface="none")
68
if iotests.qemu_default_machine == 'pc':
69
self.vm.add_drive(None, 'media=cdrom', 'ide')
70
self.vm.launch()
71
@@ -XXX,XX +XXX,XX @@ class TestSetSpeed(iotests.QMPTestCase):
72
def setUp(self):
73
qemu_img('create', '-f', iotests.imgfmt, blockdev_target_img, str(image_len))
74
75
- self.vm = iotests.VM().add_drive(test_img).add_drive(blockdev_target_img)
76
+ self.vm = iotests.VM().add_drive(test_img)
77
+ self.vm.add_drive(blockdev_target_img, interface="none")
78
self.vm.launch()
79
80
def tearDown(self):
81
@@ -XXX,XX +XXX,XX @@ class TestSingleTransaction(iotests.QMPTestCase):
82
def setUp(self):
83
qemu_img('create', '-f', iotests.imgfmt, blockdev_target_img, str(image_len))
84
85
- self.vm = iotests.VM().add_drive(test_img).add_drive(blockdev_target_img)
86
+ self.vm = iotests.VM().add_drive(test_img)
87
+ self.vm.add_drive(blockdev_target_img, interface="none")
88
if iotests.qemu_default_machine == 'pc':
89
self.vm.add_drive(None, 'media=cdrom', 'ide')
90
self.vm.launch()
91
@@ -XXX,XX +XXX,XX @@ class TestDriveCompression(iotests.QMPTestCase):
92
93
qemu_img('create', '-f', fmt, blockdev_target_img,
94
str(TestDriveCompression.image_len), *args)
95
- self.vm.add_drive(blockdev_target_img, format=fmt)
96
+ self.vm.add_drive(blockdev_target_img, format=fmt, interface="none")
97
98
self.vm.launch()
99
100
--
101
1.8.3.1
102
103
diff view generated by jsdifflib
Deleted patch
1
bdrv_append() cares about isolation of the node that it modifies, but
2
not about activity in some subtree below it. Instead of using the
3
recursive bdrv_requests_pending(), directly check bs->in_flight, which
4
considers only the node in question.
5
1
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Acked-by: Fam Zheng <famz@redhat.com>
9
---
10
block.c | 4 ++--
11
1 file changed, 2 insertions(+), 2 deletions(-)
12
13
diff --git a/block.c b/block.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/block.c
16
+++ b/block.c
17
@@ -XXX,XX +XXX,XX @@ static void change_parent_backing_link(BlockDriverState *from,
18
*/
19
void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top)
20
{
21
- assert(!bdrv_requests_pending(bs_top));
22
- assert(!bdrv_requests_pending(bs_new));
23
+ assert(!atomic_read(&bs_top->in_flight));
24
+ assert(!atomic_read(&bs_new->in_flight));
25
26
bdrv_ref(bs_top);
27
28
--
29
1.8.3.1
30
31
diff view generated by jsdifflib
Deleted patch
1
Backing files are somewhat special compared to other kinds of children
2
because they are attached and detached using bdrv_set_backing_hd()
3
rather than the normal set of functions, which does a few more things
4
like setting backing blockers, toggling the BDRV_O_NO_BACKING flag,
5
setting parent_bs->backing_file, etc.
6
1
7
These special features are a reason why change_parent_backing_link()
8
can't handle backing files yet. With abstracting the additional features
9
into .attach/.detach callbacks, we get a step closer to a function that
10
can actually deal with this.
11
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Reviewed-by: Max Reitz <mreitz@redhat.com>
14
Acked-by: Fam Zheng <famz@redhat.com>
15
---
16
block.c | 95 ++++++++++++++++++++++++++++++-----------------
17
include/block/block_int.h | 3 ++
18
2 files changed, 63 insertions(+), 35 deletions(-)
19
20
diff --git a/block.c b/block.c
21
index XXXXXXX..XXXXXXX 100644
22
--- a/block.c
23
+++ b/block.c
24
@@ -XXX,XX +XXX,XX @@ const BdrvChildRole child_format = {
25
.drained_end = bdrv_child_cb_drained_end,
26
};
27
28
+static void bdrv_backing_attach(BdrvChild *c)
29
+{
30
+ BlockDriverState *parent = c->opaque;
31
+ BlockDriverState *backing_hd = c->bs;
32
+
33
+ assert(!parent->backing_blocker);
34
+ error_setg(&parent->backing_blocker,
35
+ "node is used as backing hd of '%s'",
36
+ bdrv_get_device_or_node_name(parent));
37
+
38
+ parent->open_flags &= ~BDRV_O_NO_BACKING;
39
+ pstrcpy(parent->backing_file, sizeof(parent->backing_file),
40
+ backing_hd->filename);
41
+ pstrcpy(parent->backing_format, sizeof(parent->backing_format),
42
+ backing_hd->drv ? backing_hd->drv->format_name : "");
43
+
44
+ bdrv_op_block_all(backing_hd, parent->backing_blocker);
45
+ /* Otherwise we won't be able to commit or stream */
46
+ bdrv_op_unblock(backing_hd, BLOCK_OP_TYPE_COMMIT_TARGET,
47
+ parent->backing_blocker);
48
+ bdrv_op_unblock(backing_hd, BLOCK_OP_TYPE_STREAM,
49
+ parent->backing_blocker);
50
+ /*
51
+ * We do backup in 3 ways:
52
+ * 1. drive backup
53
+ * The target bs is new opened, and the source is top BDS
54
+ * 2. blockdev backup
55
+ * Both the source and the target are top BDSes.
56
+ * 3. internal backup(used for block replication)
57
+ * Both the source and the target are backing file
58
+ *
59
+ * In case 1 and 2, neither the source nor the target is the backing file.
60
+ * In case 3, we will block the top BDS, so there is only one block job
61
+ * for the top BDS and its backing chain.
62
+ */
63
+ bdrv_op_unblock(backing_hd, BLOCK_OP_TYPE_BACKUP_SOURCE,
64
+ parent->backing_blocker);
65
+ bdrv_op_unblock(backing_hd, BLOCK_OP_TYPE_BACKUP_TARGET,
66
+ parent->backing_blocker);
67
+}
68
+
69
+static void bdrv_backing_detach(BdrvChild *c)
70
+{
71
+ BlockDriverState *parent = c->opaque;
72
+
73
+ assert(parent->backing_blocker);
74
+ bdrv_op_unblock_all(c->bs, parent->backing_blocker);
75
+ error_free(parent->backing_blocker);
76
+ parent->backing_blocker = NULL;
77
+}
78
+
79
/*
80
* Returns the options and flags that bs->backing should get, based on the
81
* given options and flags for the parent BDS
82
@@ -XXX,XX +XXX,XX @@ static void bdrv_backing_options(int *child_flags, QDict *child_options,
83
84
const BdrvChildRole child_backing = {
85
.get_parent_desc = bdrv_child_get_parent_desc,
86
+ .attach = bdrv_backing_attach,
87
+ .detach = bdrv_backing_detach,
88
.inherit_options = bdrv_backing_options,
89
.drained_begin = bdrv_child_cb_drained_begin,
90
.drained_end = bdrv_child_cb_drained_end,
91
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs,
92
if (old_bs->quiesce_counter && child->role->drained_end) {
93
child->role->drained_end(child);
94
}
95
+ if (child->role->detach) {
96
+ child->role->detach(child);
97
+ }
98
QLIST_REMOVE(child, next_parent);
99
100
/* Update permissions for old node. This is guaranteed to succeed
101
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs,
102
bdrv_check_perm(new_bs, perm, shared_perm, &error_abort);
103
}
104
bdrv_set_perm(new_bs, perm, shared_perm);
105
+
106
+ if (child->role->attach) {
107
+ child->role->attach(child);
108
+ }
109
}
110
}
111
112
@@ -XXX,XX +XXX,XX @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd)
113
}
114
115
if (bs->backing) {
116
- assert(bs->backing_blocker);
117
- bdrv_op_unblock_all(bs->backing->bs, bs->backing_blocker);
118
bdrv_unref_child(bs, bs->backing);
119
- } else if (backing_hd) {
120
- error_setg(&bs->backing_blocker,
121
- "node is used as backing hd of '%s'",
122
- bdrv_get_device_or_node_name(bs));
123
}
124
125
if (!backing_hd) {
126
- error_free(bs->backing_blocker);
127
- bs->backing_blocker = NULL;
128
bs->backing = NULL;
129
goto out;
130
}
131
/* FIXME Error handling */
132
bs->backing = bdrv_attach_child(bs, backing_hd, "backing", &child_backing,
133
&error_abort);
134
- bs->open_flags &= ~BDRV_O_NO_BACKING;
135
- pstrcpy(bs->backing_file, sizeof(bs->backing_file), backing_hd->filename);
136
- pstrcpy(bs->backing_format, sizeof(bs->backing_format),
137
- backing_hd->drv ? backing_hd->drv->format_name : "");
138
139
- bdrv_op_block_all(backing_hd, bs->backing_blocker);
140
- /* Otherwise we won't be able to commit or stream */
141
- bdrv_op_unblock(backing_hd, BLOCK_OP_TYPE_COMMIT_TARGET,
142
- bs->backing_blocker);
143
- bdrv_op_unblock(backing_hd, BLOCK_OP_TYPE_STREAM,
144
- bs->backing_blocker);
145
- /*
146
- * We do backup in 3 ways:
147
- * 1. drive backup
148
- * The target bs is new opened, and the source is top BDS
149
- * 2. blockdev backup
150
- * Both the source and the target are top BDSes.
151
- * 3. internal backup(used for block replication)
152
- * Both the source and the target are backing file
153
- *
154
- * In case 1 and 2, neither the source nor the target is the backing file.
155
- * In case 3, we will block the top BDS, so there is only one block job
156
- * for the top BDS and its backing chain.
157
- */
158
- bdrv_op_unblock(backing_hd, BLOCK_OP_TYPE_BACKUP_SOURCE,
159
- bs->backing_blocker);
160
- bdrv_op_unblock(backing_hd, BLOCK_OP_TYPE_BACKUP_TARGET,
161
- bs->backing_blocker);
162
out:
163
bdrv_refresh_limits(bs, NULL);
164
}
165
diff --git a/include/block/block_int.h b/include/block/block_int.h
166
index XXXXXXX..XXXXXXX 100644
167
--- a/include/block/block_int.h
168
+++ b/include/block/block_int.h
169
@@ -XXX,XX +XXX,XX @@ struct BdrvChildRole {
170
*/
171
void (*drained_begin)(BdrvChild *child);
172
void (*drained_end)(BdrvChild *child);
173
+
174
+ void (*attach)(BdrvChild *child);
175
+ void (*detach)(BdrvChild *child);
176
};
177
178
extern const BdrvChildRole child_file;
179
--
180
1.8.3.1
181
182
diff view generated by jsdifflib
Deleted patch
1
The correct permissions are relatively obvious here (and explained in
2
code comments). For intermediate streaming, we need to reopen the top
3
node read-write before creating the job now because the permissions
4
system catches attempts to get the BLK_PERM_WRITE_UNCHANGED permission
5
on a read-only node.
6
1
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Acked-by: Fam Zheng <famz@redhat.com>
10
---
11
block/stream.c | 39 +++++++++++++++++++++++++++------------
12
1 file changed, 27 insertions(+), 12 deletions(-)
13
14
diff --git a/block/stream.c b/block/stream.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/block/stream.c
17
+++ b/block/stream.c
18
@@ -XXX,XX +XXX,XX @@ static void stream_complete(BlockJob *job, void *opaque)
19
20
/* Reopen the image back in read-only mode if necessary */
21
if (s->bs_flags != bdrv_get_flags(bs)) {
22
+ /* Give up write permissions before making it read-only */
23
+ blk_set_perm(job->blk, 0, BLK_PERM_ALL, &error_abort);
24
bdrv_reopen(bs, s->bs_flags, NULL);
25
}
26
27
@@ -XXX,XX +XXX,XX @@ void stream_start(const char *job_id, BlockDriverState *bs,
28
BlockDriverState *iter;
29
int orig_bs_flags;
30
31
- /* FIXME Use real permissions */
32
- s = block_job_create(job_id, &stream_job_driver, bs, 0, BLK_PERM_ALL,
33
- speed, BLOCK_JOB_DEFAULT, NULL, NULL, errp);
34
- if (!s) {
35
- return;
36
- }
37
-
38
/* Make sure that the image is opened in read-write mode */
39
orig_bs_flags = bdrv_get_flags(bs);
40
if (!(orig_bs_flags & BDRV_O_RDWR)) {
41
if (bdrv_reopen(bs, orig_bs_flags | BDRV_O_RDWR, errp) != 0) {
42
- block_job_unref(&s->common);
43
return;
44
}
45
}
46
47
- /* Block all intermediate nodes between bs and base, because they
48
- * will disappear from the chain after this operation */
49
+ /* Prevent concurrent jobs trying to modify the graph structure here, we
50
+ * already have our own plans. Also don't allow resize as the image size is
51
+ * queried only at the job start and then cached. */
52
+ s = block_job_create(job_id, &stream_job_driver, bs,
53
+ BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED |
54
+ BLK_PERM_GRAPH_MOD,
55
+ BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED |
56
+ BLK_PERM_WRITE,
57
+ speed, BLOCK_JOB_DEFAULT, NULL, NULL, errp);
58
+ if (!s) {
59
+ goto fail;
60
+ }
61
+
62
+ /* Block all intermediate nodes between bs and base, because they will
63
+ * disappear from the chain after this operation. The streaming job reads
64
+ * every block only once, assuming that it doesn't change, so block writes
65
+ * and resizes. */
66
for (iter = backing_bs(bs); iter && iter != base; iter = backing_bs(iter)) {
67
- /* FIXME Use real permissions */
68
block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
69
- BLK_PERM_ALL, &error_abort);
70
+ BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED,
71
+ &error_abort);
72
}
73
74
s->base = base;
75
@@ -XXX,XX +XXX,XX @@ void stream_start(const char *job_id, BlockDriverState *bs,
76
s->on_error = on_error;
77
trace_stream_start(bs, base, s);
78
block_job_start(&s->common);
79
+ return;
80
+
81
+fail:
82
+ if (orig_bs_flags != bdrv_get_flags(bs)) {
83
+ bdrv_reopen(bs, s->bs_flags, NULL);
84
+ }
85
}
86
--
87
1.8.3.1
88
89
diff view generated by jsdifflib
Deleted patch
1
Management tools need to be able to know about every node in the graph
2
and need a way to address them. Changing the graph structure was okay
3
because libvirt doesn't really manage the node level yet, but future
4
libvirt versions need to deal with both new and old version of qemu.
5
1
6
This new option to blockdev-mirror allows the client to set a node-name
7
for the automatically inserted filter driver, and at the same time
8
serves as a witness for a future libvirt that this version of qemu does
9
automatically insert a filter driver.
10
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Reviewed-by: Max Reitz <mreitz@redhat.com>
13
Acked-by: Fam Zheng <famz@redhat.com>
14
---
15
block/mirror.c | 14 ++++++++------
16
blockdev.c | 12 +++++++++++-
17
include/block/block_int.h | 5 ++++-
18
qapi/block-core.json | 8 +++++++-
19
4 files changed, 30 insertions(+), 9 deletions(-)
20
21
diff --git a/block/mirror.c b/block/mirror.c
22
index XXXXXXX..XXXXXXX 100644
23
--- a/block/mirror.c
24
+++ b/block/mirror.c
25
@@ -XXX,XX +XXX,XX @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
26
void *opaque, Error **errp,
27
const BlockJobDriver *driver,
28
bool is_none_mode, BlockDriverState *base,
29
- bool auto_complete)
30
+ bool auto_complete, const char *filter_node_name)
31
{
32
MirrorBlockJob *s;
33
BlockDriverState *mirror_top_bs;
34
@@ -XXX,XX +XXX,XX @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
35
/* In the case of active commit, add dummy driver to provide consistent
36
* reads on the top, while disabling it in the intermediate nodes, and make
37
* the backing chain writable. */
38
- mirror_top_bs = bdrv_new_open_driver(&bdrv_mirror_top, NULL, BDRV_O_RDWR,
39
- errp);
40
+ mirror_top_bs = bdrv_new_open_driver(&bdrv_mirror_top, filter_node_name,
41
+ BDRV_O_RDWR, errp);
42
if (mirror_top_bs == NULL) {
43
return;
44
}
45
@@ -XXX,XX +XXX,XX @@ void mirror_start(const char *job_id, BlockDriverState *bs,
46
MirrorSyncMode mode, BlockMirrorBackingMode backing_mode,
47
BlockdevOnError on_source_error,
48
BlockdevOnError on_target_error,
49
- bool unmap, Error **errp)
50
+ bool unmap, const char *filter_node_name, Error **errp)
51
{
52
bool is_none_mode;
53
BlockDriverState *base;
54
@@ -XXX,XX +XXX,XX @@ void mirror_start(const char *job_id, BlockDriverState *bs,
55
mirror_start_job(job_id, bs, BLOCK_JOB_DEFAULT, target, replaces,
56
speed, granularity, buf_size, backing_mode,
57
on_source_error, on_target_error, unmap, NULL, NULL, errp,
58
- &mirror_job_driver, is_none_mode, base, false);
59
+ &mirror_job_driver, is_none_mode, base, false,
60
+ filter_node_name);
61
}
62
63
void commit_active_start(const char *job_id, BlockDriverState *bs,
64
@@ -XXX,XX +XXX,XX @@ void commit_active_start(const char *job_id, BlockDriverState *bs,
65
mirror_start_job(job_id, bs, creation_flags, base, NULL, speed, 0, 0,
66
MIRROR_LEAVE_BACKING_CHAIN,
67
on_error, on_error, true, cb, opaque, &local_err,
68
- &commit_active_job_driver, false, base, auto_complete);
69
+ &commit_active_job_driver, false, base, auto_complete,
70
+ NULL);
71
if (local_err) {
72
error_propagate(errp, local_err);
73
goto error_restore_flags;
74
diff --git a/blockdev.c b/blockdev.c
75
index XXXXXXX..XXXXXXX 100644
76
--- a/blockdev.c
77
+++ b/blockdev.c
78
@@ -XXX,XX +XXX,XX @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs,
79
bool has_on_target_error,
80
BlockdevOnError on_target_error,
81
bool has_unmap, bool unmap,
82
+ bool has_filter_node_name,
83
+ const char *filter_node_name,
84
Error **errp)
85
{
86
87
@@ -XXX,XX +XXX,XX @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs,
88
if (!has_unmap) {
89
unmap = true;
90
}
91
+ if (!has_filter_node_name) {
92
+ filter_node_name = NULL;
93
+ }
94
95
if (granularity != 0 && (granularity < 512 || granularity > 1048576 * 64)) {
96
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "granularity",
97
@@ -XXX,XX +XXX,XX @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs,
98
mirror_start(job_id, bs, target,
99
has_replaces ? replaces : NULL,
100
speed, granularity, buf_size, sync, backing_mode,
101
- on_source_error, on_target_error, unmap, errp);
102
+ on_source_error, on_target_error, unmap, filter_node_name,
103
+ errp);
104
}
105
106
void qmp_drive_mirror(DriveMirror *arg, Error **errp)
107
@@ -XXX,XX +XXX,XX @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
108
arg->has_on_source_error, arg->on_source_error,
109
arg->has_on_target_error, arg->on_target_error,
110
arg->has_unmap, arg->unmap,
111
+ false, NULL,
112
&local_err);
113
bdrv_unref(target_bs);
114
error_propagate(errp, local_err);
115
@@ -XXX,XX +XXX,XX @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id,
116
BlockdevOnError on_source_error,
117
bool has_on_target_error,
118
BlockdevOnError on_target_error,
119
+ bool has_filter_node_name,
120
+ const char *filter_node_name,
121
Error **errp)
122
{
123
BlockDriverState *bs;
124
@@ -XXX,XX +XXX,XX @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id,
125
has_on_source_error, on_source_error,
126
has_on_target_error, on_target_error,
127
true, true,
128
+ has_filter_node_name, filter_node_name,
129
&local_err);
130
error_propagate(errp, local_err);
131
132
diff --git a/include/block/block_int.h b/include/block/block_int.h
133
index XXXXXXX..XXXXXXX 100644
134
--- a/include/block/block_int.h
135
+++ b/include/block/block_int.h
136
@@ -XXX,XX +XXX,XX @@ void commit_active_start(const char *job_id, BlockDriverState *bs,
137
* @on_source_error: The action to take upon error reading from the source.
138
* @on_target_error: The action to take upon error writing to the target.
139
* @unmap: Whether to unmap target where source sectors only contain zeroes.
140
+ * @filter_node_name: The node name that should be assigned to the filter
141
+ * driver that the mirror job inserts into the graph above @bs. NULL means that
142
+ * a node name should be autogenerated.
143
* @errp: Error object.
144
*
145
* Start a mirroring operation on @bs. Clusters that are allocated
146
@@ -XXX,XX +XXX,XX @@ void mirror_start(const char *job_id, BlockDriverState *bs,
147
MirrorSyncMode mode, BlockMirrorBackingMode backing_mode,
148
BlockdevOnError on_source_error,
149
BlockdevOnError on_target_error,
150
- bool unmap, Error **errp);
151
+ bool unmap, const char *filter_node_name, Error **errp);
152
153
/*
154
* backup_job_create:
155
diff --git a/qapi/block-core.json b/qapi/block-core.json
156
index XXXXXXX..XXXXXXX 100644
157
--- a/qapi/block-core.json
158
+++ b/qapi/block-core.json
159
@@ -XXX,XX +XXX,XX @@
160
# default 'report' (no limitations, since this applies to
161
# a different block device than @device).
162
#
163
+# @filter-node-name: #optional the node name that should be assigned to the
164
+# filter driver that the mirror job inserts into the graph
165
+# above @device. If this option is not given, a node name is
166
+# autogenerated. (Since: 2.9)
167
+#
168
# Returns: nothing on success.
169
#
170
# Since: 2.6
171
@@ -XXX,XX +XXX,XX @@
172
'sync': 'MirrorSyncMode',
173
'*speed': 'int', '*granularity': 'uint32',
174
'*buf-size': 'int', '*on-source-error': 'BlockdevOnError',
175
- '*on-target-error': 'BlockdevOnError' } }
176
+ '*on-target-error': 'BlockdevOnError',
177
+ '*filter-node-name': 'str' } }
178
179
##
180
# @block_set_io_throttle:
181
--
182
1.8.3.1
183
184
diff view generated by jsdifflib
Deleted patch
1
The HMP command 'qemu-io' is a bit tricky because it wants to work on
2
the original BlockBackend, but additional permissions could be required.
3
The details are explained in a comment in the code, but in summary, just
4
request whatever permissions the current qemu-io command needs.
5
1
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Acked-by: Fam Zheng <famz@redhat.com>
9
---
10
block/block-backend.c | 6 ++++++
11
hmp.c | 26 +++++++++++++++++++++++++-
12
include/qemu-io.h | 1 +
13
include/sysemu/block-backend.h | 1 +
14
qemu-io-cmds.c | 28 ++++++++++++++++++++++++++++
15
5 files changed, 61 insertions(+), 1 deletion(-)
16
17
diff --git a/block/block-backend.c b/block/block-backend.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/block/block-backend.c
20
+++ b/block/block-backend.c
21
@@ -XXX,XX +XXX,XX @@ int blk_set_perm(BlockBackend *blk, uint64_t perm, uint64_t shared_perm,
22
return 0;
23
}
24
25
+void blk_get_perm(BlockBackend *blk, uint64_t *perm, uint64_t *shared_perm)
26
+{
27
+ *perm = blk->perm;
28
+ *shared_perm = blk->shared_perm;
29
+}
30
+
31
static int blk_do_attach_dev(BlockBackend *blk, void *dev)
32
{
33
if (blk->dev) {
34
diff --git a/hmp.c b/hmp.c
35
index XXXXXXX..XXXXXXX 100644
36
--- a/hmp.c
37
+++ b/hmp.c
38
@@ -XXX,XX +XXX,XX @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict)
39
if (!blk) {
40
BlockDriverState *bs = bdrv_lookup_bs(NULL, device, &err);
41
if (bs) {
42
- /* FIXME Use real permissions */
43
blk = local_blk = blk_new(0, BLK_PERM_ALL);
44
ret = blk_insert_bs(blk, bs, &err);
45
if (ret < 0) {
46
@@ -XXX,XX +XXX,XX @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict)
47
aio_context = blk_get_aio_context(blk);
48
aio_context_acquire(aio_context);
49
50
+ /*
51
+ * Notably absent: Proper permission management. This is sad, but it seems
52
+ * almost impossible to achieve without changing the semantics and thereby
53
+ * limiting the use cases of the qemu-io HMP command.
54
+ *
55
+ * In an ideal world we would unconditionally create a new BlockBackend for
56
+ * qemuio_command(), but we have commands like 'reopen' and want them to
57
+ * take effect on the exact BlockBackend whose name the user passed instead
58
+ * of just on a temporary copy of it.
59
+ *
60
+ * Another problem is that deleting the temporary BlockBackend involves
61
+ * draining all requests on it first, but some qemu-iotests cases want to
62
+ * issue multiple aio_read/write requests and expect them to complete in
63
+ * the background while the monitor has already returned.
64
+ *
65
+ * This is also what prevents us from saving the original permissions and
66
+ * restoring them later: We can't revoke permissions until all requests
67
+ * have completed, and we don't know when that is nor can we really let
68
+ * anything else run before we have revoken them to avoid race conditions.
69
+ *
70
+ * What happens now is that command() in qemu-io-cmds.c can extend the
71
+ * permissions if necessary for the qemu-io command. And they simply stay
72
+ * extended, possibly resulting in a read-only guest device keeping write
73
+ * permissions. Ugly, but it appears to be the lesser evil.
74
+ */
75
qemuio_command(blk, command);
76
77
aio_context_release(aio_context);
78
diff --git a/include/qemu-io.h b/include/qemu-io.h
79
index XXXXXXX..XXXXXXX 100644
80
--- a/include/qemu-io.h
81
+++ b/include/qemu-io.h
82
@@ -XXX,XX +XXX,XX @@ typedef struct cmdinfo {
83
const char *args;
84
const char *oneline;
85
helpfunc_t help;
86
+ uint64_t perm;
87
} cmdinfo_t;
88
89
extern bool qemuio_misalign;
90
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
91
index XXXXXXX..XXXXXXX 100644
92
--- a/include/sysemu/block-backend.h
93
+++ b/include/sysemu/block-backend.h
94
@@ -XXX,XX +XXX,XX @@ bool bdrv_has_blk(BlockDriverState *bs);
95
bool bdrv_is_root_node(BlockDriverState *bs);
96
int blk_set_perm(BlockBackend *blk, uint64_t perm, uint64_t shared_perm,
97
Error **errp);
98
+void blk_get_perm(BlockBackend *blk, uint64_t *perm, uint64_t *shared_perm);
99
100
void blk_set_allow_write_beyond_eof(BlockBackend *blk, bool allow);
101
void blk_iostatus_enable(BlockBackend *blk);
102
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
103
index XXXXXXX..XXXXXXX 100644
104
--- a/qemu-io-cmds.c
105
+++ b/qemu-io-cmds.c
106
@@ -XXX,XX +XXX,XX @@ static int command(BlockBackend *blk, const cmdinfo_t *ct, int argc,
107
}
108
return 0;
109
}
110
+
111
+ /* Request additional permissions if necessary for this command. The caller
112
+ * is responsible for restoring the original permissions afterwards if this
113
+ * is what it wants. */
114
+ if (ct->perm && blk_is_available(blk)) {
115
+ uint64_t orig_perm, orig_shared_perm;
116
+ blk_get_perm(blk, &orig_perm, &orig_shared_perm);
117
+
118
+ if (ct->perm & ~orig_perm) {
119
+ uint64_t new_perm;
120
+ Error *local_err = NULL;
121
+ int ret;
122
+
123
+ new_perm = orig_perm | ct->perm;
124
+
125
+ ret = blk_set_perm(blk, new_perm, orig_shared_perm, &local_err);
126
+ if (ret < 0) {
127
+ error_report_err(local_err);
128
+ return 0;
129
+ }
130
+ }
131
+ }
132
+
133
optind = 0;
134
return ct->cfunc(blk, argc, argv);
135
}
136
@@ -XXX,XX +XXX,XX @@ static const cmdinfo_t write_cmd = {
137
.name = "write",
138
.altname = "w",
139
.cfunc = write_f,
140
+ .perm = BLK_PERM_WRITE,
141
.argmin = 2,
142
.argmax = -1,
143
.args = "[-bcCfquz] [-P pattern] off len",
144
@@ -XXX,XX +XXX,XX @@ static int writev_f(BlockBackend *blk, int argc, char **argv);
145
static const cmdinfo_t writev_cmd = {
146
.name = "writev",
147
.cfunc = writev_f,
148
+ .perm = BLK_PERM_WRITE,
149
.argmin = 2,
150
.argmax = -1,
151
.args = "[-Cfq] [-P pattern] off len [len..]",
152
@@ -XXX,XX +XXX,XX @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv);
153
static const cmdinfo_t aio_write_cmd = {
154
.name = "aio_write",
155
.cfunc = aio_write_f,
156
+ .perm = BLK_PERM_WRITE,
157
.argmin = 2,
158
.argmax = -1,
159
.args = "[-Cfiquz] [-P pattern] off len [len..]",
160
@@ -XXX,XX +XXX,XX @@ static const cmdinfo_t truncate_cmd = {
161
.name = "truncate",
162
.altname = "t",
163
.cfunc = truncate_f,
164
+ .perm = BLK_PERM_WRITE | BLK_PERM_RESIZE,
165
.argmin = 1,
166
.argmax = 1,
167
.args = "off",
168
@@ -XXX,XX +XXX,XX @@ static const cmdinfo_t discard_cmd = {
169
.name = "discard",
170
.altname = "d",
171
.cfunc = discard_f,
172
+ .perm = BLK_PERM_WRITE,
173
.argmin = 2,
174
.argmax = -1,
175
.args = "[-Cq] off len",
176
--
177
1.8.3.1
178
179
diff view generated by jsdifflib
Deleted patch
1
Request BLK_PERM_CONSISTENT_READ for the source of block migration, and
2
handle potential permission errors as good as we can in this place
3
(which is not very good, but it matches the other failure cases).
4
1
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Acked-by: Fam Zheng <famz@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
---
9
migration/block.c | 22 +++++++++++++++++-----
10
1 file changed, 17 insertions(+), 5 deletions(-)
11
12
diff --git a/migration/block.c b/migration/block.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/migration/block.c
15
+++ b/migration/block.c
16
@@ -XXX,XX +XXX,XX @@ static void unset_dirty_tracking(void)
17
}
18
}
19
20
-static void init_blk_migration(QEMUFile *f)
21
+static int init_blk_migration(QEMUFile *f)
22
{
23
BlockDriverState *bs;
24
BlkMigDevState *bmds;
25
@@ -XXX,XX +XXX,XX @@ static void init_blk_migration(QEMUFile *f)
26
BlkMigDevState *bmds;
27
BlockDriverState *bs;
28
} *bmds_bs;
29
+ Error *local_err = NULL;
30
+ int ret;
31
32
block_mig_state.submitted = 0;
33
block_mig_state.read_done = 0;
34
@@ -XXX,XX +XXX,XX @@ static void init_blk_migration(QEMUFile *f)
35
36
sectors = bdrv_nb_sectors(bs);
37
if (sectors <= 0) {
38
+ ret = sectors;
39
goto out;
40
}
41
42
bmds = g_new0(BlkMigDevState, 1);
43
- /* FIXME Use real permissions */
44
- bmds->blk = blk_new(0, BLK_PERM_ALL);
45
+ bmds->blk = blk_new(BLK_PERM_CONSISTENT_READ, BLK_PERM_ALL);
46
bmds->blk_name = g_strdup(bdrv_get_device_name(bs));
47
bmds->bulk_completed = 0;
48
bmds->total_sectors = sectors;
49
@@ -XXX,XX +XXX,XX @@ static void init_blk_migration(QEMUFile *f)
50
BlockDriverState *bs = bmds_bs[i].bs;
51
52
if (bmds) {
53
- blk_insert_bs(bmds->blk, bs, &error_abort);
54
+ ret = blk_insert_bs(bmds->blk, bs, &local_err);
55
+ if (ret < 0) {
56
+ error_report_err(local_err);
57
+ goto out;
58
+ }
59
60
alloc_aio_bitmap(bmds);
61
error_setg(&bmds->blocker, "block device is in use by migration");
62
@@ -XXX,XX +XXX,XX @@ static void init_blk_migration(QEMUFile *f)
63
}
64
}
65
66
+ ret = 0;
67
out:
68
g_free(bmds_bs);
69
+ return ret;
70
}
71
72
/* Called with no lock taken. */
73
@@ -XXX,XX +XXX,XX @@ static int block_save_setup(QEMUFile *f, void *opaque)
74
block_mig_state.submitted, block_mig_state.transferred);
75
76
qemu_mutex_lock_iothread();
77
- init_blk_migration(f);
78
+ ret = init_blk_migration(f);
79
+ if (ret < 0) {
80
+ qemu_mutex_unlock_iothread();
81
+ return ret;
82
+ }
83
84
/* start track dirty blocks */
85
ret = set_dirty_tracking();
86
--
87
1.8.3.1
88
89
diff view generated by jsdifflib
Deleted patch
1
NBD can't cope with device size changes, so resize must be forbidden,
2
but otherwise we can tolerate anything. Depending on whether the export
3
is writable or not, we only require consistent reads and writes.
4
1
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
Acked-by: Fam Zheng <famz@redhat.com>
8
---
9
nbd/server.c | 11 +++++++++--
10
1 file changed, 9 insertions(+), 2 deletions(-)
11
12
diff --git a/nbd/server.c b/nbd/server.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/nbd/server.c
15
+++ b/nbd/server.c
16
@@ -XXX,XX +XXX,XX @@ NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, off_t size,
17
{
18
BlockBackend *blk;
19
NBDExport *exp = g_malloc0(sizeof(NBDExport));
20
+ uint64_t perm;
21
int ret;
22
23
- /* FIXME Use real permissions */
24
- blk = blk_new(0, BLK_PERM_ALL);
25
+ /* Don't allow resize while the NBD server is running, otherwise we don't
26
+ * care what happens with the node. */
27
+ perm = BLK_PERM_CONSISTENT_READ;
28
+ if ((nbdflags & NBD_FLAG_READ_ONLY) == 0) {
29
+ perm |= BLK_PERM_WRITE;
30
+ }
31
+ blk = blk_new(perm, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED |
32
+ BLK_PERM_WRITE | BLK_PERM_GRAPH_MOD);
33
ret = blk_insert_bs(blk, bs, errp);
34
if (ret < 0) {
35
goto fail;
36
--
37
1.8.3.1
38
39
diff view generated by jsdifflib
Deleted patch
1
Not requesting any permissions is actually correct for these test cases
2
because no actual I/O or other operation covered by the permission
3
system is performed.
4
1
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
Acked-by: Fam Zheng <famz@redhat.com>
8
---
9
tests/test-blockjob.c | 2 +-
10
tests/test-throttle.c | 2 +-
11
2 files changed, 2 insertions(+), 2 deletions(-)
12
13
diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/tests/test-blockjob.c
16
+++ b/tests/test-blockjob.c
17
@@ -XXX,XX +XXX,XX @@ static BlockJob *do_test_id(BlockBackend *blk, const char *id,
18
* BlockDriverState inserted. */
19
static BlockBackend *create_blk(const char *name)
20
{
21
- /* FIXME Use real permissions */
22
+ /* No I/O is performed on this device */
23
BlockBackend *blk = blk_new(0, BLK_PERM_ALL);
24
BlockDriverState *bs;
25
26
diff --git a/tests/test-throttle.c b/tests/test-throttle.c
27
index XXXXXXX..XXXXXXX 100644
28
--- a/tests/test-throttle.c
29
+++ b/tests/test-throttle.c
30
@@ -XXX,XX +XXX,XX @@ static void test_groups(void)
31
BlockBackend *blk1, *blk2, *blk3;
32
BlockBackendPublic *blkp1, *blkp2, *blkp3;
33
34
- /* FIXME Use real permissions */
35
+ /* No actual I/O is performed on these devices */
36
blk1 = blk_new(0, BLK_PERM_ALL);
37
blk2 = blk_new(0, BLK_PERM_ALL);
38
blk3 = blk_new(0, BLK_PERM_ALL);
39
--
40
1.8.3.1
41
42
diff view generated by jsdifflib
Deleted patch
1
This is where we want to check the permissions, so we need to have the
2
BdrvChild around where they are stored.
3
1
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Acked-by: Fam Zheng <famz@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
---
8
block/io.c | 37 +++++++++++++++++++++----------------
9
1 file changed, 21 insertions(+), 16 deletions(-)
10
11
diff --git a/block/io.c b/block/io.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/block/io.c
14
+++ b/block/io.c
15
@@ -XXX,XX +XXX,XX @@ bdrv_driver_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
16
return drv->bdrv_co_pwritev_compressed(bs, offset, bytes, qiov);
17
}
18
19
-static int coroutine_fn bdrv_co_do_copy_on_readv(BlockDriverState *bs,
20
+static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child,
21
int64_t offset, unsigned int bytes, QEMUIOVector *qiov)
22
{
23
+ BlockDriverState *bs = child->bs;
24
+
25
/* Perform I/O through a temporary buffer so that users who scribble over
26
* their read buffer while the operation is in progress do not end up
27
* modifying the image file. This is critical for zero-copy guest I/O
28
@@ -XXX,XX +XXX,XX @@ err:
29
* handles copy on read, zeroing after EOF, and fragmentation of large
30
* reads; any other features must be implemented by the caller.
31
*/
32
-static int coroutine_fn bdrv_aligned_preadv(BlockDriverState *bs,
33
+static int coroutine_fn bdrv_aligned_preadv(BdrvChild *child,
34
BdrvTrackedRequest *req, int64_t offset, unsigned int bytes,
35
int64_t align, QEMUIOVector *qiov, int flags)
36
{
37
+ BlockDriverState *bs = child->bs;
38
int64_t total_bytes, max_bytes;
39
int ret = 0;
40
uint64_t bytes_remaining = bytes;
41
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_aligned_preadv(BlockDriverState *bs,
42
}
43
44
if (!ret || pnum != nb_sectors) {
45
- ret = bdrv_co_do_copy_on_readv(bs, offset, bytes, qiov);
46
+ ret = bdrv_co_do_copy_on_readv(child, offset, bytes, qiov);
47
goto out;
48
}
49
}
50
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_preadv(BdrvChild *child,
51
}
52
53
tracked_request_begin(&req, bs, offset, bytes, BDRV_TRACKED_READ);
54
- ret = bdrv_aligned_preadv(bs, &req, offset, bytes, align,
55
+ ret = bdrv_aligned_preadv(child, &req, offset, bytes, align,
56
use_local_qiov ? &local_qiov : qiov,
57
flags);
58
tracked_request_end(&req);
59
@@ -XXX,XX +XXX,XX @@ fail:
60
* Forwards an already correctly aligned write request to the BlockDriver,
61
* after possibly fragmenting it.
62
*/
63
-static int coroutine_fn bdrv_aligned_pwritev(BlockDriverState *bs,
64
+static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
65
BdrvTrackedRequest *req, int64_t offset, unsigned int bytes,
66
int64_t align, QEMUIOVector *qiov, int flags)
67
{
68
+ BlockDriverState *bs = child->bs;
69
BlockDriver *drv = bs->drv;
70
bool waited;
71
int ret;
72
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_aligned_pwritev(BlockDriverState *bs,
73
return ret;
74
}
75
76
-static int coroutine_fn bdrv_co_do_zero_pwritev(BlockDriverState *bs,
77
+static int coroutine_fn bdrv_co_do_zero_pwritev(BdrvChild *child,
78
int64_t offset,
79
unsigned int bytes,
80
BdrvRequestFlags flags,
81
BdrvTrackedRequest *req)
82
{
83
+ BlockDriverState *bs = child->bs;
84
uint8_t *buf = NULL;
85
QEMUIOVector local_qiov;
86
struct iovec iov;
87
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BlockDriverState *bs,
88
mark_request_serialising(req, align);
89
wait_serialising_requests(req);
90
bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_HEAD);
91
- ret = bdrv_aligned_preadv(bs, req, offset & ~(align - 1), align,
92
+ ret = bdrv_aligned_preadv(child, req, offset & ~(align - 1), align,
93
align, &local_qiov, 0);
94
if (ret < 0) {
95
goto fail;
96
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BlockDriverState *bs,
97
bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_HEAD);
98
99
memset(buf + head_padding_bytes, 0, zero_bytes);
100
- ret = bdrv_aligned_pwritev(bs, req, offset & ~(align - 1), align,
101
+ ret = bdrv_aligned_pwritev(child, req, offset & ~(align - 1), align,
102
align, &local_qiov,
103
flags & ~BDRV_REQ_ZERO_WRITE);
104
if (ret < 0) {
105
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BlockDriverState *bs,
106
if (bytes >= align) {
107
/* Write the aligned part in the middle. */
108
uint64_t aligned_bytes = bytes & ~(align - 1);
109
- ret = bdrv_aligned_pwritev(bs, req, offset, aligned_bytes, align,
110
+ ret = bdrv_aligned_pwritev(child, req, offset, aligned_bytes, align,
111
NULL, flags);
112
if (ret < 0) {
113
goto fail;
114
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BlockDriverState *bs,
115
mark_request_serialising(req, align);
116
wait_serialising_requests(req);
117
bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_TAIL);
118
- ret = bdrv_aligned_preadv(bs, req, offset, align,
119
+ ret = bdrv_aligned_preadv(child, req, offset, align,
120
align, &local_qiov, 0);
121
if (ret < 0) {
122
goto fail;
123
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BlockDriverState *bs,
124
bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL);
125
126
memset(buf, 0, bytes);
127
- ret = bdrv_aligned_pwritev(bs, req, offset, align, align,
128
+ ret = bdrv_aligned_pwritev(child, req, offset, align, align,
129
&local_qiov, flags & ~BDRV_REQ_ZERO_WRITE);
130
}
131
fail:
132
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwritev(BdrvChild *child,
133
tracked_request_begin(&req, bs, offset, bytes, BDRV_TRACKED_WRITE);
134
135
if (!qiov) {
136
- ret = bdrv_co_do_zero_pwritev(bs, offset, bytes, flags, &req);
137
+ ret = bdrv_co_do_zero_pwritev(child, offset, bytes, flags, &req);
138
goto out;
139
}
140
141
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwritev(BdrvChild *child,
142
qemu_iovec_init_external(&head_qiov, &head_iov, 1);
143
144
bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_HEAD);
145
- ret = bdrv_aligned_preadv(bs, &req, offset & ~(align - 1), align,
146
+ ret = bdrv_aligned_preadv(child, &req, offset & ~(align - 1), align,
147
align, &head_qiov, 0);
148
if (ret < 0) {
149
goto fail;
150
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwritev(BdrvChild *child,
151
qemu_iovec_init_external(&tail_qiov, &tail_iov, 1);
152
153
bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_TAIL);
154
- ret = bdrv_aligned_preadv(bs, &req, (offset + bytes) & ~(align - 1), align,
155
- align, &tail_qiov, 0);
156
+ ret = bdrv_aligned_preadv(child, &req, (offset + bytes) & ~(align - 1),
157
+ align, align, &tail_qiov, 0);
158
if (ret < 0) {
159
goto fail;
160
}
161
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwritev(BdrvChild *child,
162
bytes = ROUND_UP(bytes, align);
163
}
164
165
- ret = bdrv_aligned_pwritev(bs, &req, offset, bytes, align,
166
+ ret = bdrv_aligned_pwritev(child, &req, offset, bytes, align,
167
use_local_qiov ? &local_qiov : qiov,
168
flags);
169
170
--
171
1.8.3.1
172
173
diff view generated by jsdifflib
Deleted patch
1
This adds assertions that ensure that the necessary write permissions
2
have been granted before someone attempts to write to a node.
3
1
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Acked-by: Fam Zheng <famz@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
---
8
block/io.c | 3 +++
9
1 file changed, 3 insertions(+)
10
11
diff --git a/block/io.c b/block/io.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/block/io.c
14
+++ b/block/io.c
15
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child,
16
size_t skip_bytes;
17
int ret;
18
19
+ assert(child->perm & (BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE));
20
+
21
/* Cover entire cluster so no additional backing file I/O is required when
22
* allocating cluster in the image file.
23
*/
24
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
25
assert(!waited || !req->serialising);
26
assert(req->overlap_offset <= offset);
27
assert(offset + bytes <= req->overlap_offset + req->overlap_bytes);
28
+ assert(child->perm & BLK_PERM_WRITE);
29
30
ret = notifier_with_return_list_notify(&bs->before_write_notifiers, req);
31
32
--
33
1.8.3.1
34
35
diff view generated by jsdifflib
1
Not all callers of bdrv_set_backing_hd() know for sure that attaching
1
From: Lukáš Doktor <ldoktor@redhat.com>
2
the backing file will be allowed by the permission system. Return the
3
error from the function rather than aborting.
4
2
3
When custom TEST_DIR is specified the output includes it without leading
4
'/':
5
6
$ TEST_DIR=/var/tmp ./check -file -qcow2 051
7
....
8
-drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file":
9
{"driver": "file", "filename": "TEST_DIR/t.qcow2"}}, "driver": "qcow2",
10
"file": {"driver": "file", "filename": SNAPSHOT_PATH}} (qcow2,
11
read-only)
12
+drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file":
13
{"driver": "file", "filename": "TEST_DIR/t.qcow2"}}, "driver": "qcow2",
14
"file": {"driver": "file", "filename": "TEST_DIR/vl.ziHfeP"}} (qcow2,
15
read-only)
16
17
Let's remove it from the sed regexp.
18
19
Signed-off-by: Lukáš Doktor <ldoktor@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
20
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Acked-by: Fam Zheng <famz@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
---
21
---
9
block.c | 30 +++++++++++++++++++++++-------
22
tests/qemu-iotests/051 | 2 +-
10
block/commit.c | 14 +++++++-------
23
1 file changed, 1 insertion(+), 1 deletion(-)
11
block/mirror.c | 7 ++++++-
12
block/stream.c | 9 ++++++++-
13
block/vvfat.c | 2 +-
14
include/block/block.h | 3 ++-
15
6 files changed, 47 insertions(+), 18 deletions(-)
16
24
17
diff --git a/block.c b/block.c
25
diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051
18
index XXXXXXX..XXXXXXX 100644
26
index XXXXXXX..XXXXXXX 100755
19
--- a/block.c
27
--- a/tests/qemu-iotests/051
20
+++ b/block.c
28
+++ b/tests/qemu-iotests/051
21
@@ -XXX,XX +XXX,XX @@ static void bdrv_parent_cb_resize(BlockDriverState *bs)
29
@@ -XXX,XX +XXX,XX @@ TMPDIR=/nonexistent run_qemu -drive driver=null-co,snapshot=on
22
* Sets the backing file link of a BDS. A new reference is created; callers
30
echo "info block" |
23
* which don't need their own reference any more must call bdrv_unref().
31
run_qemu -drive file="$TEST_IMG",snapshot=on,read-only=on,if=none,id=$device_id |
24
*/
32
_filter_qemu_io |
25
-void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd)
33
- sed -e 's#"/[^"]*/vl\.[A-Za-z0-9]\{6\}"#SNAPSHOT_PATH#g'
26
+void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
34
+ sed -e 's#"[^"]*/vl\.[A-Za-z0-9]\{6\}"#SNAPSHOT_PATH#g'
27
+ Error **errp)
35
28
{
36
29
if (backing_hd) {
37
# success, all done
30
bdrv_ref(backing_hd);
31
@@ -XXX,XX +XXX,XX @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd)
32
bs->backing = NULL;
33
goto out;
34
}
35
- /* FIXME Error handling */
36
+
37
bs->backing = bdrv_attach_child(bs, backing_hd, "backing", &child_backing,
38
- &error_abort);
39
+ errp);
40
+ if (!bs->backing) {
41
+ bdrv_unref(backing_hd);
42
+ }
43
44
out:
45
bdrv_refresh_limits(bs, NULL);
46
@@ -XXX,XX +XXX,XX @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
47
48
/* Hook up the backing file link; drop our reference, bs owns the
49
* backing_hd reference now */
50
- bdrv_set_backing_hd(bs, backing_hd);
51
+ bdrv_set_backing_hd(bs, backing_hd, &local_err);
52
bdrv_unref(backing_hd);
53
+ if (local_err) {
54
+ ret = -EINVAL;
55
+ goto free_exit;
56
+ }
57
58
qdict_del(parent_options, bdref_key);
59
60
@@ -XXX,XX +XXX,XX @@ static void bdrv_close(BlockDriverState *bs)
61
bs->drv->bdrv_close(bs);
62
bs->drv = NULL;
63
64
- bdrv_set_backing_hd(bs, NULL);
65
+ bdrv_set_backing_hd(bs, NULL, &error_abort);
66
67
if (bs->file != NULL) {
68
bdrv_unref_child(bs, bs->file);
69
@@ -XXX,XX +XXX,XX @@ void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top)
70
bdrv_ref(bs_top);
71
72
change_parent_backing_link(bs_top, bs_new);
73
- bdrv_set_backing_hd(bs_new, bs_top);
74
+ /* FIXME Error handling */
75
+ bdrv_set_backing_hd(bs_new, bs_top, &error_abort);
76
bdrv_unref(bs_top);
77
78
/* bs_new is now referenced by its new parents, we don't need the
79
@@ -XXX,XX +XXX,XX @@ int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top,
80
BlockDriverState *base, const char *backing_file_str)
81
{
82
BlockDriverState *new_top_bs = NULL;
83
+ Error *local_err = NULL;
84
int ret = -EIO;
85
86
if (!top->drv || !base->drv) {
87
@@ -XXX,XX +XXX,XX @@ int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top,
88
if (ret) {
89
goto exit;
90
}
91
- bdrv_set_backing_hd(new_top_bs, base);
92
+
93
+ bdrv_set_backing_hd(new_top_bs, base, &local_err);
94
+ if (local_err) {
95
+ ret = -EPERM;
96
+ error_report_err(local_err);
97
+ goto exit;
98
+ }
99
100
ret = 0;
101
exit:
102
diff --git a/block/commit.c b/block/commit.c
103
index XXXXXXX..XXXXXXX 100644
104
--- a/block/commit.c
105
+++ b/block/commit.c
106
@@ -XXX,XX +XXX,XX @@ static void commit_complete(BlockJob *job, void *opaque)
107
* filter driver from the backing chain. Do this as the final step so that
108
* the 'consistent read' permission can be granted. */
109
if (remove_commit_top_bs) {
110
- bdrv_set_backing_hd(overlay_bs, top);
111
+ bdrv_set_backing_hd(overlay_bs, top, &error_abort);
112
}
113
}
114
115
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
116
goto fail;
117
}
118
119
- bdrv_set_backing_hd(commit_top_bs, top);
120
- bdrv_set_backing_hd(overlay_bs, commit_top_bs);
121
+ bdrv_set_backing_hd(commit_top_bs, top, &error_abort);
122
+ bdrv_set_backing_hd(overlay_bs, commit_top_bs, &error_abort);
123
124
s->commit_top_bs = commit_top_bs;
125
bdrv_unref(commit_top_bs);
126
@@ -XXX,XX +XXX,XX @@ fail:
127
blk_unref(s->top);
128
}
129
if (commit_top_bs) {
130
- bdrv_set_backing_hd(overlay_bs, top);
131
+ bdrv_set_backing_hd(overlay_bs, top, &error_abort);
132
}
133
block_job_unref(&s->common);
134
}
135
@@ -XXX,XX +XXX,XX @@ int bdrv_commit(BlockDriverState *bs)
136
goto ro_cleanup;
137
}
138
139
- bdrv_set_backing_hd(commit_top_bs, backing_file_bs);
140
- bdrv_set_backing_hd(bs, commit_top_bs);
141
+ bdrv_set_backing_hd(commit_top_bs, backing_file_bs, &error_abort);
142
+ bdrv_set_backing_hd(bs, commit_top_bs, &error_abort);
143
144
ret = blk_insert_bs(backing, backing_file_bs, &local_err);
145
if (ret < 0) {
146
@@ -XXX,XX +XXX,XX @@ ro_cleanup:
147
148
blk_unref(backing);
149
if (backing_file_bs) {
150
- bdrv_set_backing_hd(bs, backing_file_bs);
151
+ bdrv_set_backing_hd(bs, backing_file_bs, &error_abort);
152
}
153
bdrv_unref(commit_top_bs);
154
blk_unref(src);
155
diff --git a/block/mirror.c b/block/mirror.c
156
index XXXXXXX..XXXXXXX 100644
157
--- a/block/mirror.c
158
+++ b/block/mirror.c
159
@@ -XXX,XX +XXX,XX @@ static void mirror_exit(BlockJob *job, void *opaque)
160
BlockDriverState *src = s->source;
161
BlockDriverState *target_bs = blk_bs(s->target);
162
BlockDriverState *mirror_top_bs = s->mirror_top_bs;
163
+ Error *local_err = NULL;
164
165
/* Make sure that the source BDS doesn't go away before we called
166
* block_job_completed(). */
167
@@ -XXX,XX +XXX,XX @@ static void mirror_exit(BlockJob *job, void *opaque)
168
if (s->backing_mode == MIRROR_SOURCE_BACKING_CHAIN) {
169
BlockDriverState *backing = s->is_none_mode ? src : s->base;
170
if (backing_bs(target_bs) != backing) {
171
- bdrv_set_backing_hd(target_bs, backing);
172
+ bdrv_set_backing_hd(target_bs, backing, &local_err);
173
+ if (local_err) {
174
+ error_report_err(local_err);
175
+ data->ret = -EPERM;
176
+ }
177
}
178
}
179
180
diff --git a/block/stream.c b/block/stream.c
181
index XXXXXXX..XXXXXXX 100644
182
--- a/block/stream.c
183
+++ b/block/stream.c
184
@@ -XXX,XX +XXX,XX @@ static void stream_complete(BlockJob *job, void *opaque)
185
StreamCompleteData *data = opaque;
186
BlockDriverState *bs = blk_bs(job->blk);
187
BlockDriverState *base = s->base;
188
+ Error *local_err = NULL;
189
190
if (!block_job_is_cancelled(&s->common) && data->reached_end &&
191
data->ret == 0) {
192
@@ -XXX,XX +XXX,XX @@ static void stream_complete(BlockJob *job, void *opaque)
193
}
194
}
195
data->ret = bdrv_change_backing_file(bs, base_id, base_fmt);
196
- bdrv_set_backing_hd(bs, base);
197
+ bdrv_set_backing_hd(bs, base, &local_err);
198
+ if (local_err) {
199
+ error_report_err(local_err);
200
+ data->ret = -EPERM;
201
+ goto out;
202
+ }
203
}
204
205
+out:
206
/* Reopen the image back in read-only mode if necessary */
207
if (s->bs_flags != bdrv_get_flags(bs)) {
208
/* Give up write permissions before making it read-only */
209
diff --git a/block/vvfat.c b/block/vvfat.c
210
index XXXXXXX..XXXXXXX 100644
211
--- a/block/vvfat.c
212
+++ b/block/vvfat.c
213
@@ -XXX,XX +XXX,XX @@ static int enable_write_target(BlockDriverState *bs, Error **errp)
214
&error_abort);
215
*(void**) backing->opaque = s;
216
217
- bdrv_set_backing_hd(s->bs, backing);
218
+ bdrv_set_backing_hd(s->bs, backing, &error_abort);
219
bdrv_unref(backing);
220
221
return 0;
222
diff --git a/include/block/block.h b/include/block/block.h
223
index XXXXXXX..XXXXXXX 100644
224
--- a/include/block/block.h
225
+++ b/include/block/block.h
226
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_open_child(const char *filename,
227
BlockDriverState* parent,
228
const BdrvChildRole *child_role,
229
bool allow_none, Error **errp);
230
-void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd);
231
+void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
232
+ Error **errp);
233
int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
234
const char *bdref_key, Error **errp);
235
BlockDriverState *bdrv_open(const char *filename, const char *reference,
236
--
38
--
237
1.8.3.1
39
2.20.1
238
40
239
41
diff view generated by jsdifflib