1
The following changes since commit 9514f2648ca05b38e852b490a12b8cd98d5808c1:
1
The following changes since commit 1b8c45899715d292398152ba97ef755ccaf84680:
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/dgilbert/tags/pull-migration-20200507a' into staging (2020-05-07 18:43:20 +0100)
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 47e0b38a13935cb666f88964c3096654092f42d6:
11
10
12
block: Add Error parameter to bdrv_append() (2017-02-28 20:47:51 +0100)
11
block: Drop unused .bdrv_has_zero_init_truncate (2020-05-08 13:26:35 +0200)
13
12
14
----------------------------------------------------------------
13
----------------------------------------------------------------
15
Block layer patches
14
Block layer patches:
15
16
- qcow2: Fix preallocation on block devices
17
- backup: Make sure that source and target size match
18
- vmdk: Fix zero cluster handling
19
- Follow-up cleanups and fixes for the truncate changes
20
- iotests: Skip more tests if required drivers are missing
16
21
17
----------------------------------------------------------------
22
----------------------------------------------------------------
18
Kevin Wolf (44):
23
Alberto Garcia (1):
19
block: Add op blocker permission constants
24
qcow2: Avoid integer wraparound in qcow2_co_truncate()
20
block: Add Error argument to bdrv_attach_child()
21
block: Let callers request permissions when attaching a child node
22
block: Involve block drivers in permission granting
23
block: Default .bdrv_child_perm() for filter drivers
24
block: Request child permissions in filter drivers
25
block: Default .bdrv_child_perm() for format drivers
26
block: Request child permissions in format drivers
27
vvfat: Implement .bdrv_child_perm()
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
25
64
Markus Armbruster (1):
26
Eric Blake (9):
65
option: Tweak invalid size error message and unbreak iotest 049
27
gluster: Drop useless has_zero_init callback
28
file-win32: Support BDRV_REQ_ZERO_WRITE for truncate
29
nfs: Support BDRV_REQ_ZERO_WRITE for truncate
30
rbd: Support BDRV_REQ_ZERO_WRITE for truncate
31
sheepdog: Support BDRV_REQ_ZERO_WRITE for truncate
32
ssh: Support BDRV_REQ_ZERO_WRITE for truncate
33
parallels: Rework truncation logic
34
vhdx: Rework truncation logic
35
block: Drop unused .bdrv_has_zero_init_truncate
66
36
67
Peter Lieven (1):
37
Kevin Wolf (11):
68
qemu-img: make convert async
38
vmdk: Rename VmdkMetaData.valid to new_allocation
39
vmdk: Fix zero cluster allocation
40
vmdk: Fix partial overwrite of zero cluster
41
vmdk: Don't update L2 table for zero write on zero cluster
42
vmdk: Flush only once in vmdk_L2update()
43
iotests: vmdk: Enable zeroed_grained=on by default
44
iotests/283: Use consistent size for source and target
45
backup: Improve error for bdrv_getlength() failure
46
backup: Make sure that source and target size match
47
iotests: Backup with different source/target size
48
iotests/055: Use cache.no-flush for vmdk target
69
49
70
block.c | 583 ++++++++++++++++++++++++++++++++++-----
50
Max Reitz (1):
71
block/backup.c | 22 +-
51
qcow2: Fix preallocation on block devices
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
52
53
Vladimir Sementsov-Ogievskiy (8):
54
iotests: handle tmpfs
55
iotests/082: require bochs
56
iotests/148: use skip_if_unsupported
57
iotests/041: drop self.assert_no_active_block_jobs()
58
iotests/055: refactor compressed backup to vmdk
59
iotests/055: skip vmdk target tests if vmdk is not whitelisted
60
iotests/109: mark required formats as required to support whitelisting
61
iotests/113: mark bochs as required to support whitelisting
62
63
include/block/block.h | 1 -
64
include/block/block_int.h | 7 ---
65
block.c | 21 --------
66
block/backup-top.c | 14 +++--
67
block/backup.c | 18 +++++--
68
block/file-posix.c | 1 -
69
block/file-win32.c | 4 +-
70
block/gluster.c | 14 -----
71
block/nfs.c | 4 +-
72
block/parallels.c | 25 +++++----
73
block/qcow2.c | 23 ++++++---
74
block/qed.c | 1 -
75
block/raw-format.c | 6 ---
76
block/rbd.c | 4 +-
77
block/sheepdog.c | 4 +-
78
block/ssh.c | 5 +-
79
block/vhdx.c | 89 ++++++++++++++++++--------------
80
block/vmdk.c | 47 ++++++++++-------
81
tests/qemu-iotests/041 | 8 ---
82
tests/qemu-iotests/055 | 120 ++++++++++++++++++++++++++++++-------------
83
tests/qemu-iotests/055.out | 4 +-
84
tests/qemu-iotests/059 | 6 +--
85
tests/qemu-iotests/082 | 1 +
86
tests/qemu-iotests/091 | 2 +-
87
tests/qemu-iotests/109 | 1 +
88
tests/qemu-iotests/113 | 4 +-
89
tests/qemu-iotests/148 | 1 +
90
tests/qemu-iotests/283 | 6 ++-
91
tests/qemu-iotests/283.out | 2 +-
92
tests/qemu-iotests/292 | 73 ++++++++++++++++++++++++++
93
tests/qemu-iotests/292.out | 24 +++++++++
94
tests/qemu-iotests/check | 3 ++
95
tests/qemu-iotests/common.rc | 37 ++++++++++++-
96
tests/qemu-iotests/group | 1 +
97
34 files changed, 386 insertions(+), 195 deletions(-)
98
create mode 100755 tests/qemu-iotests/292
99
create mode 100644 tests/qemu-iotests/292.out
100
101
diff view generated by jsdifflib
1
In many cases, the required permissions of one node on its children
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
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
2
6
In order to achieve this, this patch introduces two new BlockDriver
3
Some tests requires O_DIRECT, or want it by default. Introduce smarter
7
callbacks. The first one lets drivers first check (recursively) whether
4
O_DIRECT handling:
8
the requested permissions can be set; the second one actually sets the
9
new permission bitmask.
10
5
11
Also add helper functions that drivers can use in their implementation
6
- Check O_DIRECT in common.rc, if it is requested by selected
12
of the callbacks to update their permissions on a specific child.
7
cache-mode.
13
8
9
- Support second fall-through argument in _default_cache_mode
10
11
Inspired-by: Max's 23e1d054112cec1e
12
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
13
Message-Id: <20200430124713.3067-2-vsementsov@virtuozzo.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
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
---
15
---
18
block.c | 206 +++++++++++++++++++++++++++++++++++++++++++++-
16
tests/qemu-iotests/091 | 2 +-
19
include/block/block_int.h | 61 ++++++++++++++
17
tests/qemu-iotests/common.rc | 37 ++++++++++++++++++++++++++++++++++--
20
2 files changed, 263 insertions(+), 4 deletions(-)
18
2 files changed, 36 insertions(+), 3 deletions(-)
21
19
22
diff --git a/block.c b/block.c
20
diff --git a/tests/qemu-iotests/091 b/tests/qemu-iotests/091
21
index XXXXXXX..XXXXXXX 100755
22
--- a/tests/qemu-iotests/091
23
+++ b/tests/qemu-iotests/091
24
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
25
_supported_fmt qcow2
26
_supported_proto file
27
_supported_os Linux
28
-_default_cache_mode none
29
_supported_cache_modes writethrough none writeback
30
+_default_cache_mode none writeback
31
32
size=1G
33
34
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
23
index XXXXXXX..XXXXXXX 100644
35
index XXXXXXX..XXXXXXX 100644
24
--- a/block.c
36
--- a/tests/qemu-iotests/common.rc
25
+++ b/block.c
37
+++ b/tests/qemu-iotests/common.rc
26
@@ -XXX,XX +XXX,XX @@ static int bdrv_fill_options(QDict **options, const char *filename,
38
@@ -XXX,XX +XXX,XX @@ _supported_cache_modes()
27
return 0;
39
_notrun "not suitable for cache mode: $CACHEMODE"
28
}
40
}
29
41
30
+/*
42
+# Check whether the filesystem supports O_DIRECT
31
+ * Check whether permissions on this node can be changed in a way that
43
+_check_o_direct()
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
+{
44
+{
42
+ BlockDriver *drv = bs->drv;
45
+ $QEMU_IMG create -f raw "$TEST_IMG".test_o_direct 1M > /dev/null
43
+ BdrvChild *c;
46
+ out=$($QEMU_IO -f raw -t none -c quit "$TEST_IMG".test_o_direct 2>&1)
44
+ int ret;
47
+ rm -f "$TEST_IMG".test_o_direct
45
+
48
+
46
+ /* Write permissions never work with read-only images */
49
+ [[ "$out" != *"O_DIRECT"* ]]
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
+}
50
+}
83
+
51
+
84
+/*
52
+_require_o_direct()
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
+{
53
+{
93
+ BlockDriver *drv = bs->drv;
54
+ if ! _check_o_direct; then
94
+ BdrvChild *c;
55
+ _notrun "file system on $TEST_DIR does not support O_DIRECT"
95
+
56
+ fi
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
+}
57
+}
108
+
58
+
109
+static void bdrv_set_perm(BlockDriverState *bs, uint64_t cumulative_perms,
59
+_check_cache_mode()
110
+ uint64_t cumulative_shared_perms)
111
+{
60
+{
112
+ BlockDriver *drv = bs->drv;
61
+ if [ $CACHEMODE == "none" ] || [ $CACHEMODE == "directsync" ]; then
113
+ BdrvChild *c;
62
+ _require_o_direct
114
+
63
+ fi
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
+}
64
+}
138
+
65
+
139
+static void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm,
66
+_check_cache_mode
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
+
67
+
146
+ QLIST_FOREACH(c, &bs->parents, next_parent) {
68
+# $1 - cache mode to use by default
147
+ cumulative_perms |= c->perm;
69
+# $2 - (optional) cache mode to use by default if O_DIRECT is not supported
148
+ cumulative_shared_perms &= c->shared_perm;
70
_default_cache_mode()
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
{
71
{
167
BdrvChild *c;
72
if $CACHEMODE_IS_DEFAULT; then
168
+ uint64_t cumulative_perms = new_used_perm;
73
- CACHEMODE="$1"
169
+ uint64_t cumulative_shared_perms = new_shared_perm;
74
- QEMU_IO="$QEMU_IO --cache $1"
170
75
+ if [ -z "$2" ] || _check_o_direct; then
171
/* There is no reason why anyone couldn't tolerate write_unchanged */
76
+ CACHEMODE="$1"
172
assert(new_shared_perm & BLK_PERM_WRITE_UNCHANGED);
77
+ else
173
@@ -XXX,XX +XXX,XX @@ static int bdrv_check_update_perm(BlockDriverState *bs, uint64_t new_used_perm,
78
+ CACHEMODE="$2"
174
error_setg(errp, "Conflicts with %s", user ?: "another operation");
79
+ fi
175
return -EPERM;
80
+ QEMU_IO="$QEMU_IO --cache $CACHEMODE"
176
}
81
+ _check_cache_mode
177
+
82
return
178
+ cumulative_perms |= c->perm;
83
fi
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
}
84
}
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
--
85
--
379
1.8.3.1
86
2.25.3
380
87
381
88
diff view generated by jsdifflib
1
Aborting on error in bdrv_append() isn't correct. This patch fixes it
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.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
Test fails if bochs not whitelisted, so, skip it in this case.
5
reversed order of bdrv_set_backing_hd() and change_parent_backing_link()
6
in bdrv_append(): When the backing file of the new node is set, the
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
4
5
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Message-Id: <20200430124713.3067-3-vsementsov@virtuozzo.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
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
---
8
---
14
block.c | 23 +++++++++++++++++------
9
tests/qemu-iotests/082 | 1 +
15
block/mirror.c | 9 ++++++++-
10
1 file changed, 1 insertion(+)
16
blockdev.c | 18 +++++++++++++++---
17
include/block/block.h | 3 ++-
18
tests/qemu-iotests/085.out | 2 +-
19
5 files changed, 43 insertions(+), 12 deletions(-)
20
11
21
diff --git a/block.c b/block.c
12
diff --git a/tests/qemu-iotests/082 b/tests/qemu-iotests/082
22
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100755
23
--- a/block.c
14
--- a/tests/qemu-iotests/082
24
+++ b/block.c
15
+++ b/tests/qemu-iotests/082
25
@@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs,
16
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
26
int64_t total_size;
17
27
QemuOpts *opts = NULL;
18
_supported_fmt qcow2
28
BlockDriverState *bs_snapshot;
19
_supported_proto file nfs
29
+ Error *local_err = NULL;
20
+_require_drivers bochs
30
int ret;
21
31
22
run_qemu_img()
32
/* if snapshot, we create a temporary backing file and open it
33
@@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs,
34
* call bdrv_unref() on it), so in order to be able to return one, we have
35
* to increase bs_snapshot's refcount here */
36
bdrv_ref(bs_snapshot);
37
- bdrv_append(bs_snapshot, bs);
38
+ bdrv_append(bs_snapshot, bs, &local_err);
39
+ if (local_err) {
40
+ error_propagate(errp, local_err);
41
+ ret = -EINVAL;
42
+ goto out;
43
+ }
44
45
g_free(tmp_filename);
46
return bs_snapshot;
47
@@ -XXX,XX +XXX,XX @@ static void change_parent_backing_link(BlockDriverState *from,
48
* parents of bs_top after bdrv_append() returns. If the caller needs to keep a
49
* reference of its own, it must call bdrv_ref().
50
*/
51
-void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top)
52
+void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
53
+ Error **errp)
54
{
23
{
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
184
--
24
--
185
1.8.3.1
25
2.25.3
186
26
187
27
diff view generated by jsdifflib
1
This adds an assertion that ensures that the necessary resize permission
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
has been granted before bdrv_truncate() is called.
3
2
3
Skip test-case with quorum if quorum is not whitelisted.
4
5
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Message-Id: <20200430124713.3067-4-vsementsov@virtuozzo.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
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
---
8
block.c | 3 +++
9
tests/qemu-iotests/148 | 1 +
9
block/io.c | 1 +
10
1 file changed, 1 insertion(+)
10
2 files changed, 4 insertions(+)
11
11
12
diff --git a/block.c b/block.c
12
diff --git a/tests/qemu-iotests/148 b/tests/qemu-iotests/148
13
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100755
14
--- a/block.c
14
--- a/tests/qemu-iotests/148
15
+++ b/block.c
15
+++ b/tests/qemu-iotests/148
16
@@ -XXX,XX +XXX,XX @@ int bdrv_truncate(BdrvChild *child, int64_t offset)
16
@@ -XXX,XX +XXX,XX @@ sector = "%d"
17
BlockDriverState *bs = child->bs;
17
''' % bad_sector)
18
BlockDriver *drv = bs->drv;
18
file.close()
19
int ret;
19
20
+
20
+ @iotests.skip_if_unsupported(['quorum'])
21
+ assert(child->perm & BLK_PERM_RESIZE);
21
def setUp(self):
22
+
22
driveopts = ['driver=quorum', 'vote-threshold=2']
23
if (!drv)
23
driveopts.append('read-pattern=%s' % self.read_pattern)
24
return -ENOMEDIUM;
25
if (!drv->bdrv_truncate)
26
diff --git a/block/io.c b/block/io.c
27
index XXXXXXX..XXXXXXX 100644
28
--- a/block/io.c
29
+++ b/block/io.c
30
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
31
assert(req->overlap_offset <= offset);
32
assert(offset + bytes <= req->overlap_offset + req->overlap_bytes);
33
assert(child->perm & BLK_PERM_WRITE);
34
+ assert(end_sector <= bs->total_sectors || child->perm & BLK_PERM_RESIZE);
35
36
ret = notifier_with_return_list_notify(&bs->before_write_notifiers, req);
37
38
--
24
--
39
1.8.3.1
25
2.25.3
40
26
41
27
diff view generated by jsdifflib
1
This adds assertions that ensure that the necessary write permissions
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
have been granted before someone attempts to write to a node.
3
2
3
Drop check for no block-jobs: it's obvious that there no jobs
4
immediately after vm.launch().
5
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Message-Id: <20200430124713.3067-5-vsementsov@virtuozzo.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
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
---
9
---
8
block/io.c | 3 +++
10
tests/qemu-iotests/041 | 8 --------
9
1 file changed, 3 insertions(+)
11
1 file changed, 8 deletions(-)
10
12
11
diff --git a/block/io.c b/block/io.c
13
diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041
12
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100755
13
--- a/block/io.c
15
--- a/tests/qemu-iotests/041
14
+++ b/block/io.c
16
+++ b/tests/qemu-iotests/041
15
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child,
17
@@ -XXX,XX +XXX,XX @@ class TestRepairQuorum(iotests.QMPTestCase):
16
size_t skip_bytes;
18
pass
17
int ret;
19
18
20
def test_complete(self):
19
+ assert(child->perm & (BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE));
21
- self.assert_no_active_block_jobs()
20
+
22
-
21
/* Cover entire cluster so no additional backing file I/O is required when
23
result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0',
22
* allocating cluster in the image file.
24
sync='full', node_name="repair0", replaces="img1",
23
*/
25
target=quorum_repair_img, format=iotests.imgfmt)
24
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
26
@@ -XXX,XX +XXX,XX @@ class TestRepairQuorum(iotests.QMPTestCase):
25
assert(!waited || !req->serialising);
27
'target image does not match source after mirroring')
26
assert(req->overlap_offset <= offset);
28
27
assert(offset + bytes <= req->overlap_offset + req->overlap_bytes);
29
def test_cancel(self):
28
+ assert(child->perm & BLK_PERM_WRITE);
30
- self.assert_no_active_block_jobs()
29
31
-
30
ret = notifier_with_return_list_notify(&bs->before_write_notifiers, req);
32
result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0',
31
33
sync='full', node_name="repair0", replaces="img1",
34
target=quorum_repair_img, format=iotests.imgfmt)
35
@@ -XXX,XX +XXX,XX @@ class TestRepairQuorum(iotests.QMPTestCase):
36
self.assert_has_block_node(None, quorum_img3)
37
38
def test_cancel_after_ready(self):
39
- self.assert_no_active_block_jobs()
40
-
41
result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0',
42
sync='full', node_name="repair0", replaces="img1",
43
target=quorum_repair_img, format=iotests.imgfmt)
44
@@ -XXX,XX +XXX,XX @@ class TestRepairQuorum(iotests.QMPTestCase):
45
'target image does not match source after mirroring')
46
47
def test_pause(self):
48
- self.assert_no_active_block_jobs()
49
-
50
result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0',
51
sync='full', node_name="repair0", replaces="img1",
52
target=quorum_repair_img, format=iotests.imgfmt)
32
--
53
--
33
1.8.3.1
54
2.25.3
34
55
35
56
diff view generated by jsdifflib
1
This is where we want to check the permissions, so we need to have the
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
BdrvChild around where they are stored.
3
2
3
Instead of looping in each test, let's better refactor vmdk target case
4
as a subclass.
5
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Message-Id: <20200430124713.3067-6-vsementsov@virtuozzo.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
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
---
9
---
8
block/io.c | 37 +++++++++++++++++++++----------------
10
tests/qemu-iotests/055 | 70 ++++++++++++++++++++------------------
9
1 file changed, 21 insertions(+), 16 deletions(-)
11
tests/qemu-iotests/055.out | 4 +--
12
2 files changed, 39 insertions(+), 35 deletions(-)
10
13
11
diff --git a/block/io.c b/block/io.c
14
diff --git a/tests/qemu-iotests/055 b/tests/qemu-iotests/055
15
index XXXXXXX..XXXXXXX 100755
16
--- a/tests/qemu-iotests/055
17
+++ b/tests/qemu-iotests/055
18
@@ -XXX,XX +XXX,XX @@ class TestSingleTransaction(iotests.QMPTestCase):
19
self.assert_no_active_block_jobs()
20
21
22
-class TestDriveCompression(iotests.QMPTestCase):
23
+class TestCompressedToQcow2(iotests.QMPTestCase):
24
image_len = 64 * 1024 * 1024 # MB
25
- fmt_supports_compression = [{'type': 'qcow2', 'args': ()},
26
- {'type': 'vmdk', 'args': ('-o', 'subformat=streamOptimized')}]
27
+ target_fmt = {'type': 'qcow2', 'args': ()}
28
29
def tearDown(self):
30
self.vm.shutdown()
31
@@ -XXX,XX +XXX,XX @@ class TestDriveCompression(iotests.QMPTestCase):
32
except OSError:
33
pass
34
35
- def do_prepare_drives(self, fmt, args, attach_target):
36
+ def do_prepare_drives(self, attach_target):
37
self.vm = iotests.VM().add_drive('blkdebug::' + test_img)
38
39
- qemu_img('create', '-f', fmt, blockdev_target_img,
40
- str(TestDriveCompression.image_len), *args)
41
+ qemu_img('create', '-f', self.target_fmt['type'], blockdev_target_img,
42
+ str(self.image_len), *self.target_fmt['args'])
43
if attach_target:
44
self.vm.add_drive(blockdev_target_img,
45
- img_format=fmt, interface="none")
46
+ img_format=self.target_fmt['type'],
47
+ interface="none")
48
49
self.vm.launch()
50
51
- def do_test_compress_complete(self, cmd, format, attach_target, **args):
52
- self.do_prepare_drives(format['type'], format['args'], attach_target)
53
+ def do_test_compress_complete(self, cmd, attach_target, **args):
54
+ self.do_prepare_drives(attach_target)
55
56
self.assert_no_active_block_jobs()
57
58
@@ -XXX,XX +XXX,XX @@ class TestDriveCompression(iotests.QMPTestCase):
59
60
self.vm.shutdown()
61
self.assertTrue(iotests.compare_images(test_img, blockdev_target_img,
62
- iotests.imgfmt, format['type']),
63
+ iotests.imgfmt,
64
+ self.target_fmt['type']),
65
'target image does not match source after backup')
66
67
def test_complete_compress_drive_backup(self):
68
- for format in TestDriveCompression.fmt_supports_compression:
69
- self.do_test_compress_complete('drive-backup', format, False,
70
- target=blockdev_target_img, mode='existing')
71
+ self.do_test_compress_complete('drive-backup', False,
72
+ target=blockdev_target_img,
73
+ mode='existing')
74
75
def test_complete_compress_blockdev_backup(self):
76
- for format in TestDriveCompression.fmt_supports_compression:
77
- self.do_test_compress_complete('blockdev-backup', format, True,
78
- target='drive1')
79
+ self.do_test_compress_complete('blockdev-backup',
80
+ True, target='drive1')
81
82
- def do_test_compress_cancel(self, cmd, format, attach_target, **args):
83
- self.do_prepare_drives(format['type'], format['args'], attach_target)
84
+ def do_test_compress_cancel(self, cmd, attach_target, **args):
85
+ self.do_prepare_drives(attach_target)
86
87
self.assert_no_active_block_jobs()
88
89
@@ -XXX,XX +XXX,XX @@ class TestDriveCompression(iotests.QMPTestCase):
90
self.vm.shutdown()
91
92
def test_compress_cancel_drive_backup(self):
93
- for format in TestDriveCompression.fmt_supports_compression:
94
- self.do_test_compress_cancel('drive-backup', format, False,
95
- target=blockdev_target_img, mode='existing')
96
+ self.do_test_compress_cancel('drive-backup', False,
97
+ target=blockdev_target_img,
98
+ mode='existing')
99
100
def test_compress_cancel_blockdev_backup(self):
101
- for format in TestDriveCompression.fmt_supports_compression:
102
- self.do_test_compress_cancel('blockdev-backup', format, True,
103
- target='drive1')
104
+ self.do_test_compress_cancel('blockdev-backup', True,
105
+ target='drive1')
106
107
- def do_test_compress_pause(self, cmd, format, attach_target, **args):
108
- self.do_prepare_drives(format['type'], format['args'], attach_target)
109
+ def do_test_compress_pause(self, cmd, attach_target, **args):
110
+ self.do_prepare_drives(attach_target)
111
112
self.assert_no_active_block_jobs()
113
114
@@ -XXX,XX +XXX,XX @@ class TestDriveCompression(iotests.QMPTestCase):
115
116
self.vm.shutdown()
117
self.assertTrue(iotests.compare_images(test_img, blockdev_target_img,
118
- iotests.imgfmt, format['type']),
119
+ iotests.imgfmt,
120
+ self.target_fmt['type']),
121
'target image does not match source after backup')
122
123
def test_compress_pause_drive_backup(self):
124
- for format in TestDriveCompression.fmt_supports_compression:
125
- self.do_test_compress_pause('drive-backup', format, False,
126
- target=blockdev_target_img, mode='existing')
127
+ self.do_test_compress_pause('drive-backup', False,
128
+ target=blockdev_target_img,
129
+ mode='existing')
130
131
def test_compress_pause_blockdev_backup(self):
132
- for format in TestDriveCompression.fmt_supports_compression:
133
- self.do_test_compress_pause('blockdev-backup', format, True,
134
- target='drive1')
135
+ self.do_test_compress_pause('blockdev-backup', True,
136
+ target='drive1')
137
+
138
+
139
+class TestCompressedToVmdk(TestCompressedToQcow2):
140
+ target_fmt = {'type': 'vmdk', 'args': ('-o', 'subformat=streamOptimized')}
141
+
142
143
if __name__ == '__main__':
144
iotests.main(supported_fmts=['raw', 'qcow2'],
145
diff --git a/tests/qemu-iotests/055.out b/tests/qemu-iotests/055.out
12
index XXXXXXX..XXXXXXX 100644
146
index XXXXXXX..XXXXXXX 100644
13
--- a/block/io.c
147
--- a/tests/qemu-iotests/055.out
14
+++ b/block/io.c
148
+++ b/tests/qemu-iotests/055.out
15
@@ -XXX,XX +XXX,XX @@ bdrv_driver_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
149
@@ -XXX,XX +XXX,XX @@
16
return drv->bdrv_co_pwritev_compressed(bs, offset, bytes, qiov);
150
-..............................
17
}
151
+....................................
18
152
----------------------------------------------------------------------
19
-static int coroutine_fn bdrv_co_do_copy_on_readv(BlockDriverState *bs,
153
-Ran 30 tests
20
+static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child,
154
+Ran 36 tests
21
int64_t offset, unsigned int bytes, QEMUIOVector *qiov)
155
22
{
156
OK
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
--
157
--
171
1.8.3.1
158
2.25.3
172
159
173
160
diff view generated by jsdifflib
1
Not requesting any permissions is actually correct for these test cases
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
because no actual I/O or other operation covered by the permission
3
system is performed.
4
2
3
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
4
Message-Id: <20200430124713.3067-7-vsementsov@virtuozzo.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
Acked-by: Fam Zheng <famz@redhat.com>
8
---
6
---
9
tests/test-blockjob.c | 2 +-
7
tests/qemu-iotests/055 | 4 ++++
10
tests/test-throttle.c | 2 +-
8
1 file changed, 4 insertions(+)
11
2 files changed, 2 insertions(+), 2 deletions(-)
12
9
13
diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c
10
diff --git a/tests/qemu-iotests/055 b/tests/qemu-iotests/055
14
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100755
15
--- a/tests/test-blockjob.c
12
--- a/tests/qemu-iotests/055
16
+++ b/tests/test-blockjob.c
13
+++ b/tests/qemu-iotests/055
17
@@ -XXX,XX +XXX,XX @@ static BlockJob *do_test_id(BlockBackend *blk, const char *id,
14
@@ -XXX,XX +XXX,XX @@ class TestCompressedToQcow2(iotests.QMPTestCase):
18
* BlockDriverState inserted. */
15
class TestCompressedToVmdk(TestCompressedToQcow2):
19
static BlockBackend *create_blk(const char *name)
16
target_fmt = {'type': 'vmdk', 'args': ('-o', 'subformat=streamOptimized')}
20
{
17
21
- /* FIXME Use real permissions */
18
+ @iotests.skip_if_unsupported(['vmdk'])
22
+ /* No I/O is performed on this device */
19
+ def setUp(self):
23
BlockBackend *blk = blk_new(0, BLK_PERM_ALL);
20
+ pass
24
BlockDriverState *bs;
21
+
25
22
26
diff --git a/tests/test-throttle.c b/tests/test-throttle.c
23
if __name__ == '__main__':
27
index XXXXXXX..XXXXXXX 100644
24
iotests.main(supported_fmts=['raw', 'qcow2'],
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
--
25
--
40
1.8.3.1
26
2.25.3
41
27
42
28
diff view generated by jsdifflib
1
When the parents' child links are updated in bdrv_append() or
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
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
2
3
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
4
Message-Id: <20200430124713.3067-8-vsementsov@virtuozzo.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
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
---
6
---
11
block.c | 3 +++
7
tests/qemu-iotests/109 | 1 +
12
include/block/block_int.h | 4 ++++
8
1 file changed, 1 insertion(+)
13
2 files changed, 7 insertions(+)
14
9
15
diff --git a/block.c b/block.c
10
diff --git a/tests/qemu-iotests/109 b/tests/qemu-iotests/109
16
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100755
17
--- a/block.c
12
--- a/tests/qemu-iotests/109
18
+++ b/block.c
13
+++ b/tests/qemu-iotests/109
19
@@ -XXX,XX +XXX,XX @@ static void change_parent_backing_link(BlockDriverState *from,
14
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
20
BdrvChild *c, *next, *to_c;
15
_supported_fmt raw
21
16
_supported_proto file
22
QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) {
17
_supported_os Linux
23
+ if (c->role->stay_at_node) {
18
+_require_drivers qcow qcow2 qed vdi vmdk vpc
24
+ continue;
19
25
+ }
20
qemu_comm_method=qmp
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
21
44
--
22
--
45
1.8.3.1
23
2.25.3
46
24
47
25
diff view generated by jsdifflib
1
bdrv_append() cares about isolation of the node that it modifies, but
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
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
2
3
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
4
Message-Id: <20200430124713.3067-9-vsementsov@virtuozzo.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Acked-by: Fam Zheng <famz@redhat.com>
9
---
6
---
10
block.c | 4 ++--
7
tests/qemu-iotests/113 | 4 ++--
11
1 file changed, 2 insertions(+), 2 deletions(-)
8
1 file changed, 2 insertions(+), 2 deletions(-)
12
9
13
diff --git a/block.c b/block.c
10
diff --git a/tests/qemu-iotests/113 b/tests/qemu-iotests/113
14
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100755
15
--- a/block.c
12
--- a/tests/qemu-iotests/113
16
+++ b/block.c
13
+++ b/tests/qemu-iotests/113
17
@@ -XXX,XX +XXX,XX @@ static void change_parent_backing_link(BlockDriverState *from,
14
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
18
*/
15
. ./common.rc
19
void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top)
16
. ./common.filter
20
{
17
21
- assert(!bdrv_requests_pending(bs_top));
18
-# Some of these test cases use bochs, but others do use raw, so this
22
- assert(!bdrv_requests_pending(bs_new));
19
-# is only half a lie.
23
+ assert(!atomic_read(&bs_top->in_flight));
20
+# Some of these test cases use bochs, but others do use raw
24
+ assert(!atomic_read(&bs_new->in_flight));
21
+_require_drivers bochs
25
22
_supported_fmt raw
26
bdrv_ref(bs_top);
23
_supported_proto file
27
24
_supported_os Linux
28
--
25
--
29
1.8.3.1
26
2.25.3
30
27
31
28
diff view generated by jsdifflib
1
Now that blk_insert_bs() requests the BlockBackend permissions for the
1
From: Alberto Garcia <berto@igalia.com>
2
node it attaches to, it can fail. Instead of aborting, pass the errors
3
to the callers.
4
2
3
After commit f01643fb8b47e8a70c04bbf45e0f12a9e5bc54de when an image is
4
extended and BDRV_REQ_ZERO_WRITE is set then the new clusters are
5
zeroized.
6
7
The code however does not detect correctly situations when the old and
8
the new end of the image are within the same cluster. The problem can
9
be reproduced with these steps:
10
11
qemu-img create -f qcow2 backing.qcow2 1M
12
qemu-img create -f qcow2 -F qcow2 -b backing.qcow2 top.qcow2
13
qemu-img resize --shrink top.qcow2 520k
14
qemu-img resize top.qcow2 567k
15
16
In the last step offset - zero_start causes an integer wraparound.
17
18
Signed-off-by: Alberto Garcia <berto@igalia.com>
19
Message-Id: <20200504155217.10325-1-berto@igalia.com>
20
Reviewed-by: Eric Blake <eblake@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
21
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
---
22
---
9
block.c | 5 ++++-
23
block/qcow2.c | 12 ++++---
10
block/backup.c | 5 ++++-
24
tests/qemu-iotests/292 | 73 ++++++++++++++++++++++++++++++++++++++
11
block/block-backend.c | 13 ++++++++-----
25
tests/qemu-iotests/292.out | 24 +++++++++++++
12
block/commit.c | 38 ++++++++++++++++++++++++++++++--------
26
tests/qemu-iotests/group | 1 +
13
block/mirror.c | 15 ++++++++++++---
27
4 files changed, 105 insertions(+), 5 deletions(-)
14
block/qcow2.c | 10 ++++++++--
28
create mode 100755 tests/qemu-iotests/292
15
blockdev.c | 11 +++++++++--
29
create mode 100644 tests/qemu-iotests/292.out
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
30
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
31
diff --git a/block/qcow2.c b/block/qcow2.c
213
index XXXXXXX..XXXXXXX 100644
32
index XXXXXXX..XXXXXXX 100644
214
--- a/block/qcow2.c
33
--- a/block/qcow2.c
215
+++ b/block/qcow2.c
34
+++ b/block/qcow2.c
216
@@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
35
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
217
uint64_t cluster_size = s->cluster_size;
36
* requires a cluster-aligned start. The end may be unaligned if it is
218
bool encrypt;
37
* at the end of the image (which it is here).
219
int refcount_bits = s->refcount_bits;
38
*/
220
+ Error *local_err = NULL;
39
- ret = qcow2_cluster_zeroize(bs, zero_start, offset - zero_start, 0);
221
int ret;
40
- if (ret < 0) {
222
QemuOptDesc *desc = opts->list->desc;
41
- error_setg_errno(errp, -ret, "Failed to zero out new clusters");
223
Qcow2AmendHelperCBInfo helper_cb_info;
42
- goto fail;
224
@@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
43
+ if (offset > zero_start) {
225
44
+ ret = qcow2_cluster_zeroize(bs, zero_start, offset - zero_start, 0);
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) {
45
+ if (ret < 0) {
322
+ goto fail;
46
+ error_setg_errno(errp, -ret, "Failed to zero out new clusters");
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;
47
+ goto fail;
349
+ }
48
+ }
350
}
49
}
351
}
50
352
if (!blk) {
51
/* Write explicit zeros for the unaligned head */
353
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
52
if (zero_start > old_length) {
53
- uint64_t len = zero_start - old_length;
54
+ uint64_t len = MIN(zero_start, offset) - old_length;
55
uint8_t *buf = qemu_blockalign0(bs, len);
56
QEMUIOVector qiov;
57
qemu_iovec_init_buf(&qiov, buf, len);
58
diff --git a/tests/qemu-iotests/292 b/tests/qemu-iotests/292
59
new file mode 100755
60
index XXXXXXX..XXXXXXX
61
--- /dev/null
62
+++ b/tests/qemu-iotests/292
63
@@ -XXX,XX +XXX,XX @@
64
+#!/usr/bin/env bash
65
+#
66
+# Test resizing a qcow2 image with a backing file
67
+#
68
+# Copyright (C) 2020 Igalia, S.L.
69
+# Author: Alberto Garcia <berto@igalia.com>
70
+#
71
+# This program is free software; you can redistribute it and/or modify
72
+# it under the terms of the GNU General Public License as published by
73
+# the Free Software Foundation; either version 2 of the License, or
74
+# (at your option) any later version.
75
+#
76
+# This program is distributed in the hope that it will be useful,
77
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
78
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
79
+# GNU General Public License for more details.
80
+#
81
+# You should have received a copy of the GNU General Public License
82
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
83
+#
84
+
85
+# creator
86
+owner=berto@igalia.com
87
+
88
+seq=`basename $0`
89
+echo "QA output created by $seq"
90
+
91
+status=1 # failure is the default!
92
+
93
+_cleanup()
94
+{
95
+ _cleanup_test_img
96
+}
97
+trap "_cleanup; exit \$status" 0 1 2 3 15
98
+
99
+# get standard environment, filters and checks
100
+. ./common.rc
101
+. ./common.filter
102
+
103
+_supported_fmt qcow2
104
+_supported_proto file
105
+_supported_os Linux
106
+
107
+echo '### Create the backing image'
108
+BACKING_IMG="$TEST_IMG.base"
109
+TEST_IMG="$BACKING_IMG" _make_test_img 1M
110
+
111
+echo '### Fill the backing image with data (0x11)'
112
+$QEMU_IO -c 'write -P 0x11 0 1M' "$BACKING_IMG" | _filter_qemu_io
113
+
114
+echo '### Create the top image'
115
+_make_test_img -F "$IMGFMT" -b "$BACKING_IMG"
116
+
117
+echo '### Fill the top image with data (0x22)'
118
+$QEMU_IO -c 'write -P 0x22 0 1M' "$TEST_IMG" | _filter_qemu_io
119
+
120
+# Both offsets are part of the same cluster.
121
+echo '### Shrink the image to 520k'
122
+$QEMU_IMG resize --shrink "$TEST_IMG" 520k
123
+echo '### Grow the image to 567k'
124
+$QEMU_IMG resize "$TEST_IMG" 567k
125
+
126
+echo '### Check that the tail of the image reads as zeroes'
127
+$QEMU_IO -c 'read -P 0x22 0 520k' "$TEST_IMG" | _filter_qemu_io
128
+$QEMU_IO -c 'read -P 0x00 520k 47k' "$TEST_IMG" | _filter_qemu_io
129
+
130
+echo '### Show output of qemu-img map'
131
+$QEMU_IMG map "$TEST_IMG" | _filter_testdir
132
+
133
+# success, all done
134
+echo "*** done"
135
+rm -f $seq.full
136
+status=0
137
diff --git a/tests/qemu-iotests/292.out b/tests/qemu-iotests/292.out
138
new file mode 100644
139
index XXXXXXX..XXXXXXX
140
--- /dev/null
141
+++ b/tests/qemu-iotests/292.out
142
@@ -XXX,XX +XXX,XX @@
143
+QA output created by 292
144
+### Create the backing image
145
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=1048576
146
+### Fill the backing image with data (0x11)
147
+wrote 1048576/1048576 bytes at offset 0
148
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
149
+### Create the top image
150
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT
151
+### Fill the top image with data (0x22)
152
+wrote 1048576/1048576 bytes at offset 0
153
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
154
+### Shrink the image to 520k
155
+Image resized.
156
+### Grow the image to 567k
157
+Image resized.
158
+### Check that the tail of the image reads as zeroes
159
+read 532480/532480 bytes at offset 0
160
+520 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
161
+read 48128/48128 bytes at offset 532480
162
+47 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
163
+### Show output of qemu-img map
164
+Offset Length Mapped to File
165
+0 0x8dc00 0x50000 TEST_DIR/t.qcow2
166
+*** done
167
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
354
index XXXXXXX..XXXXXXX 100644
168
index XXXXXXX..XXXXXXX 100644
355
--- a/include/sysemu/block-backend.h
169
--- a/tests/qemu-iotests/group
356
+++ b/include/sysemu/block-backend.h
170
+++ b/tests/qemu-iotests/group
357
@@ -XXX,XX +XXX,XX @@ BlockBackend *blk_by_public(BlockBackendPublic *public);
171
@@ -XXX,XX +XXX,XX @@
358
172
288 quick
359
BlockDriverState *blk_bs(BlockBackend *blk);
173
289 rw quick
360
void blk_remove_bs(BlockBackend *blk);
174
290 rw auto quick
361
-void blk_insert_bs(BlockBackend *blk, BlockDriverState *bs);
175
+292 rw auto quick
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
--
176
--
413
1.8.3.1
177
2.25.3
414
178
415
179
diff view generated by jsdifflib
1
From: Peter Lieven <pl@kamp.de>
1
m_data is used for zero clusters even though valid == 0. It really only
2
means that a new cluster was allocated in the image file. Rename it to
3
reflect this.
2
4
3
the convert process is currently completely implemented with sync operations.
5
While at it, change it from int to bool, too.
4
That means it reads one buffer and then writes it. No parallelism and each sync
5
request takes as long as it takes until it is completed.
6
6
7
This can be a big performance hit when the convert process reads and writes
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
to devices which do not benefit from kernel readahead or pagecache.
8
Message-Id: <20200430133007.170335-2-kwolf@redhat.com>
9
In our environment we heavily have the following two use cases when using
9
Reviewed-by: Eric Blake <eblake@redhat.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>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
37
---
11
---
38
qemu-img-cmds.hx | 4 +-
12
block/vmdk.c | 8 ++++----
39
qemu-img.c | 322 ++++++++++++++++++++++++++++++++++++++-----------------
13
1 file changed, 4 insertions(+), 4 deletions(-)
40
qemu-img.texi | 16 ++-
41
3 files changed, 243 insertions(+), 99 deletions(-)
42
14
43
diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx
15
diff --git a/block/vmdk.c b/block/vmdk.c
44
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
45
--- a/qemu-img-cmds.hx
17
--- a/block/vmdk.c
46
+++ b/qemu-img-cmds.hx
18
+++ b/block/vmdk.c
47
@@ -XXX,XX +XXX,XX @@ STEXI
19
@@ -XXX,XX +XXX,XX @@ typedef struct VmdkMetaData {
48
ETEXI
20
unsigned int l1_index;
49
21
unsigned int l2_index;
50
DEF("convert", img_convert,
22
unsigned int l2_offset;
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")
23
- int valid;
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")
24
+ bool new_allocation;
53
STEXI
25
uint32_t *l2_cache_entry;
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}
26
} VmdkMetaData;
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}
27
56
ETEXI
28
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
57
29
unsigned int l2_size_bytes = extent->l2_size * extent->entry_size;
58
DEF("dd", img_dd,
30
59
diff --git a/qemu-img.c b/qemu-img.c
31
if (m_data) {
60
index XXXXXXX..XXXXXXX 100644
32
- m_data->valid = 0;
61
--- a/qemu-img.c
33
+ m_data->new_allocation = false;
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
+
81
typedef struct ImgConvertState {
82
BlockBackend **src;
83
int64_t *src_sectors;
84
- int src_cur, src_num;
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
}
34
}
126
}
35
if (extent->flat) {
127
36
*cluster_offset = extent->flat_start_offset;
128
static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num)
37
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
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;
38
return ret;
208
}
39
}
209
@@ -XXX,XX +XXX,XX @@ static int convert_read(ImgConvertState *s, int64_t sector_num, int nb_sectors,
40
if (m_data) {
210
return 0;
41
- m_data->valid = 1;
211
}
42
+ m_data->new_allocation = true;
212
43
m_data->l1_index = l1_index;
213
-static int convert_write(ImgConvertState *s, int64_t sector_num, int nb_sectors,
44
m_data->l2_index = l2_index;
214
- const uint8_t *buf)
45
m_data->l2_offset = l2_offset;
215
+
46
@@ -XXX,XX +XXX,XX @@ static int vmdk_pwritev(BlockDriverState *bs, uint64_t offset,
216
+static int coroutine_fn convert_co_write(ImgConvertState *s, int64_t sector_num,
47
if (ret) {
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;
48
return ret;
275
}
49
}
276
@@ -XXX,XX +XXX,XX @@ static int convert_write(ImgConvertState *s, int64_t sector_num, int nb_sectors,
50
- if (m_data.valid) {
277
return 0;
51
+ if (m_data.new_allocation) {
278
}
52
/* update L2 tables */
279
53
if (vmdk_L2update(extent, &m_data,
280
-static int convert_do_copy(ImgConvertState *s)
54
cluster_offset >> BDRV_SECTOR_BITS)
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
+ }
334
+
335
+ if (status == BLK_DATA) {
336
+ ret = convert_co_read(s, sector_num, n, buf);
337
+ if (ret < 0) {
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
+ }
347
+
348
+ if (s->wr_in_order) {
349
+ /* keep writes in order */
350
+ while (s->wr_offs != sector_num) {
351
+ if (s->ret != -EINPROGRESS) {
352
+ goto out;
353
+ }
354
+ s->wait_sector_num[index] = sector_num;
355
+ qemu_coroutine_yield();
356
+ }
357
+ s->wait_sector_num[index] = -1;
358
+ }
359
+
360
+ ret = convert_co_write(s, sector_num, n, buf, status);
361
+ if (ret < 0) {
362
+ error_report("error while writing sector %" PRId64
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
+ }
384
+ }
385
+
386
+out:
387
+ qemu_vfree(buf);
388
+ s->co[index] = NULL;
389
+ s->running_coroutines--;
390
+ if (!s->running_coroutines && s->ret == -EINPROGRESS) {
391
+ /* the convert job finished successfully */
392
+ s->ret = 0;
393
+ }
394
+}
395
+
396
+static int convert_do_copy(ImgConvertState *s)
397
+{
398
+ int ret, i, n;
399
+ int64_t sector_num = 0;
400
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
}
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
-
439
- while (sector_num < s->total_sectors) {
440
- n = convert_iteration_sectors(s, sector_num);
441
- if (n < 0) {
442
- ret = n;
443
- goto fail;
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
- }
451
-
452
- if (s->status == BLK_DATA) {
453
- ret = convert_read(s, sector_num, n, buf);
454
- if (ret < 0) {
455
- error_report("error while reading sector %" PRId64
456
- ": %s", sector_num, strerror(-ret));
457
- goto fail;
458
- }
459
- } else if (!s->min_sparse && s->status == BLK_ZERO) {
460
- n = MIN(n, s->buf_sectors);
461
- memset(buf, 0, n * BDRV_SECTOR_SIZE);
462
- s->status = BLK_DATA;
463
- }
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
}
482
483
- if (s->compressed) {
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
--
55
--
602
1.8.3.1
56
2.25.3
603
57
604
58
diff view generated by jsdifflib
1
Not all callers of bdrv_set_backing_hd() know for sure that attaching
1
m_data must contain valid data even for zero clusters when no cluster
2
the backing file will be allowed by the permission system. Return the
2
was allocated in the image file. Without this, zero writes segfault with
3
error from the function rather than aborting.
3
images that have zeroed_grain=on.
4
4
5
For zero writes, we don't want to allocate a cluster in the image file
6
even in compressed files.
7
8
Fixes: 524089bce43fd1cd3daaca979872451efa2cf7c6
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Acked-by: Fam Zheng <famz@redhat.com>
10
Message-Id: <20200430133007.170335-3-kwolf@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
11
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
13
---
9
block.c | 30 +++++++++++++++++++++++-------
14
block/vmdk.c | 12 +++++++-----
10
block/commit.c | 14 +++++++-------
15
1 file changed, 7 insertions(+), 5 deletions(-)
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
16
17
diff --git a/block.c b/block.c
17
diff --git a/block/vmdk.c b/block/vmdk.c
18
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
19
--- a/block.c
19
--- a/block/vmdk.c
20
+++ b/block.c
20
+++ b/block/vmdk.c
21
@@ -XXX,XX +XXX,XX @@ static void bdrv_parent_cb_resize(BlockDriverState *bs)
21
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
22
* Sets the backing file link of a BDS. A new reference is created; callers
22
extent->l2_cache_counts[min_index] = 1;
23
* which don't need their own reference any more must call bdrv_unref().
23
found:
24
*/
24
l2_index = ((offset >> 9) / extent->cluster_sectors) % extent->l2_size;
25
-void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd)
25
+ if (m_data) {
26
+void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
26
+ m_data->l1_index = l1_index;
27
+ Error **errp)
27
+ m_data->l2_index = l2_index;
28
{
28
+ m_data->l2_offset = l2_offset;
29
if (backing_hd) {
29
+ m_data->l2_cache_entry = ((uint32_t *)l2_table) + l2_index;
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
+ }
30
+ }
43
31
44
out:
32
if (extent->sesparse) {
45
bdrv_refresh_limits(bs, NULL);
33
cluster_sector = le64_to_cpu(((uint64_t *)l2_table)[l2_index]);
46
@@ -XXX,XX +XXX,XX @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
34
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
47
35
}
48
/* Hook up the backing file link; drop our reference, bs owns the
36
if (m_data) {
49
* backing_hd reference now */
37
m_data->new_allocation = true;
50
- bdrv_set_backing_hd(bs, backing_hd);
38
- m_data->l1_index = l1_index;
51
+ bdrv_set_backing_hd(bs, backing_hd, &local_err);
39
- m_data->l2_index = l2_index;
52
bdrv_unref(backing_hd);
40
- m_data->l2_offset = l2_offset;
53
+ if (local_err) {
41
- m_data->l2_cache_entry = ((uint32_t *)l2_table) + l2_index;
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
}
42
}
178
}
43
}
179
44
*cluster_offset = cluster_sector << BDRV_SECTOR_BITS;
180
diff --git a/block/stream.c b/block/stream.c
45
@@ -XXX,XX +XXX,XX @@ static int vmdk_pwritev(BlockDriverState *bs, uint64_t offset,
181
index XXXXXXX..XXXXXXX 100644
46
error_report("Could not write to allocated cluster"
182
--- a/block/stream.c
47
" for streamOptimized");
183
+++ b/block/stream.c
48
return -EIO;
184
@@ -XXX,XX +XXX,XX @@ static void stream_complete(BlockJob *job, void *opaque)
49
- } else {
185
StreamCompleteData *data = opaque;
50
+ } else if (!zeroed) {
186
BlockDriverState *bs = blk_bs(job->blk);
51
/* allocate */
187
BlockDriverState *base = s->base;
52
ret = get_cluster_offset(bs, extent, &m_data, offset,
188
+ Error *local_err = NULL;
53
true, &cluster_offset, 0, 0);
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
--
54
--
237
1.8.3.1
55
2.25.3
238
56
239
57
diff view generated by jsdifflib
1
NBD can't cope with device size changes, so resize must be forbidden,
1
When overwriting a zero cluster, we must not perform copy-on-write from
2
but otherwise we can tolerate anything. Depending on whether the export
2
the backing file, but from a zeroed buffer.
3
is writable or not, we only require consistent reads and writes.
4
3
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>
5
Message-Id: <20200430133007.170335-4-kwolf@redhat.com>
7
Acked-by: Fam Zheng <famz@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
8
---
9
nbd/server.c | 11 +++++++++--
9
block/vmdk.c | 18 ++++++++++++------
10
1 file changed, 9 insertions(+), 2 deletions(-)
10
1 file changed, 12 insertions(+), 6 deletions(-)
11
11
12
diff --git a/nbd/server.c b/nbd/server.c
12
diff --git a/block/vmdk.c b/block/vmdk.c
13
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
14
--- a/nbd/server.c
14
--- a/block/vmdk.c
15
+++ b/nbd/server.c
15
+++ b/block/vmdk.c
16
@@ -XXX,XX +XXX,XX @@ NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, off_t size,
16
@@ -XXX,XX +XXX,XX @@ static void vmdk_refresh_limits(BlockDriverState *bs, Error **errp)
17
* get_whole_cluster
18
*
19
* Copy backing file's cluster that covers @sector_num, otherwise write zero,
20
- * to the cluster at @cluster_sector_num.
21
+ * to the cluster at @cluster_sector_num. If @zeroed is true, we're overwriting
22
+ * a zeroed cluster in the current layer and must not copy data from the
23
+ * backing file.
24
*
25
* If @skip_start_sector < @skip_end_sector, the relative range
26
* [@skip_start_sector, @skip_end_sector) is not copied or written, and leave
27
@@ -XXX,XX +XXX,XX @@ static int get_whole_cluster(BlockDriverState *bs,
28
uint64_t cluster_offset,
29
uint64_t offset,
30
uint64_t skip_start_bytes,
31
- uint64_t skip_end_bytes)
32
+ uint64_t skip_end_bytes,
33
+ bool zeroed)
17
{
34
{
18
BlockBackend *blk;
35
int ret = VMDK_OK;
19
NBDExport *exp = g_malloc0(sizeof(NBDExport));
36
int64_t cluster_bytes;
20
+ uint64_t perm;
37
uint8_t *whole_grain;
21
int ret;
38
+ bool copy_from_backing;
22
39
23
- /* FIXME Use real permissions */
40
/* For COW, align request sector_num to cluster start */
24
- blk = blk_new(0, BLK_PERM_ALL);
41
cluster_bytes = extent->cluster_sectors << BDRV_SECTOR_BITS;
25
+ /* Don't allow resize while the NBD server is running, otherwise we don't
42
offset = QEMU_ALIGN_DOWN(offset, cluster_bytes);
26
+ * care what happens with the node. */
43
whole_grain = qemu_blockalign(bs, cluster_bytes);
27
+ perm = BLK_PERM_CONSISTENT_READ;
44
+ copy_from_backing = bs->backing && !zeroed;
28
+ if ((nbdflags & NBD_FLAG_READ_ONLY) == 0) {
45
29
+ perm |= BLK_PERM_WRITE;
46
- if (!bs->backing) {
30
+ }
47
+ if (!copy_from_backing) {
31
+ blk = blk_new(perm, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED |
48
memset(whole_grain, 0, skip_start_bytes);
32
+ BLK_PERM_WRITE | BLK_PERM_GRAPH_MOD);
49
memset(whole_grain + skip_end_bytes, 0, cluster_bytes - skip_end_bytes);
33
ret = blk_insert_bs(blk, bs, errp);
50
}
34
if (ret < 0) {
51
@@ -XXX,XX +XXX,XX @@ static int get_whole_cluster(BlockDriverState *bs,
35
goto fail;
52
53
/* Read backing data before skip range */
54
if (skip_start_bytes > 0) {
55
- if (bs->backing) {
56
+ if (copy_from_backing) {
57
/* qcow2 emits this on bs->file instead of bs->backing */
58
BLKDBG_EVENT(extent->file, BLKDBG_COW_READ);
59
ret = bdrv_pread(bs->backing, offset, whole_grain,
60
@@ -XXX,XX +XXX,XX @@ static int get_whole_cluster(BlockDriverState *bs,
61
}
62
/* Read backing data after skip range */
63
if (skip_end_bytes < cluster_bytes) {
64
- if (bs->backing) {
65
+ if (copy_from_backing) {
66
/* qcow2 emits this on bs->file instead of bs->backing */
67
BLKDBG_EVENT(extent->file, BLKDBG_COW_READ);
68
ret = bdrv_pread(bs->backing, offset + skip_end_bytes,
69
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
70
* or inappropriate VM shutdown.
71
*/
72
ret = get_whole_cluster(bs, extent, cluster_sector * BDRV_SECTOR_SIZE,
73
- offset, skip_start_bytes, skip_end_bytes);
74
+ offset, skip_start_bytes, skip_end_bytes,
75
+ zeroed);
76
if (ret) {
77
return ret;
78
}
36
--
79
--
37
1.8.3.1
80
2.25.3
38
81
39
82
diff view generated by jsdifflib
1
This makes use of the .bdrv_child_perm() implementation for formats that
1
If a cluster is already zeroed, we don't have to call vmdk_L2update(),
2
we just added. All format drivers expose the permissions they actually
2
which is rather slow because it flushes the image file.
3
need nows, so that they can be set accordingly and updated when parents
4
are attached or detached.
5
6
The only format not included here is raw, which was already converted
7
with the other filter drivers.
8
3
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Reviewed-by: Max Reitz <mreitz@redhat.com>
5
Message-Id: <20200430133007.170335-5-kwolf@redhat.com>
11
Acked-by: Fam Zheng <famz@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
8
---
13
block/bochs.c | 1 +
9
block/vmdk.c | 2 +-
14
block/cloop.c | 1 +
10
1 file changed, 1 insertion(+), 1 deletion(-)
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
11
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
12
diff --git a/block/vmdk.c b/block/vmdk.c
148
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
149
--- a/block/vmdk.c
14
--- a/block/vmdk.c
150
+++ b/block/vmdk.c
15
+++ b/block/vmdk.c
151
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_vmdk = {
16
@@ -XXX,XX +XXX,XX @@ static int vmdk_pwritev(BlockDriverState *bs, uint64_t offset,
152
.bdrv_open = vmdk_open,
17
offset_in_cluster == 0 &&
153
.bdrv_check = vmdk_check,
18
n_bytes >= extent->cluster_sectors * BDRV_SECTOR_SIZE) {
154
.bdrv_reopen_prepare = vmdk_reopen_prepare,
19
n_bytes = extent->cluster_sectors * BDRV_SECTOR_SIZE;
155
+ .bdrv_child_perm = bdrv_format_default_perms,
20
- if (!zero_dry_run) {
156
.bdrv_co_preadv = vmdk_co_preadv,
21
+ if (!zero_dry_run && ret != VMDK_ZEROED) {
157
.bdrv_co_pwritev = vmdk_co_pwritev,
22
/* update L2 tables */
158
.bdrv_co_pwritev_compressed = vmdk_co_pwritev_compressed,
23
if (vmdk_L2update(extent, &m_data, VMDK_GTE_ZEROED)
159
diff --git a/block/vpc.c b/block/vpc.c
24
!= VMDK_OK) {
160
index XXXXXXX..XXXXXXX 100644
161
--- a/block/vpc.c
162
+++ b/block/vpc.c
163
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_vpc = {
164
.bdrv_open = vpc_open,
165
.bdrv_close = vpc_close,
166
.bdrv_reopen_prepare = vpc_reopen_prepare,
167
+ .bdrv_child_perm = bdrv_format_default_perms,
168
.bdrv_create = vpc_create,
169
170
.bdrv_co_preadv = vpc_co_preadv,
171
--
25
--
172
1.8.3.1
26
2.25.3
173
27
174
28
diff view generated by jsdifflib
1
Request BLK_PERM_CONSISTENT_READ for the source of block migration, and
1
If we have a backup L2 table, we currently flush once after writing to
2
handle potential permission errors as good as we can in this place
2
the active L2 table and again after writing to the backup table. A
3
(which is not very good, but it matches the other failure cases).
3
single flush is enough and makes things a little less slow.
4
4
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Acked-by: Fam Zheng <famz@redhat.com>
6
Message-Id: <20200430133007.170335-6-kwolf@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
9
---
9
migration/block.c | 22 +++++++++++++++++-----
10
block/vmdk.c | 7 +++++--
10
1 file changed, 17 insertions(+), 5 deletions(-)
11
1 file changed, 5 insertions(+), 2 deletions(-)
11
12
12
diff --git a/migration/block.c b/migration/block.c
13
diff --git a/block/vmdk.c b/block/vmdk.c
13
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
14
--- a/migration/block.c
15
--- a/block/vmdk.c
15
+++ b/migration/block.c
16
+++ b/block/vmdk.c
16
@@ -XXX,XX +XXX,XX @@ static void unset_dirty_tracking(void)
17
@@ -XXX,XX +XXX,XX @@ static int vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data,
17
}
18
offset = cpu_to_le32(offset);
18
}
19
/* update L2 table */
19
20
BLKDBG_EVENT(extent->file, BLKDBG_L2_UPDATE);
20
-static void init_blk_migration(QEMUFile *f)
21
- if (bdrv_pwrite_sync(extent->file,
21
+static int init_blk_migration(QEMUFile *f)
22
+ if (bdrv_pwrite(extent->file,
22
{
23
((int64_t)m_data->l2_offset * 512)
23
BlockDriverState *bs;
24
+ (m_data->l2_index * sizeof(offset)),
24
BlkMigDevState *bmds;
25
&offset, sizeof(offset)) < 0) {
25
@@ -XXX,XX +XXX,XX @@ static void init_blk_migration(QEMUFile *f)
26
@@ -XXX,XX +XXX,XX @@ static int vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data,
26
BlkMigDevState *bmds;
27
/* update backup L2 table */
27
BlockDriverState *bs;
28
if (extent->l1_backup_table_offset != 0) {
28
} *bmds_bs;
29
m_data->l2_offset = extent->l1_backup_table[m_data->l1_index];
29
+ Error *local_err = NULL;
30
- if (bdrv_pwrite_sync(extent->file,
30
+ int ret;
31
+ if (bdrv_pwrite(extent->file,
31
32
((int64_t)m_data->l2_offset * 512)
32
block_mig_state.submitted = 0;
33
+ (m_data->l2_index * sizeof(offset)),
33
block_mig_state.read_done = 0;
34
&offset, sizeof(offset)) < 0) {
34
@@ -XXX,XX +XXX,XX @@ static void init_blk_migration(QEMUFile *f)
35
return VMDK_ERROR;
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
}
36
}
64
}
37
}
65
38
+ if (bdrv_flush(extent->file->bs) < 0) {
66
+ ret = 0;
39
+ return VMDK_ERROR;
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
+ }
40
+ }
83
41
if (m_data->l2_cache_entry) {
84
/* start track dirty blocks */
42
*m_data->l2_cache_entry = offset;
85
ret = set_dirty_tracking();
43
}
86
--
44
--
87
1.8.3.1
45
2.25.3
88
46
89
47
diff view generated by jsdifflib
1
The HMP command 'qemu-io' is a bit tricky because it wants to work on
1
In order to avoid bitrot in the zero cluster code in VMDK, enable
2
the original BlockBackend, but additional permissions could be required.
2
zeroed_grain=on by default for the tests.
3
The details are explained in a comment in the code, but in summary, just
3
4
request whatever permissions the current qemu-io command needs.
4
059 now unsets the default options because zeroed_grain=on works only
5
with some subformats and the test case tests many different subformats,
6
including those for which it doesn't work.
5
7
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Message-Id: <20200430133007.170335-7-kwolf@redhat.com>
8
Acked-by: Fam Zheng <famz@redhat.com>
10
Reviewed-by: Eric Blake <eblake@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
12
---
10
block/block-backend.c | 6 ++++++
13
tests/qemu-iotests/059 | 6 +++---
11
hmp.c | 26 +++++++++++++++++++++++++-
14
tests/qemu-iotests/check | 3 +++
12
include/qemu-io.h | 1 +
15
2 files changed, 6 insertions(+), 3 deletions(-)
13
include/sysemu/block-backend.h | 1 +
14
qemu-io-cmds.c | 28 ++++++++++++++++++++++++++++
15
5 files changed, 61 insertions(+), 1 deletion(-)
16
16
17
diff --git a/block/block-backend.c b/block/block-backend.c
17
diff --git a/tests/qemu-iotests/059 b/tests/qemu-iotests/059
18
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100755
19
--- a/block/block-backend.c
19
--- a/tests/qemu-iotests/059
20
+++ b/block/block-backend.c
20
+++ b/tests/qemu-iotests/059
21
@@ -XXX,XX +XXX,XX @@ int blk_set_perm(BlockBackend *blk, uint64_t perm, uint64_t shared_perm,
21
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
22
return 0;
22
_supported_fmt vmdk
23
}
23
_supported_proto file
24
24
_supported_os Linux
25
+void blk_get_perm(BlockBackend *blk, uint64_t *perm, uint64_t *shared_perm)
25
-_unsupported_imgopts "subformat=monolithicFlat" \
26
+{
26
- "subformat=twoGbMaxExtentFlat" \
27
+ *perm = blk->perm;
27
- "subformat=twoGbMaxExtentSparse"
28
+ *shared_perm = blk->shared_perm;
29
+}
30
+
28
+
31
static int blk_do_attach_dev(BlockBackend *blk, void *dev)
29
+# We test all kinds of VMDK options here, so ignore user-specified options
32
{
30
+IMGOPTS=""
33
if (blk->dev) {
31
34
diff --git a/hmp.c b/hmp.c
32
capacity_offset=16
35
index XXXXXXX..XXXXXXX 100644
33
granularity_offset=20
36
--- a/hmp.c
34
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
37
+++ b/hmp.c
35
index XXXXXXX..XXXXXXX 100755
38
@@ -XXX,XX +XXX,XX @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict)
36
--- a/tests/qemu-iotests/check
39
if (!blk) {
37
+++ b/tests/qemu-iotests/check
40
BlockDriverState *bs = bdrv_lookup_bs(NULL, device, &err);
38
@@ -XXX,XX +XXX,XX @@ fi
41
if (bs) {
39
if [ "$IMGFMT" == "luks" ] && ! (echo "$IMGOPTS" | grep "iter-time=" > /dev/null); then
42
- /* FIXME Use real permissions */
40
IMGOPTS=$(_optstr_add "$IMGOPTS" "iter-time=10")
43
blk = local_blk = blk_new(0, BLK_PERM_ALL);
41
fi
44
ret = blk_insert_bs(blk, bs, &err);
42
+if [ "$IMGFMT" == "vmdk" ] && ! (echo "$IMGOPTS" | grep "zeroed_grain=" > /dev/null); then
45
if (ret < 0) {
43
+ IMGOPTS=$(_optstr_add "$IMGOPTS" "zeroed_grain=on")
46
@@ -XXX,XX +XXX,XX @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict)
44
+fi
47
aio_context = blk_get_aio_context(blk);
45
48
aio_context_acquire(aio_context);
46
if [ -z "$SAMPLE_IMG_DIR" ]; then
49
47
SAMPLE_IMG_DIR="$source_iotests/sample_images"
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
--
48
--
177
1.8.3.1
49
2.25.3
178
50
179
51
diff view generated by jsdifflib
1
The mirror block job is mainly used for two different scenarios:
1
The test case forgot to specify the null-co size for the target node.
2
Mirroring to an otherwise unused, independent target node, or for active
2
When adding a check to backup that both sizes match, this would fail
3
commit where the target node is part of the backing chain of the source.
3
because of the size mismatch and not the behaviour that the test really
4
wanted to test.
4
5
5
Similarly to the commit block job patch, we need to insert a new filter
6
Fixes: a541fcc27c98b96da187c7d4573f3270f3ddd283
6
node to keep the permissions correct during active commit.
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Message-Id: <20200430142755.315494-2-kwolf@redhat.com>
9
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
12
tests/qemu-iotests/283 | 6 +++++-
13
tests/qemu-iotests/283.out | 2 +-
14
2 files changed, 6 insertions(+), 2 deletions(-)
7
15
8
Note that one change this implies is that job->blk points to
16
diff --git a/tests/qemu-iotests/283 b/tests/qemu-iotests/283
9
mirror_top_bs as its root now, and mirror_top_bs (rather than the actual
10
source node) contains the bs->job pointer. This requires qemu-img commit
11
to get the job by name now rather than just taking bs->job.
12
13
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
---
17
block/mirror.c | 216 ++++++++++++++++++++++++++++++++++++++-------
18
qemu-img.c | 6 +-
19
tests/qemu-iotests/141 | 2 +-
20
tests/qemu-iotests/141.out | 4 +-
21
4 files changed, 190 insertions(+), 38 deletions(-)
22
23
diff --git a/block/mirror.c b/block/mirror.c
24
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
25
--- a/block/mirror.c
18
--- a/tests/qemu-iotests/283
26
+++ b/block/mirror.c
19
+++ b/tests/qemu-iotests/283
27
@@ -XXX,XX +XXX,XX @@ typedef struct MirrorBlockJob {
20
@@ -XXX,XX +XXX,XX @@ to check that crash is fixed :)
28
BlockJob common;
21
vm = iotests.VM()
29
RateLimit limit;
22
vm.launch()
30
BlockBackend *target;
23
31
+ BlockDriverState *mirror_top_bs;
24
-vm.qmp_log('blockdev-add', **{'node-name': 'target', 'driver': 'null-co'})
32
+ BlockDriverState *source;
25
+vm.qmp_log('blockdev-add', **{
33
BlockDriverState *base;
26
+ 'node-name': 'target',
34
+
27
+ 'driver': 'null-co',
35
/* The name of the graph node to replace */
28
+ 'size': size,
36
char *replaces;
29
+})
37
/* The BDS to replace */
30
38
@@ -XXX,XX +XXX,XX @@ static void mirror_do_zero_or_discard(MirrorBlockJob *s,
31
vm.qmp_log('blockdev-add', **{
39
32
'node-name': 'source',
40
static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
33
diff --git a/tests/qemu-iotests/283.out b/tests/qemu-iotests/283.out
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);
76
bdrv_replace_in_backing_chain(to_replace, target_bs);
77
bdrv_drained_end(target_bs);
78
-
79
- /* We just changed the BDS the job BB refers to, so switch the BB back
80
- * so the cleanup does the right thing. We don't need any permissions
81
- * any more now. */
82
- blk_remove_bs(job->blk);
83
- blk_set_perm(job->blk, 0, BLK_PERM_ALL, &error_abort);
84
- blk_insert_bs(job->blk, src, &error_abort);
85
}
86
if (s->to_replace) {
87
bdrv_op_unblock_all(s->to_replace, s->replace_blocker);
88
@@ -XXX,XX +XXX,XX @@ static void mirror_exit(BlockJob *job, void *opaque)
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
{
136
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
+
179
+static int coroutine_fn bdrv_mirror_top_pwritev(BlockDriverState *bs,
180
+ uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags)
181
+{
182
+ return bdrv_co_pwritev(bs->backing, offset, bytes, qiov, flags);
183
+}
184
+
185
+static int coroutine_fn bdrv_mirror_top_flush(BlockDriverState *bs)
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
+ }
226
+
227
+ *nshared = BLK_PERM_ALL;
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
}
366
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
34
index XXXXXXX..XXXXXXX 100644
370
--- a/qemu-img.c
35
--- a/tests/qemu-iotests/283.out
371
+++ b/qemu-img.c
36
+++ b/tests/qemu-iotests/283.out
372
@@ -XXX,XX +XXX,XX @@ static void run_block_job(BlockJob *job, Error **errp)
37
@@ -XXX,XX +XXX,XX @@
373
{
38
-{"execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "target"}}
374
AioContext *aio_context = blk_get_aio_context(job->blk);
39
+{"execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "target", "size": 1048576}}
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": {}}
40
{"return": {}}
420
-{"error": {"class": "GenericError", "desc": "Node drv0 is in use"}}
41
{"execute": "blockdev-add", "arguments": {"driver": "blkdebug", "image": {"driver": "null-co", "node-name": "base", "size": 1048576}, "node-name": "source"}}
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": {}}
42
{"return": {}}
434
--
43
--
435
1.8.3.1
44
2.25.3
436
45
437
46
diff view generated by jsdifflib
1
This functions creates a BlockBackend internally, so the block jobs need
1
bdrv_get_device_name() will be an empty string with modern management
2
to tell it what they want to do with the BB.
2
tools that don't use -drive. Use bdrv_get_device_or_node_name() instead
3
so that the node name is used if the BlockBackend is anonymous.
4
5
While at it, start with upper case to make the message consistent with
6
the rest of the function.
3
7
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Acked-by: Fam Zheng <famz@redhat.com>
10
Reviewed-by: Alberto Garcia <berto@igalia.com>
11
Message-Id: <20200430142755.315494-3-kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
13
---
8
block/backup.c | 5 +++--
14
block/backup.c | 4 ++--
9
block/commit.c | 5 +++--
15
1 file changed, 2 insertions(+), 2 deletions(-)
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
16
18
diff --git a/block/backup.c b/block/backup.c
17
diff --git a/block/backup.c b/block/backup.c
19
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
20
--- a/block/backup.c
19
--- a/block/backup.c
21
+++ b/block/backup.c
20
+++ b/block/backup.c
22
@@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
21
@@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
22
23
len = bdrv_getlength(bs);
24
if (len < 0) {
25
- error_setg_errno(errp, -len, "unable to get length for '%s'",
26
- bdrv_get_device_name(bs));
27
+ error_setg_errno(errp, -len, "Unable to get length for '%s'",
28
+ bdrv_get_device_or_node_name(bs));
23
goto error;
29
goto error;
24
}
30
}
25
31
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
--
32
--
162
1.8.3.1
33
2.25.3
163
34
164
35
diff view generated by jsdifflib
1
Block jobs don't actually do I/O through the the reference they create
1
Since the introduction of a backup filter node in commit 00e30f05d, the
2
with block_job_add_bdrv(), but they might want to use the permisssion
2
backup block job crashes when the target image is smaller than the
3
system to express what the block job does to intermediate nodes. This
3
source image because it will try to write after the end of the target
4
adds permissions to block_job_add_bdrv() to provide the means to request
4
node without having BLK_PERM_RESIZE. (Previously, the BlockBackend layer
5
permissions.
5
would have caught this and errored out gracefully.)
6
6
7
We can fix this and even do better than the old behaviour: Check that
8
source and target have the same image size at the start of the block job
9
and unshare BLK_PERM_RESIZE. (This permission was already unshared
10
before the same commit 00e30f05d, but the BlockBackend that was used to
11
make the restriction was removed without a replacement.) This will
12
immediately error out when starting the job instead of only when writing
13
to a block that doesn't exist in the target.
14
15
Longer target than source would technically work because we would never
16
write to blocks that don't exist, but semantically these are invalid,
17
too, because a backup is supposed to create a copy, not just an image
18
that starts with a copy.
19
20
Fixes: 00e30f05de1d19586345ec373970ef4c192c6270
21
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1778593
22
Cc: qemu-stable@nongnu.org
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
23
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
24
Message-Id: <20200430142755.315494-4-kwolf@redhat.com>
9
Acked-by: Fam Zheng <famz@redhat.com>
25
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
26
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
27
---
11
block/backup.c | 4 +++-
28
block/backup-top.c | 14 +++++++++-----
12
block/commit.c | 8 ++++++--
29
block/backup.c | 14 +++++++++++++-
13
block/mirror.c | 9 +++++++--
30
2 files changed, 22 insertions(+), 6 deletions(-)
14
block/stream.c | 4 +++-
15
blockjob.c | 36 ++++++++++++++++++++++++++++++------
16
include/block/blockjob.h | 5 ++++-
17
6 files changed, 53 insertions(+), 13 deletions(-)
18
31
32
diff --git a/block/backup-top.c b/block/backup-top.c
33
index XXXXXXX..XXXXXXX 100644
34
--- a/block/backup-top.c
35
+++ b/block/backup-top.c
36
@@ -XXX,XX +XXX,XX @@ static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c,
37
*
38
* Share write to target (child_file), to not interfere
39
* with guest writes to its disk which may be in target backing chain.
40
+ * Can't resize during a backup block job because we check the size
41
+ * only upfront.
42
*/
43
- *nshared = BLK_PERM_ALL;
44
+ *nshared = BLK_PERM_ALL & ~BLK_PERM_RESIZE;
45
*nperm = BLK_PERM_WRITE;
46
} else {
47
/* Source child */
48
@@ -XXX,XX +XXX,XX @@ static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c,
49
if (perm & BLK_PERM_WRITE) {
50
*nperm = *nperm | BLK_PERM_CONSISTENT_READ;
51
}
52
- *nshared &= ~BLK_PERM_WRITE;
53
+ *nshared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE);
54
}
55
}
56
57
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source,
58
{
59
Error *local_err = NULL;
60
BDRVBackupTopState *state;
61
- BlockDriverState *top = bdrv_new_open_driver(&bdrv_backup_top_filter,
62
- filter_node_name,
63
- BDRV_O_RDWR, errp);
64
+ BlockDriverState *top;
65
bool appended = false;
66
67
+ assert(source->total_sectors == target->total_sectors);
68
+
69
+ top = bdrv_new_open_driver(&bdrv_backup_top_filter, filter_node_name,
70
+ BDRV_O_RDWR, errp);
71
if (!top) {
72
return NULL;
73
}
19
diff --git a/block/backup.c b/block/backup.c
74
diff --git a/block/backup.c b/block/backup.c
20
index XXXXXXX..XXXXXXX 100644
75
index XXXXXXX..XXXXXXX 100644
21
--- a/block/backup.c
76
--- a/block/backup.c
22
+++ b/block/backup.c
77
+++ b/block/backup.c
23
@@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
78
@@ -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);
79
BlockCompletionFunc *cb, void *opaque,
80
JobTxn *txn, Error **errp)
81
{
82
- int64_t len;
83
+ int64_t len, target_len;
84
BackupBlockJob *job = NULL;
85
int64_t cluster_size;
86
BdrvRequestFlags write_flags;
87
@@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
88
goto error;
25
}
89
}
26
90
27
- block_job_add_bdrv(&job->common, target);
91
+ target_len = bdrv_getlength(target);
28
+ /* FIXME Use real permissions */
92
+ if (target_len < 0) {
29
+ block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL,
93
+ error_setg_errno(errp, -target_len, "Unable to get length for '%s'",
30
+ &error_abort);
94
+ bdrv_get_device_or_node_name(bs));
31
job->common.len = len;
95
+ goto error;
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
+ }
96
+ }
138
+
97
+
139
+ job->nodes = g_slist_prepend(job->nodes, c);
98
+ if (target_len != len) {
140
bdrv_ref(bs);
99
+ error_setg(errp, "Source and target image have different sizes");
141
bdrv_op_block_all(bs, job->blocker);
100
+ goto error;
101
+ }
142
+
102
+
143
+ return 0;
103
cluster_size = backup_calculate_cluster_size(target, errp);
144
}
104
if (cluster_size < 0) {
145
105
goto error;
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
--
106
--
192
1.8.3.1
107
2.25.3
193
108
194
109
diff view generated by jsdifflib
1
The backup block job doesn't have very complicated requirements: It
1
This tests that the backup job catches situations where the target node
2
needs to read from the source and write to the target, but it's fine
2
has a different size than the source node. It must also forbid resize
3
with either side being changed. The only restriction is that we can't
3
operations when the job is already running.
4
resize the image because the job uses a cached value.
5
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
4
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Message-Id: <20200430142755.315494-5-kwolf@redhat.com>
13
Acked-by: Fam Zheng <famz@redhat.com>
7
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
9
---
15
block/backup.c | 15 ++++++++++-----
10
tests/qemu-iotests/055 | 41 ++++++++++++++++++++++++++++++++++++--
16
tests/qemu-iotests/055 | 11 +++++++----
11
tests/qemu-iotests/055.out | 4 ++--
17
2 files changed, 17 insertions(+), 9 deletions(-)
12
2 files changed, 41 insertions(+), 4 deletions(-)
18
13
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
14
diff --git a/tests/qemu-iotests/055 b/tests/qemu-iotests/055
58
index XXXXXXX..XXXXXXX 100755
15
index XXXXXXX..XXXXXXX 100755
59
--- a/tests/qemu-iotests/055
16
--- a/tests/qemu-iotests/055
60
+++ b/tests/qemu-iotests/055
17
+++ b/tests/qemu-iotests/055
61
@@ -XXX,XX +XXX,XX @@ class TestSingleDrive(iotests.QMPTestCase):
18
@@ -XXX,XX +XXX,XX @@ class TestSingleDrive(iotests.QMPTestCase):
62
def setUp(self):
19
def setUp(self):
63
qemu_img('create', '-f', iotests.imgfmt, blockdev_target_img, str(image_len))
20
qemu_img('create', '-f', iotests.imgfmt, blockdev_target_img, str(image_len))
64
21
65
- self.vm = iotests.VM().add_drive(test_img).add_drive(blockdev_target_img)
22
- self.vm = iotests.VM().add_drive('blkdebug::' + test_img)
66
+ self.vm = iotests.VM().add_drive(test_img)
23
- self.vm.add_drive(blockdev_target_img, interface="none")
67
+ self.vm.add_drive(blockdev_target_img, interface="none")
24
+ self.vm = iotests.VM()
25
+ self.vm.add_drive('blkdebug::' + test_img, 'node-name=source')
26
+ self.vm.add_drive(blockdev_target_img, 'node-name=target',
27
+ interface="none")
68
if iotests.qemu_default_machine == 'pc':
28
if iotests.qemu_default_machine == 'pc':
69
self.vm.add_drive(None, 'media=cdrom', 'ide')
29
self.vm.add_drive(None, 'media=cdrom', 'ide')
70
self.vm.launch()
30
self.vm.launch()
71
@@ -XXX,XX +XXX,XX @@ class TestSetSpeed(iotests.QMPTestCase):
31
@@ -XXX,XX +XXX,XX @@ class TestSingleDrive(iotests.QMPTestCase):
72
def setUp(self):
32
def test_pause_blockdev_backup(self):
73
qemu_img('create', '-f', iotests.imgfmt, blockdev_target_img, str(image_len))
33
self.do_test_pause('blockdev-backup', 'drive1', blockdev_target_img)
74
34
75
- self.vm = iotests.VM().add_drive(test_img).add_drive(blockdev_target_img)
35
+ def do_test_resize_blockdev_backup(self, device, node):
76
+ self.vm = iotests.VM().add_drive(test_img)
36
+ def pre_finalize():
77
+ self.vm.add_drive(blockdev_target_img, interface="none")
37
+ result = self.vm.qmp('block_resize', device=device, size=65536)
78
self.vm.launch()
38
+ self.assert_qmp(result, 'error/class', 'GenericError')
79
39
+
80
def tearDown(self):
40
+ result = self.vm.qmp('block_resize', node_name=node, size=65536)
81
@@ -XXX,XX +XXX,XX @@ class TestSingleTransaction(iotests.QMPTestCase):
41
+ self.assert_qmp(result, 'error/class', 'GenericError')
82
def setUp(self):
42
+
83
qemu_img('create', '-f', iotests.imgfmt, blockdev_target_img, str(image_len))
43
+ result = self.vm.qmp('blockdev-backup', job_id='job0', device='drive0',
84
44
+ target='drive1', sync='full', auto_finalize=False,
85
- self.vm = iotests.VM().add_drive(test_img).add_drive(blockdev_target_img)
45
+ auto_dismiss=False)
86
+ self.vm = iotests.VM().add_drive(test_img)
46
+ self.assert_qmp(result, 'return', {})
87
+ self.vm.add_drive(blockdev_target_img, interface="none")
47
+
88
if iotests.qemu_default_machine == 'pc':
48
+ self.vm.run_job('job0', auto_finalize=False, pre_finalize=pre_finalize)
89
self.vm.add_drive(None, 'media=cdrom', 'ide')
49
+
90
self.vm.launch()
50
+ def test_source_resize_blockdev_backup(self):
91
@@ -XXX,XX +XXX,XX @@ class TestDriveCompression(iotests.QMPTestCase):
51
+ self.do_test_resize_blockdev_backup('drive0', 'source')
92
52
+
93
qemu_img('create', '-f', fmt, blockdev_target_img,
53
+ def test_target_resize_blockdev_backup(self):
94
str(TestDriveCompression.image_len), *args)
54
+ self.do_test_resize_blockdev_backup('drive1', 'target')
95
- self.vm.add_drive(blockdev_target_img, format=fmt)
55
+
96
+ self.vm.add_drive(blockdev_target_img, format=fmt, interface="none")
56
+ def do_test_target_size(self, size):
97
57
+ result = self.vm.qmp('block_resize', device='drive1', size=size)
98
self.vm.launch()
58
+ self.assert_qmp(result, 'return', {})
99
59
+
60
+ result = self.vm.qmp('blockdev-backup', job_id='job0', device='drive0',
61
+ target='drive1', sync='full')
62
+ self.assert_qmp(result, 'error/class', 'GenericError')
63
+
64
+ def test_small_target(self):
65
+ self.do_test_target_size(image_len // 2)
66
+
67
+ def test_large_target(self):
68
+ self.do_test_target_size(image_len * 2)
69
+
70
def test_medium_not_found(self):
71
if iotests.qemu_default_machine != 'pc':
72
return
73
diff --git a/tests/qemu-iotests/055.out b/tests/qemu-iotests/055.out
74
index XXXXXXX..XXXXXXX 100644
75
--- a/tests/qemu-iotests/055.out
76
+++ b/tests/qemu-iotests/055.out
77
@@ -XXX,XX +XXX,XX @@
78
-....................................
79
+........................................
80
----------------------------------------------------------------------
81
-Ran 36 tests
82
+Ran 40 tests
83
84
OK
100
--
85
--
101
1.8.3.1
86
2.25.3
102
87
103
88
diff view generated by jsdifflib
1
Management tools need to be able to know about every node in the graph
1
055 uses the backup block job to create a compressed backup of an
2
and need a way to address them. Changing the graph structure was okay
2
$IMGFMT image with both qcow2 and vmdk targets. However, cluster
3
because libvirt doesn't really manage the node level yet, but future
3
allocation in vmdk is very slow because it flushes the image file after
4
libvirt versions need to deal with both new and old version of qemu.
4
each L2 update.
5
5
6
This new option to blockdev-commit allows the client to set a node-name
6
There is no reason why we need this level of safety in this test, so
7
for the automatically inserted filter driver, and at the same time
7
let's disable flushes for vmdk. For the blockdev-backup tests this is
8
serves as a witness for a future libvirt that this version of qemu does
8
achieved by simply adding the cache.no-flush=on to the drive_add() for
9
automatically insert a filter driver.
9
the target. For drive-backup, the caching flags are copied from the
10
source node, so we'll also add the flag to the source node, even though
11
it is not vmdk.
12
13
This can make the test run significantly faster (though it doesn't make
14
a difference on tmpfs). In my usual setup it goes from ~45s to ~15s.
10
15
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Acked-by: Fam Zheng <famz@redhat.com>
17
Message-Id: <20200505064618.16267-1-kwolf@redhat.com>
13
Reviewed-by: Max Reitz <mreitz@redhat.com>
18
Reviewed-by: Eric Blake <eblake@redhat.com>
19
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
20
---
15
block/commit.c | 5 +++--
21
tests/qemu-iotests/055 | 11 +++++++----
16
block/mirror.c | 3 ++-
22
1 file changed, 7 insertions(+), 4 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
23
24
diff --git a/block/commit.c b/block/commit.c
24
diff --git a/tests/qemu-iotests/055 b/tests/qemu-iotests/055
25
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100755
26
--- a/block/commit.c
26
--- a/tests/qemu-iotests/055
27
+++ b/block/commit.c
27
+++ b/tests/qemu-iotests/055
28
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_commit_top = {
28
@@ -XXX,XX +XXX,XX @@ class TestSingleTransaction(iotests.QMPTestCase):
29
void commit_start(const char *job_id, BlockDriverState *bs,
29
30
BlockDriverState *base, BlockDriverState *top, int64_t speed,
30
class TestCompressedToQcow2(iotests.QMPTestCase):
31
BlockdevOnError on_error, const char *backing_file_str,
31
image_len = 64 * 1024 * 1024 # MB
32
- Error **errp)
32
- target_fmt = {'type': 'qcow2', 'args': ()}
33
+ const char *filter_node_name, Error **errp)
33
+ target_fmt = {'type': 'qcow2', 'args': (), 'drive-opts': ''}
34
{
34
35
CommitBlockJob *s;
35
def tearDown(self):
36
BlockReopenQueue *reopen_queue = NULL;
36
self.vm.shutdown()
37
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
37
@@ -XXX,XX +XXX,XX @@ class TestCompressedToQcow2(iotests.QMPTestCase):
38
38
pass
39
/* Insert commit_top block node above top, so we can block consistent read
39
40
* on the backing chain below it */
40
def do_prepare_drives(self, attach_target):
41
- commit_top_bs = bdrv_new_open_driver(&bdrv_commit_top, NULL, 0, errp);
41
- self.vm = iotests.VM().add_drive('blkdebug::' + test_img)
42
+ commit_top_bs = bdrv_new_open_driver(&bdrv_commit_top, filter_node_name, 0,
42
+ self.vm = iotests.VM().add_drive('blkdebug::' + test_img,
43
+ errp);
43
+ opts=self.target_fmt['drive-opts'])
44
if (commit_top_bs == NULL) {
44
45
goto fail;
45
qemu_img('create', '-f', self.target_fmt['type'], blockdev_target_img,
46
}
46
str(self.image_len), *self.target_fmt['args'])
47
diff --git a/block/mirror.c b/block/mirror.c
47
if attach_target:
48
index XXXXXXX..XXXXXXX 100644
48
self.vm.add_drive(blockdev_target_img,
49
--- a/block/mirror.c
49
img_format=self.target_fmt['type'],
50
+++ b/block/mirror.c
50
- interface="none")
51
@@ -XXX,XX +XXX,XX @@ void mirror_start(const char *job_id, BlockDriverState *bs,
51
+ interface="none",
52
void commit_active_start(const char *job_id, BlockDriverState *bs,
52
+ opts=self.target_fmt['drive-opts'])
53
BlockDriverState *base, int creation_flags,
53
54
int64_t speed, BlockdevOnError on_error,
54
self.vm.launch()
55
+ const char *filter_node_name,
55
56
BlockCompletionFunc *cb, void *opaque, Error **errp,
56
@@ -XXX,XX +XXX,XX @@ class TestCompressedToQcow2(iotests.QMPTestCase):
57
bool auto_complete)
57
58
{
58
59
@@ -XXX,XX +XXX,XX @@ void commit_active_start(const char *job_id, BlockDriverState *bs,
59
class TestCompressedToVmdk(TestCompressedToQcow2):
60
MIRROR_LEAVE_BACKING_CHAIN,
60
- target_fmt = {'type': 'vmdk', 'args': ('-o', 'subformat=streamOptimized')}
61
on_error, on_error, true, cb, opaque, &local_err,
61
+ target_fmt = {'type': 'vmdk', 'args': ('-o', 'subformat=streamOptimized'),
62
&commit_active_job_driver, false, base, auto_complete,
62
+ 'drive-opts': 'cache.no-flush=on'}
63
- NULL);
63
64
+ filter_node_name);
64
@iotests.skip_if_unsupported(['vmdk'])
65
if (local_err) {
65
def setUp(self):
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
168
index XXXXXXX..XXXXXXX 100644
169
--- a/qapi/block-core.json
170
+++ b/qapi/block-core.json
171
@@ -XXX,XX +XXX,XX @@
172
#
173
# @speed: #optional the maximum speed, in bytes per second
174
#
175
+# @filter-node-name: #optional the node name that should be assigned to the
176
+# filter driver that the commit job inserts into the graph
177
+# above @top. If this option is not given, a node name is
178
+# autogenerated. (Since: 2.9)
179
+#
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 @@
184
##
185
{ 'command': 'block-commit',
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
--
66
--
209
1.8.3.1
67
2.25.3
210
68
211
69
diff view generated by jsdifflib
1
We want every user to be specific about the permissions it needs, so
1
From: Max Reitz <mreitz@redhat.com>
2
we'll pass the initial permissions as parameters to blk_new(). A user
3
only needs to call blk_set_perm() if it wants to change the permissions
4
after the fact.
5
2
6
The permissions are stored in the BlockBackend and applied whenever a
3
Calling bdrv_getlength() to get the pre-truncate file size will not
7
BlockDriverState should be attached in blk_insert_bs().
4
really work on block devices, because they have always the same length,
5
and trying to write beyond it will fail with a rather cryptic error
6
message.
8
7
9
This does not include actually choosing the right set of permissions
8
Instead, we should use qcow2_get_last_cluster() and bdrv_getlength()
10
everywhere yet. Instead, the usual FIXME comment is added to each place
9
only as a fallback.
11
and will be addressed in individual patches.
12
10
11
Before this patch:
12
$ truncate -s 1G test.img
13
$ sudo losetup -f --show test.img
14
/dev/loop0
15
$ sudo qemu-img create -f qcow2 -o preallocation=full /dev/loop0 64M
16
Formatting '/dev/loop0', fmt=qcow2 size=67108864 cluster_size=65536
17
preallocation=full lazy_refcounts=off refcount_bits=16
18
qemu-img: /dev/loop0: Could not resize image: Failed to resize refcount
19
structures: No space left on device
20
21
With this patch:
22
$ sudo qemu-img create -f qcow2 -o preallocation=full /dev/loop0 64M
23
Formatting '/dev/loop0', fmt=qcow2 size=67108864 cluster_size=65536
24
preallocation=full lazy_refcounts=off refcount_bits=16
25
qemu-img: /dev/loop0: Could not resize image: Failed to resize
26
underlying file: Preallocation mode 'full' unsupported for this
27
non-regular file
28
29
So as you can see, it still fails, but now the problem is missing
30
support on the block device level, so we at least get a better error
31
message.
32
33
Note that we cannot preallocate block devices on truncate by design,
34
because we do not know what area to preallocate. Their length is always
35
the same, the truncate operation does not change it.
36
37
Signed-off-by: Max Reitz <mreitz@redhat.com>
38
Message-Id: <20200505141801.1096763-1-mreitz@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
39
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Reviewed-by: Max Reitz <mreitz@redhat.com>
15
Acked-by: Fam Zheng <famz@redhat.com>
16
---
40
---
17
block.c | 2 +-
41
block/qcow2.c | 10 ++++++++--
18
block/backup.c | 3 ++-
42
1 file changed, 8 insertions(+), 2 deletions(-)
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
43
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
44
diff --git a/block/qcow2.c b/block/qcow2.c
167
index XXXXXXX..XXXXXXX 100644
45
index XXXXXXX..XXXXXXX 100644
168
--- a/block/qcow2.c
46
--- a/block/qcow2.c
169
+++ b/block/qcow2.c
47
+++ b/block/qcow2.c
170
@@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
48
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
171
}
49
{
172
50
int64_t allocation_start, host_offset, guest_offset;
173
if (new_size) {
51
int64_t clusters_allocated;
174
- BlockBackend *blk = blk_new();
52
- int64_t old_file_size, new_file_size;
175
+ BlockBackend *blk = blk_new(BLK_PERM_RESIZE, BLK_PERM_ALL);
53
+ int64_t old_file_size, last_cluster, new_file_size;
176
blk_insert_bs(blk, bs);
54
uint64_t nb_new_data_clusters, nb_new_l2_tables;
177
ret = blk_truncate(blk, new_size);
55
178
blk_unref(blk);
56
/* With a data file, preallocation means just allocating the metadata
179
diff --git a/blockdev.c b/blockdev.c
57
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
180
index XXXXXXX..XXXXXXX 100644
58
ret = old_file_size;
181
--- a/blockdev.c
59
goto fail;
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
}
60
}
207
}
61
- old_file_size = ROUND_UP(old_file_size, s->cluster_size);
208
62
+
209
- blk = blk_new();
63
+ last_cluster = qcow2_get_last_cluster(bs, old_file_size);
210
+ /* FIXME Use real permissions */
64
+ if (last_cluster >= 0) {
211
+ blk = blk_new(0, BLK_PERM_ALL);
65
+ old_file_size = (last_cluster + 1) * s->cluster_size;
212
blk_insert_bs(blk, bs);
66
+ } else {
213
67
+ old_file_size = ROUND_UP(old_file_size, s->cluster_size);
214
job = g_malloc0(driver->instance_size);
68
+ }
215
diff --git a/hmp.c b/hmp.c
69
216
index XXXXXXX..XXXXXXX 100644
70
nb_new_data_clusters = DIV_ROUND_UP(offset - old_length,
217
--- a/hmp.c
71
s->cluster_size);
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
}
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
--
72
--
359
1.8.3.1
73
2.25.3
360
74
361
75
diff view generated by jsdifflib
1
Backing files are somewhat special compared to other kinds of children
1
From: Eric Blake <eblake@redhat.com>
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
2
7
These special features are a reason why change_parent_backing_link()
3
block.c already defaults to 0 if we don't provide a callback; there's
8
can't handle backing files yet. With abstracting the additional features
4
no need to write a callback that always fails.
9
into .attach/.detach callbacks, we get a step closer to a function that
10
can actually deal with this.
11
5
6
Signed-off-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Reviewed-by: Alberto Garcia <berto@igalia.com>
9
Message-Id: <20200428202905.770727-2-eblake@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
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
---
11
---
16
block.c | 95 ++++++++++++++++++++++++++++++-----------------
12
block/gluster.c | 14 --------------
17
include/block/block_int.h | 3 ++
13
1 file changed, 14 deletions(-)
18
2 files changed, 63 insertions(+), 35 deletions(-)
19
14
20
diff --git a/block.c b/block.c
15
diff --git a/block/gluster.c b/block/gluster.c
21
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
22
--- a/block.c
17
--- a/block/gluster.c
23
+++ b/block.c
18
+++ b/block/gluster.c
24
@@ -XXX,XX +XXX,XX @@ const BdrvChildRole child_format = {
19
@@ -XXX,XX +XXX,XX @@ static int64_t qemu_gluster_allocated_file_size(BlockDriverState *bs)
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
}
20
}
110
}
21
}
111
22
112
@@ -XXX,XX +XXX,XX @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd)
23
-static int qemu_gluster_has_zero_init(BlockDriverState *bs)
113
}
24
-{
114
25
- /* GlusterFS volume could be backed by a block device */
115
if (bs->backing) {
26
- return 0;
116
- assert(bs->backing_blocker);
27
-}
117
- bdrv_op_unblock_all(bs->backing->bs, bs->backing_blocker);
28
-
118
bdrv_unref_child(bs, bs->backing);
29
/*
119
- } else if (backing_hd) {
30
* Find allocation range in @bs around offset @start.
120
- error_setg(&bs->backing_blocker,
31
* May change underlying file descriptor's file offset.
121
- "node is used as backing hd of '%s'",
32
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_gluster = {
122
- bdrv_get_device_or_node_name(bs));
33
.bdrv_co_readv = qemu_gluster_co_readv,
123
}
34
.bdrv_co_writev = qemu_gluster_co_writev,
124
35
.bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
125
if (!backing_hd) {
36
- .bdrv_has_zero_init = qemu_gluster_has_zero_init,
126
- error_free(bs->backing_blocker);
37
- .bdrv_has_zero_init_truncate = qemu_gluster_has_zero_init,
127
- bs->backing_blocker = NULL;
38
#ifdef CONFIG_GLUSTERFS_DISCARD
128
bs->backing = NULL;
39
.bdrv_co_pdiscard = qemu_gluster_co_pdiscard,
129
goto out;
40
#endif
130
}
41
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_gluster_tcp = {
131
/* FIXME Error handling */
42
.bdrv_co_readv = qemu_gluster_co_readv,
132
bs->backing = bdrv_attach_child(bs, backing_hd, "backing", &child_backing,
43
.bdrv_co_writev = qemu_gluster_co_writev,
133
&error_abort);
44
.bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
134
- bs->open_flags &= ~BDRV_O_NO_BACKING;
45
- .bdrv_has_zero_init = qemu_gluster_has_zero_init,
135
- pstrcpy(bs->backing_file, sizeof(bs->backing_file), backing_hd->filename);
46
- .bdrv_has_zero_init_truncate = qemu_gluster_has_zero_init,
136
- pstrcpy(bs->backing_format, sizeof(bs->backing_format),
47
#ifdef CONFIG_GLUSTERFS_DISCARD
137
- backing_hd->drv ? backing_hd->drv->format_name : "");
48
.bdrv_co_pdiscard = qemu_gluster_co_pdiscard,
138
49
#endif
139
- bdrv_op_block_all(backing_hd, bs->backing_blocker);
50
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_gluster_unix = {
140
- /* Otherwise we won't be able to commit or stream */
51
.bdrv_co_readv = qemu_gluster_co_readv,
141
- bdrv_op_unblock(backing_hd, BLOCK_OP_TYPE_COMMIT_TARGET,
52
.bdrv_co_writev = qemu_gluster_co_writev,
142
- bs->backing_blocker);
53
.bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
143
- bdrv_op_unblock(backing_hd, BLOCK_OP_TYPE_STREAM,
54
- .bdrv_has_zero_init = qemu_gluster_has_zero_init,
144
- bs->backing_blocker);
55
- .bdrv_has_zero_init_truncate = qemu_gluster_has_zero_init,
145
- /*
56
#ifdef CONFIG_GLUSTERFS_DISCARD
146
- * We do backup in 3 ways:
57
.bdrv_co_pdiscard = qemu_gluster_co_pdiscard,
147
- * 1. drive backup
58
#endif
148
- * The target bs is new opened, and the source is top BDS
59
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_gluster_rdma = {
149
- * 2. blockdev backup
60
.bdrv_co_readv = qemu_gluster_co_readv,
150
- * Both the source and the target are top BDSes.
61
.bdrv_co_writev = qemu_gluster_co_writev,
151
- * 3. internal backup(used for block replication)
62
.bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
152
- * Both the source and the target are backing file
63
- .bdrv_has_zero_init = qemu_gluster_has_zero_init,
153
- *
64
- .bdrv_has_zero_init_truncate = qemu_gluster_has_zero_init,
154
- * In case 1 and 2, neither the source nor the target is the backing file.
65
#ifdef CONFIG_GLUSTERFS_DISCARD
155
- * In case 3, we will block the top BDS, so there is only one block job
66
.bdrv_co_pdiscard = qemu_gluster_co_pdiscard,
156
- * for the top BDS and its backing chain.
67
#endif
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
--
68
--
180
1.8.3.1
69
2.25.3
181
70
182
71
diff view generated by jsdifflib
1
The correct permissions are relatively obvious here (and explained in
1
From: Eric Blake <eblake@redhat.com>
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
2
3
When using bdrv_file, .bdrv_has_zero_init_truncate always returns 1;
4
therefore, we can behave just like file-posix, and always implement
5
BDRV_REQ_ZERO_WRITE by ignoring it since the OS gives it to us for
6
free (note that file-posix.c had to use an 'if' because it shared code
7
between regular files and block devices, but in file-win32.c,
8
bdrv_host_device uses a separate .bdrv_file_open).
9
10
Signed-off-by: Eric Blake <eblake@redhat.com>
11
Message-Id: <20200428202905.770727-3-eblake@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
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
---
13
---
11
block/stream.c | 39 +++++++++++++++++++++++++++------------
14
block/file-win32.c | 3 +++
12
1 file changed, 27 insertions(+), 12 deletions(-)
15
1 file changed, 3 insertions(+)
13
16
14
diff --git a/block/stream.c b/block/stream.c
17
diff --git a/block/file-win32.c b/block/file-win32.c
15
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
16
--- a/block/stream.c
19
--- a/block/file-win32.c
17
+++ b/block/stream.c
20
+++ b/block/file-win32.c
18
@@ -XXX,XX +XXX,XX @@ static void stream_complete(BlockJob *job, void *opaque)
21
@@ -XXX,XX +XXX,XX @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
19
22
win32_aio_attach_aio_context(s->aio, bdrv_get_aio_context(bs));
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
}
23
}
26
24
27
@@ -XXX,XX +XXX,XX @@ void stream_start(const char *job_id, BlockDriverState *bs,
25
+ /* When extending regular files, we get zeros from the OS */
28
BlockDriverState *iter;
26
+ bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE;
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
+
27
+
62
+ /* Block all intermediate nodes between bs and base, because they will
28
ret = 0;
63
+ * disappear from the chain after this operation. The streaming job reads
29
fail:
64
+ * every block only once, assuming that it doesn't change, so block writes
30
qemu_opts_del(opts);
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
--
31
--
87
1.8.3.1
32
2.25.3
88
33
89
34
diff view generated by jsdifflib
1
For meaningful error messages in the permission system, we need to get
1
From: Eric Blake <eblake@redhat.com>
2
some human-readable description of the parent of a BdrvChild.
3
2
3
Our .bdrv_has_zero_init_truncate returns 1 if we detect that the OS
4
always 0-fills; we can use that same knowledge to implement
5
BDRV_REQ_ZERO_WRITE by ignoring it when the OS gives it to us for
6
free.
7
8
Signed-off-by: Eric Blake <eblake@redhat.com>
9
Message-Id: <20200428202905.770727-4-eblake@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
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
---
11
---
8
block.c | 9 +++++++++
12
block/nfs.c | 3 +++
9
block/block-backend.c | 21 +++++++++++++++++++++
13
1 file changed, 3 insertions(+)
10
include/block/block_int.h | 6 ++++++
11
3 files changed, 36 insertions(+)
12
14
13
diff --git a/block.c b/block.c
15
diff --git a/block/nfs.c b/block/nfs.c
14
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
15
--- a/block.c
17
--- a/block/nfs.c
16
+++ b/block.c
18
+++ b/block/nfs.c
17
@@ -XXX,XX +XXX,XX @@ int bdrv_parse_cache_mode(const char *mode, int *flags, bool *writethrough)
19
@@ -XXX,XX +XXX,XX @@ static int nfs_file_open(BlockDriverState *bs, QDict *options, int flags,
20
}
21
22
bs->total_sectors = ret;
23
+ if (client->has_zero_init) {
24
+ bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE;
25
+ }
18
return 0;
26
return 0;
19
}
27
}
20
28
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
--
29
--
118
1.8.3.1
30
2.25.3
119
31
120
32
diff view generated by jsdifflib
1
This is probably one of the most interesting conversions to the new
1
From: Eric Blake <eblake@redhat.com>
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
2
6
In order to provide the 'consistent read' permission to the parents of
3
Our .bdrv_has_zero_init_truncate always returns 1 because rbd always
7
the 'top' node of the commit job, a new filter block driver is inserted
4
0-fills; we can use that same knowledge to implement
8
above 'top' which doesn't require 'consistent read' on its backing
5
BDRV_REQ_ZERO_WRITE by ignoring it.
9
chain. Subsequently, the commit job can block 'consistent read' on all
10
intermediate nodes without causing a conflict.
11
6
7
Signed-off-by: Eric Blake <eblake@redhat.com>
8
Message-Id: <20200428202905.770727-5-eblake@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
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
---
10
---
16
block/commit.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++---------
11
block/rbd.c | 3 +++
17
1 file changed, 95 insertions(+), 18 deletions(-)
12
1 file changed, 3 insertions(+)
18
13
19
diff --git a/block/commit.c b/block/commit.c
14
diff --git a/block/rbd.c b/block/rbd.c
20
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
21
--- a/block/commit.c
16
--- a/block/rbd.c
22
+++ b/block/commit.c
17
+++ b/block/rbd.c
23
@@ -XXX,XX +XXX,XX @@ typedef struct CommitBlockJob {
18
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
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
}
19
}
127
}
20
}
128
21
129
+ /* Insert commit_top block node above top, so we can block consistent read
22
+ /* When extending regular files, we get zeros from the OS */
130
+ * on the backing chain below it */
23
+ bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE;
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
+
24
+
136
+ bdrv_set_backing_hd(commit_top_bs, top);
25
r = 0;
137
+ bdrv_set_backing_hd(overlay_bs, commit_top_bs);
26
goto out;
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
27
212
--
28
--
213
1.8.3.1
29
2.25.3
214
30
215
31
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
From: Eric Blake <eblake@redhat.com>
2
2
3
Commit 75cdcd1 neglected to update tests/qemu-iotests/049.out, and
3
Our .bdrv_has_zero_init_truncate always returns 1 because sheepdog
4
made the error message for negative size worse. Fix that.
4
always 0-fills; we can use that same knowledge to implement
5
BDRV_REQ_ZERO_WRITE by ignoring it.
5
6
6
Reported-by: Thomas Huth <thuth@redhat.com>
7
Signed-off-by: Eric Blake <eblake@redhat.com>
7
Signed-off-by: Markus Armbruster <armbru@redhat.com>
8
Message-Id: <20200428202905.770727-6-eblake@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>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
10
---
13
tests/qemu-iotests/049.out | 14 +++++++++-----
11
block/sheepdog.c | 1 +
14
util/qemu-option.c | 2 +-
12
1 file changed, 1 insertion(+)
15
2 files changed, 10 insertions(+), 6 deletions(-)
16
13
17
diff --git a/tests/qemu-iotests/049.out b/tests/qemu-iotests/049.out
14
diff --git a/block/sheepdog.c b/block/sheepdog.c
18
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
19
--- a/tests/qemu-iotests/049.out
16
--- a/block/sheepdog.c
20
+++ b/tests/qemu-iotests/049.out
17
+++ b/block/sheepdog.c
21
@@ -XXX,XX +XXX,XX @@ qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- -1024
18
@@ -XXX,XX +XXX,XX @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags,
22
qemu-img: Image size must be less than 8 EiB!
19
memcpy(&s->inode, buf, sizeof(s->inode));
23
20
24
qemu-img create -f qcow2 -o size=-1024 TEST_DIR/t.qcow2
21
bs->total_sectors = s->inode.vdi_size / BDRV_SECTOR_SIZE;
25
-qemu-img: Parameter 'size' expects a non-negative number below 2^64
22
+ bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE;
26
+qemu-img: Value '-1024' is out of range for parameter 'size'
23
pstrcpy(s->name, sizeof(s->name), vdi);
27
qemu-img: TEST_DIR/t.qcow2: Invalid options for file format 'qcow2'
24
qemu_co_mutex_init(&s->lock);
28
25
qemu_co_mutex_init(&s->queue_lock);
29
qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- -1k
30
qemu-img: Image size must be less than 8 EiB!
31
32
qemu-img create -f qcow2 -o size=-1k TEST_DIR/t.qcow2
33
-qemu-img: Parameter 'size' expects a non-negative number below 2^64
34
+qemu-img: Value '-1k' is out of range for parameter 'size'
35
qemu-img: TEST_DIR/t.qcow2: Invalid options for file format 'qcow2'
36
37
qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- 1kilobyte
38
@@ -XXX,XX +XXX,XX @@ qemu-img: Invalid image size specified! You may use k, M, G, T, P or E suffixes
39
qemu-img: kilobytes, megabytes, gigabytes, terabytes, petabytes and exabytes.
40
41
qemu-img create -f qcow2 -o size=1kilobyte TEST_DIR/t.qcow2
42
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
43
+qemu-img: Parameter 'size' expects a non-negative number below 2^64
44
+Optional suffix k, M, G, T, P or E means kilo-, mega-, giga-, tera-, peta-
45
+and exabytes, respectively.
46
+qemu-img: TEST_DIR/t.qcow2: Invalid options for file format 'qcow2'
47
48
qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- foobar
49
qemu-img: Invalid image size specified! You may use k, M, G, T, P or E suffixes for
50
qemu-img: kilobytes, megabytes, gigabytes, terabytes, petabytes and exabytes.
51
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
}
74
--
26
--
75
1.8.3.1
27
2.25.3
76
28
77
29
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
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
All callers will have to request permissions for all of their child
2
nodes. Block drivers that act as simply filters can use the default
3
implementation of .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/blkdebug.c | 2 ++
10
block/blkreplay.c | 1 +
11
block/blkverify.c | 1 +
12
block/quorum.c | 2 ++
13
block/raw-format.c | 1 +
14
block/replication.c | 1 +
15
6 files changed, 8 insertions(+)
16
17
diff --git a/block/blkdebug.c b/block/blkdebug.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/block/blkdebug.c
20
+++ b/block/blkdebug.c
21
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_blkdebug = {
22
.bdrv_file_open = blkdebug_open,
23
.bdrv_close = blkdebug_close,
24
.bdrv_reopen_prepare = blkdebug_reopen_prepare,
25
+ .bdrv_child_perm = bdrv_filter_default_perms,
26
+
27
.bdrv_getlength = blkdebug_getlength,
28
.bdrv_truncate = blkdebug_truncate,
29
.bdrv_refresh_filename = blkdebug_refresh_filename,
30
diff --git a/block/blkreplay.c b/block/blkreplay.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
44
--- a/block/blkverify.c
45
+++ b/block/blkverify.c
46
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_blkverify = {
47
.bdrv_parse_filename = blkverify_parse_filename,
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
};
67
diff --git a/block/raw-format.c b/block/raw-format.c
68
index XXXXXXX..XXXXXXX 100644
69
--- a/block/raw-format.c
70
+++ b/block/raw-format.c
71
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_raw = {
72
.bdrv_reopen_abort = &raw_reopen_abort,
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
80
index XXXXXXX..XXXXXXX 100644
81
--- a/block/replication.c
82
+++ b/block/replication.c
83
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_replication = {
84
85
.bdrv_open = replication_open,
86
.bdrv_close = replication_close,
87
+ .bdrv_child_perm = bdrv_filter_default_perms,
88
89
.bdrv_getlength = replication_getlength,
90
.bdrv_co_readv = replication_co_readv,
91
--
92
1.8.3.1
93
94
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
1
This is a little simpler than the commit block job because it's
1
From: Eric Blake <eblake@redhat.com>
2
synchronous and only commits into the immediate backing file, but
3
otherwise doing more or less the same.
4
2
3
Our .bdrv_has_zero_init_truncate can detect when the remote side
4
always zero fills; we can reuse that same knowledge to implement
5
BDRV_REQ_ZERO_WRITE by ignoring it when the server gives it to us for
6
free.
7
8
Signed-off-by: Eric Blake <eblake@redhat.com>
9
Message-Id: <20200428202905.770727-7-eblake@redhat.com>
10
Reviewed-by: Richard W.M. Jones <rjones@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
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
---
12
---
9
block/commit.c | 33 +++++++++++++++++++++++++++------
13
block/ssh.c | 4 ++++
10
1 file changed, 27 insertions(+), 6 deletions(-)
14
1 file changed, 4 insertions(+)
11
15
12
diff --git a/block/commit.c b/block/commit.c
16
diff --git a/block/ssh.c b/block/ssh.c
13
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
14
--- a/block/commit.c
18
--- a/block/ssh.c
15
+++ b/block/commit.c
19
+++ b/block/ssh.c
16
@@ -XXX,XX +XXX,XX @@ fail:
20
@@ -XXX,XX +XXX,XX @@ static int ssh_file_open(BlockDriverState *bs, QDict *options, int bdrv_flags,
17
int bdrv_commit(BlockDriverState *bs)
21
/* Go non-blocking. */
18
{
22
ssh_set_blocking(s->session, 0);
19
BlockBackend *src, *backing;
23
20
+ BlockDriverState *backing_file_bs = NULL;
24
+ if (s->attrs->type == SSH_FILEXFER_TYPE_REGULAR) {
21
+ BlockDriverState *commit_top_bs = NULL;
25
+ bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE;
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
+ }
26
+ }
47
+
27
+
48
+ /* Insert commit_top block node above backing, so we can write to it */
28
qapi_free_BlockdevOptionsSsh(opts);
49
+ backing_file_bs = backing_bs(bs);
29
50
+
30
return 0;
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
--
31
--
83
1.8.3.1
32
2.25.3
84
33
85
34
diff view generated by jsdifflib
1
This makes all device emulations with a qdev drive property request
1
From: Eric Blake <eblake@redhat.com>
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
2
3
The parallels driver tries to use truncation for image growth, but can
4
only do so when reads are guaranteed as zero. Now that we have a way
5
to request zero contents from truncation, we can defer the decision to
6
actual allocation attempts rather than up front, reducing the number
7
of places that still use bdrv_has_zero_init_truncate.
8
9
Signed-off-by: Eric Blake <eblake@redhat.com>
10
Message-Id: <20200428202905.770727-8-eblake@redhat.com>
11
Reviewed-by: Denis V. Lunev <den@openvz.org>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
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
---
13
---
9
hw/block/block.c | 22 +++++++++++++++++++++-
14
block/parallels.c | 25 ++++++++++++++++---------
10
hw/block/fdc.c | 25 +++++++++++++++++++++++--
15
1 file changed, 16 insertions(+), 9 deletions(-)
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
16
28
diff --git a/hw/block/block.c b/hw/block/block.c
17
diff --git a/block/parallels.c b/block/parallels.c
29
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
30
--- a/hw/block/block.c
19
--- a/block/parallels.c
31
+++ b/hw/block/block.c
20
+++ b/block/parallels.c
32
@@ -XXX,XX +XXX,XX @@ void blkconf_blocksizes(BlockConf *conf)
21
@@ -XXX,XX +XXX,XX @@ static int64_t block_status(BDRVParallelsState *s, int64_t sector_num,
22
static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num,
23
int nb_sectors, int *pnum)
24
{
25
- int ret;
26
+ int ret = 0;
27
BDRVParallelsState *s = bs->opaque;
28
int64_t pos, space, idx, to_allocate, i, len;
29
30
@@ -XXX,XX +XXX,XX @@ static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num,
33
}
31
}
34
}
32
if (s->data_end + space > (len >> BDRV_SECTOR_BITS)) {
35
33
space += s->prealloc_size;
36
-void blkconf_apply_backend_options(BlockConf *conf)
34
+ /*
37
+void blkconf_apply_backend_options(BlockConf *conf, bool readonly,
35
+ * We require the expanded size to read back as zero. If the
38
+ bool resizable, Error **errp)
36
+ * user permitted truncation, we try that; but if it fails, we
39
{
37
+ * force the safer-but-slower fallocate.
40
BlockBackend *blk = conf->blk;
38
+ */
41
BlockdevOnError rerror, werror;
39
+ if (s->prealloc_mode == PRL_PREALLOC_MODE_TRUNCATE) {
42
+ uint64_t perm, shared_perm;
40
+ ret = bdrv_truncate(bs->file,
43
bool wce;
41
+ (s->data_end + space) << BDRV_SECTOR_BITS,
44
+ int ret;
42
+ false, PREALLOC_MODE_OFF, BDRV_REQ_ZERO_WRITE,
45
+
43
+ NULL);
46
+ perm = BLK_PERM_CONSISTENT_READ;
44
+ if (ret == -ENOTSUP) {
47
+ if (!readonly) {
45
+ s->prealloc_mode = PRL_PREALLOC_MODE_FALLOCATE;
48
+ perm |= BLK_PERM_WRITE;
46
+ }
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
+ }
47
+ }
93
+ }
48
if (s->prealloc_mode == PRL_PREALLOC_MODE_FALLOCATE) {
94
49
ret = bdrv_pwrite_zeroes(bs->file,
95
drive->media_changed = 1;
50
s->data_end << BDRV_SECTOR_BITS,
96
drive->media_validated = false;
51
space << BDRV_SECTOR_BITS, 0);
97
@@ -XXX,XX +XXX,XX @@ static int floppy_drive_init(DeviceState *qdev)
52
- } else {
98
FloppyDrive *dev = FLOPPY_DRIVE(qdev);
53
- ret = bdrv_truncate(bs->file,
99
FloppyBus *bus = FLOPPY_BUS(qdev->parent_bus);
54
- (s->data_end + space) << BDRV_SECTOR_BITS,
100
FDrive *drive;
55
- false, PREALLOC_MODE_OFF, 0, NULL);
101
+ Error *local_err = NULL;
56
}
102
int ret;
57
if (ret < 0) {
103
58
return ret;
104
if (dev->unit == -1) {
59
@@ -XXX,XX +XXX,XX @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
105
@@ -XXX,XX +XXX,XX @@ static int floppy_drive_init(DeviceState *qdev)
60
qemu_opt_get_size_del(opts, PARALLELS_OPT_PREALLOC_SIZE, 0);
106
61
s->prealloc_size = MAX(s->tracks, s->prealloc_size >> BDRV_SECTOR_BITS);
107
if (!dev->conf.blk) {
62
buf = qemu_opt_get_del(opts, PARALLELS_OPT_PREALLOC_MODE);
108
/* Anonymous BlockBackend for an empty drive */
63
+ /* prealloc_mode can be downgraded later during allocate_clusters */
109
- /* FIXME Use real permissions */
64
s->prealloc_mode = qapi_enum_parse(&prealloc_mode_lookup, buf,
110
dev->conf.blk = blk_new(0, BLK_PERM_ALL);
65
PRL_PREALLOC_MODE_FALLOCATE,
111
ret = blk_attach_dev(dev->conf.blk, qdev);
66
&local_err);
112
assert(ret == 0);
67
@@ -XXX,XX +XXX,XX @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
113
@@ -XXX,XX +XXX,XX @@ static int floppy_drive_init(DeviceState *qdev)
68
goto fail_options;
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
}
69
}
131
70
132
+ drive->conf = &dev->conf;
71
- if (!bdrv_has_zero_init_truncate(bs->file->bs)) {
133
drive->blk = dev->conf.blk;
72
- s->prealloc_mode = PRL_PREALLOC_MODE_FALLOCATE;
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
- }
73
- }
270
-
74
-
271
/* Default to devices being used at their maximum device width. This was
75
if ((flags & BDRV_O_RDWR) && !(flags & BDRV_O_INACTIVE)) {
272
* assumed before the device_width support was added.
76
s->header->inuse = cpu_to_le32(HEADER_INUSE_MAGIC);
273
*/
77
ret = parallels_update_header(bs);
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
--
78
--
501
1.8.3.1
79
2.25.3
502
80
503
81
diff view generated by jsdifflib
1
The BlockBackend can now store the permissions that its user requires.
1
From: Eric Blake <eblake@redhat.com>
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
2
3
The vhdx driver uses truncation for image growth, with a special case
4
for blocks that already read as zero but which are only being
5
partially written. But with a bit of rearranging, it's just as easy
6
to defer the decision on whether truncation resulted in zeroes to the
7
actual allocation attempt, reducing the number of places that still
8
use bdrv_has_zero_init_truncate.
9
10
Signed-off-by: Eric Blake <eblake@redhat.com>
11
Message-Id: <20200428202905.770727-9-eblake@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
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
---
13
---
10
block/block-backend.c | 27 +++++++++++++++++++++++++++
14
block/vhdx.c | 89 ++++++++++++++++++++++++++++++----------------------
11
include/sysemu/block-backend.h | 2 ++
15
1 file changed, 51 insertions(+), 38 deletions(-)
12
2 files changed, 29 insertions(+)
13
16
14
diff --git a/block/block-backend.c b/block/block-backend.c
17
diff --git a/block/vhdx.c b/block/vhdx.c
15
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
16
--- a/block/block-backend.c
19
--- a/block/vhdx.c
17
+++ b/block/block-backend.c
20
+++ b/block/vhdx.c
18
@@ -XXX,XX +XXX,XX @@ struct BlockBackend {
21
@@ -XXX,XX +XXX,XX @@ exit:
19
bool iostatus_enabled;
22
/*
20
BlockDeviceIoStatus iostatus;
23
* Allocate a new payload block at the end of the file.
21
24
*
22
+ uint64_t perm;
25
- * Allocation will happen at 1MB alignment inside the file
23
+ uint64_t shared_perm;
26
+ * Allocation will happen at 1MB alignment inside the file.
27
+ *
28
+ * If @need_zero is set on entry but not cleared on return, then truncation
29
+ * could not guarantee that the new portion reads as zero, and the caller
30
+ * will take care of it instead.
31
*
32
* Returns the file offset start of the new payload block
33
*/
34
static int vhdx_allocate_block(BlockDriverState *bs, BDRVVHDXState *s,
35
- uint64_t *new_offset)
36
+ uint64_t *new_offset, bool *need_zero)
37
{
38
int64_t current_len;
39
40
@@ -XXX,XX +XXX,XX @@ static int vhdx_allocate_block(BlockDriverState *bs, BDRVVHDXState *s,
41
return -EINVAL;
42
}
43
44
+ if (*need_zero) {
45
+ int ret;
24
+
46
+
25
bool allow_write_beyond_eof;
47
+ ret = bdrv_truncate(bs->file, *new_offset + s->block_size, false,
26
48
+ PREALLOC_MODE_OFF, BDRV_REQ_ZERO_WRITE, NULL);
27
NotifierList remove_bs_notifiers, insert_bs_notifiers;
49
+ if (ret != -ENOTSUP) {
28
@@ -XXX,XX +XXX,XX @@ BlockBackend *blk_new(void)
50
+ *need_zero = false;
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;
51
+ return ret;
53
+ }
52
+ }
54
+ }
53
+ }
55
+
54
+
56
+ blk->perm = perm;
55
return bdrv_truncate(bs->file, *new_offset + s->block_size, false,
57
+ blk->shared_perm = shared_perm;
56
PREALLOC_MODE_OFF, 0, NULL);
57
}
58
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int vhdx_co_writev(BlockDriverState *bs, int64_t sector_num,
59
/* in this case, we need to preserve zero writes for
60
* data that is not part of this write, so we must pad
61
* the rest of the buffer to zeroes */
62
-
63
- /* if we are on a posix system with ftruncate() that extends
64
- * a file, then it is zero-filled for us. On Win32, the raw
65
- * layer uses SetFilePointer and SetFileEnd, which does not
66
- * zero fill AFAIK */
67
-
68
- /* Queue another write of zero buffers if the underlying file
69
- * does not zero-fill on file extension */
70
-
71
- if (bdrv_has_zero_init_truncate(bs->file->bs) == 0) {
72
- use_zero_buffers = true;
73
-
74
+ use_zero_buffers = true;
75
+ /* fall through */
76
+ case PAYLOAD_BLOCK_NOT_PRESENT: /* fall through */
77
+ case PAYLOAD_BLOCK_UNMAPPED:
78
+ case PAYLOAD_BLOCK_UNMAPPED_v095:
79
+ case PAYLOAD_BLOCK_UNDEFINED:
80
+ bat_prior_offset = sinfo.file_offset;
81
+ ret = vhdx_allocate_block(bs, s, &sinfo.file_offset,
82
+ &use_zero_buffers);
83
+ if (ret < 0) {
84
+ goto exit;
85
+ }
86
+ /*
87
+ * once we support differencing files, this may also be
88
+ * partially present
89
+ */
90
+ /* update block state to the newly specified state */
91
+ vhdx_update_bat_table_entry(bs, s, &sinfo, &bat_entry,
92
+ &bat_entry_offset,
93
+ PAYLOAD_BLOCK_FULLY_PRESENT);
94
+ bat_update = true;
95
+ /*
96
+ * Since we just allocated a block, file_offset is the
97
+ * beginning of the payload block. It needs to be the
98
+ * write address, which includes the offset into the
99
+ * block, unless the entire block needs to read as
100
+ * zeroes but truncation was not able to provide them,
101
+ * in which case we need to fill in the rest.
102
+ */
103
+ if (!use_zero_buffers) {
104
+ sinfo.file_offset += sinfo.block_offset;
105
+ } else {
106
/* zero fill the front, if any */
107
if (sinfo.block_offset) {
108
iov1.iov_len = sinfo.block_offset;
109
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int vhdx_co_writev(BlockDriverState *bs, int64_t sector_num,
110
}
111
112
/* our actual data */
113
- qemu_iovec_concat(&hd_qiov, qiov, bytes_done,
114
+ qemu_iovec_concat(&hd_qiov, qiov, bytes_done,
115
sinfo.bytes_avail);
116
117
/* zero fill the back, if any */
118
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int vhdx_co_writev(BlockDriverState *bs, int64_t sector_num,
119
sectors_to_write += iov2.iov_len >> BDRV_SECTOR_BITS;
120
}
121
}
122
- /* fall through */
123
- case PAYLOAD_BLOCK_NOT_PRESENT: /* fall through */
124
- case PAYLOAD_BLOCK_UNMAPPED:
125
- case PAYLOAD_BLOCK_UNMAPPED_v095:
126
- case PAYLOAD_BLOCK_UNDEFINED:
127
- bat_prior_offset = sinfo.file_offset;
128
- ret = vhdx_allocate_block(bs, s, &sinfo.file_offset);
129
- if (ret < 0) {
130
- goto exit;
131
- }
132
- /* once we support differencing files, this may also be
133
- * partially present */
134
- /* update block state to the newly specified state */
135
- vhdx_update_bat_table_entry(bs, s, &sinfo, &bat_entry,
136
- &bat_entry_offset,
137
- PAYLOAD_BLOCK_FULLY_PRESENT);
138
- bat_update = true;
139
- /* since we just allocated a block, file_offset is the
140
- * beginning of the payload block. It needs to be the
141
- * write address, which includes the offset into the block */
142
- if (!use_zero_buffers) {
143
- sinfo.file_offset += sinfo.block_offset;
144
- }
58
+
145
+
59
+ return 0;
146
/* fall through */
60
+}
147
case PAYLOAD_BLOCK_FULLY_PRESENT:
61
+
148
/* if the file offset address is in the header zone,
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
--
149
--
87
1.8.3.1
150
2.25.3
88
151
89
152
diff view generated by jsdifflib
1
blk_new_open() is a convenience function that processes flags rather
1
From: Eric Blake <eblake@redhat.com>
2
than QDict options as a simple way to just open an image file.
2
3
3
Now that there are no clients of bdrv_has_zero_init_truncate, none of
4
In order to keep it convenient in the future, it must automatically
4
the drivers need to worry about providing it.
5
request the necessary permissions. This can easily be inferred from the
5
6
flags for read and write, but we need another flag that tells us whether
6
What's more, this eliminates a source of some confusion: a literal
7
to get the resize permission.
7
reading of the documentation as written in ceaca56f and implemented in
8
8
commit 1dcaf527 claims that a driver which returns 0 for
9
We can't just always request it because that means that no block jobs
9
bdrv_has_zero_init_truncate() must not return 1 for
10
can run on the resulting BlockBackend (which is something that e.g.
10
bdrv_has_zero_init(); this condition was violated for parallels, qcow,
11
qemu-img commit wants to do), but we also can't request it never because
11
and sometimes for vdi, although in practice it did not matter since
12
most of the .bdrv_create() implementations call blk_truncate().
12
those drivers also lacked .bdrv_co_truncate.
13
13
14
The solution is to introduce another flag that is passed by all users
14
Signed-off-by: Eric Blake <eblake@redhat.com>
15
that want to resize the image.
15
Message-Id: <20200428202905.770727-10-eblake@redhat.com>
16
16
Acked-by: Richard W.M. Jones <rjones@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
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
---
18
---
21
block/parallels.c | 3 ++-
19
include/block/block.h | 1 -
22
block/qcow.c | 3 ++-
20
include/block/block_int.h | 7 -------
23
block/qcow2.c | 6 ++++--
21
block.c | 21 ---------------------
24
block/qed.c | 3 ++-
22
block/file-posix.c | 1 -
25
block/sheepdog.c | 2 +-
23
block/file-win32.c | 1 -
26
block/vdi.c | 3 ++-
24
block/nfs.c | 1 -
27
block/vhdx.c | 3 ++-
25
block/qcow2.c | 1 -
28
block/vmdk.c | 6 ++++--
26
block/qed.c | 1 -
29
block/vpc.c | 3 ++-
27
block/raw-format.c | 6 ------
30
include/block/block.h | 1 +
28
block/rbd.c | 1 -
31
qemu-img.c | 2 +-
29
block/sheepdog.c | 3 ---
32
11 files changed, 23 insertions(+), 12 deletions(-)
30
block/ssh.c | 1 -
33
31
12 files changed, 45 deletions(-)
34
diff --git a/block/parallels.c b/block/parallels.c
32
35
index XXXXXXX..XXXXXXX 100644
33
diff --git a/include/block/block.h b/include/block/block.h
36
--- a/block/parallels.c
34
index XXXXXXX..XXXXXXX 100644
37
+++ b/block/parallels.c
35
--- a/include/block/block.h
38
@@ -XXX,XX +XXX,XX @@ static int parallels_create(const char *filename, QemuOpts *opts, Error **errp)
36
+++ b/include/block/block.h
39
}
37
@@ -XXX,XX +XXX,XX @@ int bdrv_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes);
40
38
int bdrv_co_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes);
41
file = blk_new_open(filename, NULL, NULL,
39
int bdrv_has_zero_init_1(BlockDriverState *bs);
42
- BDRV_O_RDWR | BDRV_O_PROTOCOL, &local_err);
40
int bdrv_has_zero_init(BlockDriverState *bs);
43
+ BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL,
41
-int bdrv_has_zero_init_truncate(BlockDriverState *bs);
44
+ &local_err);
42
bool bdrv_unallocated_blocks_are_zero(BlockDriverState *bs);
45
if (file == NULL) {
43
bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs);
46
error_propagate(errp, local_err);
44
int bdrv_block_status(BlockDriverState *bs, int64_t offset,
47
return -EIO;
45
diff --git a/include/block/block_int.h b/include/block/block_int.h
48
diff --git a/block/qcow.c b/block/qcow.c
46
index XXXXXXX..XXXXXXX 100644
49
index XXXXXXX..XXXXXXX 100644
47
--- a/include/block/block_int.h
50
--- a/block/qcow.c
48
+++ b/include/block/block_int.h
51
+++ b/block/qcow.c
49
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
52
@@ -XXX,XX +XXX,XX @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp)
50
/*
53
}
51
* Returns 1 if newly created images are guaranteed to contain only
54
52
* zeros, 0 otherwise.
55
qcow_blk = blk_new_open(filename, NULL, NULL,
53
- * Must return 0 if .bdrv_has_zero_init_truncate() returns 0.
56
- BDRV_O_RDWR | BDRV_O_PROTOCOL, &local_err);
54
*/
57
+ BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL,
55
int (*bdrv_has_zero_init)(BlockDriverState *bs);
58
+ &local_err);
56
59
if (qcow_blk == NULL) {
57
- /*
60
error_propagate(errp, local_err);
58
- * Returns 1 if new areas added by growing the image with
61
ret = -EIO;
59
- * PREALLOC_MODE_OFF contain only zeros, 0 otherwise.
60
- */
61
- int (*bdrv_has_zero_init_truncate)(BlockDriverState *bs);
62
-
63
/* Remove fd handlers, timers, and other event loop callbacks so the event
64
* loop is no longer in use. Called with no in-flight requests and in
65
* depth-first traversal order with parents before child nodes.
66
diff --git a/block.c b/block.c
67
index XXXXXXX..XXXXXXX 100644
68
--- a/block.c
69
+++ b/block.c
70
@@ -XXX,XX +XXX,XX @@ int bdrv_has_zero_init(BlockDriverState *bs)
71
return 0;
72
}
73
74
-int bdrv_has_zero_init_truncate(BlockDriverState *bs)
75
-{
76
- if (!bs->drv) {
77
- return 0;
78
- }
79
-
80
- if (bs->backing) {
81
- /* Depends on the backing image length, but better safe than sorry */
82
- return 0;
83
- }
84
- if (bs->drv->bdrv_has_zero_init_truncate) {
85
- return bs->drv->bdrv_has_zero_init_truncate(bs);
86
- }
87
- if (bs->file && bs->drv->is_filter) {
88
- return bdrv_has_zero_init_truncate(bs->file->bs);
89
- }
90
-
91
- /* safe default */
92
- return 0;
93
-}
94
-
95
bool bdrv_unallocated_blocks_are_zero(BlockDriverState *bs)
96
{
97
BlockDriverInfo bdi;
98
diff --git a/block/file-posix.c b/block/file-posix.c
99
index XXXXXXX..XXXXXXX 100644
100
--- a/block/file-posix.c
101
+++ b/block/file-posix.c
102
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_file = {
103
.bdrv_co_create = raw_co_create,
104
.bdrv_co_create_opts = raw_co_create_opts,
105
.bdrv_has_zero_init = bdrv_has_zero_init_1,
106
- .bdrv_has_zero_init_truncate = bdrv_has_zero_init_1,
107
.bdrv_co_block_status = raw_co_block_status,
108
.bdrv_co_invalidate_cache = raw_co_invalidate_cache,
109
.bdrv_co_pwrite_zeroes = raw_co_pwrite_zeroes,
110
diff --git a/block/file-win32.c b/block/file-win32.c
111
index XXXXXXX..XXXXXXX 100644
112
--- a/block/file-win32.c
113
+++ b/block/file-win32.c
114
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_file = {
115
.bdrv_close = raw_close,
116
.bdrv_co_create_opts = raw_co_create_opts,
117
.bdrv_has_zero_init = bdrv_has_zero_init_1,
118
- .bdrv_has_zero_init_truncate = bdrv_has_zero_init_1,
119
120
.bdrv_aio_preadv = raw_aio_preadv,
121
.bdrv_aio_pwritev = raw_aio_pwritev,
122
diff --git a/block/nfs.c b/block/nfs.c
123
index XXXXXXX..XXXXXXX 100644
124
--- a/block/nfs.c
125
+++ b/block/nfs.c
126
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_nfs = {
127
.create_opts = &nfs_create_opts,
128
129
.bdrv_has_zero_init = nfs_has_zero_init,
130
- .bdrv_has_zero_init_truncate = nfs_has_zero_init,
131
.bdrv_get_allocated_file_size = nfs_get_allocated_file_size,
132
.bdrv_co_truncate = nfs_file_co_truncate,
133
62
diff --git a/block/qcow2.c b/block/qcow2.c
134
diff --git a/block/qcow2.c b/block/qcow2.c
63
index XXXXXXX..XXXXXXX 100644
135
index XXXXXXX..XXXXXXX 100644
64
--- a/block/qcow2.c
136
--- a/block/qcow2.c
65
+++ b/block/qcow2.c
137
+++ b/block/qcow2.c
66
@@ -XXX,XX +XXX,XX @@ static int qcow2_create2(const char *filename, int64_t total_size,
138
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_qcow2 = {
67
}
139
.bdrv_co_create_opts = qcow2_co_create_opts,
68
140
.bdrv_co_create = qcow2_co_create,
69
blk = blk_new_open(filename, NULL, NULL,
141
.bdrv_has_zero_init = qcow2_has_zero_init,
70
- BDRV_O_RDWR | BDRV_O_PROTOCOL, &local_err);
142
- .bdrv_has_zero_init_truncate = bdrv_has_zero_init_1,
71
+ BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL,
143
.bdrv_co_block_status = qcow2_co_block_status,
72
+ &local_err);
144
73
if (blk == NULL) {
145
.bdrv_co_preadv_part = qcow2_co_preadv_part,
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
146
diff --git a/block/qed.c b/block/qed.c
87
index XXXXXXX..XXXXXXX 100644
147
index XXXXXXX..XXXXXXX 100644
88
--- a/block/qed.c
148
--- a/block/qed.c
89
+++ b/block/qed.c
149
+++ b/block/qed.c
90
@@ -XXX,XX +XXX,XX @@ static int qed_create(const char *filename, uint32_t cluster_size,
150
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_qed = {
91
}
151
.bdrv_co_create = bdrv_qed_co_create,
92
152
.bdrv_co_create_opts = bdrv_qed_co_create_opts,
93
blk = blk_new_open(filename, NULL, NULL,
153
.bdrv_has_zero_init = bdrv_has_zero_init_1,
94
- BDRV_O_RDWR | BDRV_O_PROTOCOL, &local_err);
154
- .bdrv_has_zero_init_truncate = bdrv_has_zero_init_1,
95
+ BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL,
155
.bdrv_co_block_status = bdrv_qed_co_block_status,
96
+ &local_err);
156
.bdrv_co_readv = bdrv_qed_co_readv,
97
if (blk == NULL) {
157
.bdrv_co_writev = bdrv_qed_co_writev,
98
error_propagate(errp, local_err);
158
diff --git a/block/raw-format.c b/block/raw-format.c
99
return -EIO;
159
index XXXXXXX..XXXXXXX 100644
160
--- a/block/raw-format.c
161
+++ b/block/raw-format.c
162
@@ -XXX,XX +XXX,XX @@ static int raw_has_zero_init(BlockDriverState *bs)
163
return bdrv_has_zero_init(bs->file->bs);
164
}
165
166
-static int raw_has_zero_init_truncate(BlockDriverState *bs)
167
-{
168
- return bdrv_has_zero_init_truncate(bs->file->bs);
169
-}
170
-
171
static int coroutine_fn raw_co_create_opts(BlockDriver *drv,
172
const char *filename,
173
QemuOpts *opts,
174
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_raw = {
175
.bdrv_co_ioctl = &raw_co_ioctl,
176
.create_opts = &raw_create_opts,
177
.bdrv_has_zero_init = &raw_has_zero_init,
178
- .bdrv_has_zero_init_truncate = &raw_has_zero_init_truncate,
179
.strong_runtime_opts = raw_strong_runtime_opts,
180
.mutable_opts = mutable_opts,
181
};
182
diff --git a/block/rbd.c b/block/rbd.c
183
index XXXXXXX..XXXXXXX 100644
184
--- a/block/rbd.c
185
+++ b/block/rbd.c
186
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_rbd = {
187
.bdrv_co_create = qemu_rbd_co_create,
188
.bdrv_co_create_opts = qemu_rbd_co_create_opts,
189
.bdrv_has_zero_init = bdrv_has_zero_init_1,
190
- .bdrv_has_zero_init_truncate = bdrv_has_zero_init_1,
191
.bdrv_get_info = qemu_rbd_getinfo,
192
.create_opts = &qemu_rbd_create_opts,
193
.bdrv_getlength = qemu_rbd_getlength,
100
diff --git a/block/sheepdog.c b/block/sheepdog.c
194
diff --git a/block/sheepdog.c b/block/sheepdog.c
101
index XXXXXXX..XXXXXXX 100644
195
index XXXXXXX..XXXXXXX 100644
102
--- a/block/sheepdog.c
196
--- a/block/sheepdog.c
103
+++ b/block/sheepdog.c
197
+++ b/block/sheepdog.c
104
@@ -XXX,XX +XXX,XX @@ static int sd_prealloc(const char *filename, Error **errp)
198
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_sheepdog = {
105
int ret;
199
.bdrv_co_create = sd_co_create,
106
200
.bdrv_co_create_opts = sd_co_create_opts,
107
blk = blk_new_open(filename, NULL, NULL,
201
.bdrv_has_zero_init = bdrv_has_zero_init_1,
108
- BDRV_O_RDWR | BDRV_O_PROTOCOL, errp);
202
- .bdrv_has_zero_init_truncate = bdrv_has_zero_init_1,
109
+ BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp);
203
.bdrv_getlength = sd_getlength,
110
if (blk == NULL) {
204
.bdrv_get_allocated_file_size = sd_get_allocated_file_size,
111
ret = -EIO;
205
.bdrv_co_truncate = sd_co_truncate,
112
goto out_with_err_set;
206
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_sheepdog_tcp = {
113
diff --git a/block/vdi.c b/block/vdi.c
207
.bdrv_co_create = sd_co_create,
114
index XXXXXXX..XXXXXXX 100644
208
.bdrv_co_create_opts = sd_co_create_opts,
115
--- a/block/vdi.c
209
.bdrv_has_zero_init = bdrv_has_zero_init_1,
116
+++ b/block/vdi.c
210
- .bdrv_has_zero_init_truncate = bdrv_has_zero_init_1,
117
@@ -XXX,XX +XXX,XX @@ static int vdi_create(const char *filename, QemuOpts *opts, Error **errp)
211
.bdrv_getlength = sd_getlength,
118
}
212
.bdrv_get_allocated_file_size = sd_get_allocated_file_size,
119
213
.bdrv_co_truncate = sd_co_truncate,
120
blk = blk_new_open(filename, NULL, NULL,
214
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_sheepdog_unix = {
121
- BDRV_O_RDWR | BDRV_O_PROTOCOL, &local_err);
215
.bdrv_co_create = sd_co_create,
122
+ BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL,
216
.bdrv_co_create_opts = sd_co_create_opts,
123
+ &local_err);
217
.bdrv_has_zero_init = bdrv_has_zero_init_1,
124
if (blk == NULL) {
218
- .bdrv_has_zero_init_truncate = bdrv_has_zero_init_1,
125
error_propagate(errp, local_err);
219
.bdrv_getlength = sd_getlength,
126
ret = -EIO;
220
.bdrv_get_allocated_file_size = sd_get_allocated_file_size,
127
diff --git a/block/vhdx.c b/block/vhdx.c
221
.bdrv_co_truncate = sd_co_truncate,
128
index XXXXXXX..XXXXXXX 100644
222
diff --git a/block/ssh.c b/block/ssh.c
129
--- a/block/vhdx.c
223
index XXXXXXX..XXXXXXX 100644
130
+++ b/block/vhdx.c
224
--- a/block/ssh.c
131
@@ -XXX,XX +XXX,XX @@ static int vhdx_create(const char *filename, QemuOpts *opts, Error **errp)
225
+++ b/block/ssh.c
132
}
226
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_ssh = {
133
227
.bdrv_co_create_opts = ssh_co_create_opts,
134
blk = blk_new_open(filename, NULL, NULL,
228
.bdrv_close = ssh_close,
135
- BDRV_O_RDWR | BDRV_O_PROTOCOL, &local_err);
229
.bdrv_has_zero_init = ssh_has_zero_init,
136
+ BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL,
230
- .bdrv_has_zero_init_truncate = ssh_has_zero_init,
137
+ &local_err);
231
.bdrv_co_readv = ssh_co_readv,
138
if (blk == NULL) {
232
.bdrv_co_writev = ssh_co_writev,
139
error_propagate(errp, local_err);
233
.bdrv_getlength = ssh_getlength,
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
--
234
--
205
1.8.3.1
235
2.25.3
206
236
207
237
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
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
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
Now that the backing file child role implements .attach/.detach
2
callbacks, nothing prevents us from modifying the graph even if that
3
involves changing backing file links.
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 | 7 +++----
10
1 file changed, 3 insertions(+), 4 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 change_parent_backing_link(BlockDriverState *from,
17
continue;
18
}
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
--
38
1.8.3.1
39
40
diff view generated by jsdifflib
Deleted patch
1
In some cases, we want to remove op blockers on intermediate nodes
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
1
6
The whole block job lifecycle is a bit messed up and it's hard to
7
actually do all things in the right order, but I'll leave simplifying
8
this for another day.
9
10
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
---
14
blockjob.c | 20 +++++++++++++-------
15
include/block/blockjob.h | 9 +++++++++
16
2 files changed, 22 insertions(+), 7 deletions(-)
17
18
diff --git a/blockjob.c b/blockjob.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/blockjob.c
21
+++ b/blockjob.c
22
@@ -XXX,XX +XXX,XX @@ static void block_job_detach_aio_context(void *opaque)
23
block_job_unref(job);
24
}
25
26
+void block_job_remove_all_bdrv(BlockJob *job)
27
+{
28
+ GSList *l;
29
+ for (l = job->nodes; l; l = l->next) {
30
+ BdrvChild *c = l->data;
31
+ bdrv_op_unblock_all(c->bs, job->blocker);
32
+ bdrv_root_unref_child(c);
33
+ }
34
+ g_slist_free(job->nodes);
35
+ job->nodes = NULL;
36
+}
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
--
79
1.8.3.1
80
81
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