1
The following changes since commit 75ee62ac606bfc9eb59310b9446df3434bf6e8c2:
1
The following changes since commit ccdf06c1db192152ac70a1dd974c624f566cb7d4:
2
2
3
Merge remote-tracking branch 'remotes/ehabkost-gl/tags/x86-next-pull-request' into staging (2020-12-17 18:53:36 +0000)
3
Open 6.1 development tree (2021-04-30 11:15:40 +0100)
4
4
5
are available in the Git repository at:
5
are available in the Git repository at:
6
6
7
git://repo.or.cz/qemu/kevin.git tags/for-upstream
7
git://repo.or.cz/qemu/kevin.git tags/for-upstream
8
8
9
for you to fetch changes up to be7c5ddd0d80e2d6cf8e3ef12c049851d28d9c26:
9
for you to fetch changes up to 68bf7336533faa6aa90fdd4558edddbf5d8ef814:
10
10
11
block/vpc: Use sizeof() instead of HEADER_SIZE for footer size (2020-12-18 12:43:30 +0100)
11
vhost-user-blk: Fail gracefully on too large queue size (2021-04-30 12:27:48 +0200)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block layer patches:
14
Block layer patches
15
15
16
- Add qemu-storage-daemon documentation
16
- Fix permission update order problems with block graph changes
17
- hw/block/nand: Decommission the NAND museum
17
- qemu-img convert: Unshare write permission for source
18
- vpc: Clean up some buffer abuse
18
- vhost-user-blk: Fail gracefully on too large queue size
19
- nfs: fix int overflow in nfs_client_open_qdict
20
- Several iotests fixes
21
19
22
----------------------------------------------------------------
20
----------------------------------------------------------------
23
Markus Armbruster (9):
21
Kevin Wolf (3):
24
block/vpc: Make vpc_open() read the full dynamic header
22
block: Add BDRV_O_NO_SHARE for blk_new_open()
25
block/vpc: Don't abuse the footer buffer as BAT sector buffer
23
qemu-img convert: Unshare write permission for source
26
block/vpc: Don't abuse the footer buffer for dynamic header
24
vhost-user-blk: Fail gracefully on too large queue size
27
block/vpc: Make vpc_checksum() take void *
28
block/vpc: Pad VHDDynDiskHeader, replace uint8_t[] buffers
29
block/vpc: Use sizeof() instead of 1024 for dynamic header size
30
block/vpc: Pad VHDFooter, replace uint8_t[] buffers
31
block/vpc: Pass footer buffers as VHDFooter * instead of uint8_t *
32
block/vpc: Use sizeof() instead of HEADER_SIZE for footer size
33
25
34
Max Reitz (1):
26
Vladimir Sementsov-Ogievskiy (36):
35
iotests/210: Fix reference output
27
tests/test-bdrv-graph-mod: add test_parallel_exclusive_write
28
tests/test-bdrv-graph-mod: add test_parallel_perm_update
29
tests/test-bdrv-graph-mod: add test_append_greedy_filter
30
block: bdrv_append(): don't consume reference
31
block: BdrvChildClass: add .get_parent_aio_context handler
32
block: drop ctx argument from bdrv_root_attach_child
33
block: make bdrv_reopen_{prepare,commit,abort} private
34
util: add transactions.c
35
block: bdrv_refresh_perms: check for parents permissions conflict
36
block: refactor bdrv_child* permission functions
37
block: rewrite bdrv_child_try_set_perm() using bdrv_refresh_perms()
38
block: inline bdrv_child_*() permission functions calls
39
block: use topological sort for permission update
40
block: add bdrv_drv_set_perm transaction action
41
block: add bdrv_list_* permission update functions
42
block: add bdrv_replace_child_safe() transaction action
43
block: fix bdrv_replace_node_common
44
block: add bdrv_attach_child_common() transaction action
45
block: add bdrv_attach_child_noperm() transaction action
46
block: split out bdrv_replace_node_noperm()
47
block: adapt bdrv_append() for inserting filters
48
block: add bdrv_remove_filter_or_cow transaction action
49
block: introduce bdrv_drop_filter()
50
block/backup-top: drop .active
51
block: drop ignore_children for permission update functions
52
block: make bdrv_unset_inherits_from to be a transaction action
53
block: make bdrv_refresh_limits() to be a transaction action
54
block: add bdrv_set_backing_noperm() transaction action
55
block: bdrv_reopen_multiple(): move bdrv_flush to separate pre-prepare
56
block: bdrv_reopen_multiple: refresh permissions on updated graph
57
block: drop unused permission update functions
58
block: inline bdrv_check_perm_common()
59
block: inline bdrv_replace_child()
60
block: refactor bdrv_child_set_perm_safe() transaction action
61
block: rename bdrv_replace_child_safe() to bdrv_replace_child()
62
block: refactor bdrv_node_check_perm()
36
63
37
Peter Lieven (1):
64
include/block/block.h | 14 +-
38
block/nfs: fix int overflow in nfs_client_open_qdict
65
include/block/block_int.h | 8 +-
39
66
include/qemu/transactions.h | 63 ++
40
Philippe Mathieu-Daudé (1):
67
block.c | 1329 ++++++++++++++++++++-------------
41
hw/block/nand: Decommission the NAND museum
68
block/backup-top.c | 48 +-
42
69
block/block-backend.c | 30 +-
43
Stefan Hajnoczi (3):
70
block/commit.c | 1 +
44
docs: generate qemu-storage-daemon-qmp-ref(7) man page
71
block/file-posix.c | 91 +--
45
docs: add qemu-storage-daemon(1) man page
72
block/io.c | 31 +-
46
MAINTAINERS: add Kevin Wolf as storage daemon maintainer
73
block/mirror.c | 3 -
47
74
blockdev.c | 4 -
48
Vladimir Sementsov-Ogievskiy (2):
75
blockjob.c | 11 +-
49
iotests: make _filter_qom_path more strict
76
hw/block/vhost-user-blk.c | 5 +
50
iotests:172: use _filter_qom_path
77
qemu-img.c | 2 +-
51
78
tests/unit/test-bdrv-drain.c | 2 +-
52
docs/interop/conf.py | 2 +
79
tests/unit/test-bdrv-graph-mod.c | 209 +++++-
53
docs/interop/index.rst | 1 +
80
util/transactions.c | 96 +++
54
docs/interop/qemu-storage-daemon-qmp-ref.rst | 13 +++
81
MAINTAINERS | 6 +
55
docs/meson.build | 1 +
82
tests/qemu-iotests/245 | 2 +-
56
docs/tools/conf.py | 2 +
83
tests/qemu-iotests/283.out | 2 +-
57
docs/tools/index.rst | 1 +
84
tests/qemu-iotests/tests/qsd-jobs.out | 2 +-
58
docs/tools/qemu-storage-daemon.rst | 148 ++++++++++++++++++++++++++
85
util/meson.build | 1 +
59
block/nfs.c | 2 +-
86
22 files changed, 1280 insertions(+), 680 deletions(-)
60
block/vpc.c | 146 +++++++++++++------------
87
create mode 100644 include/qemu/transactions.h
61
hw/block/nand.c | 12 +--
88
create mode 100644 util/transactions.c
62
MAINTAINERS | 9 ++
63
storage-daemon/qapi/qapi-schema.json | 3 +
64
tests/qemu-iotests/172 | 2 +-
65
tests/qemu-iotests/172.out | 152 +++++++++++++--------------
66
tests/qemu-iotests/186.out | 56 +++++-----
67
tests/qemu-iotests/210.out | 2 +-
68
tests/qemu-iotests/common.filter | 2 +-
69
17 files changed, 361 insertions(+), 193 deletions(-)
70
create mode 100644 docs/interop/qemu-storage-daemon-qmp-ref.rst
71
create mode 100644 docs/tools/qemu-storage-daemon.rst
72
89
73
90
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
Add the test that shows that concept of ignore_children is incomplete.
4
Actually, when we want to update something, ignoring permission of some
5
existing BdrvChild, we should ignore also the propagated effect of this
6
child to the other children. But that's not done. Better approach
7
(update permissions on already updated graph) will be implemented
8
later.
9
10
Now the test fails, so it's added with -d argument to not break make
11
check.
12
13
Test fails with
14
15
"Conflicts with use by fl1 as 'backing', which does not allow 'write' on base"
16
17
because when updating permissions we can ignore original top->fl1
18
BdrvChild. But we don't ignore exclusive write permission in fl1->base
19
BdrvChild, which is propagated. Correct thing to do is make graph
20
change first and then do permission update from the top node.
21
22
To run test do
23
24
./test-bdrv-graph-mod -d -p /bdrv-graph-mod/parallel-exclusive-write
25
26
from <build-directory>/tests.
27
28
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
29
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
30
Message-Id: <20210428151804.439460-2-vsementsov@virtuozzo.com>
31
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
32
---
33
tests/unit/test-bdrv-graph-mod.c | 70 +++++++++++++++++++++++++++++++-
34
1 file changed, 69 insertions(+), 1 deletion(-)
35
36
diff --git a/tests/unit/test-bdrv-graph-mod.c b/tests/unit/test-bdrv-graph-mod.c
37
index XXXXXXX..XXXXXXX 100644
38
--- a/tests/unit/test-bdrv-graph-mod.c
39
+++ b/tests/unit/test-bdrv-graph-mod.c
40
@@ -XXX,XX +XXX,XX @@
41
/*
42
* Block node graph modifications tests
43
*
44
- * Copyright (c) 2019 Virtuozzo International GmbH. All rights reserved.
45
+ * Copyright (c) 2019-2021 Virtuozzo International GmbH. All rights reserved.
46
*
47
* This program is free software; you can redistribute it and/or modify
48
* it under the terms of the GNU General Public License as published by
49
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_no_perm = {
50
.bdrv_child_perm = no_perm_default_perms,
51
};
52
53
+static void exclusive_write_perms(BlockDriverState *bs, BdrvChild *c,
54
+ BdrvChildRole role,
55
+ BlockReopenQueue *reopen_queue,
56
+ uint64_t perm, uint64_t shared,
57
+ uint64_t *nperm, uint64_t *nshared)
58
+{
59
+ *nperm = BLK_PERM_WRITE;
60
+ *nshared = BLK_PERM_ALL & ~BLK_PERM_WRITE;
61
+}
62
+
63
+static BlockDriver bdrv_exclusive_writer = {
64
+ .format_name = "exclusive-writer",
65
+ .bdrv_child_perm = exclusive_write_perms,
66
+};
67
+
68
static BlockDriverState *no_perm_node(const char *name)
69
{
70
return bdrv_new_open_driver(&bdrv_no_perm, name, BDRV_O_RDWR, &error_abort);
71
@@ -XXX,XX +XXX,XX @@ static BlockDriverState *pass_through_node(const char *name)
72
BDRV_O_RDWR, &error_abort);
73
}
74
75
+static BlockDriverState *exclusive_writer_node(const char *name)
76
+{
77
+ return bdrv_new_open_driver(&bdrv_exclusive_writer, name,
78
+ BDRV_O_RDWR, &error_abort);
79
+}
80
+
81
/*
82
* test_update_perm_tree
83
*
84
@@ -XXX,XX +XXX,XX @@ static void test_should_update_child(void)
85
blk_unref(root);
86
}
87
88
+/*
89
+ * test_parallel_exclusive_write
90
+ *
91
+ * Check that when we replace node, old permissions of the node being removed
92
+ * doesn't break the replacement.
93
+ */
94
+static void test_parallel_exclusive_write(void)
95
+{
96
+ BlockDriverState *top = exclusive_writer_node("top");
97
+ BlockDriverState *base = no_perm_node("base");
98
+ BlockDriverState *fl1 = pass_through_node("fl1");
99
+ BlockDriverState *fl2 = pass_through_node("fl2");
100
+
101
+ /*
102
+ * bdrv_attach_child() eats child bs reference, so we need two @base
103
+ * references for two filters:
104
+ */
105
+ bdrv_ref(base);
106
+
107
+ bdrv_attach_child(top, fl1, "backing", &child_of_bds, BDRV_CHILD_DATA,
108
+ &error_abort);
109
+ bdrv_attach_child(fl1, base, "backing", &child_of_bds, BDRV_CHILD_FILTERED,
110
+ &error_abort);
111
+ bdrv_attach_child(fl2, base, "backing", &child_of_bds, BDRV_CHILD_FILTERED,
112
+ &error_abort);
113
+
114
+ bdrv_replace_node(fl1, fl2, &error_abort);
115
+
116
+ bdrv_unref(fl2);
117
+ bdrv_unref(top);
118
+}
119
+
120
int main(int argc, char *argv[])
121
{
122
+ int i;
123
+ bool debug = false;
124
+
125
+ for (i = 1; i < argc; i++) {
126
+ if (!strcmp(argv[i], "-d")) {
127
+ debug = true;
128
+ break;
129
+ }
130
+ }
131
+
132
bdrv_init();
133
qemu_init_main_loop(&error_abort);
134
135
@@ -XXX,XX +XXX,XX @@ int main(int argc, char *argv[])
136
g_test_add_func("/bdrv-graph-mod/should-update-child",
137
test_should_update_child);
138
139
+ if (debug) {
140
+ g_test_add_func("/bdrv-graph-mod/parallel-exclusive-write",
141
+ test_parallel_exclusive_write);
142
+ }
143
+
144
return g_test_run();
145
}
146
--
147
2.30.2
148
149
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
Add test to show that simple DFS recursion order is not correct for
4
permission update. Correct order is topological-sort order, which will
5
be introduced later.
6
7
Consider the block driver which has two filter children: one active
8
with exclusive write access and one inactive with no specific
9
permissions.
10
11
And, these two children has a common base child, like this:
12
13
┌─────┐ ┌──────┐
14
│ fl2 │ ◀── │ top │
15
└─────┘ └──────┘
16
│ │
17
│ │ w
18
│ ▼
19
│ ┌──────┐
20
│ │ fl1 │
21
│ └──────┘
22
│ │
23
│ │ w
24
│ ▼
25
│ ┌──────┐
26
└───────▶ │ base │
27
└──────┘
28
29
So, exclusive write is propagated.
30
31
Assume, we want to make fl2 active instead of fl1.
32
So, we set some option for top driver and do permission update.
33
34
If permission update (remember, it's DFS) goes first through
35
top->fl1->base branch it will succeed: it firstly drop exclusive write
36
permissions and than apply them for another BdrvChildren.
37
But if permission update goes first through top->fl2->base branch it
38
will fail, as when we try to update fl2->base child, old not yet
39
updated fl1->base child will be in conflict.
40
41
Now test fails, so it runs only with -d flag. To run do
42
43
./test-bdrv-graph-mod -d -p /bdrv-graph-mod/parallel-perm-update
44
45
from <build-directory>/tests.
46
47
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
48
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
49
Message-Id: <20210428151804.439460-3-vsementsov@virtuozzo.com>
50
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
51
---
52
tests/unit/test-bdrv-graph-mod.c | 116 +++++++++++++++++++++++++++++++
53
1 file changed, 116 insertions(+)
54
55
diff --git a/tests/unit/test-bdrv-graph-mod.c b/tests/unit/test-bdrv-graph-mod.c
56
index XXXXXXX..XXXXXXX 100644
57
--- a/tests/unit/test-bdrv-graph-mod.c
58
+++ b/tests/unit/test-bdrv-graph-mod.c
59
@@ -XXX,XX +XXX,XX @@ static void test_parallel_exclusive_write(void)
60
bdrv_unref(top);
61
}
62
63
+static void write_to_file_perms(BlockDriverState *bs, BdrvChild *c,
64
+ BdrvChildRole role,
65
+ BlockReopenQueue *reopen_queue,
66
+ uint64_t perm, uint64_t shared,
67
+ uint64_t *nperm, uint64_t *nshared)
68
+{
69
+ if (bs->file && c == bs->file) {
70
+ *nperm = BLK_PERM_WRITE;
71
+ *nshared = BLK_PERM_ALL & ~BLK_PERM_WRITE;
72
+ } else {
73
+ *nperm = 0;
74
+ *nshared = BLK_PERM_ALL;
75
+ }
76
+}
77
+
78
+static BlockDriver bdrv_write_to_file = {
79
+ .format_name = "tricky-perm",
80
+ .bdrv_child_perm = write_to_file_perms,
81
+};
82
+
83
+
84
+/*
85
+ * The following test shows that topological-sort order is required for
86
+ * permission update, simple DFS is not enough.
87
+ *
88
+ * Consider the block driver which has two filter children: one active
89
+ * with exclusive write access and one inactive with no specific
90
+ * permissions.
91
+ *
92
+ * And, these two children has a common base child, like this:
93
+ *
94
+ * ┌─────┐ ┌──────┐
95
+ * │ fl2 │ ◀── │ top │
96
+ * └─────┘ └──────┘
97
+ * │ │
98
+ * │ │ w
99
+ * │ ▼
100
+ * │ ┌──────┐
101
+ * │ │ fl1 │
102
+ * │ └──────┘
103
+ * │ │
104
+ * │ │ w
105
+ * │ ▼
106
+ * │ ┌──────┐
107
+ * └───────▶ │ base │
108
+ * └──────┘
109
+ *
110
+ * So, exclusive write is propagated.
111
+ *
112
+ * Assume, we want to make fl2 active instead of fl1.
113
+ * So, we set some option for top driver and do permission update.
114
+ *
115
+ * With simple DFS, if permission update goes first through
116
+ * top->fl1->base branch it will succeed: it firstly drop exclusive write
117
+ * permissions and than apply them for another BdrvChildren.
118
+ * But if permission update goes first through top->fl2->base branch it
119
+ * will fail, as when we try to update fl2->base child, old not yet
120
+ * updated fl1->base child will be in conflict.
121
+ *
122
+ * With topological-sort order we always update parents before children, so fl1
123
+ * and fl2 are both updated when we update base and there is no conflict.
124
+ */
125
+static void test_parallel_perm_update(void)
126
+{
127
+ BlockDriverState *top = no_perm_node("top");
128
+ BlockDriverState *tricky =
129
+ bdrv_new_open_driver(&bdrv_write_to_file, "tricky", BDRV_O_RDWR,
130
+ &error_abort);
131
+ BlockDriverState *base = no_perm_node("base");
132
+ BlockDriverState *fl1 = pass_through_node("fl1");
133
+ BlockDriverState *fl2 = pass_through_node("fl2");
134
+ BdrvChild *c_fl1, *c_fl2;
135
+
136
+ /*
137
+ * bdrv_attach_child() eats child bs reference, so we need two @base
138
+ * references for two filters:
139
+ */
140
+ bdrv_ref(base);
141
+
142
+ bdrv_attach_child(top, tricky, "file", &child_of_bds, BDRV_CHILD_DATA,
143
+ &error_abort);
144
+ c_fl1 = bdrv_attach_child(tricky, fl1, "first", &child_of_bds,
145
+ BDRV_CHILD_FILTERED, &error_abort);
146
+ c_fl2 = bdrv_attach_child(tricky, fl2, "second", &child_of_bds,
147
+ BDRV_CHILD_FILTERED, &error_abort);
148
+ bdrv_attach_child(fl1, base, "backing", &child_of_bds, BDRV_CHILD_FILTERED,
149
+ &error_abort);
150
+ bdrv_attach_child(fl2, base, "backing", &child_of_bds, BDRV_CHILD_FILTERED,
151
+ &error_abort);
152
+
153
+ /* Select fl1 as first child to be active */
154
+ tricky->file = c_fl1;
155
+ bdrv_child_refresh_perms(top, top->children.lh_first, &error_abort);
156
+
157
+ assert(c_fl1->perm & BLK_PERM_WRITE);
158
+ assert(!(c_fl2->perm & BLK_PERM_WRITE));
159
+
160
+ /* Now, try to switch active child and update permissions */
161
+ tricky->file = c_fl2;
162
+ bdrv_child_refresh_perms(top, top->children.lh_first, &error_abort);
163
+
164
+ assert(c_fl2->perm & BLK_PERM_WRITE);
165
+ assert(!(c_fl1->perm & BLK_PERM_WRITE));
166
+
167
+ /* Switch once more, to not care about real child order in the list */
168
+ tricky->file = c_fl1;
169
+ bdrv_child_refresh_perms(top, top->children.lh_first, &error_abort);
170
+
171
+ assert(c_fl1->perm & BLK_PERM_WRITE);
172
+ assert(!(c_fl2->perm & BLK_PERM_WRITE));
173
+
174
+ bdrv_unref(top);
175
+}
176
+
177
int main(int argc, char *argv[])
178
{
179
int i;
180
@@ -XXX,XX +XXX,XX @@ int main(int argc, char *argv[])
181
if (debug) {
182
g_test_add_func("/bdrv-graph-mod/parallel-exclusive-write",
183
test_parallel_exclusive_write);
184
+ g_test_add_func("/bdrv-graph-mod/parallel-perm-update",
185
+ test_parallel_perm_update);
186
}
187
188
return g_test_run();
189
--
190
2.30.2
191
192
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
bdrv_append() is not quite good for inserting filters: it does extra
4
permission update in intermediate state, where filter get it filtered
5
child but is not yet replace it in a backing chain.
6
7
Some filters (for example backup-top) may want permissions even when
8
have no parents. And described intermediate state becomes invalid.
9
10
That's (half a) reason, why we need "inactive" state for backup-top
11
filter.
12
13
bdrv_append() will be improved later, now let's add a unit test.
14
15
Now test fails, so it runs only with -d flag. To run do
16
17
./test-bdrv-graph-mod -d -p /bdrv-graph-mod/append-greedy-filter
18
19
from <build-directory>/tests.
20
21
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
22
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
23
Message-Id: <20210428151804.439460-4-vsementsov@virtuozzo.com>
24
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
25
---
26
tests/unit/test-bdrv-graph-mod.c | 33 ++++++++++++++++++++++++++++++++
27
1 file changed, 33 insertions(+)
28
29
diff --git a/tests/unit/test-bdrv-graph-mod.c b/tests/unit/test-bdrv-graph-mod.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/tests/unit/test-bdrv-graph-mod.c
32
+++ b/tests/unit/test-bdrv-graph-mod.c
33
@@ -XXX,XX +XXX,XX @@ static void test_parallel_perm_update(void)
34
bdrv_unref(top);
35
}
36
37
+/*
38
+ * It's possible that filter required permissions allows to insert it to backing
39
+ * chain, like:
40
+ *
41
+ * 1. [top] -> [filter] -> [base]
42
+ *
43
+ * but doesn't allow to add it as a branch:
44
+ *
45
+ * 2. [filter] --\
46
+ * v
47
+ * [top] -> [base]
48
+ *
49
+ * So, inserting such filter should do all graph modifications and only then
50
+ * update permissions. If we try to go through intermediate state [2] and update
51
+ * permissions on it we'll fail.
52
+ *
53
+ * Let's check that bdrv_append() can append such a filter.
54
+ */
55
+static void test_append_greedy_filter(void)
56
+{
57
+ BlockDriverState *top = exclusive_writer_node("top");
58
+ BlockDriverState *base = no_perm_node("base");
59
+ BlockDriverState *fl = exclusive_writer_node("fl1");
60
+
61
+ bdrv_attach_child(top, base, "backing", &child_of_bds, BDRV_CHILD_COW,
62
+ &error_abort);
63
+
64
+ bdrv_append(fl, base, &error_abort);
65
+ bdrv_unref(top);
66
+}
67
+
68
int main(int argc, char *argv[])
69
{
70
int i;
71
@@ -XXX,XX +XXX,XX @@ int main(int argc, char *argv[])
72
test_parallel_exclusive_write);
73
g_test_add_func("/bdrv-graph-mod/parallel-perm-update",
74
test_parallel_perm_update);
75
+ g_test_add_func("/bdrv-graph-mod/append-greedy-filter",
76
+ test_append_greedy_filter);
77
}
78
79
return g_test_run();
80
--
81
2.30.2
82
83
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
We have too much comments for this feature. It seems better just don't
4
do it. Most of real users (tests don't count) have to create additional
5
reference.
6
7
Drop also comment in external_snapshot_prepare:
8
- bdrv_append doesn't "remove" old bs in common sense, it sounds
9
strange
10
- the fact that bdrv_append can fail is obvious from the context
11
- the fact that we must rollback all changes in transaction abort is
12
known (it's the direct role of abort)
13
14
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
15
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
16
Message-Id: <20210428151804.439460-5-vsementsov@virtuozzo.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
---
19
block.c | 25 +++----------------------
20
block/backup-top.c | 1 -
21
block/commit.c | 1 +
22
block/mirror.c | 3 ---
23
blockdev.c | 4 ----
24
tests/unit/test-bdrv-drain.c | 2 +-
25
tests/unit/test-bdrv-graph-mod.c | 3 +++
26
7 files changed, 8 insertions(+), 31 deletions(-)
27
28
diff --git a/block.c b/block.c
29
index XXXXXXX..XXXXXXX 100644
30
--- a/block.c
31
+++ b/block.c
32
@@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs,
33
goto out;
34
}
35
36
- /* bdrv_append() consumes a strong reference to bs_snapshot
37
- * (i.e. it will call bdrv_unref() on it) even on error, so in
38
- * order to be able to return one, we have to increase
39
- * bs_snapshot's refcount here */
40
- bdrv_ref(bs_snapshot);
41
ret = bdrv_append(bs_snapshot, bs, errp);
42
if (ret < 0) {
43
bs_snapshot = NULL;
44
@@ -XXX,XX +XXX,XX @@ int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
45
* bs_new must not be attached to a BlockBackend.
46
*
47
* This function does not create any image files.
48
- *
49
- * bdrv_append() takes ownership of a bs_new reference and unrefs it because
50
- * that's what the callers commonly need. bs_new will be referenced by the old
51
- * parents of bs_top after bdrv_append() returns. If the caller needs to keep a
52
- * reference of its own, it must call bdrv_ref().
53
*/
54
int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
55
Error **errp)
56
{
57
int ret = bdrv_set_backing_hd(bs_new, bs_top, errp);
58
if (ret < 0) {
59
- goto out;
60
+ return ret;
61
}
62
63
ret = bdrv_replace_node(bs_top, bs_new, errp);
64
if (ret < 0) {
65
bdrv_set_backing_hd(bs_new, NULL, &error_abort);
66
- goto out;
67
+ return ret;
68
}
69
70
- ret = 0;
71
-
72
-out:
73
- /*
74
- * bs_new is now referenced by its new parents, we don't need the
75
- * additional reference any more.
76
- */
77
- bdrv_unref(bs_new);
78
-
79
- return ret;
80
+ return 0;
81
}
82
83
static void bdrv_delete(BlockDriverState *bs)
84
diff --git a/block/backup-top.c b/block/backup-top.c
85
index XXXXXXX..XXXXXXX 100644
86
--- a/block/backup-top.c
87
+++ b/block/backup-top.c
88
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source,
89
90
bdrv_drained_begin(source);
91
92
- bdrv_ref(top);
93
ret = bdrv_append(top, source, errp);
94
if (ret < 0) {
95
error_prepend(errp, "Cannot append backup-top filter: ");
96
diff --git a/block/commit.c b/block/commit.c
97
index XXXXXXX..XXXXXXX 100644
98
--- a/block/commit.c
99
+++ b/block/commit.c
100
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
101
commit_top_bs->total_sectors = top->total_sectors;
102
103
ret = bdrv_append(commit_top_bs, top, errp);
104
+ bdrv_unref(commit_top_bs); /* referenced by new parents or failed */
105
if (ret < 0) {
106
commit_top_bs = NULL;
107
goto fail;
108
diff --git a/block/mirror.c b/block/mirror.c
109
index XXXXXXX..XXXXXXX 100644
110
--- a/block/mirror.c
111
+++ b/block/mirror.c
112
@@ -XXX,XX +XXX,XX @@ static BlockJob *mirror_start_job(
113
114
bs_opaque->is_commit = target_is_backing;
115
116
- /* bdrv_append takes ownership of the mirror_top_bs reference, need to keep
117
- * it alive until block_job_create() succeeds even if bs has no parent. */
118
- bdrv_ref(mirror_top_bs);
119
bdrv_drained_begin(bs);
120
ret = bdrv_append(mirror_top_bs, bs, errp);
121
bdrv_drained_end(bs);
122
diff --git a/blockdev.c b/blockdev.c
123
index XXXXXXX..XXXXXXX 100644
124
--- a/blockdev.c
125
+++ b/blockdev.c
126
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_prepare(BlkActionState *common,
127
goto out;
128
}
129
130
- /* This removes our old bs and adds the new bs. This is an operation that
131
- * can fail, so we need to do it in .prepare; undoing it for abort is
132
- * always possible. */
133
- bdrv_ref(state->new_bs);
134
ret = bdrv_append(state->new_bs, state->old_bs, errp);
135
if (ret < 0) {
136
goto out;
137
diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c
138
index XXXXXXX..XXXXXXX 100644
139
--- a/tests/unit/test-bdrv-drain.c
140
+++ b/tests/unit/test-bdrv-drain.c
141
@@ -XXX,XX +XXX,XX @@ static void test_append_to_drained(void)
142
g_assert_cmpint(base_s->drain_count, ==, 1);
143
g_assert_cmpint(base->in_flight, ==, 0);
144
145
- /* Takes ownership of overlay, so we don't have to unref it later */
146
bdrv_append(overlay, base, &error_abort);
147
g_assert_cmpint(base->in_flight, ==, 0);
148
g_assert_cmpint(overlay->in_flight, ==, 0);
149
@@ -XXX,XX +XXX,XX @@ static void test_append_to_drained(void)
150
g_assert_cmpint(overlay->quiesce_counter, ==, 0);
151
g_assert_cmpint(overlay_s->drain_count, ==, 0);
152
153
+ bdrv_unref(overlay);
154
bdrv_unref(base);
155
blk_unref(blk);
156
}
157
diff --git a/tests/unit/test-bdrv-graph-mod.c b/tests/unit/test-bdrv-graph-mod.c
158
index XXXXXXX..XXXXXXX 100644
159
--- a/tests/unit/test-bdrv-graph-mod.c
160
+++ b/tests/unit/test-bdrv-graph-mod.c
161
@@ -XXX,XX +XXX,XX @@ static void test_update_perm_tree(void)
162
ret = bdrv_append(filter, bs, NULL);
163
g_assert_cmpint(ret, <, 0);
164
165
+ bdrv_unref(filter);
166
blk_unref(root);
167
}
168
169
@@ -XXX,XX +XXX,XX @@ static void test_should_update_child(void)
170
bdrv_append(filter, bs, &error_abort);
171
g_assert(target->backing->bs == bs);
172
173
+ bdrv_unref(filter);
174
bdrv_unref(bs);
175
blk_unref(root);
176
}
177
@@ -XXX,XX +XXX,XX @@ static void test_append_greedy_filter(void)
178
&error_abort);
179
180
bdrv_append(fl, base, &error_abort);
181
+ bdrv_unref(fl);
182
bdrv_unref(top);
183
}
184
185
--
186
2.30.2
187
188
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
Add new handler to get aio context and implement it in all child
4
classes. Add corresponding public interface to be used soon.
5
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Reviewed-by: Alberto Garcia <berto@igalia.com>
8
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9
Message-Id: <20210428151804.439460-6-vsementsov@virtuozzo.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
12
include/block/block.h | 2 ++
13
include/block/block_int.h | 2 ++
14
block.c | 13 +++++++++++++
15
block/block-backend.c | 9 +++++++++
16
blockjob.c | 8 ++++++++
17
5 files changed, 34 insertions(+)
18
19
diff --git a/include/block/block.h b/include/block/block.h
20
index XXXXXXX..XXXXXXX 100644
21
--- a/include/block/block.h
22
+++ b/include/block/block.h
23
@@ -XXX,XX +XXX,XX @@ bool bdrv_child_can_set_aio_context(BdrvChild *c, AioContext *ctx,
24
GSList **ignore, Error **errp);
25
bool bdrv_can_set_aio_context(BlockDriverState *bs, AioContext *ctx,
26
GSList **ignore, Error **errp);
27
+AioContext *bdrv_child_get_parent_aio_context(BdrvChild *c);
28
+
29
int bdrv_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz);
30
int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo);
31
32
diff --git a/include/block/block_int.h b/include/block/block_int.h
33
index XXXXXXX..XXXXXXX 100644
34
--- a/include/block/block_int.h
35
+++ b/include/block/block_int.h
36
@@ -XXX,XX +XXX,XX @@ struct BdrvChildClass {
37
bool (*can_set_aio_ctx)(BdrvChild *child, AioContext *ctx,
38
GSList **ignore, Error **errp);
39
void (*set_aio_ctx)(BdrvChild *child, AioContext *ctx, GSList **ignore);
40
+
41
+ AioContext *(*get_parent_aio_context)(BdrvChild *child);
42
};
43
44
extern const BdrvChildClass child_of_bds;
45
diff --git a/block.c b/block.c
46
index XXXXXXX..XXXXXXX 100644
47
--- a/block.c
48
+++ b/block.c
49
@@ -XXX,XX +XXX,XX @@ static int bdrv_child_cb_update_filename(BdrvChild *c, BlockDriverState *base,
50
return 0;
51
}
52
53
+static AioContext *bdrv_child_cb_get_parent_aio_context(BdrvChild *c)
54
+{
55
+ BlockDriverState *bs = c->opaque;
56
+
57
+ return bdrv_get_aio_context(bs);
58
+}
59
+
60
const BdrvChildClass child_of_bds = {
61
.parent_is_bds = true,
62
.get_parent_desc = bdrv_child_get_parent_desc,
63
@@ -XXX,XX +XXX,XX @@ const BdrvChildClass child_of_bds = {
64
.can_set_aio_ctx = bdrv_child_cb_can_set_aio_ctx,
65
.set_aio_ctx = bdrv_child_cb_set_aio_ctx,
66
.update_filename = bdrv_child_cb_update_filename,
67
+ .get_parent_aio_context = bdrv_child_cb_get_parent_aio_context,
68
};
69
70
+AioContext *bdrv_child_get_parent_aio_context(BdrvChild *c)
71
+{
72
+ return c->klass->get_parent_aio_context(c);
73
+}
74
+
75
static int bdrv_open_flags(BlockDriverState *bs, int flags)
76
{
77
int open_flags = flags;
78
diff --git a/block/block-backend.c b/block/block-backend.c
79
index XXXXXXX..XXXXXXX 100644
80
--- a/block/block-backend.c
81
+++ b/block/block-backend.c
82
@@ -XXX,XX +XXX,XX @@ static void blk_root_detach(BdrvChild *child)
83
}
84
}
85
86
+static AioContext *blk_root_get_parent_aio_context(BdrvChild *c)
87
+{
88
+ BlockBackend *blk = c->opaque;
89
+
90
+ return blk_get_aio_context(blk);
91
+}
92
+
93
static const BdrvChildClass child_root = {
94
.inherit_options = blk_root_inherit_options,
95
96
@@ -XXX,XX +XXX,XX @@ static const BdrvChildClass child_root = {
97
98
.can_set_aio_ctx = blk_root_can_set_aio_ctx,
99
.set_aio_ctx = blk_root_set_aio_ctx,
100
+
101
+ .get_parent_aio_context = blk_root_get_parent_aio_context,
102
};
103
104
/*
105
diff --git a/blockjob.c b/blockjob.c
106
index XXXXXXX..XXXXXXX 100644
107
--- a/blockjob.c
108
+++ b/blockjob.c
109
@@ -XXX,XX +XXX,XX @@ static void child_job_set_aio_ctx(BdrvChild *c, AioContext *ctx,
110
job->job.aio_context = ctx;
111
}
112
113
+static AioContext *child_job_get_parent_aio_context(BdrvChild *c)
114
+{
115
+ BlockJob *job = c->opaque;
116
+
117
+ return job->job.aio_context;
118
+}
119
+
120
static const BdrvChildClass child_job = {
121
.get_parent_desc = child_job_get_parent_desc,
122
.drained_begin = child_job_drained_begin,
123
@@ -XXX,XX +XXX,XX @@ static const BdrvChildClass child_job = {
124
.can_set_aio_ctx = child_job_can_set_aio_ctx,
125
.set_aio_ctx = child_job_set_aio_ctx,
126
.stay_at_node = true,
127
+ .get_parent_aio_context = child_job_get_parent_aio_context,
128
};
129
130
void block_job_remove_all_bdrv(BlockJob *job)
131
--
132
2.30.2
133
134
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
Passing parent aio context is redundant, as child_class and parent
4
opaque pointer are enough to retrieve it. Drop the argument and use new
5
bdrv_child_get_parent_aio_context() interface.
6
7
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Reviewed-by: Alberto Garcia <berto@igalia.com>
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
10
Message-Id: <20210428151804.439460-7-vsementsov@virtuozzo.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
13
include/block/block_int.h | 1 -
14
block.c | 8 +++++---
15
block/block-backend.c | 4 ++--
16
blockjob.c | 3 +--
17
4 files changed, 8 insertions(+), 8 deletions(-)
18
19
diff --git a/include/block/block_int.h b/include/block/block_int.h
20
index XXXXXXX..XXXXXXX 100644
21
--- a/include/block/block_int.h
22
+++ b/include/block/block_int.h
23
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
24
const char *child_name,
25
const BdrvChildClass *child_class,
26
BdrvChildRole child_role,
27
- AioContext *ctx,
28
uint64_t perm, uint64_t shared_perm,
29
void *opaque, Error **errp);
30
void bdrv_root_unref_child(BdrvChild *child);
31
diff --git a/block.c b/block.c
32
index XXXXXXX..XXXXXXX 100644
33
--- a/block.c
34
+++ b/block.c
35
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
36
const char *child_name,
37
const BdrvChildClass *child_class,
38
BdrvChildRole child_role,
39
- AioContext *ctx,
40
uint64_t perm, uint64_t shared_perm,
41
void *opaque, Error **errp)
42
{
43
BdrvChild *child;
44
Error *local_err = NULL;
45
int ret;
46
+ AioContext *ctx;
47
48
ret = bdrv_check_update_perm(child_bs, NULL, perm, shared_perm, NULL, errp);
49
if (ret < 0) {
50
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
51
.opaque = opaque,
52
};
53
54
+ ctx = bdrv_child_get_parent_aio_context(child);
55
+
56
/* If the AioContexts don't match, first try to move the subtree of
57
* child_bs into the AioContext of the new parent. If this doesn't work,
58
* try moving the parent into the AioContext of child_bs instead. */
59
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
60
perm, shared_perm, &perm, &shared_perm);
61
62
child = bdrv_root_attach_child(child_bs, child_name, child_class,
63
- child_role, bdrv_get_aio_context(parent_bs),
64
- perm, shared_perm, parent_bs, errp);
65
+ child_role, perm, shared_perm, parent_bs,
66
+ errp);
67
if (child == NULL) {
68
return NULL;
69
}
70
diff --git a/block/block-backend.c b/block/block-backend.c
71
index XXXXXXX..XXXXXXX 100644
72
--- a/block/block-backend.c
73
+++ b/block/block-backend.c
74
@@ -XXX,XX +XXX,XX @@ BlockBackend *blk_new_open(const char *filename, const char *reference,
75
76
blk->root = bdrv_root_attach_child(bs, "root", &child_root,
77
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
78
- blk->ctx, perm, BLK_PERM_ALL, blk, errp);
79
+ perm, BLK_PERM_ALL, blk, errp);
80
if (!blk->root) {
81
blk_unref(blk);
82
return NULL;
83
@@ -XXX,XX +XXX,XX @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp)
84
bdrv_ref(bs);
85
blk->root = bdrv_root_attach_child(bs, "root", &child_root,
86
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
87
- blk->ctx, blk->perm, blk->shared_perm,
88
+ blk->perm, blk->shared_perm,
89
blk, errp);
90
if (blk->root == NULL) {
91
return -EPERM;
92
diff --git a/blockjob.c b/blockjob.c
93
index XXXXXXX..XXXXXXX 100644
94
--- a/blockjob.c
95
+++ b/blockjob.c
96
@@ -XXX,XX +XXX,XX @@ int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs,
97
if (need_context_ops && job->job.aio_context != qemu_get_aio_context()) {
98
aio_context_release(job->job.aio_context);
99
}
100
- c = bdrv_root_attach_child(bs, name, &child_job, 0,
101
- job->job.aio_context, perm, shared_perm, job,
102
+ c = bdrv_root_attach_child(bs, name, &child_job, 0, perm, shared_perm, job,
103
errp);
104
if (need_context_ops && job->job.aio_context != qemu_get_aio_context()) {
105
aio_context_acquire(job->job.aio_context);
106
--
107
2.30.2
108
109
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
These functions are called only from bdrv_reopen_multiple() in block.c.
4
No reason to publish them.
5
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Reviewed-by: Alberto Garcia <berto@igalia.com>
8
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9
Message-Id: <20210428151804.439460-8-vsementsov@virtuozzo.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
12
include/block/block.h | 4 ----
13
block.c | 13 +++++++++----
14
2 files changed, 9 insertions(+), 8 deletions(-)
15
16
diff --git a/include/block/block.h b/include/block/block.h
17
index XXXXXXX..XXXXXXX 100644
18
--- a/include/block/block.h
19
+++ b/include/block/block.h
20
@@ -XXX,XX +XXX,XX @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
21
int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp);
22
int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only,
23
Error **errp);
24
-int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
25
- BlockReopenQueue *queue, Error **errp);
26
-void bdrv_reopen_commit(BDRVReopenState *reopen_state);
27
-void bdrv_reopen_abort(BDRVReopenState *reopen_state);
28
int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset,
29
int64_t bytes, BdrvRequestFlags flags);
30
int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags);
31
diff --git a/block.c b/block.c
32
index XXXXXXX..XXXXXXX 100644
33
--- a/block.c
34
+++ b/block.c
35
@@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
36
BdrvChildRole child_role,
37
Error **errp);
38
39
+static int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue
40
+ *queue, Error **errp);
41
+static void bdrv_reopen_commit(BDRVReopenState *reopen_state);
42
+static void bdrv_reopen_abort(BDRVReopenState *reopen_state);
43
+
44
/* If non-zero, use only whitelisted block drivers */
45
static int use_bdrv_whitelist;
46
47
@@ -XXX,XX +XXX,XX @@ static int bdrv_reopen_parse_backing(BDRVReopenState *reopen_state,
48
* commit() for any other BDS that have been left in a prepare() state
49
*
50
*/
51
-int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
52
- Error **errp)
53
+static int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
54
+ BlockReopenQueue *queue, Error **errp)
55
{
56
int ret = -1;
57
int old_flags;
58
@@ -XXX,XX +XXX,XX @@ error:
59
* makes them final by swapping the staging BlockDriverState contents into
60
* the active BlockDriverState contents.
61
*/
62
-void bdrv_reopen_commit(BDRVReopenState *reopen_state)
63
+static void bdrv_reopen_commit(BDRVReopenState *reopen_state)
64
{
65
BlockDriver *drv;
66
BlockDriverState *bs;
67
@@ -XXX,XX +XXX,XX @@ void bdrv_reopen_commit(BDRVReopenState *reopen_state)
68
* Abort the reopen, and delete and free the staged changes in
69
* reopen_state
70
*/
71
-void bdrv_reopen_abort(BDRVReopenState *reopen_state)
72
+static void bdrv_reopen_abort(BDRVReopenState *reopen_state)
73
{
74
BlockDriver *drv;
75
76
--
77
2.30.2
78
79
diff view generated by jsdifflib
1
From: Stefan Hajnoczi <stefanha@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
The MAINTAINERS file was not updated when the storage daemon was merged.
3
Add simple transaction API to use in further update of block graph
4
4
operations.
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
5
6
Acked-by: Kevin Wolf <kwolf@redhat.com>
6
Supposed usage is:
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
7
8
Message-Id: <20201209103802.350848-4-stefanha@redhat.com>
8
- "prepare" is main function of the action and it should make the main
9
effect of the action to be visible for the following actions, keeping
10
possibility of roll-back, saving necessary things in action state,
11
which is prepended to the action list (to do that, prepare func
12
should call tran_add()). So, driver struct doesn't include "prepare"
13
field, as it is supposed to be called directly.
14
15
- commit/rollback is supposed to be called for the list of action
16
states, to commit/rollback all the actions in reverse order
17
18
- When possible "commit" should not make visible effect for other
19
actions, which make possible transparent logical interaction between
20
actions.
21
22
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
23
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
24
Message-Id: <20210428151804.439460-9-vsementsov@virtuozzo.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
25
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
26
---
11
MAINTAINERS | 9 +++++++++
27
include/qemu/transactions.h | 63 ++++++++++++++++++++++++
12
1 file changed, 9 insertions(+)
28
util/transactions.c | 96 +++++++++++++++++++++++++++++++++++++
13
29
MAINTAINERS | 6 +++
30
util/meson.build | 1 +
31
4 files changed, 166 insertions(+)
32
create mode 100644 include/qemu/transactions.h
33
create mode 100644 util/transactions.c
34
35
diff --git a/include/qemu/transactions.h b/include/qemu/transactions.h
36
new file mode 100644
37
index XXXXXXX..XXXXXXX
38
--- /dev/null
39
+++ b/include/qemu/transactions.h
40
@@ -XXX,XX +XXX,XX @@
41
+/*
42
+ * Simple transactions API
43
+ *
44
+ * Copyright (c) 2021 Virtuozzo International GmbH.
45
+ *
46
+ * Author:
47
+ * Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
48
+ *
49
+ * This program is free software; you can redistribute it and/or modify
50
+ * it under the terms of the GNU General Public License as published by
51
+ * the Free Software Foundation; either version 2 of the License, or
52
+ * (at your option) any later version.
53
+ *
54
+ * This program is distributed in the hope that it will be useful,
55
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
56
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
57
+ * GNU General Public License for more details.
58
+ *
59
+ * You should have received a copy of the GNU General Public License
60
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
61
+ *
62
+ *
63
+ * = Generic transaction API =
64
+ *
65
+ * The intended usage is the following: you create "prepare" functions, which
66
+ * represents the actions. They will usually have Transaction* argument, and
67
+ * call tran_add() to register finalization callbacks. For finalization
68
+ * callbacks, prepare corresponding TransactionActionDrv structures.
69
+ *
70
+ * Then, when you need to make a transaction, create an empty Transaction by
71
+ * tran_create(), call your "prepare" functions on it, and finally call
72
+ * tran_abort() or tran_commit() to finalize the transaction by corresponding
73
+ * finalization actions in reverse order.
74
+ */
75
+
76
+#ifndef QEMU_TRANSACTIONS_H
77
+#define QEMU_TRANSACTIONS_H
78
+
79
+#include <gmodule.h>
80
+
81
+typedef struct TransactionActionDrv {
82
+ void (*abort)(void *opaque);
83
+ void (*commit)(void *opaque);
84
+ void (*clean)(void *opaque);
85
+} TransactionActionDrv;
86
+
87
+typedef struct Transaction Transaction;
88
+
89
+Transaction *tran_new(void);
90
+void tran_add(Transaction *tran, TransactionActionDrv *drv, void *opaque);
91
+void tran_abort(Transaction *tran);
92
+void tran_commit(Transaction *tran);
93
+
94
+static inline void tran_finalize(Transaction *tran, int ret)
95
+{
96
+ if (ret < 0) {
97
+ tran_abort(tran);
98
+ } else {
99
+ tran_commit(tran);
100
+ }
101
+}
102
+
103
+#endif /* QEMU_TRANSACTIONS_H */
104
diff --git a/util/transactions.c b/util/transactions.c
105
new file mode 100644
106
index XXXXXXX..XXXXXXX
107
--- /dev/null
108
+++ b/util/transactions.c
109
@@ -XXX,XX +XXX,XX @@
110
+/*
111
+ * Simple transactions API
112
+ *
113
+ * Copyright (c) 2021 Virtuozzo International GmbH.
114
+ *
115
+ * Author:
116
+ * Sementsov-Ogievskiy Vladimir <vsementsov@virtuozzo.com>
117
+ *
118
+ * This program is free software; you can redistribute it and/or modify
119
+ * it under the terms of the GNU General Public License as published by
120
+ * the Free Software Foundation; either version 2 of the License, or
121
+ * (at your option) any later version.
122
+ *
123
+ * This program is distributed in the hope that it will be useful,
124
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
125
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
126
+ * GNU General Public License for more details.
127
+ *
128
+ * You should have received a copy of the GNU General Public License
129
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
130
+ */
131
+
132
+#include "qemu/osdep.h"
133
+
134
+#include "qemu/transactions.h"
135
+#include "qemu/queue.h"
136
+
137
+typedef struct TransactionAction {
138
+ TransactionActionDrv *drv;
139
+ void *opaque;
140
+ QSLIST_ENTRY(TransactionAction) entry;
141
+} TransactionAction;
142
+
143
+struct Transaction {
144
+ QSLIST_HEAD(, TransactionAction) actions;
145
+};
146
+
147
+Transaction *tran_new(void)
148
+{
149
+ Transaction *tran = g_new(Transaction, 1);
150
+
151
+ QSLIST_INIT(&tran->actions);
152
+
153
+ return tran;
154
+}
155
+
156
+void tran_add(Transaction *tran, TransactionActionDrv *drv, void *opaque)
157
+{
158
+ TransactionAction *act;
159
+
160
+ act = g_new(TransactionAction, 1);
161
+ *act = (TransactionAction) {
162
+ .drv = drv,
163
+ .opaque = opaque
164
+ };
165
+
166
+ QSLIST_INSERT_HEAD(&tran->actions, act, entry);
167
+}
168
+
169
+void tran_abort(Transaction *tran)
170
+{
171
+ TransactionAction *act, *next;
172
+
173
+ QSLIST_FOREACH_SAFE(act, &tran->actions, entry, next) {
174
+ if (act->drv->abort) {
175
+ act->drv->abort(act->opaque);
176
+ }
177
+
178
+ if (act->drv->clean) {
179
+ act->drv->clean(act->opaque);
180
+ }
181
+
182
+ g_free(act);
183
+ }
184
+
185
+ g_free(tran);
186
+}
187
+
188
+void tran_commit(Transaction *tran)
189
+{
190
+ TransactionAction *act, *next;
191
+
192
+ QSLIST_FOREACH_SAFE(act, &tran->actions, entry, next) {
193
+ if (act->drv->commit) {
194
+ act->drv->commit(act->opaque);
195
+ }
196
+
197
+ if (act->drv->clean) {
198
+ act->drv->clean(act->opaque);
199
+ }
200
+
201
+ g_free(act);
202
+ }
203
+
204
+ g_free(tran);
205
+}
14
diff --git a/MAINTAINERS b/MAINTAINERS
206
diff --git a/MAINTAINERS b/MAINTAINERS
15
index XXXXXXX..XXXXXXX 100644
207
index XXXXXXX..XXXXXXX 100644
16
--- a/MAINTAINERS
208
--- a/MAINTAINERS
17
+++ b/MAINTAINERS
209
+++ b/MAINTAINERS
18
@@ -XXX,XX +XXX,XX @@ F: qobject/block-qdict.c
210
@@ -XXX,XX +XXX,XX @@ M: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
19
F: tests/check-block-qdict.c
211
S: Maintained
20
T: git https://repo.or.cz/qemu/kevin.git block
212
F: scripts/simplebench/
21
213
22
+Storage daemon
214
+Transactions helper
23
+M: Kevin Wolf <kwolf@redhat.com>
215
+M: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
24
+L: qemu-block@nongnu.org
216
+S: Maintained
25
+S: Supported
217
+F: include/qemu/transactions.h
26
+F: storage-daemon/
218
+F: util/transactions.c
27
+F: docs/interop/qemu-storage-daemon-qmp-ref.rst
219
+
28
+F: docs/tools/qemu-storage-daemon.rst
220
QAPI
29
+T: git https://repo.or.cz/qemu/kevin.git block
221
M: Markus Armbruster <armbru@redhat.com>
30
+
222
M: Michael Roth <michael.roth@amd.com>
31
Block I/O path
223
diff --git a/util/meson.build b/util/meson.build
32
M: Stefan Hajnoczi <stefanha@redhat.com>
224
index XXXXXXX..XXXXXXX 100644
33
M: Fam Zheng <fam@euphon.net>
225
--- a/util/meson.build
226
+++ b/util/meson.build
227
@@ -XXX,XX +XXX,XX @@ util_ss.add(files('qsp.c'))
228
util_ss.add(files('range.c'))
229
util_ss.add(files('stats64.c'))
230
util_ss.add(files('systemd.c'))
231
+util_ss.add(files('transactions.c'))
232
util_ss.add(when: 'CONFIG_POSIX', if_true: files('drm.c'))
233
util_ss.add(files('guest-random.c'))
234
util_ss.add(files('yank.c'))
34
--
235
--
35
2.29.2
236
2.30.2
36
237
37
238
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
Add additional check that node parents do not interfere with each
4
other. This should not hurt existing callers and allows in further
5
patch use bdrv_refresh_perms() to update a subtree of changed
6
BdrvChild (check that change is correct).
7
8
New check will substitute bdrv_check_update_perm() in following
9
permissions refactoring, so keep error messages the same to avoid
10
unit test result changes.
11
12
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
13
Reviewed-by: Alberto Garcia <berto@igalia.com>
14
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
15
Message-Id: <20210428151804.439460-10-vsementsov@virtuozzo.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
---
18
block.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++---------
19
1 file changed, 54 insertions(+), 9 deletions(-)
20
21
diff --git a/block.c b/block.c
22
index XXXXXXX..XXXXXXX 100644
23
--- a/block.c
24
+++ b/block.c
25
@@ -XXX,XX +XXX,XX @@ bool bdrv_is_writable(BlockDriverState *bs)
26
return bdrv_is_writable_after_reopen(bs, NULL);
27
}
28
29
+static char *bdrv_child_user_desc(BdrvChild *c)
30
+{
31
+ if (c->klass->get_parent_desc) {
32
+ return c->klass->get_parent_desc(c);
33
+ }
34
+
35
+ return g_strdup("another user");
36
+}
37
+
38
+static bool bdrv_a_allow_b(BdrvChild *a, BdrvChild *b, Error **errp)
39
+{
40
+ g_autofree char *user = NULL;
41
+ g_autofree char *perm_names = NULL;
42
+
43
+ if ((b->perm & a->shared_perm) == b->perm) {
44
+ return true;
45
+ }
46
+
47
+ perm_names = bdrv_perm_names(b->perm & ~a->shared_perm);
48
+ user = bdrv_child_user_desc(a);
49
+ error_setg(errp, "Conflicts with use by %s as '%s', which does not "
50
+ "allow '%s' on %s",
51
+ user, a->name, perm_names, bdrv_get_node_name(b->bs));
52
+
53
+ return false;
54
+}
55
+
56
+static bool bdrv_parent_perms_conflict(BlockDriverState *bs, Error **errp)
57
+{
58
+ BdrvChild *a, *b;
59
+
60
+ /*
61
+ * During the loop we'll look at each pair twice. That's correct because
62
+ * bdrv_a_allow_b() is asymmetric and we should check each pair in both
63
+ * directions.
64
+ */
65
+ QLIST_FOREACH(a, &bs->parents, next_parent) {
66
+ QLIST_FOREACH(b, &bs->parents, next_parent) {
67
+ if (a == b) {
68
+ continue;
69
+ }
70
+
71
+ if (!bdrv_a_allow_b(a, b, errp)) {
72
+ return true;
73
+ }
74
+ }
75
+ }
76
+
77
+ return false;
78
+}
79
+
80
static void bdrv_child_perm(BlockDriverState *bs, BlockDriverState *child_bs,
81
BdrvChild *c, BdrvChildRole role,
82
BlockReopenQueue *reopen_queue,
83
@@ -XXX,XX +XXX,XX @@ void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm,
84
*shared_perm = cumulative_shared_perms;
85
}
86
87
-static char *bdrv_child_user_desc(BdrvChild *c)
88
-{
89
- if (c->klass->get_parent_desc) {
90
- return c->klass->get_parent_desc(c);
91
- }
92
-
93
- return g_strdup("another user");
94
-}
95
-
96
char *bdrv_perm_names(uint64_t perm)
97
{
98
struct perm_name {
99
@@ -XXX,XX +XXX,XX @@ static int bdrv_refresh_perms(BlockDriverState *bs, Error **errp)
100
int ret;
101
uint64_t perm, shared_perm;
102
103
+ if (bdrv_parent_perms_conflict(bs, errp)) {
104
+ return -EPERM;
105
+ }
106
bdrv_get_cumulative_perm(bs, &perm, &shared_perm);
107
ret = bdrv_check_perm(bs, NULL, perm, shared_perm, NULL, errp);
108
if (ret < 0) {
109
--
110
2.30.2
111
112
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
Split out non-recursive parts, and refactor as block graph transaction
4
action.
5
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
8
Message-Id: <20210428151804.439460-11-vsementsov@virtuozzo.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
block.c | 79 ++++++++++++++++++++++++++++++++++++++++++---------------
12
1 file changed, 59 insertions(+), 20 deletions(-)
13
14
diff --git a/block.c b/block.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/block.c
17
+++ b/block.c
18
@@ -XXX,XX +XXX,XX @@
19
#include "qemu/timer.h"
20
#include "qemu/cutils.h"
21
#include "qemu/id.h"
22
+#include "qemu/transactions.h"
23
#include "block/coroutines.h"
24
25
#ifdef CONFIG_BSD
26
@@ -XXX,XX +XXX,XX @@ static void bdrv_child_perm(BlockDriverState *bs, BlockDriverState *child_bs,
27
}
28
}
29
30
+static void bdrv_child_set_perm_commit(void *opaque)
31
+{
32
+ BdrvChild *c = opaque;
33
+
34
+ c->has_backup_perm = false;
35
+}
36
+
37
+static void bdrv_child_set_perm_abort(void *opaque)
38
+{
39
+ BdrvChild *c = opaque;
40
+ /*
41
+ * We may have child->has_backup_perm unset at this point, as in case of
42
+ * _check_ stage of permission update failure we may _check_ not the whole
43
+ * subtree. Still, _abort_ is called on the whole subtree anyway.
44
+ */
45
+ if (c->has_backup_perm) {
46
+ c->perm = c->backup_perm;
47
+ c->shared_perm = c->backup_shared_perm;
48
+ c->has_backup_perm = false;
49
+ }
50
+}
51
+
52
+static TransactionActionDrv bdrv_child_set_pem_drv = {
53
+ .abort = bdrv_child_set_perm_abort,
54
+ .commit = bdrv_child_set_perm_commit,
55
+};
56
+
57
+/*
58
+ * With tran=NULL needs to be followed by direct call to either
59
+ * bdrv_child_set_perm_commit() or bdrv_child_set_perm_abort().
60
+ *
61
+ * With non-NULL tran needs to be followed by tran_abort() or tran_commit()
62
+ * instead.
63
+ */
64
+static void bdrv_child_set_perm_safe(BdrvChild *c, uint64_t perm,
65
+ uint64_t shared, Transaction *tran)
66
+{
67
+ if (!c->has_backup_perm) {
68
+ c->has_backup_perm = true;
69
+ c->backup_perm = c->perm;
70
+ c->backup_shared_perm = c->shared_perm;
71
+ }
72
+ /*
73
+ * Note: it's OK if c->has_backup_perm was already set, as we can find the
74
+ * same c twice during check_perm procedure
75
+ */
76
+
77
+ c->perm = perm;
78
+ c->shared_perm = shared;
79
+
80
+ if (tran) {
81
+ tran_add(tran, &bdrv_child_set_pem_drv, c);
82
+ }
83
+}
84
+
85
/*
86
* Check whether permissions on this node can be changed in a way that
87
* @cumulative_perms and @cumulative_shared_perms are the new cumulative
88
@@ -XXX,XX +XXX,XX @@ static int bdrv_child_check_perm(BdrvChild *c, BlockReopenQueue *q,
89
return ret;
90
}
91
92
- if (!c->has_backup_perm) {
93
- c->has_backup_perm = true;
94
- c->backup_perm = c->perm;
95
- c->backup_shared_perm = c->shared_perm;
96
- }
97
- /*
98
- * Note: it's OK if c->has_backup_perm was already set, as we can find the
99
- * same child twice during check_perm procedure
100
- */
101
-
102
- c->perm = perm;
103
- c->shared_perm = shared;
104
+ bdrv_child_set_perm_safe(c, perm, shared, NULL);
105
106
return 0;
107
}
108
109
static void bdrv_child_set_perm(BdrvChild *c)
110
{
111
- c->has_backup_perm = false;
112
-
113
+ bdrv_child_set_perm_commit(c);
114
bdrv_set_perm(c->bs);
115
}
116
117
static void bdrv_child_abort_perm_update(BdrvChild *c)
118
{
119
- if (c->has_backup_perm) {
120
- c->perm = c->backup_perm;
121
- c->shared_perm = c->backup_shared_perm;
122
- c->has_backup_perm = false;
123
- }
124
-
125
+ bdrv_child_set_perm_abort(c);
126
bdrv_abort_perm_update(c->bs);
127
}
128
129
--
130
2.30.2
131
132
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
We are going to drop recursive bdrv_child_* functions, so stop use them
4
in bdrv_child_try_set_perm() as a first step.
5
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
8
Message-Id: <20210428151804.439460-12-vsementsov@virtuozzo.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
block.c | 14 ++++++++------
12
1 file changed, 8 insertions(+), 6 deletions(-)
13
14
diff --git a/block.c b/block.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/block.c
17
+++ b/block.c
18
@@ -XXX,XX +XXX,XX @@ int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared,
19
Error **errp)
20
{
21
Error *local_err = NULL;
22
+ Transaction *tran = tran_new();
23
int ret;
24
25
- ret = bdrv_child_check_perm(c, NULL, perm, shared, NULL, &local_err);
26
+ bdrv_child_set_perm_safe(c, perm, shared, tran);
27
+
28
+ ret = bdrv_refresh_perms(c->bs, &local_err);
29
+
30
+ tran_finalize(tran, ret);
31
+
32
if (ret < 0) {
33
- bdrv_child_abort_perm_update(c);
34
if ((perm & ~c->perm) || (c->shared_perm & ~shared)) {
35
/* tighten permissions */
36
error_propagate(errp, local_err);
37
@@ -XXX,XX +XXX,XX @@ int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared,
38
error_free(local_err);
39
ret = 0;
40
}
41
- return ret;
42
}
43
44
- bdrv_child_set_perm(c);
45
-
46
- return 0;
47
+ return ret;
48
}
49
50
int bdrv_child_refresh_perms(BlockDriverState *bs, BdrvChild *c, Error **errp)
51
--
52
2.30.2
53
54
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
Signed-off-by: Markus Armbruster <armbru@redhat.com>
3
Each of them has only one caller. Open-coding simplifies further
4
Message-Id: <20201217162003.1102738-9-armbru@redhat.com>
4
pemission-update system changes.
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
5
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Reviewed-by: Alberto Garcia <berto@igalia.com>
8
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9
Message-Id: <20210428151804.439460-13-vsementsov@virtuozzo.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
11
---
8
block/vpc.c | 14 +++++++-------
12
block.c | 59 +++++++++++++++++----------------------------------------
9
1 file changed, 7 insertions(+), 7 deletions(-)
13
1 file changed, 17 insertions(+), 42 deletions(-)
10
14
11
diff --git a/block/vpc.c b/block/vpc.c
15
diff --git a/block.c b/block.c
12
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
13
--- a/block/vpc.c
17
--- a/block.c
14
+++ b/block/vpc.c
18
+++ b/block.c
15
@@ -XXX,XX +XXX,XX @@ static int calculate_geometry(int64_t total_sectors, uint16_t *cyls,
19
@@ -XXX,XX +XXX,XX @@ static int bdrv_fill_options(QDict **options, const char *filename,
16
return 0;
20
return 0;
17
}
21
}
18
22
19
-static int create_dynamic_disk(BlockBackend *blk, uint8_t *buf,
23
-static int bdrv_child_check_perm(BdrvChild *c, BlockReopenQueue *q,
20
+static int create_dynamic_disk(BlockBackend *blk, VHDFooter *footer,
24
- uint64_t perm, uint64_t shared,
21
int64_t total_sectors)
25
- GSList *ignore_children, Error **errp);
22
{
26
-static void bdrv_child_abort_perm_update(BdrvChild *c);
23
VHDDynDiskHeader dyndisk_header;
27
-static void bdrv_child_set_perm(BdrvChild *c);
24
@@ -XXX,XX +XXX,XX @@ static int create_dynamic_disk(BlockBackend *blk, uint8_t *buf,
28
+static int bdrv_check_update_perm(BlockDriverState *bs, BlockReopenQueue *q,
25
block_size = 0x200000;
29
+ uint64_t new_used_perm,
26
num_bat_entries = DIV_ROUND_UP(total_sectors, block_size / 512);
30
+ uint64_t new_shared_perm,
27
31
+ GSList *ignore_children,
28
- ret = blk_pwrite(blk, offset, buf, HEADER_SIZE, 0);
32
+ Error **errp);
29
+ ret = blk_pwrite(blk, offset, footer, HEADER_SIZE, 0);
33
30
if (ret < 0) {
34
typedef struct BlockReopenQueueEntry {
31
goto fail;
35
bool prepared;
36
@@ -XXX,XX +XXX,XX @@ static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q,
37
/* Check all children */
38
QLIST_FOREACH(c, &bs->children, next) {
39
uint64_t cur_perm, cur_shared;
40
+ GSList *cur_ignore_children;
41
42
bdrv_child_perm(bs, c->bs, c, c->role, q,
43
cumulative_perms, cumulative_shared_perms,
44
&cur_perm, &cur_shared);
45
- ret = bdrv_child_check_perm(c, q, cur_perm, cur_shared, ignore_children,
46
- errp);
47
+
48
+ cur_ignore_children = g_slist_prepend(g_slist_copy(ignore_children), c);
49
+ ret = bdrv_check_update_perm(c->bs, q, cur_perm, cur_shared,
50
+ cur_ignore_children, errp);
51
+ g_slist_free(cur_ignore_children);
52
if (ret < 0) {
53
return ret;
54
}
55
+
56
+ bdrv_child_set_perm_safe(c, cur_perm, cur_shared, NULL);
32
}
57
}
33
58
34
offset = 1536 + ((num_bat_entries * 4 + 511) & ~511);
59
return 0;
35
- ret = blk_pwrite(blk, offset, buf, HEADER_SIZE, 0);
60
@@ -XXX,XX +XXX,XX @@ static void bdrv_abort_perm_update(BlockDriverState *bs)
36
+ ret = blk_pwrite(blk, offset, footer, HEADER_SIZE, 0);
37
if (ret < 0) {
38
goto fail;
39
}
61
}
40
@@ -XXX,XX +XXX,XX @@ static int create_dynamic_disk(BlockBackend *blk, uint8_t *buf,
62
41
return ret;
63
QLIST_FOREACH(c, &bs->children, next) {
64
- bdrv_child_abort_perm_update(c);
65
+ bdrv_child_set_perm_abort(c);
66
+ bdrv_abort_perm_update(c->bs);
67
}
42
}
68
}
43
69
44
-static int create_fixed_disk(BlockBackend *blk, uint8_t *buf,
70
@@ -XXX,XX +XXX,XX @@ static void bdrv_set_perm(BlockDriverState *bs)
45
+static int create_fixed_disk(BlockBackend *blk, VHDFooter *footer,
71
46
int64_t total_size, Error **errp)
72
/* Update all children */
73
QLIST_FOREACH(c, &bs->children, next) {
74
- bdrv_child_set_perm(c);
75
+ bdrv_child_set_perm_commit(c);
76
+ bdrv_set_perm(c->bs);
77
}
78
}
79
80
@@ -XXX,XX +XXX,XX @@ static int bdrv_check_update_perm(BlockDriverState *bs, BlockReopenQueue *q,
81
ignore_children, errp);
82
}
83
84
-/* Needs to be followed by a call to either bdrv_child_set_perm() or
85
- * bdrv_child_abort_perm_update(). */
86
-static int bdrv_child_check_perm(BdrvChild *c, BlockReopenQueue *q,
87
- uint64_t perm, uint64_t shared,
88
- GSList *ignore_children, Error **errp)
89
-{
90
- int ret;
91
-
92
- ignore_children = g_slist_prepend(g_slist_copy(ignore_children), c);
93
- ret = bdrv_check_update_perm(c->bs, q, perm, shared, ignore_children, errp);
94
- g_slist_free(ignore_children);
95
-
96
- if (ret < 0) {
97
- return ret;
98
- }
99
-
100
- bdrv_child_set_perm_safe(c, perm, shared, NULL);
101
-
102
- return 0;
103
-}
104
-
105
-static void bdrv_child_set_perm(BdrvChild *c)
106
-{
107
- bdrv_child_set_perm_commit(c);
108
- bdrv_set_perm(c->bs);
109
-}
110
-
111
-static void bdrv_child_abort_perm_update(BdrvChild *c)
112
-{
113
- bdrv_child_set_perm_abort(c);
114
- bdrv_abort_perm_update(c->bs);
115
-}
116
-
117
static int bdrv_refresh_perms(BlockDriverState *bs, Error **errp)
47
{
118
{
48
int ret;
119
int ret;
49
@@ -XXX,XX +XXX,XX @@ static int create_fixed_disk(BlockBackend *blk, uint8_t *buf,
50
return ret;
51
}
52
53
- ret = blk_pwrite(blk, total_size - HEADER_SIZE, buf, HEADER_SIZE, 0);
54
+ ret = blk_pwrite(blk, total_size - HEADER_SIZE, footer, HEADER_SIZE, 0);
55
if (ret < 0) {
56
error_setg_errno(errp, -ret, "Unable to write VHD header");
57
return ret;
58
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_create(BlockdevCreateOptions *opts,
59
footer.checksum = cpu_to_be32(vpc_checksum(&footer, HEADER_SIZE));
60
61
if (disk_type == VHD_DYNAMIC) {
62
- ret = create_dynamic_disk(blk, (uint8_t *)&footer, total_sectors);
63
+ ret = create_dynamic_disk(blk, &footer, total_sectors);
64
if (ret < 0) {
65
error_setg(errp, "Unable to create or write VHD header");
66
}
67
} else {
68
- ret = create_fixed_disk(blk, (uint8_t *)&footer, total_size, errp);
69
+ ret = create_fixed_disk(blk, &footer, total_size, errp);
70
}
71
72
out:
73
--
120
--
74
2.29.2
121
2.30.2
75
122
76
123
diff view generated by jsdifflib
New patch
1
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
3
Rewrite bdrv_check_perm(), bdrv_abort_perm_update() and bdrv_set_perm()
4
to update nodes in topological sort order instead of simple DFS. With
5
topologically sorted nodes, we update a node only when all its parents
6
already updated. With DFS it's not so.
7
8
Consider the following example:
9
10
A -+
11
| |
12
| v
13
| B
14
| |
15
v |
16
C<-+
17
18
A is parent for B and C, B is parent for C.
19
20
Obviously, to update permissions, we should go in order A B C, so, when
21
we update C, all parent permissions already updated. But with current
22
approach (simple recursion) we can update in sequence A C B C (C is
23
updated twice). On first update of C, we consider old B permissions, so
24
doing wrong thing. If it succeed, all is OK, on second C update we will
25
finish with correct graph. But if the wrong thing failed, we break the
26
whole process for no reason (it's possible that updated B permission
27
will be less strict, but we will never check it).
28
29
Also new approach gives a way to simultaneously and correctly update
30
several nodes, we just need to run bdrv_topological_dfs() several times
31
to add all nodes and their subtrees into one topologically sorted list
32
(next patch will update bdrv_replace_node() in this manner).
33
34
Test test_parallel_perm_update() is now passing, so move it out of
35
debugging "if".
36
37
We also need to support ignore_children in
38
bdrv_parent_perms_conflict()
39
40
For test 283 order of conflicting parents check is changed.
41
42
Note also that in bdrv_check_perm() we don't check for parents conflict
43
at root bs, as we may be in the middle of permission update in
44
bdrv_reopen_multiple(). bdrv_reopen_multiple() will be updated soon.
45
46
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
47
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
48
Message-Id: <20210428151804.439460-14-vsementsov@virtuozzo.com>
49
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
50
---
51
block.c | 116 +++++++++++++++++++++++++------
52
tests/unit/test-bdrv-graph-mod.c | 4 +-
53
tests/qemu-iotests/283.out | 2 +-
54
3 files changed, 99 insertions(+), 23 deletions(-)
55
56
diff --git a/block.c b/block.c
57
index XXXXXXX..XXXXXXX 100644
58
--- a/block.c
59
+++ b/block.c
60
@@ -XXX,XX +XXX,XX @@ static bool bdrv_a_allow_b(BdrvChild *a, BdrvChild *b, Error **errp)
61
return false;
62
}
63
64
-static bool bdrv_parent_perms_conflict(BlockDriverState *bs, Error **errp)
65
+static bool bdrv_parent_perms_conflict(BlockDriverState *bs,
66
+ GSList *ignore_children,
67
+ Error **errp)
68
{
69
BdrvChild *a, *b;
70
71
@@ -XXX,XX +XXX,XX @@ static bool bdrv_parent_perms_conflict(BlockDriverState *bs, Error **errp)
72
* directions.
73
*/
74
QLIST_FOREACH(a, &bs->parents, next_parent) {
75
+ if (g_slist_find(ignore_children, a)) {
76
+ continue;
77
+ }
78
+
79
QLIST_FOREACH(b, &bs->parents, next_parent) {
80
- if (a == b) {
81
+ if (a == b || g_slist_find(ignore_children, b)) {
82
continue;
83
}
84
85
@@ -XXX,XX +XXX,XX @@ static void bdrv_child_perm(BlockDriverState *bs, BlockDriverState *child_bs,
86
}
87
}
88
89
+/*
90
+ * Adds the whole subtree of @bs (including @bs itself) to the @list (except for
91
+ * nodes that are already in the @list, of course) so that final list is
92
+ * topologically sorted. Return the result (GSList @list object is updated, so
93
+ * don't use old reference after function call).
94
+ *
95
+ * On function start @list must be already topologically sorted and for any node
96
+ * in the @list the whole subtree of the node must be in the @list as well. The
97
+ * simplest way to satisfy this criteria: use only result of
98
+ * bdrv_topological_dfs() or NULL as @list parameter.
99
+ */
100
+static GSList *bdrv_topological_dfs(GSList *list, GHashTable *found,
101
+ BlockDriverState *bs)
102
+{
103
+ BdrvChild *child;
104
+ g_autoptr(GHashTable) local_found = NULL;
105
+
106
+ if (!found) {
107
+ assert(!list);
108
+ found = local_found = g_hash_table_new(NULL, NULL);
109
+ }
110
+
111
+ if (g_hash_table_contains(found, bs)) {
112
+ return list;
113
+ }
114
+ g_hash_table_add(found, bs);
115
+
116
+ QLIST_FOREACH(child, &bs->children, next) {
117
+ list = bdrv_topological_dfs(list, found, child->bs);
118
+ }
119
+
120
+ return g_slist_prepend(list, bs);
121
+}
122
+
123
static void bdrv_child_set_perm_commit(void *opaque)
124
{
125
BdrvChild *c = opaque;
126
@@ -XXX,XX +XXX,XX @@ static void bdrv_child_set_perm_safe(BdrvChild *c, uint64_t perm,
127
* A call to this function must always be followed by a call to bdrv_set_perm()
128
* or bdrv_abort_perm_update().
129
*/
130
-static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q,
131
- uint64_t cumulative_perms,
132
- uint64_t cumulative_shared_perms,
133
- GSList *ignore_children, Error **errp)
134
+static int bdrv_node_check_perm(BlockDriverState *bs, BlockReopenQueue *q,
135
+ uint64_t cumulative_perms,
136
+ uint64_t cumulative_shared_perms,
137
+ GSList *ignore_children, Error **errp)
138
{
139
BlockDriver *drv = bs->drv;
140
BdrvChild *c;
141
@@ -XXX,XX +XXX,XX @@ static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q,
142
/* Check all children */
143
QLIST_FOREACH(c, &bs->children, next) {
144
uint64_t cur_perm, cur_shared;
145
- GSList *cur_ignore_children;
146
147
bdrv_child_perm(bs, c->bs, c, c->role, q,
148
cumulative_perms, cumulative_shared_perms,
149
&cur_perm, &cur_shared);
150
+ bdrv_child_set_perm_safe(c, cur_perm, cur_shared, NULL);
151
+ }
152
+
153
+ return 0;
154
+}
155
+
156
+static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q,
157
+ uint64_t cumulative_perms,
158
+ uint64_t cumulative_shared_perms,
159
+ GSList *ignore_children, Error **errp)
160
+{
161
+ int ret;
162
+ BlockDriverState *root = bs;
163
+ g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, root);
164
165
- cur_ignore_children = g_slist_prepend(g_slist_copy(ignore_children), c);
166
- ret = bdrv_check_update_perm(c->bs, q, cur_perm, cur_shared,
167
- cur_ignore_children, errp);
168
- g_slist_free(cur_ignore_children);
169
+ for ( ; list; list = list->next) {
170
+ bs = list->data;
171
+
172
+ if (bs != root) {
173
+ if (bdrv_parent_perms_conflict(bs, ignore_children, errp)) {
174
+ return -EINVAL;
175
+ }
176
+
177
+ bdrv_get_cumulative_perm(bs, &cumulative_perms,
178
+ &cumulative_shared_perms);
179
+ }
180
+
181
+ ret = bdrv_node_check_perm(bs, q, cumulative_perms,
182
+ cumulative_shared_perms,
183
+ ignore_children, errp);
184
if (ret < 0) {
185
return ret;
186
}
187
-
188
- bdrv_child_set_perm_safe(c, cur_perm, cur_shared, NULL);
189
}
190
191
return 0;
192
@@ -XXX,XX +XXX,XX @@ static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q,
193
* Notifies drivers that after a previous bdrv_check_perm() call, the
194
* permission update is not performed and any preparations made for it (e.g.
195
* taken file locks) need to be undone.
196
- *
197
- * This function recursively notifies all child nodes.
198
*/
199
-static void bdrv_abort_perm_update(BlockDriverState *bs)
200
+static void bdrv_node_abort_perm_update(BlockDriverState *bs)
201
{
202
BlockDriver *drv = bs->drv;
203
BdrvChild *c;
204
@@ -XXX,XX +XXX,XX @@ static void bdrv_abort_perm_update(BlockDriverState *bs)
205
206
QLIST_FOREACH(c, &bs->children, next) {
207
bdrv_child_set_perm_abort(c);
208
- bdrv_abort_perm_update(c->bs);
209
}
210
}
211
212
-static void bdrv_set_perm(BlockDriverState *bs)
213
+static void bdrv_abort_perm_update(BlockDriverState *bs)
214
+{
215
+ g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, bs);
216
+
217
+ for ( ; list; list = list->next) {
218
+ bdrv_node_abort_perm_update((BlockDriverState *)list->data);
219
+ }
220
+}
221
+
222
+static void bdrv_node_set_perm(BlockDriverState *bs)
223
{
224
uint64_t cumulative_perms, cumulative_shared_perms;
225
BlockDriver *drv = bs->drv;
226
@@ -XXX,XX +XXX,XX @@ static void bdrv_set_perm(BlockDriverState *bs)
227
/* Update all children */
228
QLIST_FOREACH(c, &bs->children, next) {
229
bdrv_child_set_perm_commit(c);
230
- bdrv_set_perm(c->bs);
231
+ }
232
+}
233
+
234
+static void bdrv_set_perm(BlockDriverState *bs)
235
+{
236
+ g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, bs);
237
+
238
+ for ( ; list; list = list->next) {
239
+ bdrv_node_set_perm((BlockDriverState *)list->data);
240
}
241
}
242
243
@@ -XXX,XX +XXX,XX @@ static int bdrv_refresh_perms(BlockDriverState *bs, Error **errp)
244
int ret;
245
uint64_t perm, shared_perm;
246
247
- if (bdrv_parent_perms_conflict(bs, errp)) {
248
+ if (bdrv_parent_perms_conflict(bs, NULL, errp)) {
249
return -EPERM;
250
}
251
bdrv_get_cumulative_perm(bs, &perm, &shared_perm);
252
diff --git a/tests/unit/test-bdrv-graph-mod.c b/tests/unit/test-bdrv-graph-mod.c
253
index XXXXXXX..XXXXXXX 100644
254
--- a/tests/unit/test-bdrv-graph-mod.c
255
+++ b/tests/unit/test-bdrv-graph-mod.c
256
@@ -XXX,XX +XXX,XX @@ int main(int argc, char *argv[])
257
g_test_add_func("/bdrv-graph-mod/update-perm-tree", test_update_perm_tree);
258
g_test_add_func("/bdrv-graph-mod/should-update-child",
259
test_should_update_child);
260
+ g_test_add_func("/bdrv-graph-mod/parallel-perm-update",
261
+ test_parallel_perm_update);
262
263
if (debug) {
264
g_test_add_func("/bdrv-graph-mod/parallel-exclusive-write",
265
test_parallel_exclusive_write);
266
- g_test_add_func("/bdrv-graph-mod/parallel-perm-update",
267
- test_parallel_perm_update);
268
g_test_add_func("/bdrv-graph-mod/append-greedy-filter",
269
test_append_greedy_filter);
270
}
271
diff --git a/tests/qemu-iotests/283.out b/tests/qemu-iotests/283.out
272
index XXXXXXX..XXXXXXX 100644
273
--- a/tests/qemu-iotests/283.out
274
+++ b/tests/qemu-iotests/283.out
275
@@ -XXX,XX +XXX,XX @@
276
{"execute": "blockdev-add", "arguments": {"driver": "blkdebug", "image": "base", "node-name": "other", "take-child-perms": ["write"]}}
277
{"return": {}}
278
{"execute": "blockdev-backup", "arguments": {"device": "source", "sync": "full", "target": "target"}}
279
-{"error": {"class": "GenericError", "desc": "Cannot set permissions for backup-top filter: Conflicts with use by other as 'image', which uses 'write' on base"}}
280
+{"error": {"class": "GenericError", "desc": "Cannot set permissions for backup-top filter: Conflicts with use by source as 'image', which does not allow 'write' on base"}}
281
282
=== backup-top should be gone after job-finalize ===
283
284
--
285
2.30.2
286
287
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
Refactor calling driver callbacks to a separate transaction action to
4
be used later.
5
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
8
Message-Id: <20210428151804.439460-15-vsementsov@virtuozzo.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
block.c | 70 ++++++++++++++++++++++++++++++++++++++++++++-------------
12
1 file changed, 54 insertions(+), 16 deletions(-)
13
14
diff --git a/block.c b/block.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/block.c
17
+++ b/block.c
18
@@ -XXX,XX +XXX,XX @@ static void bdrv_child_set_perm_safe(BdrvChild *c, uint64_t perm,
19
}
20
}
21
22
+static void bdrv_drv_set_perm_commit(void *opaque)
23
+{
24
+ BlockDriverState *bs = opaque;
25
+ uint64_t cumulative_perms, cumulative_shared_perms;
26
+
27
+ if (bs->drv->bdrv_set_perm) {
28
+ bdrv_get_cumulative_perm(bs, &cumulative_perms,
29
+ &cumulative_shared_perms);
30
+ bs->drv->bdrv_set_perm(bs, cumulative_perms, cumulative_shared_perms);
31
+ }
32
+}
33
+
34
+static void bdrv_drv_set_perm_abort(void *opaque)
35
+{
36
+ BlockDriverState *bs = opaque;
37
+
38
+ if (bs->drv->bdrv_abort_perm_update) {
39
+ bs->drv->bdrv_abort_perm_update(bs);
40
+ }
41
+}
42
+
43
+TransactionActionDrv bdrv_drv_set_perm_drv = {
44
+ .abort = bdrv_drv_set_perm_abort,
45
+ .commit = bdrv_drv_set_perm_commit,
46
+};
47
+
48
+static int bdrv_drv_set_perm(BlockDriverState *bs, uint64_t perm,
49
+ uint64_t shared_perm, Transaction *tran,
50
+ Error **errp)
51
+{
52
+ if (!bs->drv) {
53
+ return 0;
54
+ }
55
+
56
+ if (bs->drv->bdrv_check_perm) {
57
+ int ret = bs->drv->bdrv_check_perm(bs, perm, shared_perm, errp);
58
+ if (ret < 0) {
59
+ return ret;
60
+ }
61
+ }
62
+
63
+ if (tran) {
64
+ tran_add(tran, &bdrv_drv_set_perm_drv, bs);
65
+ }
66
+
67
+ return 0;
68
+}
69
+
70
/*
71
* Check whether permissions on this node can be changed in a way that
72
* @cumulative_perms and @cumulative_shared_perms are the new cumulative
73
@@ -XXX,XX +XXX,XX @@ static int bdrv_node_check_perm(BlockDriverState *bs, BlockReopenQueue *q,
74
return 0;
75
}
76
77
- if (drv->bdrv_check_perm) {
78
- ret = drv->bdrv_check_perm(bs, cumulative_perms,
79
- cumulative_shared_perms, errp);
80
- if (ret < 0) {
81
- return ret;
82
- }
83
+ ret = bdrv_drv_set_perm(bs, cumulative_perms, cumulative_shared_perms, NULL,
84
+ errp);
85
+ if (ret < 0) {
86
+ return ret;
87
}
88
89
/* Drivers that never have children can omit .bdrv_child_perm() */
90
@@ -XXX,XX +XXX,XX @@ static void bdrv_node_abort_perm_update(BlockDriverState *bs)
91
return;
92
}
93
94
- if (drv->bdrv_abort_perm_update) {
95
- drv->bdrv_abort_perm_update(bs);
96
- }
97
+ bdrv_drv_set_perm_abort(bs);
98
99
QLIST_FOREACH(c, &bs->children, next) {
100
bdrv_child_set_perm_abort(c);
101
@@ -XXX,XX +XXX,XX @@ static void bdrv_abort_perm_update(BlockDriverState *bs)
102
103
static void bdrv_node_set_perm(BlockDriverState *bs)
104
{
105
- uint64_t cumulative_perms, cumulative_shared_perms;
106
BlockDriver *drv = bs->drv;
107
BdrvChild *c;
108
109
@@ -XXX,XX +XXX,XX @@ static void bdrv_node_set_perm(BlockDriverState *bs)
110
return;
111
}
112
113
- bdrv_get_cumulative_perm(bs, &cumulative_perms, &cumulative_shared_perms);
114
-
115
- /* Update this node */
116
- if (drv->bdrv_set_perm) {
117
- drv->bdrv_set_perm(bs, cumulative_perms, cumulative_shared_perms);
118
- }
119
+ bdrv_drv_set_perm_commit(bs);
120
121
/* Drivers that never have children can omit .bdrv_child_perm() */
122
if (!drv->bdrv_child_perm) {
123
--
124
2.30.2
125
126
diff view generated by jsdifflib
New patch
1
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
3
Add new interface, allowing use of existing node list. It will be used
4
to fix bdrv_replace_node() in the further commit.
5
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
8
Message-Id: <20210428151804.439460-16-vsementsov@virtuozzo.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
block.c | 106 +++++++++++++++++++++++++++++++++++++-------------------
12
1 file changed, 71 insertions(+), 35 deletions(-)
13
14
diff --git a/block.c b/block.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/block.c
17
+++ b/block.c
18
@@ -XXX,XX +XXX,XX @@ static int bdrv_drv_set_perm(BlockDriverState *bs, uint64_t perm,
19
static int bdrv_node_check_perm(BlockDriverState *bs, BlockReopenQueue *q,
20
uint64_t cumulative_perms,
21
uint64_t cumulative_shared_perms,
22
- GSList *ignore_children, Error **errp)
23
+ GSList *ignore_children,
24
+ Transaction *tran, Error **errp)
25
{
26
BlockDriver *drv = bs->drv;
27
BdrvChild *c;
28
@@ -XXX,XX +XXX,XX @@ static int bdrv_node_check_perm(BlockDriverState *bs, BlockReopenQueue *q,
29
return 0;
30
}
31
32
- ret = bdrv_drv_set_perm(bs, cumulative_perms, cumulative_shared_perms, NULL,
33
+ ret = bdrv_drv_set_perm(bs, cumulative_perms, cumulative_shared_perms, tran,
34
errp);
35
if (ret < 0) {
36
return ret;
37
@@ -XXX,XX +XXX,XX @@ static int bdrv_node_check_perm(BlockDriverState *bs, BlockReopenQueue *q,
38
bdrv_child_perm(bs, c->bs, c, c->role, q,
39
cumulative_perms, cumulative_shared_perms,
40
&cur_perm, &cur_shared);
41
- bdrv_child_set_perm_safe(c, cur_perm, cur_shared, NULL);
42
+ bdrv_child_set_perm_safe(c, cur_perm, cur_shared, tran);
43
}
44
45
return 0;
46
}
47
48
-static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q,
49
- uint64_t cumulative_perms,
50
- uint64_t cumulative_shared_perms,
51
- GSList *ignore_children, Error **errp)
52
+/*
53
+ * If use_cumulative_perms is true, use cumulative_perms and
54
+ * cumulative_shared_perms for first element of the list. Otherwise just refresh
55
+ * all permissions.
56
+ */
57
+static int bdrv_check_perm_common(GSList *list, BlockReopenQueue *q,
58
+ bool use_cumulative_perms,
59
+ uint64_t cumulative_perms,
60
+ uint64_t cumulative_shared_perms,
61
+ GSList *ignore_children,
62
+ Transaction *tran, Error **errp)
63
{
64
int ret;
65
- BlockDriverState *root = bs;
66
- g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, root);
67
+ BlockDriverState *bs;
68
69
- for ( ; list; list = list->next) {
70
+ if (use_cumulative_perms) {
71
bs = list->data;
72
73
- if (bs != root) {
74
- if (bdrv_parent_perms_conflict(bs, ignore_children, errp)) {
75
- return -EINVAL;
76
- }
77
+ ret = bdrv_node_check_perm(bs, q, cumulative_perms,
78
+ cumulative_shared_perms,
79
+ ignore_children, tran, errp);
80
+ if (ret < 0) {
81
+ return ret;
82
+ }
83
84
- bdrv_get_cumulative_perm(bs, &cumulative_perms,
85
- &cumulative_shared_perms);
86
+ list = list->next;
87
+ }
88
+
89
+ for ( ; list; list = list->next) {
90
+ bs = list->data;
91
+
92
+ if (bdrv_parent_perms_conflict(bs, ignore_children, errp)) {
93
+ return -EINVAL;
94
}
95
96
+ bdrv_get_cumulative_perm(bs, &cumulative_perms,
97
+ &cumulative_shared_perms);
98
+
99
ret = bdrv_node_check_perm(bs, q, cumulative_perms,
100
cumulative_shared_perms,
101
- ignore_children, errp);
102
+ ignore_children, tran, errp);
103
if (ret < 0) {
104
return ret;
105
}
106
@@ -XXX,XX +XXX,XX @@ static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q,
107
return 0;
108
}
109
110
+static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q,
111
+ uint64_t cumulative_perms,
112
+ uint64_t cumulative_shared_perms,
113
+ GSList *ignore_children, Error **errp)
114
+{
115
+ g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, bs);
116
+ return bdrv_check_perm_common(list, q, true, cumulative_perms,
117
+ cumulative_shared_perms, ignore_children,
118
+ NULL, errp);
119
+}
120
+
121
+static int bdrv_list_refresh_perms(GSList *list, BlockReopenQueue *q,
122
+ Transaction *tran, Error **errp)
123
+{
124
+ return bdrv_check_perm_common(list, q, false, 0, 0, NULL, tran, errp);
125
+}
126
+
127
/*
128
* Notifies drivers that after a previous bdrv_check_perm() call, the
129
* permission update is not performed and any preparations made for it (e.g.
130
@@ -XXX,XX +XXX,XX @@ static void bdrv_node_abort_perm_update(BlockDriverState *bs)
131
}
132
}
133
134
-static void bdrv_abort_perm_update(BlockDriverState *bs)
135
+static void bdrv_list_abort_perm_update(GSList *list)
136
{
137
- g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, bs);
138
-
139
for ( ; list; list = list->next) {
140
bdrv_node_abort_perm_update((BlockDriverState *)list->data);
141
}
142
}
143
144
+static void bdrv_abort_perm_update(BlockDriverState *bs)
145
+{
146
+ g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, bs);
147
+ return bdrv_list_abort_perm_update(list);
148
+}
149
+
150
static void bdrv_node_set_perm(BlockDriverState *bs)
151
{
152
BlockDriver *drv = bs->drv;
153
@@ -XXX,XX +XXX,XX @@ static void bdrv_node_set_perm(BlockDriverState *bs)
154
}
155
}
156
157
-static void bdrv_set_perm(BlockDriverState *bs)
158
+static void bdrv_list_set_perm(GSList *list)
159
{
160
- g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, bs);
161
-
162
for ( ; list; list = list->next) {
163
bdrv_node_set_perm((BlockDriverState *)list->data);
164
}
165
}
166
167
+static void bdrv_set_perm(BlockDriverState *bs)
168
+{
169
+ g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, bs);
170
+ return bdrv_list_set_perm(list);
171
+}
172
+
173
void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm,
174
uint64_t *shared_perm)
175
{
176
@@ -XXX,XX +XXX,XX @@ static int bdrv_check_update_perm(BlockDriverState *bs, BlockReopenQueue *q,
177
static int bdrv_refresh_perms(BlockDriverState *bs, Error **errp)
178
{
179
int ret;
180
- uint64_t perm, shared_perm;
181
+ Transaction *tran = tran_new();
182
+ g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, bs);
183
184
- if (bdrv_parent_perms_conflict(bs, NULL, errp)) {
185
- return -EPERM;
186
- }
187
- bdrv_get_cumulative_perm(bs, &perm, &shared_perm);
188
- ret = bdrv_check_perm(bs, NULL, perm, shared_perm, NULL, errp);
189
- if (ret < 0) {
190
- bdrv_abort_perm_update(bs);
191
- return ret;
192
- }
193
- bdrv_set_perm(bs);
194
+ ret = bdrv_list_refresh_perms(list, NULL, tran, errp);
195
+ tran_finalize(tran, ret);
196
197
- return 0;
198
+ return ret;
199
}
200
201
int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared,
202
--
203
2.30.2
204
205
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
To be used in the following commit.
4
5
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
7
Message-Id: <20210428151804.439460-17-vsementsov@virtuozzo.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
10
block.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
11
1 file changed, 54 insertions(+)
12
13
diff --git a/block.c b/block.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/block.c
16
+++ b/block.c
17
@@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
18
BdrvChildRole child_role,
19
Error **errp);
20
21
+static void bdrv_replace_child_noperm(BdrvChild *child,
22
+ BlockDriverState *new_bs);
23
+
24
static int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue
25
*queue, Error **errp);
26
static void bdrv_reopen_commit(BDRVReopenState *reopen_state);
27
@@ -XXX,XX +XXX,XX @@ static int bdrv_drv_set_perm(BlockDriverState *bs, uint64_t perm,
28
return 0;
29
}
30
31
+typedef struct BdrvReplaceChildState {
32
+ BdrvChild *child;
33
+ BlockDriverState *old_bs;
34
+} BdrvReplaceChildState;
35
+
36
+static void bdrv_replace_child_commit(void *opaque)
37
+{
38
+ BdrvReplaceChildState *s = opaque;
39
+
40
+ bdrv_unref(s->old_bs);
41
+}
42
+
43
+static void bdrv_replace_child_abort(void *opaque)
44
+{
45
+ BdrvReplaceChildState *s = opaque;
46
+ BlockDriverState *new_bs = s->child->bs;
47
+
48
+ /* old_bs reference is transparently moved from @s to @s->child */
49
+ bdrv_replace_child_noperm(s->child, s->old_bs);
50
+ bdrv_unref(new_bs);
51
+}
52
+
53
+static TransactionActionDrv bdrv_replace_child_drv = {
54
+ .commit = bdrv_replace_child_commit,
55
+ .abort = bdrv_replace_child_abort,
56
+ .clean = g_free,
57
+};
58
+
59
+/*
60
+ * bdrv_replace_child_safe
61
+ *
62
+ * Note: real unref of old_bs is done only on commit.
63
+ */
64
+__attribute__((unused))
65
+static void bdrv_replace_child_safe(BdrvChild *child, BlockDriverState *new_bs,
66
+ Transaction *tran)
67
+{
68
+ BdrvReplaceChildState *s = g_new(BdrvReplaceChildState, 1);
69
+ *s = (BdrvReplaceChildState) {
70
+ .child = child,
71
+ .old_bs = child->bs,
72
+ };
73
+ tran_add(tran, &bdrv_replace_child_drv, s);
74
+
75
+ if (new_bs) {
76
+ bdrv_ref(new_bs);
77
+ }
78
+ bdrv_replace_child_noperm(child, new_bs);
79
+ /* old_bs reference is transparently moved from @child to @s */
80
+}
81
+
82
/*
83
* Check whether permissions on this node can be changed in a way that
84
* @cumulative_perms and @cumulative_shared_perms are the new cumulative
85
--
86
2.30.2
87
88
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
Signed-off-by: Markus Armbruster <armbru@redhat.com>
3
inore_children thing doesn't help to track all propagated permissions
4
Message-Id: <20201217162003.1102738-7-armbru@redhat.com>
4
of children we want to ignore. The simplest way to correctly update
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
5
permissions is update graph first and then do permission update. In
6
this case we just referesh permissions for the whole subgraph (in
7
topological-sort defined order) and everything is correctly calculated
8
automatically without any ignore_children.
9
10
So, refactor bdrv_replace_node_common to first do graph update and then
11
refresh the permissions.
12
13
Test test_parallel_exclusive_write() now pass, so move it out of
14
debugging "if".
15
16
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
17
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
18
Message-Id: <20210428151804.439460-18-vsementsov@virtuozzo.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
20
---
8
block/vpc.c | 9 +++++----
21
block.c | 43 +++++++++++++-------------------
9
1 file changed, 5 insertions(+), 4 deletions(-)
22
tests/unit/test-bdrv-graph-mod.c | 4 +--
23
2 files changed, 20 insertions(+), 27 deletions(-)
10
24
11
diff --git a/block/vpc.c b/block/vpc.c
25
diff --git a/block.c b/block.c
12
index XXXXXXX..XXXXXXX 100644
26
index XXXXXXX..XXXXXXX 100644
13
--- a/block/vpc.c
27
--- a/block.c
14
+++ b/block/vpc.c
28
+++ b/block.c
15
@@ -XXX,XX +XXX,XX @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
29
@@ -XXX,XX +XXX,XX @@ static TransactionActionDrv bdrv_replace_child_drv = {
16
30
*
17
if (disk_type == VHD_DYNAMIC) {
31
* Note: real unref of old_bs is done only on commit.
18
ret = bdrv_pread(bs->file, be64_to_cpu(footer->data_offset),
32
*/
19
- &dyndisk_header, 1024);
33
-__attribute__((unused))
20
+ &dyndisk_header, sizeof(dyndisk_header));
34
static void bdrv_replace_child_safe(BdrvChild *child, BlockDriverState *new_bs,
21
if (ret < 0) {
35
Transaction *tran)
22
error_setg(errp, "Error reading dynamic VHD header");
36
{
23
goto fail;
37
@@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_common(BlockDriverState *from,
24
@@ -XXX,XX +XXX,XX @@ static int create_dynamic_disk(BlockBackend *blk, uint8_t *buf,
38
bool auto_skip, Error **errp)
39
{
40
BdrvChild *c, *next;
41
- GSList *list = NULL, *p;
42
- uint64_t perm = 0, shared = BLK_PERM_ALL;
43
+ Transaction *tran = tran_new();
44
+ g_autoptr(GHashTable) found = NULL;
45
+ g_autoptr(GSList) refresh_list = NULL;
46
int ret;
47
48
/* Make sure that @from doesn't go away until we have successfully attached
49
@@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_common(BlockDriverState *from,
50
assert(bdrv_get_aio_context(from) == bdrv_get_aio_context(to));
51
bdrv_drained_begin(from);
52
53
- /* Put all parents into @list and calculate their cumulative permissions */
54
+ /*
55
+ * Do the replacement without permission update.
56
+ * Replacement may influence the permissions, we should calculate new
57
+ * permissions based on new graph. If we fail, we'll roll-back the
58
+ * replacement.
59
+ */
60
QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) {
61
assert(c->bs == from);
62
if (!should_update_child(c, to)) {
63
@@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_common(BlockDriverState *from,
64
c->name, from->node_name);
65
goto out;
66
}
67
- list = g_slist_prepend(list, c);
68
- perm |= c->perm;
69
- shared &= c->shared_perm;
70
+ bdrv_replace_child_safe(c, to, tran);
25
}
71
}
26
72
27
/* Prepare the Dynamic Disk Header */
73
- /* Check whether the required permissions can be granted on @to, ignoring
28
- memset(&dyndisk_header, 0, 1024);
74
- * all BdrvChild in @list so that they can't block themselves. */
29
+ memset(&dyndisk_header, 0, sizeof(dyndisk_header));
75
- ret = bdrv_check_update_perm(to, NULL, perm, shared, list, errp);
30
76
- if (ret < 0) {
31
memcpy(dyndisk_header.magic, "cxsparse", 8);
77
- bdrv_abort_perm_update(to);
32
78
- goto out;
33
@@ -XXX,XX +XXX,XX @@ static int create_dynamic_disk(BlockBackend *blk, uint8_t *buf,
79
- }
34
dyndisk_header.block_size = cpu_to_be32(block_size);
80
+ found = g_hash_table_new(NULL, NULL);
35
dyndisk_header.max_table_entries = cpu_to_be32(num_bat_entries);
81
36
82
- /* Now actually perform the change. We performed the permission check for
37
- dyndisk_header.checksum = cpu_to_be32(vpc_checksum(&dyndisk_header, 1024));
83
- * all elements of @list at once, so set the permissions all at once at the
38
+ dyndisk_header.checksum = cpu_to_be32(
84
- * very end. */
39
+ vpc_checksum(&dyndisk_header, sizeof(dyndisk_header)));
85
- for (p = list; p != NULL; p = p->next) {
40
86
- c = p->data;
41
/* Write the header */
87
+ refresh_list = bdrv_topological_dfs(refresh_list, found, to);
42
offset = 512;
88
+ refresh_list = bdrv_topological_dfs(refresh_list, found, from);
43
89
44
- ret = blk_pwrite(blk, offset, &dyndisk_header, 1024, 0);
90
- bdrv_ref(to);
45
+ ret = blk_pwrite(blk, offset, &dyndisk_header, sizeof(dyndisk_header), 0);
91
- bdrv_replace_child_noperm(c, to);
46
if (ret < 0) {
92
- bdrv_unref(from);
47
goto fail;
93
+ ret = bdrv_list_refresh_perms(refresh_list, NULL, tran, errp);
94
+ if (ret < 0) {
95
+ goto out;
96
}
97
98
- bdrv_set_perm(to);
99
-
100
ret = 0;
101
102
out:
103
- g_slist_free(list);
104
+ tran_finalize(tran, ret);
105
+
106
bdrv_drained_end(from);
107
bdrv_unref(from);
108
109
diff --git a/tests/unit/test-bdrv-graph-mod.c b/tests/unit/test-bdrv-graph-mod.c
110
index XXXXXXX..XXXXXXX 100644
111
--- a/tests/unit/test-bdrv-graph-mod.c
112
+++ b/tests/unit/test-bdrv-graph-mod.c
113
@@ -XXX,XX +XXX,XX @@ int main(int argc, char *argv[])
114
test_should_update_child);
115
g_test_add_func("/bdrv-graph-mod/parallel-perm-update",
116
test_parallel_perm_update);
117
+ g_test_add_func("/bdrv-graph-mod/parallel-exclusive-write",
118
+ test_parallel_exclusive_write);
119
120
if (debug) {
121
- g_test_add_func("/bdrv-graph-mod/parallel-exclusive-write",
122
- test_parallel_exclusive_write);
123
g_test_add_func("/bdrv-graph-mod/append-greedy-filter",
124
test_append_greedy_filter);
48
}
125
}
49
--
126
--
50
2.29.2
127
2.30.2
51
128
52
129
diff view generated by jsdifflib
New patch
1
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
3
Split out no-perm part of bdrv_root_attach_child() into separate
4
transaction action. bdrv_root_attach_child() now moves to new
5
permission update paradigm: first update graph relations then update
6
permissions.
7
8
qsd-jobs test output updated. Seems now permission update goes in
9
another order. Still, the test comment say that we only want to check
10
that command doesn't crash, and it's still so.
11
12
Error message is a bit misleading as it looks like job was added first.
13
But actually in new paradigm of graph update we can't distinguish such
14
things. We should update the error message, but let's not do it now.
15
16
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
17
Message-Id: <20210428151804.439460-19-vsementsov@virtuozzo.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
---
20
block.c | 190 ++++++++++++++++++--------
21
tests/qemu-iotests/tests/qsd-jobs.out | 2 +-
22
2 files changed, 137 insertions(+), 55 deletions(-)
23
24
diff --git a/block.c b/block.c
25
index XXXXXXX..XXXXXXX 100644
26
--- a/block.c
27
+++ b/block.c
28
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs)
29
}
30
}
31
32
-/*
33
- * This function steals the reference to child_bs from the caller.
34
- * That reference is later dropped by bdrv_root_unref_child().
35
- *
36
- * On failure NULL is returned, errp is set and the reference to
37
- * child_bs is also dropped.
38
- *
39
- * The caller must hold the AioContext lock @child_bs, but not that of @ctx
40
- * (unless @child_bs is already in @ctx).
41
- */
42
-BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
43
- const char *child_name,
44
- const BdrvChildClass *child_class,
45
- BdrvChildRole child_role,
46
- uint64_t perm, uint64_t shared_perm,
47
- void *opaque, Error **errp)
48
+static void bdrv_remove_empty_child(BdrvChild *child)
49
{
50
- BdrvChild *child;
51
- Error *local_err = NULL;
52
- int ret;
53
- AioContext *ctx;
54
+ assert(!child->bs);
55
+ QLIST_SAFE_REMOVE(child, next);
56
+ g_free(child->name);
57
+ g_free(child);
58
+}
59
60
- ret = bdrv_check_update_perm(child_bs, NULL, perm, shared_perm, NULL, errp);
61
- if (ret < 0) {
62
- bdrv_abort_perm_update(child_bs);
63
- bdrv_unref(child_bs);
64
- return NULL;
65
+typedef struct BdrvAttachChildCommonState {
66
+ BdrvChild **child;
67
+ AioContext *old_parent_ctx;
68
+ AioContext *old_child_ctx;
69
+} BdrvAttachChildCommonState;
70
+
71
+static void bdrv_attach_child_common_abort(void *opaque)
72
+{
73
+ BdrvAttachChildCommonState *s = opaque;
74
+ BdrvChild *child = *s->child;
75
+ BlockDriverState *bs = child->bs;
76
+
77
+ bdrv_replace_child_noperm(child, NULL);
78
+
79
+ if (bdrv_get_aio_context(bs) != s->old_child_ctx) {
80
+ bdrv_try_set_aio_context(bs, s->old_child_ctx, &error_abort);
81
}
82
83
- child = g_new(BdrvChild, 1);
84
- *child = (BdrvChild) {
85
+ if (bdrv_child_get_parent_aio_context(child) != s->old_parent_ctx) {
86
+ GSList *ignore = g_slist_prepend(NULL, child);
87
+
88
+ child->klass->can_set_aio_ctx(child, s->old_parent_ctx, &ignore,
89
+ &error_abort);
90
+ g_slist_free(ignore);
91
+ ignore = g_slist_prepend(NULL, child);
92
+ child->klass->set_aio_ctx(child, s->old_parent_ctx, &ignore);
93
+
94
+ g_slist_free(ignore);
95
+ }
96
+
97
+ bdrv_unref(bs);
98
+ bdrv_remove_empty_child(child);
99
+ *s->child = NULL;
100
+}
101
+
102
+static TransactionActionDrv bdrv_attach_child_common_drv = {
103
+ .abort = bdrv_attach_child_common_abort,
104
+ .clean = g_free,
105
+};
106
+
107
+/*
108
+ * Common part of attaching bdrv child to bs or to blk or to job
109
+ */
110
+static int bdrv_attach_child_common(BlockDriverState *child_bs,
111
+ const char *child_name,
112
+ const BdrvChildClass *child_class,
113
+ BdrvChildRole child_role,
114
+ uint64_t perm, uint64_t shared_perm,
115
+ void *opaque, BdrvChild **child,
116
+ Transaction *tran, Error **errp)
117
+{
118
+ BdrvChild *new_child;
119
+ AioContext *parent_ctx;
120
+ AioContext *child_ctx = bdrv_get_aio_context(child_bs);
121
+
122
+ assert(child);
123
+ assert(*child == NULL);
124
+
125
+ new_child = g_new(BdrvChild, 1);
126
+ *new_child = (BdrvChild) {
127
.bs = NULL,
128
.name = g_strdup(child_name),
129
.klass = child_class,
130
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
131
.opaque = opaque,
132
};
133
134
- ctx = bdrv_child_get_parent_aio_context(child);
135
-
136
- /* If the AioContexts don't match, first try to move the subtree of
137
+ /*
138
+ * If the AioContexts don't match, first try to move the subtree of
139
* child_bs into the AioContext of the new parent. If this doesn't work,
140
- * try moving the parent into the AioContext of child_bs instead. */
141
- if (bdrv_get_aio_context(child_bs) != ctx) {
142
- ret = bdrv_try_set_aio_context(child_bs, ctx, &local_err);
143
+ * try moving the parent into the AioContext of child_bs instead.
144
+ */
145
+ parent_ctx = bdrv_child_get_parent_aio_context(new_child);
146
+ if (child_ctx != parent_ctx) {
147
+ Error *local_err = NULL;
148
+ int ret = bdrv_try_set_aio_context(child_bs, parent_ctx, &local_err);
149
+
150
if (ret < 0 && child_class->can_set_aio_ctx) {
151
- GSList *ignore = g_slist_prepend(NULL, child);
152
- ctx = bdrv_get_aio_context(child_bs);
153
- if (child_class->can_set_aio_ctx(child, ctx, &ignore, NULL)) {
154
+ GSList *ignore = g_slist_prepend(NULL, new_child);
155
+ if (child_class->can_set_aio_ctx(new_child, child_ctx, &ignore,
156
+ NULL))
157
+ {
158
error_free(local_err);
159
ret = 0;
160
g_slist_free(ignore);
161
- ignore = g_slist_prepend(NULL, child);
162
- child_class->set_aio_ctx(child, ctx, &ignore);
163
+ ignore = g_slist_prepend(NULL, new_child);
164
+ child_class->set_aio_ctx(new_child, child_ctx, &ignore);
165
}
166
g_slist_free(ignore);
167
}
168
+
169
if (ret < 0) {
170
error_propagate(errp, local_err);
171
- g_free(child);
172
- bdrv_abort_perm_update(child_bs);
173
- bdrv_unref(child_bs);
174
- return NULL;
175
+ bdrv_remove_empty_child(new_child);
176
+ return ret;
177
}
178
}
179
180
- /* This performs the matching bdrv_set_perm() for the above check. */
181
- bdrv_replace_child(child, child_bs);
182
+ bdrv_ref(child_bs);
183
+ bdrv_replace_child_noperm(new_child, child_bs);
184
185
+ *child = new_child;
186
+
187
+ BdrvAttachChildCommonState *s = g_new(BdrvAttachChildCommonState, 1);
188
+ *s = (BdrvAttachChildCommonState) {
189
+ .child = child,
190
+ .old_parent_ctx = parent_ctx,
191
+ .old_child_ctx = child_ctx,
192
+ };
193
+ tran_add(tran, &bdrv_attach_child_common_drv, s);
194
+
195
+ return 0;
196
+}
197
+
198
+static void bdrv_detach_child(BdrvChild *child)
199
+{
200
+ bdrv_replace_child(child, NULL);
201
+ bdrv_remove_empty_child(child);
202
+}
203
+
204
+/*
205
+ * This function steals the reference to child_bs from the caller.
206
+ * That reference is later dropped by bdrv_root_unref_child().
207
+ *
208
+ * On failure NULL is returned, errp is set and the reference to
209
+ * child_bs is also dropped.
210
+ *
211
+ * The caller must hold the AioContext lock @child_bs, but not that of @ctx
212
+ * (unless @child_bs is already in @ctx).
213
+ */
214
+BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
215
+ const char *child_name,
216
+ const BdrvChildClass *child_class,
217
+ BdrvChildRole child_role,
218
+ uint64_t perm, uint64_t shared_perm,
219
+ void *opaque, Error **errp)
220
+{
221
+ int ret;
222
+ BdrvChild *child = NULL;
223
+ Transaction *tran = tran_new();
224
+
225
+ ret = bdrv_attach_child_common(child_bs, child_name, child_class,
226
+ child_role, perm, shared_perm, opaque,
227
+ &child, tran, errp);
228
+ if (ret < 0) {
229
+ bdrv_unref(child_bs);
230
+ return NULL;
231
+ }
232
+
233
+ ret = bdrv_refresh_perms(child_bs, errp);
234
+ tran_finalize(tran, ret);
235
+
236
+ bdrv_unref(child_bs);
237
return child;
238
}
239
240
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
241
return child;
242
}
243
244
-static void bdrv_detach_child(BdrvChild *child)
245
-{
246
- QLIST_SAFE_REMOVE(child, next);
247
-
248
- bdrv_replace_child(child, NULL);
249
-
250
- g_free(child->name);
251
- g_free(child);
252
-}
253
-
254
/* Callers must ensure that child->frozen is false. */
255
void bdrv_root_unref_child(BdrvChild *child)
256
{
257
diff --git a/tests/qemu-iotests/tests/qsd-jobs.out b/tests/qemu-iotests/tests/qsd-jobs.out
258
index XXXXXXX..XXXXXXX 100644
259
--- a/tests/qemu-iotests/tests/qsd-jobs.out
260
+++ b/tests/qemu-iotests/tests/qsd-jobs.out
261
@@ -XXX,XX +XXX,XX @@ QMP_VERSION
262
{"return": {}}
263
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}}
264
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job0"}}
265
-{"error": {"class": "GenericError", "desc": "Conflicts with use by a block device as 'root', which uses 'write' on fmt_base"}}
266
+{"error": {"class": "GenericError", "desc": "Conflicts with use by stream job 'job0' as 'intermediate node', which does not allow 'write' on fmt_base"}}
267
{"return": {}}
268
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "export1"}}
269
*** done
270
--
271
2.30.2
272
273
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
Split no-perm part of bdrv_attach_child as separate transaction action.
4
It will be used in later commits.
5
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
8
Message-Id: <20210428151804.439460-20-vsementsov@virtuozzo.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
block.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++-----------
12
1 file changed, 58 insertions(+), 13 deletions(-)
13
14
diff --git a/block.c b/block.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/block.c
17
+++ b/block.c
18
@@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
19
20
static void bdrv_replace_child_noperm(BdrvChild *child,
21
BlockDriverState *new_bs);
22
+static int bdrv_attach_child_noperm(BlockDriverState *parent_bs,
23
+ BlockDriverState *child_bs,
24
+ const char *child_name,
25
+ const BdrvChildClass *child_class,
26
+ BdrvChildRole child_role,
27
+ BdrvChild **child,
28
+ Transaction *tran,
29
+ Error **errp);
30
31
static int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue
32
*queue, Error **errp);
33
@@ -XXX,XX +XXX,XX @@ static int bdrv_attach_child_common(BlockDriverState *child_bs,
34
return 0;
35
}
36
37
+static int bdrv_attach_child_noperm(BlockDriverState *parent_bs,
38
+ BlockDriverState *child_bs,
39
+ const char *child_name,
40
+ const BdrvChildClass *child_class,
41
+ BdrvChildRole child_role,
42
+ BdrvChild **child,
43
+ Transaction *tran,
44
+ Error **errp)
45
+{
46
+ int ret;
47
+ uint64_t perm, shared_perm;
48
+
49
+ assert(parent_bs->drv);
50
+
51
+ bdrv_get_cumulative_perm(parent_bs, &perm, &shared_perm);
52
+ bdrv_child_perm(parent_bs, child_bs, NULL, child_role, NULL,
53
+ perm, shared_perm, &perm, &shared_perm);
54
+
55
+ ret = bdrv_attach_child_common(child_bs, child_name, child_class,
56
+ child_role, perm, shared_perm, parent_bs,
57
+ child, tran, errp);
58
+ if (ret < 0) {
59
+ return ret;
60
+ }
61
+
62
+ QLIST_INSERT_HEAD(&parent_bs->children, *child, next);
63
+ /*
64
+ * child is removed in bdrv_attach_child_common_abort(), so don't care to
65
+ * abort this change separately.
66
+ */
67
+
68
+ return 0;
69
+}
70
+
71
static void bdrv_detach_child(BdrvChild *child)
72
{
73
bdrv_replace_child(child, NULL);
74
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
75
BdrvChildRole child_role,
76
Error **errp)
77
{
78
- BdrvChild *child;
79
- uint64_t perm, shared_perm;
80
-
81
- bdrv_get_cumulative_perm(parent_bs, &perm, &shared_perm);
82
+ int ret;
83
+ BdrvChild *child = NULL;
84
+ Transaction *tran = tran_new();
85
86
- assert(parent_bs->drv);
87
- bdrv_child_perm(parent_bs, child_bs, NULL, child_role, NULL,
88
- perm, shared_perm, &perm, &shared_perm);
89
+ ret = bdrv_attach_child_noperm(parent_bs, child_bs, child_name, child_class,
90
+ child_role, &child, tran, errp);
91
+ if (ret < 0) {
92
+ goto out;
93
+ }
94
95
- child = bdrv_root_attach_child(child_bs, child_name, child_class,
96
- child_role, perm, shared_perm, parent_bs,
97
- errp);
98
- if (child == NULL) {
99
- return NULL;
100
+ ret = bdrv_refresh_perms(parent_bs, errp);
101
+ if (ret < 0) {
102
+ goto out;
103
}
104
105
- QLIST_INSERT_HEAD(&parent_bs->children, child, next);
106
+out:
107
+ tran_finalize(tran, ret);
108
+
109
+ bdrv_unref(child_bs);
110
+
111
return child;
112
}
113
114
--
115
2.30.2
116
117
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
Split part of bdrv_replace_node_common() to be used separately.
4
5
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
7
Message-Id: <20210428151804.439460-21-vsementsov@virtuozzo.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
10
block.c | 50 +++++++++++++++++++++++++++++++-------------------
11
1 file changed, 31 insertions(+), 19 deletions(-)
12
13
diff --git a/block.c b/block.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/block.c
16
+++ b/block.c
17
@@ -XXX,XX +XXX,XX @@ static bool should_update_child(BdrvChild *c, BlockDriverState *to)
18
return ret;
19
}
20
21
+static int bdrv_replace_node_noperm(BlockDriverState *from,
22
+ BlockDriverState *to,
23
+ bool auto_skip, Transaction *tran,
24
+ Error **errp)
25
+{
26
+ BdrvChild *c, *next;
27
+
28
+ QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) {
29
+ assert(c->bs == from);
30
+ if (!should_update_child(c, to)) {
31
+ if (auto_skip) {
32
+ continue;
33
+ }
34
+ error_setg(errp, "Should not change '%s' link to '%s'",
35
+ c->name, from->node_name);
36
+ return -EINVAL;
37
+ }
38
+ if (c->frozen) {
39
+ error_setg(errp, "Cannot change '%s' link to '%s'",
40
+ c->name, from->node_name);
41
+ return -EPERM;
42
+ }
43
+ bdrv_replace_child_safe(c, to, tran);
44
+ }
45
+
46
+ return 0;
47
+}
48
+
49
/*
50
* With auto_skip=true bdrv_replace_node_common skips updating from parents
51
* if it creates a parent-child relation loop or if parent is block-job.
52
@@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_common(BlockDriverState *from,
53
BlockDriverState *to,
54
bool auto_skip, Error **errp)
55
{
56
- BdrvChild *c, *next;
57
Transaction *tran = tran_new();
58
g_autoptr(GHashTable) found = NULL;
59
g_autoptr(GSList) refresh_list = NULL;
60
@@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_common(BlockDriverState *from,
61
* permissions based on new graph. If we fail, we'll roll-back the
62
* replacement.
63
*/
64
- QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) {
65
- assert(c->bs == from);
66
- if (!should_update_child(c, to)) {
67
- if (auto_skip) {
68
- continue;
69
- }
70
- ret = -EINVAL;
71
- error_setg(errp, "Should not change '%s' link to '%s'",
72
- c->name, from->node_name);
73
- goto out;
74
- }
75
- if (c->frozen) {
76
- ret = -EPERM;
77
- error_setg(errp, "Cannot change '%s' link to '%s'",
78
- c->name, from->node_name);
79
- goto out;
80
- }
81
- bdrv_replace_child_safe(c, to, tran);
82
+ ret = bdrv_replace_node_noperm(from, to, auto_skip, tran, errp);
83
+ if (ret < 0) {
84
+ goto out;
85
}
86
87
found = g_hash_table_new(NULL, NULL);
88
--
89
2.30.2
90
91
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
bdrv_append is not very good for inserting filters: it does extra
4
permission update as part of bdrv_set_backing_hd(). During this update
5
filter may conflict with other parents of top_bs.
6
7
Instead, let's first do all graph modifications and after it update
8
permissions.
9
10
append-greedy-filter test-case in test-bdrv-graph-mod is now works, so
11
move it out of debug option.
12
13
Note: bdrv_append() is still only works for backing-child based
14
filters. It's something to improve later.
15
16
Note2: we use the fact that bdrv_append() is used to append new nodes,
17
without backing child, so we don't need frozen check and inherits_from
18
logic from bdrv_set_backing_hd().
19
20
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
21
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
22
Message-Id: <20210428151804.439460-22-vsementsov@virtuozzo.com>
23
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
24
---
25
block.c | 27 ++++++++++++++++++++-------
26
tests/unit/test-bdrv-graph-mod.c | 17 ++---------------
27
2 files changed, 22 insertions(+), 22 deletions(-)
28
29
diff --git a/block.c b/block.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/block.c
32
+++ b/block.c
33
@@ -XXX,XX +XXX,XX @@ int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
34
* This will modify the BlockDriverState fields, and swap contents
35
* between bs_new and bs_top. Both bs_new and bs_top are modified.
36
*
37
- * bs_new must not be attached to a BlockBackend.
38
+ * bs_new must not be attached to a BlockBackend and must not have backing
39
+ * child.
40
*
41
* This function does not create any image files.
42
*/
43
int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
44
Error **errp)
45
{
46
- int ret = bdrv_set_backing_hd(bs_new, bs_top, errp);
47
+ int ret;
48
+ Transaction *tran = tran_new();
49
+
50
+ assert(!bs_new->backing);
51
+
52
+ ret = bdrv_attach_child_noperm(bs_new, bs_top, "backing",
53
+ &child_of_bds, bdrv_backing_role(bs_new),
54
+ &bs_new->backing, tran, errp);
55
if (ret < 0) {
56
- return ret;
57
+ goto out;
58
}
59
60
- ret = bdrv_replace_node(bs_top, bs_new, errp);
61
+ ret = bdrv_replace_node_noperm(bs_top, bs_new, true, tran, errp);
62
if (ret < 0) {
63
- bdrv_set_backing_hd(bs_new, NULL, &error_abort);
64
- return ret;
65
+ goto out;
66
}
67
68
- return 0;
69
+ ret = bdrv_refresh_perms(bs_new, errp);
70
+out:
71
+ tran_finalize(tran, ret);
72
+
73
+ bdrv_refresh_limits(bs_top, NULL);
74
+
75
+ return ret;
76
}
77
78
static void bdrv_delete(BlockDriverState *bs)
79
diff --git a/tests/unit/test-bdrv-graph-mod.c b/tests/unit/test-bdrv-graph-mod.c
80
index XXXXXXX..XXXXXXX 100644
81
--- a/tests/unit/test-bdrv-graph-mod.c
82
+++ b/tests/unit/test-bdrv-graph-mod.c
83
@@ -XXX,XX +XXX,XX @@ static void test_append_greedy_filter(void)
84
85
int main(int argc, char *argv[])
86
{
87
- int i;
88
- bool debug = false;
89
-
90
- for (i = 1; i < argc; i++) {
91
- if (!strcmp(argv[i], "-d")) {
92
- debug = true;
93
- break;
94
- }
95
- }
96
-
97
bdrv_init();
98
qemu_init_main_loop(&error_abort);
99
100
@@ -XXX,XX +XXX,XX @@ int main(int argc, char *argv[])
101
test_parallel_perm_update);
102
g_test_add_func("/bdrv-graph-mod/parallel-exclusive-write",
103
test_parallel_exclusive_write);
104
-
105
- if (debug) {
106
- g_test_add_func("/bdrv-graph-mod/append-greedy-filter",
107
- test_append_greedy_filter);
108
- }
109
+ g_test_add_func("/bdrv-graph-mod/append-greedy-filter",
110
+ test_append_greedy_filter);
111
112
return g_test_run();
113
}
114
--
115
2.30.2
116
117
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
4
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
5
Message-Id: <20210428151804.439460-23-vsementsov@virtuozzo.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
8
block.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
9
1 file changed, 82 insertions(+), 2 deletions(-)
10
11
diff --git a/block.c b/block.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/block.c
14
+++ b/block.c
15
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs)
16
}
17
}
18
19
+static void bdrv_child_free(void *opaque)
20
+{
21
+ BdrvChild *c = opaque;
22
+
23
+ g_free(c->name);
24
+ g_free(c);
25
+}
26
+
27
static void bdrv_remove_empty_child(BdrvChild *child)
28
{
29
assert(!child->bs);
30
QLIST_SAFE_REMOVE(child, next);
31
- g_free(child->name);
32
- g_free(child);
33
+ bdrv_child_free(child);
34
}
35
36
typedef struct BdrvAttachChildCommonState {
37
@@ -XXX,XX +XXX,XX @@ static bool should_update_child(BdrvChild *c, BlockDriverState *to)
38
return ret;
39
}
40
41
+typedef struct BdrvRemoveFilterOrCowChild {
42
+ BdrvChild *child;
43
+ bool is_backing;
44
+} BdrvRemoveFilterOrCowChild;
45
+
46
+static void bdrv_remove_filter_or_cow_child_abort(void *opaque)
47
+{
48
+ BdrvRemoveFilterOrCowChild *s = opaque;
49
+ BlockDriverState *parent_bs = s->child->opaque;
50
+
51
+ QLIST_INSERT_HEAD(&parent_bs->children, s->child, next);
52
+ if (s->is_backing) {
53
+ parent_bs->backing = s->child;
54
+ } else {
55
+ parent_bs->file = s->child;
56
+ }
57
+
58
+ /*
59
+ * We don't have to restore child->bs here to undo bdrv_replace_child()
60
+ * because that function is transactionable and it registered own completion
61
+ * entries in @tran, so .abort() for bdrv_replace_child_safe() will be
62
+ * called automatically.
63
+ */
64
+}
65
+
66
+static void bdrv_remove_filter_or_cow_child_commit(void *opaque)
67
+{
68
+ BdrvRemoveFilterOrCowChild *s = opaque;
69
+
70
+ bdrv_child_free(s->child);
71
+}
72
+
73
+static TransactionActionDrv bdrv_remove_filter_or_cow_child_drv = {
74
+ .abort = bdrv_remove_filter_or_cow_child_abort,
75
+ .commit = bdrv_remove_filter_or_cow_child_commit,
76
+ .clean = g_free,
77
+};
78
+
79
+/*
80
+ * A function to remove backing-chain child of @bs if exists: cow child for
81
+ * format nodes (always .backing) and filter child for filters (may be .file or
82
+ * .backing)
83
+ */
84
+__attribute__((unused))
85
+static void bdrv_remove_filter_or_cow_child(BlockDriverState *bs,
86
+ Transaction *tran)
87
+{
88
+ BdrvRemoveFilterOrCowChild *s;
89
+ BdrvChild *child = bdrv_filter_or_cow_child(bs);
90
+
91
+ if (!child) {
92
+ return;
93
+ }
94
+
95
+ if (child->bs) {
96
+ bdrv_replace_child_safe(child, NULL, tran);
97
+ }
98
+
99
+ s = g_new(BdrvRemoveFilterOrCowChild, 1);
100
+ *s = (BdrvRemoveFilterOrCowChild) {
101
+ .child = child,
102
+ .is_backing = (child == bs->backing),
103
+ };
104
+ tran_add(tran, &bdrv_remove_filter_or_cow_child_drv, s);
105
+
106
+ QLIST_SAFE_REMOVE(child, next);
107
+ if (s->is_backing) {
108
+ bs->backing = NULL;
109
+ } else {
110
+ bs->file = NULL;
111
+ }
112
+}
113
+
114
static int bdrv_replace_node_noperm(BlockDriverState *from,
115
BlockDriverState *to,
116
bool auto_skip, Transaction *tran,
117
--
118
2.30.2
119
120
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
Using bdrv_replace_node() for removing filter is not good enough: it
4
keeps child reference of the filter, which may conflict with original
5
top node during permission update.
6
7
Instead let's create new interface, which will do all graph
8
modifications first and then update permissions.
9
10
Let's modify bdrv_replace_node_common(), allowing it additionally drop
11
backing chain child link pointing to new node. This is quite
12
appropriate for bdrv_drop_intermediate() and makes possible to add
13
new bdrv_drop_filter() as a simple wrapper.
14
15
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
16
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
17
Message-Id: <20210428151804.439460-24-vsementsov@virtuozzo.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
---
20
include/block/block.h | 1 +
21
block.c | 43 +++++++++++++++++++++++++++++++++++++++----
22
2 files changed, 40 insertions(+), 4 deletions(-)
23
24
diff --git a/include/block/block.h b/include/block/block.h
25
index XXXXXXX..XXXXXXX 100644
26
--- a/include/block/block.h
27
+++ b/include/block/block.h
28
@@ -XXX,XX +XXX,XX @@ int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
29
Error **errp);
30
BlockDriverState *bdrv_insert_node(BlockDriverState *bs, QDict *node_options,
31
int flags, Error **errp);
32
+int bdrv_drop_filter(BlockDriverState *bs, Error **errp);
33
34
int bdrv_parse_aio(const char *mode, int *flags);
35
int bdrv_parse_cache_mode(const char *mode, int *flags, bool *writethrough);
36
diff --git a/block.c b/block.c
37
index XXXXXXX..XXXXXXX 100644
38
--- a/block.c
39
+++ b/block.c
40
@@ -XXX,XX +XXX,XX @@ static TransactionActionDrv bdrv_remove_filter_or_cow_child_drv = {
41
* format nodes (always .backing) and filter child for filters (may be .file or
42
* .backing)
43
*/
44
-__attribute__((unused))
45
static void bdrv_remove_filter_or_cow_child(BlockDriverState *bs,
46
Transaction *tran)
47
{
48
@@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_noperm(BlockDriverState *from,
49
*
50
* With auto_skip=false the error is returned if from has a parent which should
51
* not be updated.
52
+ *
53
+ * With @detach_subchain=true @to must be in a backing chain of @from. In this
54
+ * case backing link of the cow-parent of @to is removed.
55
*/
56
static int bdrv_replace_node_common(BlockDriverState *from,
57
BlockDriverState *to,
58
- bool auto_skip, Error **errp)
59
+ bool auto_skip, bool detach_subchain,
60
+ Error **errp)
61
{
62
Transaction *tran = tran_new();
63
g_autoptr(GHashTable) found = NULL;
64
g_autoptr(GSList) refresh_list = NULL;
65
+ BlockDriverState *to_cow_parent;
66
int ret;
67
68
+ if (detach_subchain) {
69
+ assert(bdrv_chain_contains(from, to));
70
+ assert(from != to);
71
+ for (to_cow_parent = from;
72
+ bdrv_filter_or_cow_bs(to_cow_parent) != to;
73
+ to_cow_parent = bdrv_filter_or_cow_bs(to_cow_parent))
74
+ {
75
+ ;
76
+ }
77
+ }
78
+
79
/* Make sure that @from doesn't go away until we have successfully attached
80
* all of its parents to @to. */
81
bdrv_ref(from);
82
@@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_common(BlockDriverState *from,
83
goto out;
84
}
85
86
+ if (detach_subchain) {
87
+ bdrv_remove_filter_or_cow_child(to_cow_parent, tran);
88
+ }
89
+
90
found = g_hash_table_new(NULL, NULL);
91
92
refresh_list = bdrv_topological_dfs(refresh_list, found, to);
93
@@ -XXX,XX +XXX,XX @@ out:
94
int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
95
Error **errp)
96
{
97
- return bdrv_replace_node_common(from, to, true, errp);
98
+ return bdrv_replace_node_common(from, to, true, false, errp);
99
+}
100
+
101
+int bdrv_drop_filter(BlockDriverState *bs, Error **errp)
102
+{
103
+ return bdrv_replace_node_common(bs, bdrv_filter_or_cow_bs(bs), true, true,
104
+ errp);
105
}
106
107
/*
108
@@ -XXX,XX +XXX,XX @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
109
updated_children = g_slist_prepend(updated_children, c);
110
}
111
112
- bdrv_replace_node_common(top, base, false, &local_err);
113
+ /*
114
+ * It seems correct to pass detach_subchain=true here, but it triggers
115
+ * one more yet not fixed bug, when due to nested aio_poll loop we switch to
116
+ * another drained section, which modify the graph (for example, removing
117
+ * the child, which we keep in updated_children list). So, it's a TODO.
118
+ *
119
+ * Note, bug triggered if pass detach_subchain=true here and run
120
+ * test-bdrv-drain. test_drop_intermediate_poll() test-case will crash.
121
+ * That's a FIXME.
122
+ */
123
+ bdrv_replace_node_common(top, base, false, false, &local_err);
124
if (local_err) {
125
error_report_err(local_err);
126
goto exit;
127
--
128
2.30.2
129
130
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
We don't need this workaround anymore: bdrv_append is already smart
4
enough and we can use new bdrv_drop_filter().
5
6
This commit efficiently reverts also recent 705dde27c6c53b73, which
7
checked .active on io path. Still it said that the problem should be
8
theoretical. And the logic of filter removement is changed anyway.
9
10
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
11
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
12
Message-Id: <20210428151804.439460-25-vsementsov@virtuozzo.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
15
block/backup-top.c | 47 +-------------------------------------
16
tests/qemu-iotests/283.out | 2 +-
17
2 files changed, 2 insertions(+), 47 deletions(-)
18
19
diff --git a/block/backup-top.c b/block/backup-top.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/block/backup-top.c
22
+++ b/block/backup-top.c
23
@@ -XXX,XX +XXX,XX @@
24
typedef struct BDRVBackupTopState {
25
BlockCopyState *bcs;
26
BdrvChild *target;
27
- bool active;
28
int64_t cluster_size;
29
} BDRVBackupTopState;
30
31
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int backup_top_co_preadv(
32
BlockDriverState *bs, uint64_t offset, uint64_t bytes,
33
QEMUIOVector *qiov, int flags)
34
{
35
- BDRVBackupTopState *s = bs->opaque;
36
-
37
- if (!s->active) {
38
- return -EIO;
39
- }
40
-
41
return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags);
42
}
43
44
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int backup_top_cbw(BlockDriverState *bs, uint64_t offset,
45
BDRVBackupTopState *s = bs->opaque;
46
uint64_t off, end;
47
48
- if (!s->active) {
49
- return -EIO;
50
- }
51
-
52
if (flags & BDRV_REQ_WRITE_UNCHANGED) {
53
return 0;
54
}
55
@@ -XXX,XX +XXX,XX @@ static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c,
56
uint64_t perm, uint64_t shared,
57
uint64_t *nperm, uint64_t *nshared)
58
{
59
- BDRVBackupTopState *s = bs->opaque;
60
-
61
- if (!s->active) {
62
- /*
63
- * The filter node may be in process of bdrv_append(), which firstly do
64
- * bdrv_set_backing_hd() and then bdrv_replace_node(). This means that
65
- * we can't unshare BLK_PERM_WRITE during bdrv_append() operation. So,
66
- * let's require nothing during bdrv_append() and refresh permissions
67
- * after it (see bdrv_backup_top_append()).
68
- */
69
- *nperm = 0;
70
- *nshared = BLK_PERM_ALL;
71
- return;
72
- }
73
-
74
if (!(role & BDRV_CHILD_FILTERED)) {
75
/*
76
* Target child
77
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source,
78
}
79
appended = true;
80
81
- /*
82
- * bdrv_append() finished successfully, now we can require permissions
83
- * we want.
84
- */
85
- state->active = true;
86
- ret = bdrv_child_refresh_perms(top, top->backing, errp);
87
- if (ret < 0) {
88
- error_prepend(errp, "Cannot set permissions for backup-top filter: ");
89
- goto fail;
90
- }
91
-
92
state->cluster_size = cluster_size;
93
state->bcs = block_copy_state_new(top->backing, state->target,
94
cluster_size, perf->use_copy_range,
95
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source,
96
97
fail:
98
if (appended) {
99
- state->active = false;
100
bdrv_backup_top_drop(top);
101
} else {
102
bdrv_unref(top);
103
@@ -XXX,XX +XXX,XX @@ void bdrv_backup_top_drop(BlockDriverState *bs)
104
{
105
BDRVBackupTopState *s = bs->opaque;
106
107
- bdrv_drained_begin(bs);
108
+ bdrv_drop_filter(bs, &error_abort);
109
110
block_copy_state_free(s->bcs);
111
112
- s->active = false;
113
- bdrv_child_refresh_perms(bs, bs->backing, &error_abort);
114
- bdrv_replace_node(bs, bs->backing->bs, &error_abort);
115
- bdrv_set_backing_hd(bs, NULL, &error_abort);
116
-
117
- bdrv_drained_end(bs);
118
-
119
bdrv_unref(bs);
120
}
121
diff --git a/tests/qemu-iotests/283.out b/tests/qemu-iotests/283.out
122
index XXXXXXX..XXXXXXX 100644
123
--- a/tests/qemu-iotests/283.out
124
+++ b/tests/qemu-iotests/283.out
125
@@ -XXX,XX +XXX,XX @@
126
{"execute": "blockdev-add", "arguments": {"driver": "blkdebug", "image": "base", "node-name": "other", "take-child-perms": ["write"]}}
127
{"return": {}}
128
{"execute": "blockdev-backup", "arguments": {"device": "source", "sync": "full", "target": "target"}}
129
-{"error": {"class": "GenericError", "desc": "Cannot set permissions for backup-top filter: Conflicts with use by source as 'image', which does not allow 'write' on base"}}
130
+{"error": {"class": "GenericError", "desc": "Cannot append backup-top filter: Conflicts with use by source as 'image', which does not allow 'write' on base"}}
131
132
=== backup-top should be gone after job-finalize ===
133
134
--
135
2.30.2
136
137
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
The dynamic header's size is 1024 bytes.
3
This argument is always NULL. Drop it.
4
4
5
vpc_open() reads only the 512 bytes of the dynamic header into buf[].
5
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Works, because it doesn't actually access the second half. However, a
6
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
7
colleague told me that GCC 11 warns:
7
Message-Id: <20210428151804.439460-26-vsementsov@virtuozzo.com>
8
9
../block/vpc.c:358:51: error: array subscript 'struct VHDDynDiskHeader[0]' is partly outside array bounds of 'uint8_t[512]' [-Werror=array-bounds]
10
11
Clean up to read the full header.
12
13
Rename buf[] to dyndisk_header_buf[] while there.
14
15
Signed-off-by: Markus Armbruster <armbru@redhat.com>
16
Message-Id: <20201217162003.1102738-2-armbru@redhat.com>
17
Reviewed-by: Max Reitz <mreitz@redhat.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
---
9
---
20
block/vpc.c | 8 ++++----
10
block.c | 38 +++++++++++---------------------------
21
1 file changed, 4 insertions(+), 4 deletions(-)
11
1 file changed, 11 insertions(+), 27 deletions(-)
22
12
23
diff --git a/block/vpc.c b/block/vpc.c
13
diff --git a/block.c b/block.c
24
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
25
--- a/block/vpc.c
15
--- a/block.c
26
+++ b/block/vpc.c
16
+++ b/block.c
27
@@ -XXX,XX +XXX,XX @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
17
@@ -XXX,XX +XXX,XX @@ static int bdrv_fill_options(QDict **options, const char *filename,
28
QemuOpts *opts = NULL;
18
static int bdrv_check_update_perm(BlockDriverState *bs, BlockReopenQueue *q,
29
Error *local_err = NULL;
19
uint64_t new_used_perm,
30
bool use_chs;
20
uint64_t new_shared_perm,
31
- uint8_t buf[HEADER_SIZE];
21
- GSList *ignore_children,
32
+ uint8_t dyndisk_header_buf[1024];
22
Error **errp);
33
uint32_t checksum;
23
34
uint64_t computed_size;
24
typedef struct BlockReopenQueueEntry {
35
uint64_t pagetable_size;
25
@@ -XXX,XX +XXX,XX @@ static bool bdrv_a_allow_b(BdrvChild *a, BdrvChild *b, Error **errp)
36
@@ -XXX,XX +XXX,XX @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
26
return false;
27
}
28
29
-static bool bdrv_parent_perms_conflict(BlockDriverState *bs,
30
- GSList *ignore_children,
31
- Error **errp)
32
+static bool bdrv_parent_perms_conflict(BlockDriverState *bs, Error **errp)
33
{
34
BdrvChild *a, *b;
35
36
@@ -XXX,XX +XXX,XX @@ static bool bdrv_parent_perms_conflict(BlockDriverState *bs,
37
* directions.
38
*/
39
QLIST_FOREACH(a, &bs->parents, next_parent) {
40
- if (g_slist_find(ignore_children, a)) {
41
- continue;
42
- }
43
-
44
QLIST_FOREACH(b, &bs->parents, next_parent) {
45
- if (a == b || g_slist_find(ignore_children, b)) {
46
+ if (a == b) {
47
continue;
48
}
49
50
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_safe(BdrvChild *child, BlockDriverState *new_bs,
51
static int bdrv_node_check_perm(BlockDriverState *bs, BlockReopenQueue *q,
52
uint64_t cumulative_perms,
53
uint64_t cumulative_shared_perms,
54
- GSList *ignore_children,
55
Transaction *tran, Error **errp)
56
{
57
BlockDriver *drv = bs->drv;
58
@@ -XXX,XX +XXX,XX @@ static int bdrv_check_perm_common(GSList *list, BlockReopenQueue *q,
59
bool use_cumulative_perms,
60
uint64_t cumulative_perms,
61
uint64_t cumulative_shared_perms,
62
- GSList *ignore_children,
63
Transaction *tran, Error **errp)
64
{
65
int ret;
66
@@ -XXX,XX +XXX,XX @@ static int bdrv_check_perm_common(GSList *list, BlockReopenQueue *q,
67
68
ret = bdrv_node_check_perm(bs, q, cumulative_perms,
69
cumulative_shared_perms,
70
- ignore_children, tran, errp);
71
+ tran, errp);
72
if (ret < 0) {
73
return ret;
74
}
75
@@ -XXX,XX +XXX,XX @@ static int bdrv_check_perm_common(GSList *list, BlockReopenQueue *q,
76
for ( ; list; list = list->next) {
77
bs = list->data;
78
79
- if (bdrv_parent_perms_conflict(bs, ignore_children, errp)) {
80
+ if (bdrv_parent_perms_conflict(bs, errp)) {
81
return -EINVAL;
82
}
83
84
@@ -XXX,XX +XXX,XX @@ static int bdrv_check_perm_common(GSList *list, BlockReopenQueue *q,
85
86
ret = bdrv_node_check_perm(bs, q, cumulative_perms,
87
cumulative_shared_perms,
88
- ignore_children, tran, errp);
89
+ tran, errp);
90
if (ret < 0) {
91
return ret;
92
}
93
@@ -XXX,XX +XXX,XX @@ static int bdrv_check_perm_common(GSList *list, BlockReopenQueue *q,
94
95
static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q,
96
uint64_t cumulative_perms,
97
- uint64_t cumulative_shared_perms,
98
- GSList *ignore_children, Error **errp)
99
+ uint64_t cumulative_shared_perms, Error **errp)
100
{
101
g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, bs);
102
return bdrv_check_perm_common(list, q, true, cumulative_perms,
103
- cumulative_shared_perms, ignore_children,
104
- NULL, errp);
105
+ cumulative_shared_perms, NULL, errp);
106
}
107
108
static int bdrv_list_refresh_perms(GSList *list, BlockReopenQueue *q,
109
Transaction *tran, Error **errp)
110
{
111
- return bdrv_check_perm_common(list, q, false, 0, 0, NULL, tran, errp);
112
+ return bdrv_check_perm_common(list, q, false, 0, 0, tran, errp);
113
}
114
115
/*
116
@@ -XXX,XX +XXX,XX @@ char *bdrv_perm_names(uint64_t perm)
117
static int bdrv_check_update_perm(BlockDriverState *bs, BlockReopenQueue *q,
118
uint64_t new_used_perm,
119
uint64_t new_shared_perm,
120
- GSList *ignore_children,
121
Error **errp)
122
{
123
BdrvChild *c;
124
@@ -XXX,XX +XXX,XX @@ static int bdrv_check_update_perm(BlockDriverState *bs, BlockReopenQueue *q,
125
assert(new_shared_perm & BLK_PERM_WRITE_UNCHANGED);
126
127
QLIST_FOREACH(c, &bs->parents, next_parent) {
128
- if (g_slist_find(ignore_children, c)) {
129
- continue;
130
- }
131
-
132
if ((new_used_perm & c->shared_perm) != new_used_perm) {
133
char *user = bdrv_child_user_desc(c);
134
char *perm_names = bdrv_perm_names(new_used_perm & ~c->shared_perm);
135
@@ -XXX,XX +XXX,XX @@ static int bdrv_check_update_perm(BlockDriverState *bs, BlockReopenQueue *q,
37
}
136
}
38
137
39
if (disk_type == VHD_DYNAMIC) {
138
return bdrv_check_perm(bs, q, cumulative_perms, cumulative_shared_perms,
40
- ret = bdrv_pread(bs->file, be64_to_cpu(footer->data_offset), buf,
139
- ignore_children, errp);
41
- HEADER_SIZE);
140
+ errp);
42
+ ret = bdrv_pread(bs->file, be64_to_cpu(footer->data_offset),
141
}
43
+ dyndisk_header_buf, 1024);
142
143
static int bdrv_refresh_perms(BlockDriverState *bs, Error **errp)
144
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
145
QTAILQ_FOREACH(bs_entry, bs_queue, entry) {
146
BDRVReopenState *state = &bs_entry->state;
147
ret = bdrv_check_perm(state->bs, bs_queue, state->perm,
148
- state->shared_perm, NULL, errp);
149
+ state->shared_perm, errp);
44
if (ret < 0) {
150
if (ret < 0) {
45
error_setg(errp, "Error reading dynamic VHD header");
151
goto cleanup_perm;
46
goto fail;
47
}
152
}
48
153
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
49
- dyndisk_header = (VHDDynDiskHeader *) buf;
154
bs_queue, state->perm, state->shared_perm,
50
+ dyndisk_header = (VHDDynDiskHeader *)dyndisk_header_buf;
155
&nperm, &nshared);
51
156
ret = bdrv_check_update_perm(state->new_backing_bs, NULL,
52
if (strncmp(dyndisk_header->magic, "cxsparse", 8)) {
157
- nperm, nshared, NULL, errp);
53
error_setg(errp, "Invalid header magic");
158
+ nperm, nshared, errp);
159
if (ret < 0) {
160
goto cleanup_perm;
161
}
54
--
162
--
55
2.29.2
163
2.30.2
56
164
57
165
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
Pad VHDDynDiskHeader as specified in the "Virtual Hard Disk Image
3
To be used in the further commit.
4
Format Specification" version 1.0[*]. Change dynamic disk header
5
buffers from uint8_t[1024] to VHDDynDiskHeader. Their size remains
6
the same.
7
4
8
The VHDDynDiskHeader * variables pointing to a VHDDynDiskHeader
5
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
variable right next to it are now silly. Eliminate them.
6
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
10
7
Message-Id: <20210428151804.439460-27-vsementsov@virtuozzo.com>
11
[*] http://download.microsoft.com/download/f/f/e/ffef50a5-07dd-4cf8-aaa3-442c0673a029/Virtual%20Hard%20Disk%20Format%20Spec_10_18_06.doc
12
13
Signed-off-by: Markus Armbruster <armbru@redhat.com>
14
Message-Id: <20201217162003.1102738-6-armbru@redhat.com>
15
Reviewed-by: Max Reitz <mreitz@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
---
9
---
18
block/vpc.c | 41 +++++++++++++++++++----------------------
10
block.c | 46 ++++++++++++++++++++++++++++++++++++++++++----
19
1 file changed, 19 insertions(+), 22 deletions(-)
11
1 file changed, 42 insertions(+), 4 deletions(-)
20
12
21
diff --git a/block/vpc.c b/block/vpc.c
13
diff --git a/block.c b/block.c
22
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
23
--- a/block/vpc.c
15
--- a/block.c
24
+++ b/block/vpc.c
16
+++ b/block.c
25
@@ -XXX,XX +XXX,XX @@ typedef struct vhd_dyndisk_header {
17
@@ -XXX,XX +XXX,XX @@ void bdrv_root_unref_child(BdrvChild *child)
26
uint32_t reserved;
18
bdrv_unref(child_bs);
27
uint64_t data_offset;
19
}
28
} parent_locator[8];
20
29
+ uint8_t reserved2[256];
21
+typedef struct BdrvSetInheritsFrom {
30
} QEMU_PACKED VHDDynDiskHeader;
22
+ BlockDriverState *bs;
31
23
+ BlockDriverState *old_inherits_from;
32
+QEMU_BUILD_BUG_ON(sizeof(VHDDynDiskHeader) != 1024);
24
+} BdrvSetInheritsFrom;
33
+
25
+
34
typedef struct BDRVVPCState {
26
+static void bdrv_set_inherits_from_abort(void *opaque)
35
CoMutex lock;
27
+{
36
uint8_t footer_buf[HEADER_SIZE];
28
+ BdrvSetInheritsFrom *s = opaque;
37
@@ -XXX,XX +XXX,XX @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
29
+
38
BDRVVPCState *s = bs->opaque;
30
+ s->bs->inherits_from = s->old_inherits_from;
39
int i;
31
+}
40
VHDFooter *footer;
32
+
41
- VHDDynDiskHeader *dyndisk_header;
33
+static TransactionActionDrv bdrv_set_inherits_from_drv = {
42
QemuOpts *opts = NULL;
34
+ .abort = bdrv_set_inherits_from_abort,
43
Error *local_err = NULL;
35
+ .clean = g_free,
44
bool use_chs;
36
+};
45
- uint8_t dyndisk_header_buf[1024];
37
+
46
+ VHDDynDiskHeader dyndisk_header;
38
+/* @tran is allowed to be NULL. In this case no rollback is possible */
47
uint32_t checksum;
39
+static void bdrv_set_inherits_from(BlockDriverState *bs,
48
uint64_t computed_size;
40
+ BlockDriverState *new_inherits_from,
49
uint64_t pagetable_size;
41
+ Transaction *tran)
50
@@ -XXX,XX +XXX,XX @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
42
+{
51
43
+ if (tran) {
52
if (disk_type == VHD_DYNAMIC) {
44
+ BdrvSetInheritsFrom *s = g_new(BdrvSetInheritsFrom, 1);
53
ret = bdrv_pread(bs->file, be64_to_cpu(footer->data_offset),
45
+
54
- dyndisk_header_buf, 1024);
46
+ *s = (BdrvSetInheritsFrom) {
55
+ &dyndisk_header, 1024);
47
+ .bs = bs,
56
if (ret < 0) {
48
+ .old_inherits_from = bs->inherits_from,
57
error_setg(errp, "Error reading dynamic VHD header");
49
+ };
58
goto fail;
50
+
51
+ tran_add(tran, &bdrv_set_inherits_from_drv, s);
52
+ }
53
+
54
+ bs->inherits_from = new_inherits_from;
55
+}
56
+
57
/**
58
* Clear all inherits_from pointers from children and grandchildren of
59
* @root that point to @root, where necessary.
60
+ * @tran is allowed to be NULL. In this case no rollback is possible
61
*/
62
-static void bdrv_unset_inherits_from(BlockDriverState *root, BdrvChild *child)
63
+static void bdrv_unset_inherits_from(BlockDriverState *root, BdrvChild *child,
64
+ Transaction *tran)
65
{
66
BdrvChild *c;
67
68
@@ -XXX,XX +XXX,XX @@ static void bdrv_unset_inherits_from(BlockDriverState *root, BdrvChild *child)
69
}
59
}
70
}
60
71
if (c == NULL) {
61
- dyndisk_header = (VHDDynDiskHeader *)dyndisk_header_buf;
72
- child->bs->inherits_from = NULL;
62
-
73
+ bdrv_set_inherits_from(child->bs, NULL, tran);
63
- if (strncmp(dyndisk_header->magic, "cxsparse", 8)) {
64
+ if (strncmp(dyndisk_header.magic, "cxsparse", 8)) {
65
error_setg(errp, "Invalid header magic");
66
ret = -EINVAL;
67
goto fail;
68
}
74
}
69
70
- s->block_size = be32_to_cpu(dyndisk_header->block_size);
71
+ s->block_size = be32_to_cpu(dyndisk_header.block_size);
72
if (!is_power_of_2(s->block_size) || s->block_size < BDRV_SECTOR_SIZE) {
73
error_setg(errp, "Invalid block size %" PRIu32, s->block_size);
74
ret = -EINVAL;
75
@@ -XXX,XX +XXX,XX @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
76
}
77
s->bitmap_size = ((s->block_size / (8 * 512)) + 511) & ~511;
78
79
- s->max_table_entries = be32_to_cpu(dyndisk_header->max_table_entries);
80
+ s->max_table_entries = be32_to_cpu(dyndisk_header.max_table_entries);
81
82
if ((bs->total_sectors * 512) / s->block_size > 0xffffffffU) {
83
error_setg(errp, "Too many blocks");
84
@@ -XXX,XX +XXX,XX @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
85
goto fail;
86
}
87
88
- s->bat_offset = be64_to_cpu(dyndisk_header->table_offset);
89
+ s->bat_offset = be64_to_cpu(dyndisk_header.table_offset);
90
91
ret = bdrv_pread(bs->file, s->bat_offset, s->pagetable,
92
pagetable_size);
93
@@ -XXX,XX +XXX,XX @@ static int calculate_geometry(int64_t total_sectors, uint16_t *cyls,
94
static int create_dynamic_disk(BlockBackend *blk, uint8_t *buf,
95
int64_t total_sectors)
96
{
97
- uint8_t dyndisk_header_buf[1024];
98
- VHDDynDiskHeader *dyndisk_header =
99
- (VHDDynDiskHeader *)dyndisk_header_buf;
100
+ VHDDynDiskHeader dyndisk_header;
101
uint8_t bat_sector[512];
102
size_t block_size, num_bat_entries;
103
int i;
104
@@ -XXX,XX +XXX,XX @@ static int create_dynamic_disk(BlockBackend *blk, uint8_t *buf,
105
}
75
}
106
76
107
/* Prepare the Dynamic Disk Header */
77
QLIST_FOREACH(c, &child->bs->children, next) {
108
- memset(dyndisk_header_buf, 0, 1024);
78
- bdrv_unset_inherits_from(root, c);
109
+ memset(&dyndisk_header, 0, 1024);
79
+ bdrv_unset_inherits_from(root, c, tran);
110
111
- memcpy(dyndisk_header->magic, "cxsparse", 8);
112
+ memcpy(dyndisk_header.magic, "cxsparse", 8);
113
114
/*
115
* Note: The spec is actually wrong here for data_offset, it says
116
* 0xFFFFFFFF, but MS tools expect all 64 bits to be set.
117
*/
118
- dyndisk_header->data_offset = cpu_to_be64(0xFFFFFFFFFFFFFFFFULL);
119
- dyndisk_header->table_offset = cpu_to_be64(3 * 512);
120
- dyndisk_header->version = cpu_to_be32(0x00010000);
121
- dyndisk_header->block_size = cpu_to_be32(block_size);
122
- dyndisk_header->max_table_entries = cpu_to_be32(num_bat_entries);
123
+ dyndisk_header.data_offset = cpu_to_be64(0xFFFFFFFFFFFFFFFFULL);
124
+ dyndisk_header.table_offset = cpu_to_be64(3 * 512);
125
+ dyndisk_header.version = cpu_to_be32(0x00010000);
126
+ dyndisk_header.block_size = cpu_to_be32(block_size);
127
+ dyndisk_header.max_table_entries = cpu_to_be32(num_bat_entries);
128
129
- dyndisk_header->checksum = cpu_to_be32(vpc_checksum(dyndisk_header_buf,
130
- 1024));
131
+ dyndisk_header.checksum = cpu_to_be32(vpc_checksum(&dyndisk_header, 1024));
132
133
/* Write the header */
134
offset = 512;
135
136
- ret = blk_pwrite(blk, offset, dyndisk_header_buf, 1024, 0);
137
+ ret = blk_pwrite(blk, offset, &dyndisk_header, 1024, 0);
138
if (ret < 0) {
139
goto fail;
140
}
80
}
81
}
82
83
@@ -XXX,XX +XXX,XX @@ void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child)
84
return;
85
}
86
87
- bdrv_unset_inherits_from(parent, child);
88
+ bdrv_unset_inherits_from(parent, child, NULL);
89
bdrv_root_unref_child(child);
90
}
91
141
--
92
--
142
2.29.2
93
2.30.2
143
94
144
95
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
Signed-off-by: Markus Armbruster <armbru@redhat.com>
3
To be used in further commit.
4
Message-Id: <20201217162003.1102738-10-armbru@redhat.com>
4
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
5
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
7
Message-Id: <20210428151804.439460-28-vsementsov@virtuozzo.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
9
---
8
block/vpc.c | 29 ++++++++++++++---------------
10
include/block/block.h | 3 ++-
9
1 file changed, 14 insertions(+), 15 deletions(-)
11
block.c | 9 ++++-----
12
block/io.c | 31 +++++++++++++++++++++++++++++--
13
3 files changed, 35 insertions(+), 8 deletions(-)
10
14
11
diff --git a/block/vpc.c b/block/vpc.c
15
diff --git a/include/block/block.h b/include/block/block.h
12
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
13
--- a/block/vpc.c
17
--- a/include/block/block.h
14
+++ b/block/vpc.c
18
+++ b/include/block/block.h
15
@@ -XXX,XX +XXX,XX @@
19
@@ -XXX,XX +XXX,XX @@
16
20
#include "block/dirty-bitmap.h"
17
/**************************************************************/
21
#include "block/blockjob.h"
18
22
#include "qemu/hbitmap.h"
19
-#define HEADER_SIZE 512
23
+#include "qemu/transactions.h"
20
-
24
21
//#define CACHE
25
/*
22
26
* generated_co_wrapper
23
enum vhd_type {
27
@@ -XXX,XX +XXX,XX @@ int64_t bdrv_get_allocated_file_size(BlockDriverState *bs);
24
@@ -XXX,XX +XXX,XX @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
28
BlockMeasureInfo *bdrv_measure(BlockDriver *drv, QemuOpts *opts,
25
goto fail;
29
BlockDriverState *in_bs, Error **errp);
26
}
30
void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr);
27
31
-void bdrv_refresh_limits(BlockDriverState *bs, Error **errp);
28
- ret = bdrv_pread(bs->file, 0, &s->footer, HEADER_SIZE);
32
+void bdrv_refresh_limits(BlockDriverState *bs, Transaction *tran, Error **errp);
29
+ ret = bdrv_pread(bs->file, 0, &s->footer, sizeof(s->footer));
33
int bdrv_commit(BlockDriverState *bs);
30
if (ret < 0) {
34
int bdrv_make_empty(BdrvChild *c, Error **errp);
31
error_setg(errp, "Unable to read VHD header");
35
int bdrv_change_backing_file(BlockDriverState *bs, const char *backing_file,
32
goto fail;
36
diff --git a/block.c b/block.c
33
@@ -XXX,XX +XXX,XX @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
37
index XXXXXXX..XXXXXXX 100644
34
ret = offset;
38
--- a/block.c
35
error_setg(errp, "Invalid file size");
39
+++ b/block.c
36
goto fail;
40
@@ -XXX,XX +XXX,XX @@
37
- } else if (offset < HEADER_SIZE) {
41
#include "qemu/timer.h"
38
+ } else if (offset < sizeof(*footer)) {
42
#include "qemu/cutils.h"
39
ret = -EINVAL;
43
#include "qemu/id.h"
40
error_setg(errp, "File too small for a VHD header");
44
-#include "qemu/transactions.h"
41
goto fail;
45
#include "block/coroutines.h"
42
}
46
43
47
#ifdef CONFIG_BSD
44
/* If a fixed disk, the footer is found only at the end of the file */
48
@@ -XXX,XX +XXX,XX @@ static int bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv,
45
- ret = bdrv_pread(bs->file, offset - HEADER_SIZE, footer,
46
- HEADER_SIZE);
47
+ ret = bdrv_pread(bs->file, offset - sizeof(*footer),
48
+ footer, sizeof(*footer));
49
if (ret < 0) {
50
goto fail;
51
}
52
@@ -XXX,XX +XXX,XX @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
53
54
checksum = be32_to_cpu(footer->checksum);
55
footer->checksum = 0;
56
- if (vpc_checksum(footer, HEADER_SIZE) != checksum) {
57
+ if (vpc_checksum(footer, sizeof(*footer)) != checksum) {
58
error_setg(errp, "Incorrect header checksum");
59
ret = -EINVAL;
60
goto fail;
61
@@ -XXX,XX +XXX,XX @@ static int rewrite_footer(BlockDriverState *bs)
62
BDRVVPCState *s = bs->opaque;
63
int64_t offset = s->free_data_block_offset;
64
65
- ret = bdrv_pwrite_sync(bs->file, offset, &s->footer, HEADER_SIZE);
66
+ ret = bdrv_pwrite_sync(bs->file, offset, &s->footer, sizeof(s->footer));
67
if (ret < 0)
68
return ret;
69
70
@@ -XXX,XX +XXX,XX @@ static int create_dynamic_disk(BlockBackend *blk, VHDFooter *footer,
71
block_size = 0x200000;
72
num_bat_entries = DIV_ROUND_UP(total_sectors, block_size / 512);
73
74
- ret = blk_pwrite(blk, offset, footer, HEADER_SIZE, 0);
75
+ ret = blk_pwrite(blk, offset, footer, sizeof(*footer), 0);
76
if (ret < 0) {
77
goto fail;
78
}
79
80
offset = 1536 + ((num_bat_entries * 4 + 511) & ~511);
81
- ret = blk_pwrite(blk, offset, footer, HEADER_SIZE, 0);
82
+ ret = blk_pwrite(blk, offset, footer, sizeof(*footer), 0);
83
if (ret < 0) {
84
goto fail;
85
}
86
@@ -XXX,XX +XXX,XX @@ static int create_fixed_disk(BlockBackend *blk, VHDFooter *footer,
87
int ret;
88
89
/* Add footer to total size */
90
- total_size += HEADER_SIZE;
91
+ total_size += sizeof(*footer);
92
93
ret = blk_truncate(blk, total_size, false, PREALLOC_MODE_OFF, 0, errp);
94
if (ret < 0) {
95
return ret;
49
return ret;
96
}
50
}
97
51
98
- ret = blk_pwrite(blk, total_size - HEADER_SIZE, footer, HEADER_SIZE, 0);
52
- bdrv_refresh_limits(bs, &local_err);
99
+ ret = blk_pwrite(blk, total_size - sizeof(*footer),
53
+ bdrv_refresh_limits(bs, NULL, &local_err);
100
+ footer, sizeof(*footer), 0);
54
if (local_err) {
101
if (ret < 0) {
55
error_propagate(errp, local_err);
102
error_setg_errno(errp, -ret, "Unable to write VHD header");
56
return -EINVAL;
103
return ret;
57
@@ -XXX,XX +XXX,XX @@ int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
104
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_create(BlockdevCreateOptions *opts,
105
}
58
}
106
59
107
/* Prepare the Hard Disk Footer */
60
out:
108
- memset(&footer, 0, HEADER_SIZE);
61
- bdrv_refresh_limits(bs, NULL);
109
+ memset(&footer, 0, sizeof(footer));
62
+ bdrv_refresh_limits(bs, NULL, NULL);
110
63
111
memcpy(footer.creator, "conectix", 8);
64
return ret;
112
if (vpc_opts->force_size) {
65
}
113
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_create(BlockdevCreateOptions *opts,
66
@@ -XXX,XX +XXX,XX @@ static void bdrv_reopen_commit(BDRVReopenState *reopen_state)
114
footer.features = cpu_to_be32(0x02);
67
bdrv_set_backing_hd(bs, reopen_state->new_backing_bs, &error_abort);
115
footer.version = cpu_to_be32(0x00010000);
116
if (disk_type == VHD_DYNAMIC) {
117
- footer.data_offset = cpu_to_be64(HEADER_SIZE);
118
+ footer.data_offset = cpu_to_be64(sizeof(footer));
119
} else {
120
footer.data_offset = cpu_to_be64(0xFFFFFFFFFFFFFFFFULL);
121
}
68
}
122
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_create(BlockdevCreateOptions *opts,
69
123
qemu_uuid_generate(&uuid);
70
- bdrv_refresh_limits(bs, NULL);
124
footer.uuid = uuid;
71
+ bdrv_refresh_limits(bs, NULL, NULL);
125
72
}
126
- footer.checksum = cpu_to_be32(vpc_checksum(&footer, HEADER_SIZE));
73
127
+ footer.checksum = cpu_to_be32(vpc_checksum(&footer, sizeof(footer)));
74
/*
128
75
@@ -XXX,XX +XXX,XX @@ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
129
if (disk_type == VHD_DYNAMIC) {
76
out:
130
ret = create_dynamic_disk(blk, &footer, total_sectors);
77
tran_finalize(tran, ret);
78
79
- bdrv_refresh_limits(bs_top, NULL);
80
+ bdrv_refresh_limits(bs_top, NULL, NULL);
81
82
return ret;
83
}
84
diff --git a/block/io.c b/block/io.c
85
index XXXXXXX..XXXXXXX 100644
86
--- a/block/io.c
87
+++ b/block/io.c
88
@@ -XXX,XX +XXX,XX @@ static void bdrv_merge_limits(BlockLimits *dst, const BlockLimits *src)
89
dst->max_iov = MIN_NON_ZERO(dst->max_iov, src->max_iov);
90
}
91
92
-void bdrv_refresh_limits(BlockDriverState *bs, Error **errp)
93
+typedef struct BdrvRefreshLimitsState {
94
+ BlockDriverState *bs;
95
+ BlockLimits old_bl;
96
+} BdrvRefreshLimitsState;
97
+
98
+static void bdrv_refresh_limits_abort(void *opaque)
99
+{
100
+ BdrvRefreshLimitsState *s = opaque;
101
+
102
+ s->bs->bl = s->old_bl;
103
+}
104
+
105
+static TransactionActionDrv bdrv_refresh_limits_drv = {
106
+ .abort = bdrv_refresh_limits_abort,
107
+ .clean = g_free,
108
+};
109
+
110
+/* @tran is allowed to be NULL, in this case no rollback is possible. */
111
+void bdrv_refresh_limits(BlockDriverState *bs, Transaction *tran, Error **errp)
112
{
113
ERRP_GUARD();
114
BlockDriver *drv = bs->drv;
115
BdrvChild *c;
116
bool have_limits;
117
118
+ if (tran) {
119
+ BdrvRefreshLimitsState *s = g_new(BdrvRefreshLimitsState, 1);
120
+ *s = (BdrvRefreshLimitsState) {
121
+ .bs = bs,
122
+ .old_bl = bs->bl,
123
+ };
124
+ tran_add(tran, &bdrv_refresh_limits_drv, s);
125
+ }
126
+
127
memset(&bs->bl, 0, sizeof(bs->bl));
128
129
if (!drv) {
130
@@ -XXX,XX +XXX,XX @@ void bdrv_refresh_limits(BlockDriverState *bs, Error **errp)
131
QLIST_FOREACH(c, &bs->children, next) {
132
if (c->role & (BDRV_CHILD_DATA | BDRV_CHILD_FILTERED | BDRV_CHILD_COW))
133
{
134
- bdrv_refresh_limits(c->bs, errp);
135
+ bdrv_refresh_limits(c->bs, tran, errp);
136
if (*errp) {
137
return;
138
}
131
--
139
--
132
2.29.2
140
2.30.2
133
141
134
142
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
create_dynamic_disk() takes a buffer holding the footer as first
3
Split out no-perm part of bdrv_set_backing_hd() as a separate
4
argument. It writes out the footer (512 bytes), then reuses the
4
transaction action. Note the in case of existing BdrvChild we reuse it,
5
buffer to initialize and write out the dynamic header (1024 bytes).
5
not recreate, just to do less actions.
6
6
7
Works, because the caller passes a buffer that is large enough for
7
We don't need to create extra reference to backing_hd as we don't lose
8
both purposes. I hate that.
8
it in bdrv_attach_child().
9
9
10
Use a separate buffer for the dynamic header, and adjust the caller's
10
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
11
buffer.
11
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
12
12
Message-Id: <20210428151804.439460-29-vsementsov@virtuozzo.com>
13
Signed-off-by: Markus Armbruster <armbru@redhat.com>
14
Message-Id: <20201217162003.1102738-4-armbru@redhat.com>
15
Reviewed-by: Max Reitz <mreitz@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
---
14
---
18
block/vpc.c | 22 ++++++++++++----------
15
block.c | 54 +++++++++++++++++++++++++++++++++++++-----------------
19
1 file changed, 12 insertions(+), 10 deletions(-)
16
1 file changed, 37 insertions(+), 17 deletions(-)
20
17
21
diff --git a/block/vpc.c b/block/vpc.c
18
diff --git a/block.c b/block.c
22
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
23
--- a/block/vpc.c
20
--- a/block.c
24
+++ b/block/vpc.c
21
+++ b/block.c
25
@@ -XXX,XX +XXX,XX @@ static int calculate_geometry(int64_t total_sectors, uint16_t *cyls,
22
@@ -XXX,XX +XXX,XX @@ static int bdrv_attach_child_noperm(BlockDriverState *parent_bs,
26
static int create_dynamic_disk(BlockBackend *blk, uint8_t *buf,
23
BdrvChild **child,
27
int64_t total_sectors)
24
Transaction *tran,
25
Error **errp);
26
+static void bdrv_remove_filter_or_cow_child(BlockDriverState *bs,
27
+ Transaction *tran);
28
29
static int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue
30
*queue, Error **errp);
31
@@ -XXX,XX +XXX,XX @@ static BdrvChildRole bdrv_backing_role(BlockDriverState *bs)
32
* Sets the bs->backing link of a BDS. A new reference is created; callers
33
* which don't need their own reference any more must call bdrv_unref().
34
*/
35
-int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
36
- Error **errp)
37
+static int bdrv_set_backing_noperm(BlockDriverState *bs,
38
+ BlockDriverState *backing_hd,
39
+ Transaction *tran, Error **errp)
28
{
40
{
29
+ uint8_t dyndisk_header_buf[1024];
41
int ret = 0;
30
VHDDynDiskHeader *dyndisk_header =
42
bool update_inherits_from = bdrv_chain_contains(bs, backing_hd) &&
31
- (VHDDynDiskHeader *) buf;
43
@@ -XXX,XX +XXX,XX @@ int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
32
+ (VHDDynDiskHeader *)dyndisk_header_buf;
44
return -EPERM;
33
uint8_t bat_sector[512];
34
size_t block_size, num_bat_entries;
35
int i;
36
@@ -XXX,XX +XXX,XX @@ static int create_dynamic_disk(BlockBackend *blk, uint8_t *buf,
37
}
45
}
38
46
39
/* Prepare the Dynamic Disk Header */
47
- if (backing_hd) {
40
- memset(buf, 0, 1024);
48
- bdrv_ref(backing_hd);
41
+ memset(dyndisk_header_buf, 0, 1024);
49
- }
42
50
-
43
memcpy(dyndisk_header->magic, "cxsparse", 8);
51
if (bs->backing) {
44
52
/* Cannot be frozen, we checked that above */
45
@@ -XXX,XX +XXX,XX @@ static int create_dynamic_disk(BlockBackend *blk, uint8_t *buf,
53
- bdrv_unref_child(bs, bs->backing);
46
dyndisk_header->block_size = cpu_to_be32(block_size);
54
- bs->backing = NULL;
47
dyndisk_header->max_table_entries = cpu_to_be32(num_bat_entries);
55
+ bdrv_unset_inherits_from(bs, bs->backing, tran);
48
56
+ bdrv_remove_filter_or_cow_child(bs, tran);
49
- dyndisk_header->checksum = cpu_to_be32(vpc_checksum(buf, 1024));
50
+ dyndisk_header->checksum = cpu_to_be32(vpc_checksum(dyndisk_header_buf,
51
+ 1024));
52
53
/* Write the header */
54
offset = 512;
55
56
- ret = blk_pwrite(blk, offset, buf, 1024, 0);
57
+ ret = blk_pwrite(blk, offset, dyndisk_header_buf, 1024, 0);
58
if (ret < 0) {
59
goto fail;
60
}
57
}
61
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_create(BlockdevCreateOptions *opts,
58
62
BlockBackend *blk = NULL;
59
if (!backing_hd) {
63
BlockDriverState *bs = NULL;
60
goto out;
64
65
- uint8_t buf[1024];
66
- VHDFooter *footer = (VHDFooter *) buf;
67
+ uint8_t footer_buf[HEADER_SIZE];
68
+ VHDFooter *footer = (VHDFooter *)footer_buf;
69
uint16_t cyls = 0;
70
uint8_t heads = 0;
71
uint8_t secs_per_cyl = 0;
72
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_create(BlockdevCreateOptions *opts,
73
}
61
}
74
62
75
/* Prepare the Hard Disk Footer */
63
- bs->backing = bdrv_attach_child(bs, backing_hd, "backing", &child_of_bds,
76
- memset(buf, 0, 1024);
64
- bdrv_backing_role(bs), errp);
77
+ memset(footer_buf, 0, HEADER_SIZE);
65
- if (!bs->backing) {
78
66
- ret = -EPERM;
79
memcpy(footer->creator, "conectix", 8);
67
- goto out;
80
if (vpc_opts->force_size) {
68
+ ret = bdrv_attach_child_noperm(bs, backing_hd, "backing",
81
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_create(BlockdevCreateOptions *opts,
69
+ &child_of_bds, bdrv_backing_role(bs),
82
qemu_uuid_generate(&uuid);
70
+ &bs->backing, tran, errp);
83
footer->uuid = uuid;
71
+ if (ret < 0) {
84
72
+ return ret;
85
- footer->checksum = cpu_to_be32(vpc_checksum(buf, HEADER_SIZE));
86
+ footer->checksum = cpu_to_be32(vpc_checksum(footer_buf, HEADER_SIZE));
87
88
if (disk_type == VHD_DYNAMIC) {
89
- ret = create_dynamic_disk(blk, buf, total_sectors);
90
+ ret = create_dynamic_disk(blk, footer_buf, total_sectors);
91
if (ret < 0) {
92
error_setg(errp, "Unable to create or write VHD header");
93
}
94
} else {
95
- ret = create_fixed_disk(blk, buf, total_size, errp);
96
+ ret = create_fixed_disk(blk, footer_buf, total_size, errp);
97
}
73
}
98
74
75
- /* If backing_hd was already part of bs's backing chain, and
76
+
77
+ /*
78
+ * If backing_hd was already part of bs's backing chain, and
79
* inherits_from pointed recursively to bs then let's update it to
80
- * point directly to bs (else it will become NULL). */
81
+ * point directly to bs (else it will become NULL).
82
+ */
83
if (update_inherits_from) {
84
- backing_hd->inherits_from = bs;
85
+ bdrv_set_inherits_from(backing_hd, bs, tran);
86
}
87
99
out:
88
out:
89
- bdrv_refresh_limits(bs, NULL, NULL);
90
+ bdrv_refresh_limits(bs, tran, NULL);
91
+
92
+ return 0;
93
+}
94
+
95
+int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
96
+ Error **errp)
97
+{
98
+ int ret;
99
+ Transaction *tran = tran_new();
100
+
101
+ ret = bdrv_set_backing_noperm(bs, backing_hd, tran, errp);
102
+ if (ret < 0) {
103
+ goto out;
104
+ }
105
+
106
+ ret = bdrv_refresh_perms(bs, errp);
107
+out:
108
+ tran_finalize(tran, ret);
109
110
return ret;
111
}
100
--
112
--
101
2.29.2
113
2.30.2
102
114
103
115
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
During reopen we may add backing bs from other aio context, which may
4
lead to changing original context of top bs.
5
6
We are going to move graph modification to prepare stage. So, it will
7
be possible that bdrv_flush() in bdrv_reopen_prepare called on bs in
8
non-original aio context, which we didn't aquire which leads to crash.
9
10
To avoid this problem move bdrv_flush() to be a separate reopen stage
11
before bdrv_reopen_prepare().
12
13
This doesn't seem correct to acquire only one aio context and not all
14
contexts participating in reopen. But it's not obvious how to do it
15
correctly, keeping in mind:
16
17
1. rules of bdrv_set_aio_context_ignore() that requires new_context
18
lock not being held
19
20
2. possible deadlocks because of holding all (or several?) AioContext
21
locks
22
23
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
24
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
25
Message-Id: <20210428151804.439460-30-vsementsov@virtuozzo.com>
26
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
27
---
28
block.c | 14 ++++++++------
29
1 file changed, 8 insertions(+), 6 deletions(-)
30
31
diff --git a/block.c b/block.c
32
index XXXXXXX..XXXXXXX 100644
33
--- a/block.c
34
+++ b/block.c
35
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
36
37
assert(bs_queue != NULL);
38
39
+ QTAILQ_FOREACH(bs_entry, bs_queue, entry) {
40
+ ret = bdrv_flush(bs_entry->state.bs);
41
+ if (ret < 0) {
42
+ error_setg_errno(errp, -ret, "Error flushing drive");
43
+ goto cleanup;
44
+ }
45
+ }
46
+
47
QTAILQ_FOREACH(bs_entry, bs_queue, entry) {
48
assert(bs_entry->state.bs->quiesce_counter > 0);
49
if (bdrv_reopen_prepare(&bs_entry->state, bs_queue, errp)) {
50
@@ -XXX,XX +XXX,XX @@ static int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
51
bdrv_reopen_perm(queue, reopen_state->bs,
52
&reopen_state->perm, &reopen_state->shared_perm);
53
54
- ret = bdrv_flush(reopen_state->bs);
55
- if (ret) {
56
- error_setg_errno(errp, -ret, "Error flushing drive");
57
- goto error;
58
- }
59
-
60
if (drv->bdrv_reopen_prepare) {
61
/*
62
* If a driver-specific option is missing, it means that we
63
--
64
2.30.2
65
66
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
create_dynamic_disk() takes a buffer holding the footer as first
3
Move bdrv_reopen_multiple to new paradigm of permission update:
4
argument. It writes out the footer (512 bytes), then reuses the
4
first update graph relations, then do refresh the permissions.
5
buffer to initialize and write out the dynamic header (1024 bytes),
6
then reuses it again to initialize and write out BAT sectors (512).
7
5
8
Works, because the caller passes a buffer that is large enough for all
6
We have to modify reopen process in file-posix driver: with new scheme
9
three purposes. I hate that.
7
we don't have prepared permissions in raw_reopen_prepare(), so we
8
should reconfigure fd in raw_check_perm(). Still this seems more native
9
and simple anyway.
10
10
11
Use a separate buffer for writing out BAT sectors. The next commit
11
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
12
will do the same for the dynamic header.
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
13
13
Message-Id: <20210428151804.439460-31-vsementsov@virtuozzo.com>
14
Signed-off-by: Markus Armbruster <armbru@redhat.com>
15
Message-Id: <20201217162003.1102738-3-armbru@redhat.com>
16
Reviewed-by: Max Reitz <mreitz@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
---
15
---
19
block/vpc.c | 5 +++--
16
include/block/block.h | 3 +-
20
1 file changed, 3 insertions(+), 2 deletions(-)
17
block.c | 187 ++++++++++++------------------------------
18
block/file-posix.c | 91 +++++++-------------
19
3 files changed, 84 insertions(+), 197 deletions(-)
21
20
22
diff --git a/block/vpc.c b/block/vpc.c
21
diff --git a/include/block/block.h b/include/block/block.h
23
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
24
--- a/block/vpc.c
23
--- a/include/block/block.h
25
+++ b/block/vpc.c
24
+++ b/include/block/block.h
26
@@ -XXX,XX +XXX,XX @@ static int create_dynamic_disk(BlockBackend *blk, uint8_t *buf,
25
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVReopenState {
26
BlockdevDetectZeroesOptions detect_zeroes;
27
bool backing_missing;
28
bool replace_backing_bs; /* new_backing_bs is ignored if this is false */
29
- BlockDriverState *new_backing_bs; /* If NULL then detach the current bs */
30
- uint64_t perm, shared_perm;
31
+ BlockDriverState *old_backing_bs; /* keep pointer for permissions update */
32
QDict *options;
33
QDict *explicit_options;
34
void *opaque;
35
diff --git a/block.c b/block.c
36
index XXXXXXX..XXXXXXX 100644
37
--- a/block.c
38
+++ b/block.c
39
@@ -XXX,XX +XXX,XX @@ static int bdrv_attach_child_noperm(BlockDriverState *parent_bs,
40
static void bdrv_remove_filter_or_cow_child(BlockDriverState *bs,
41
Transaction *tran);
42
43
-static int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue
44
- *queue, Error **errp);
45
+static int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
46
+ BlockReopenQueue *queue,
47
+ Transaction *set_backings_tran, Error **errp);
48
static void bdrv_reopen_commit(BDRVReopenState *reopen_state);
49
static void bdrv_reopen_abort(BDRVReopenState *reopen_state);
50
51
@@ -XXX,XX +XXX,XX @@ static void bdrv_list_abort_perm_update(GSList *list)
52
}
53
}
54
55
+__attribute__((unused))
56
static void bdrv_abort_perm_update(BlockDriverState *bs)
27
{
57
{
28
VHDDynDiskHeader *dyndisk_header =
58
g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, bs);
29
(VHDDynDiskHeader *) buf;
59
@@ -XXX,XX +XXX,XX @@ char *bdrv_perm_names(uint64_t perm)
30
+ uint8_t bat_sector[512];
60
*
31
size_t block_size, num_bat_entries;
61
* Needs to be followed by a call to either bdrv_set_perm() or
32
int i;
62
* bdrv_abort_perm_update(). */
63
+__attribute__((unused))
64
static int bdrv_check_update_perm(BlockDriverState *bs, BlockReopenQueue *q,
65
uint64_t new_used_perm,
66
uint64_t new_shared_perm,
67
@@ -XXX,XX +XXX,XX @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
68
bs_entry->state.explicit_options = explicit_options;
69
bs_entry->state.flags = flags;
70
71
- /* This needs to be overwritten in bdrv_reopen_prepare() */
72
- bs_entry->state.perm = UINT64_MAX;
73
- bs_entry->state.shared_perm = 0;
74
-
75
/*
76
* If keep_old_opts is false then it means that unspecified
77
* options must be reset to their original value. We don't allow
78
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
79
{
80
int ret = -1;
81
BlockReopenQueueEntry *bs_entry, *next;
82
+ Transaction *tran = tran_new();
83
+ g_autoptr(GHashTable) found = NULL;
84
+ g_autoptr(GSList) refresh_list = NULL;
85
86
assert(bs_queue != NULL);
87
88
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
89
90
QTAILQ_FOREACH(bs_entry, bs_queue, entry) {
91
assert(bs_entry->state.bs->quiesce_counter > 0);
92
- if (bdrv_reopen_prepare(&bs_entry->state, bs_queue, errp)) {
93
- goto cleanup;
94
+ ret = bdrv_reopen_prepare(&bs_entry->state, bs_queue, tran, errp);
95
+ if (ret < 0) {
96
+ goto abort;
97
}
98
bs_entry->prepared = true;
99
}
100
101
+ found = g_hash_table_new(NULL, NULL);
102
QTAILQ_FOREACH(bs_entry, bs_queue, entry) {
103
BDRVReopenState *state = &bs_entry->state;
104
- ret = bdrv_check_perm(state->bs, bs_queue, state->perm,
105
- state->shared_perm, errp);
106
- if (ret < 0) {
107
- goto cleanup_perm;
108
- }
109
- /* Check if new_backing_bs would accept the new permissions */
110
- if (state->replace_backing_bs && state->new_backing_bs) {
111
- uint64_t nperm, nshared;
112
- bdrv_child_perm(state->bs, state->new_backing_bs,
113
- NULL, bdrv_backing_role(state->bs),
114
- bs_queue, state->perm, state->shared_perm,
115
- &nperm, &nshared);
116
- ret = bdrv_check_update_perm(state->new_backing_bs, NULL,
117
- nperm, nshared, errp);
118
- if (ret < 0) {
119
- goto cleanup_perm;
120
- }
121
+
122
+ refresh_list = bdrv_topological_dfs(refresh_list, found, state->bs);
123
+ if (state->old_backing_bs) {
124
+ refresh_list = bdrv_topological_dfs(refresh_list, found,
125
+ state->old_backing_bs);
126
}
127
- bs_entry->perms_checked = true;
128
+ }
129
+
130
+ /*
131
+ * Note that file-posix driver rely on permission update done during reopen
132
+ * (even if no permission changed), because it wants "new" permissions for
133
+ * reconfiguring the fd and that's why it does it in raw_check_perm(), not
134
+ * in raw_reopen_prepare() which is called with "old" permissions.
135
+ */
136
+ ret = bdrv_list_refresh_perms(refresh_list, bs_queue, tran, errp);
137
+ if (ret < 0) {
138
+ goto abort;
139
}
140
141
/*
142
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
143
bdrv_reopen_commit(&bs_entry->state);
144
}
145
146
- ret = 0;
147
-cleanup_perm:
148
- QTAILQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) {
149
- BDRVReopenState *state = &bs_entry->state;
150
-
151
- if (!bs_entry->perms_checked) {
152
- continue;
153
- }
154
-
155
- if (ret == 0) {
156
- uint64_t perm, shared;
157
+ tran_commit(tran);
158
159
- bdrv_get_cumulative_perm(state->bs, &perm, &shared);
160
- assert(perm == state->perm);
161
- assert(shared == state->shared_perm);
162
+ QTAILQ_FOREACH_REVERSE(bs_entry, bs_queue, entry) {
163
+ BlockDriverState *bs = bs_entry->state.bs;
164
165
- bdrv_set_perm(state->bs);
166
- } else {
167
- bdrv_abort_perm_update(state->bs);
168
- if (state->replace_backing_bs && state->new_backing_bs) {
169
- bdrv_abort_perm_update(state->new_backing_bs);
170
- }
171
+ if (bs->drv->bdrv_reopen_commit_post) {
172
+ bs->drv->bdrv_reopen_commit_post(&bs_entry->state);
173
}
174
}
175
176
- if (ret == 0) {
177
- QTAILQ_FOREACH_REVERSE(bs_entry, bs_queue, entry) {
178
- BlockDriverState *bs = bs_entry->state.bs;
179
+ ret = 0;
180
+ goto cleanup;
181
182
- if (bs->drv->bdrv_reopen_commit_post)
183
- bs->drv->bdrv_reopen_commit_post(&bs_entry->state);
184
+abort:
185
+ tran_abort(tran);
186
+ QTAILQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) {
187
+ if (bs_entry->prepared) {
188
+ bdrv_reopen_abort(&bs_entry->state);
189
}
190
+ qobject_unref(bs_entry->state.explicit_options);
191
+ qobject_unref(bs_entry->state.options);
192
}
193
+
194
cleanup:
195
QTAILQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) {
196
- if (ret) {
197
- if (bs_entry->prepared) {
198
- bdrv_reopen_abort(&bs_entry->state);
199
- }
200
- qobject_unref(bs_entry->state.explicit_options);
201
- qobject_unref(bs_entry->state.options);
202
- }
203
- if (bs_entry->state.new_backing_bs) {
204
- bdrv_unref(bs_entry->state.new_backing_bs);
205
- }
206
g_free(bs_entry);
207
}
208
g_free(bs_queue);
209
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only,
210
return ret;
211
}
212
213
-static BlockReopenQueueEntry *find_parent_in_reopen_queue(BlockReopenQueue *q,
214
- BdrvChild *c)
215
-{
216
- BlockReopenQueueEntry *entry;
217
-
218
- QTAILQ_FOREACH(entry, q, entry) {
219
- BlockDriverState *bs = entry->state.bs;
220
- BdrvChild *child;
221
-
222
- QLIST_FOREACH(child, &bs->children, next) {
223
- if (child == c) {
224
- return entry;
225
- }
226
- }
227
- }
228
-
229
- return NULL;
230
-}
231
-
232
-static void bdrv_reopen_perm(BlockReopenQueue *q, BlockDriverState *bs,
233
- uint64_t *perm, uint64_t *shared)
234
-{
235
- BdrvChild *c;
236
- BlockReopenQueueEntry *parent;
237
- uint64_t cumulative_perms = 0;
238
- uint64_t cumulative_shared_perms = BLK_PERM_ALL;
239
-
240
- QLIST_FOREACH(c, &bs->parents, next_parent) {
241
- parent = find_parent_in_reopen_queue(q, c);
242
- if (!parent) {
243
- cumulative_perms |= c->perm;
244
- cumulative_shared_perms &= c->shared_perm;
245
- } else {
246
- uint64_t nperm, nshared;
247
-
248
- bdrv_child_perm(parent->state.bs, bs, c, c->role, q,
249
- parent->state.perm, parent->state.shared_perm,
250
- &nperm, &nshared);
251
-
252
- cumulative_perms |= nperm;
253
- cumulative_shared_perms &= nshared;
254
- }
255
- }
256
- *perm = cumulative_perms;
257
- *shared = cumulative_shared_perms;
258
-}
259
-
260
static bool bdrv_reopen_can_attach(BlockDriverState *parent,
261
BdrvChild *child,
262
BlockDriverState *new_child,
263
@@ -XXX,XX +XXX,XX @@ static bool bdrv_reopen_can_attach(BlockDriverState *parent,
264
* Return 0 on success, otherwise return < 0 and set @errp.
265
*/
266
static int bdrv_reopen_parse_backing(BDRVReopenState *reopen_state,
267
+ Transaction *set_backings_tran,
268
Error **errp)
269
{
270
BlockDriverState *bs = reopen_state->bs;
271
@@ -XXX,XX +XXX,XX @@ static int bdrv_reopen_parse_backing(BDRVReopenState *reopen_state,
272
273
/* If we want to replace the backing file we need some extra checks */
274
if (new_backing_bs != bdrv_filter_or_cow_bs(overlay_bs)) {
275
+ int ret;
276
+
277
/* Check for implicit nodes between bs and its backing file */
278
if (bs != overlay_bs) {
279
error_setg(errp, "Cannot change backing link if '%s' has "
280
@@ -XXX,XX +XXX,XX @@ static int bdrv_reopen_parse_backing(BDRVReopenState *reopen_state,
281
return -EPERM;
282
}
283
reopen_state->replace_backing_bs = true;
284
- if (new_backing_bs) {
285
- bdrv_ref(new_backing_bs);
286
- reopen_state->new_backing_bs = new_backing_bs;
287
+ reopen_state->old_backing_bs = bs->backing ? bs->backing->bs : NULL;
288
+ ret = bdrv_set_backing_noperm(bs, new_backing_bs, set_backings_tran,
289
+ errp);
290
+ if (ret < 0) {
291
+ return ret;
292
}
293
}
294
295
@@ -XXX,XX +XXX,XX @@ static int bdrv_reopen_parse_backing(BDRVReopenState *reopen_state,
296
*
297
*/
298
static int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
299
- BlockReopenQueue *queue, Error **errp)
300
+ BlockReopenQueue *queue,
301
+ Transaction *set_backings_tran, Error **errp)
302
{
303
int ret = -1;
304
int old_flags;
305
@@ -XXX,XX +XXX,XX @@ static int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
306
goto error;
307
}
308
309
- /* Calculate required permissions after reopening */
310
- bdrv_reopen_perm(queue, reopen_state->bs,
311
- &reopen_state->perm, &reopen_state->shared_perm);
312
-
313
if (drv->bdrv_reopen_prepare) {
314
/*
315
* If a driver-specific option is missing, it means that we
316
@@ -XXX,XX +XXX,XX @@ static int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
317
* either a reference to an existing node (using its node name)
318
* or NULL to simply detach the current backing file.
319
*/
320
- ret = bdrv_reopen_parse_backing(reopen_state, errp);
321
+ ret = bdrv_reopen_parse_backing(reopen_state, set_backings_tran, errp);
322
if (ret < 0) {
323
goto error;
324
}
325
@@ -XXX,XX +XXX,XX @@ static void bdrv_reopen_commit(BDRVReopenState *reopen_state)
326
qdict_del(bs->explicit_options, child->name);
327
qdict_del(bs->options, child->name);
328
}
329
-
330
- /*
331
- * Change the backing file if a new one was specified. We do this
332
- * after updating bs->options, so bdrv_refresh_filename() (called
333
- * from bdrv_set_backing_hd()) has the new values.
334
- */
335
- if (reopen_state->replace_backing_bs) {
336
- BlockDriverState *old_backing_bs = child_bs(bs->backing);
337
- assert(!old_backing_bs || !old_backing_bs->implicit);
338
- /* Abort the permission update on the backing bs we're detaching */
339
- if (old_backing_bs) {
340
- bdrv_abort_perm_update(old_backing_bs);
341
- }
342
- bdrv_set_backing_hd(bs, reopen_state->new_backing_bs, &error_abort);
343
- }
344
-
345
bdrv_refresh_limits(bs, NULL, NULL);
346
}
347
348
diff --git a/block/file-posix.c b/block/file-posix.c
349
index XXXXXXX..XXXXXXX 100644
350
--- a/block/file-posix.c
351
+++ b/block/file-posix.c
352
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVRawState {
353
} BDRVRawState;
354
355
typedef struct BDRVRawReopenState {
356
- int fd;
357
int open_flags;
358
bool drop_cache;
359
bool check_cache_dropped;
360
@@ -XXX,XX +XXX,XX @@ static int raw_reopen_prepare(BDRVReopenState *state,
361
BDRVRawReopenState *rs;
362
QemuOpts *opts;
33
int ret;
363
int ret;
34
@@ -XXX,XX +XXX,XX @@ static int create_dynamic_disk(BlockBackend *blk, uint8_t *buf,
364
- Error *local_err = NULL;
35
/* Write the initial BAT */
365
36
offset = 3 * 512;
366
assert(state != NULL);
37
367
assert(state->bs != NULL);
38
- memset(buf, 0xFF, 512);
368
@@ -XXX,XX +XXX,XX @@ static int raw_reopen_prepare(BDRVReopenState *state,
39
+ memset(bat_sector, 0xFF, 512);
369
* bdrv_reopen_prepare() will detect changes and complain. */
40
for (i = 0; i < DIV_ROUND_UP(num_bat_entries * 4, 512); i++) {
370
qemu_opts_to_qdict(opts, state->options);
41
- ret = blk_pwrite(blk, offset, buf, 512, 0);
371
42
+ ret = blk_pwrite(blk, offset, bat_sector, 512, 0);
372
- rs->fd = raw_reconfigure_getfd(state->bs, state->flags, &rs->open_flags,
43
if (ret < 0) {
373
- state->perm, true, &local_err);
44
goto fail;
374
- if (local_err) {
45
}
375
- error_propagate(errp, local_err);
376
- ret = -1;
377
- goto out;
378
- }
379
-
380
- /* Fail already reopen_prepare() if we can't get a working O_DIRECT
381
- * alignment with the new fd. */
382
- if (rs->fd != -1) {
383
- raw_probe_alignment(state->bs, rs->fd, &local_err);
384
- if (local_err) {
385
- error_propagate(errp, local_err);
386
- ret = -EINVAL;
387
- goto out_fd;
388
- }
389
- }
390
+ /*
391
+ * As part of reopen prepare we also want to create new fd by
392
+ * raw_reconfigure_getfd(). But it wants updated "perm", when in
393
+ * bdrv_reopen_multiple() .bdrv_reopen_prepare() callback called prior to
394
+ * permission update. Happily, permission update is always a part (a seprate
395
+ * stage) of bdrv_reopen_multiple() so we can rely on this fact and
396
+ * reconfigure fd in raw_check_perm().
397
+ */
398
399
s->reopen_state = state;
400
ret = 0;
401
-out_fd:
402
- if (ret < 0) {
403
- qemu_close(rs->fd);
404
- rs->fd = -1;
405
- }
406
+
407
out:
408
qemu_opts_del(opts);
409
return ret;
410
@@ -XXX,XX +XXX,XX @@ static void raw_reopen_commit(BDRVReopenState *state)
411
s->drop_cache = rs->drop_cache;
412
s->check_cache_dropped = rs->check_cache_dropped;
413
s->open_flags = rs->open_flags;
414
-
415
- qemu_close(s->fd);
416
- s->fd = rs->fd;
417
-
418
g_free(state->opaque);
419
state->opaque = NULL;
420
421
@@ -XXX,XX +XXX,XX @@ static void raw_reopen_abort(BDRVReopenState *state)
422
return;
423
}
424
425
- if (rs->fd >= 0) {
426
- qemu_close(rs->fd);
427
- rs->fd = -1;
428
- }
429
g_free(state->opaque);
430
state->opaque = NULL;
431
432
@@ -XXX,XX +XXX,XX @@ static int raw_check_perm(BlockDriverState *bs, uint64_t perm, uint64_t shared,
433
Error **errp)
434
{
435
BDRVRawState *s = bs->opaque;
436
- BDRVRawReopenState *rs = NULL;
437
+ int input_flags = s->reopen_state ? s->reopen_state->flags : bs->open_flags;
438
int open_flags;
439
int ret;
440
441
- if (s->perm_change_fd) {
442
+ /* We may need a new fd if auto-read-only switches the mode */
443
+ ret = raw_reconfigure_getfd(bs, input_flags, &open_flags, perm,
444
+ false, errp);
445
+ if (ret < 0) {
446
+ return ret;
447
+ } else if (ret != s->fd) {
448
+ Error *local_err = NULL;
449
+
450
/*
451
- * In the context of reopen, this function may be called several times
452
- * (directly and recursively while change permissions of the parent).
453
- * This is even true for children that don't inherit from the original
454
- * reopen node, so s->reopen_state is not set.
455
- *
456
- * Ignore all but the first call.
457
+ * Fail already check_perm() if we can't get a working O_DIRECT
458
+ * alignment with the new fd.
459
*/
460
- return 0;
461
- }
462
-
463
- if (s->reopen_state) {
464
- /* We already have a new file descriptor to set permissions for */
465
- assert(s->reopen_state->perm == perm);
466
- assert(s->reopen_state->shared_perm == shared);
467
- rs = s->reopen_state->opaque;
468
- s->perm_change_fd = rs->fd;
469
- s->perm_change_flags = rs->open_flags;
470
- } else {
471
- /* We may need a new fd if auto-read-only switches the mode */
472
- ret = raw_reconfigure_getfd(bs, bs->open_flags, &open_flags, perm,
473
- false, errp);
474
- if (ret < 0) {
475
- return ret;
476
- } else if (ret != s->fd) {
477
- s->perm_change_fd = ret;
478
- s->perm_change_flags = open_flags;
479
+ raw_probe_alignment(bs, ret, &local_err);
480
+ if (local_err) {
481
+ error_propagate(errp, local_err);
482
+ return -EINVAL;
483
}
484
+
485
+ s->perm_change_fd = ret;
486
+ s->perm_change_flags = open_flags;
487
}
488
489
/* Prepare permissions on old fd to avoid conflicts between old and new,
490
@@ -XXX,XX +XXX,XX @@ static int raw_check_perm(BlockDriverState *bs, uint64_t perm, uint64_t shared,
491
return 0;
492
493
fail:
494
- if (s->perm_change_fd && !s->reopen_state) {
495
+ if (s->perm_change_fd) {
496
qemu_close(s->perm_change_fd);
497
}
498
s->perm_change_fd = 0;
499
@@ -XXX,XX +XXX,XX @@ static void raw_abort_perm_update(BlockDriverState *bs)
500
501
/* For reopen, .bdrv_reopen_abort is called afterwards and will close
502
* the file descriptor. */
503
- if (s->perm_change_fd && !s->reopen_state) {
504
+ if (s->perm_change_fd) {
505
qemu_close(s->perm_change_fd);
506
}
507
s->perm_change_fd = 0;
46
--
508
--
47
2.29.2
509
2.30.2
48
510
49
511
diff view generated by jsdifflib
1
From: Stefan Hajnoczi <stefanha@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
Document the qemu-storage-daemon tool. Most of the command-line options
3
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
4
are identical to their QEMU counterparts. Perhaps Sphinx hxtool
4
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
5
integration could be extended to extract documentation for individual
5
Message-Id: <20210428151804.439460-32-vsementsov@virtuozzo.com>
6
command-line options so they can be shared. For now the
7
qemu-storage-daemon simply refers to the qemu(1) man page where the
8
command-line options are identical.
9
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Message-Id: <20201209103802.350848-3-stefanha@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
7
---
14
docs/tools/conf.py | 2 +
8
block.c | 103 --------------------------------------------------------
15
docs/tools/index.rst | 1 +
9
1 file changed, 103 deletions(-)
16
docs/tools/qemu-storage-daemon.rst | 148 +++++++++++++++++++++++++++++
17
3 files changed, 151 insertions(+)
18
create mode 100644 docs/tools/qemu-storage-daemon.rst
19
10
20
diff --git a/docs/tools/conf.py b/docs/tools/conf.py
11
diff --git a/block.c b/block.c
21
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
22
--- a/docs/tools/conf.py
13
--- a/block.c
23
+++ b/docs/tools/conf.py
14
+++ b/block.c
24
@@ -XXX,XX +XXX,XX @@ html_theme_options['description'] = \
15
@@ -XXX,XX +XXX,XX @@ static int bdrv_fill_options(QDict **options, const char *filename,
25
man_pages = [
16
return 0;
26
('qemu-img', 'qemu-img', u'QEMU disk image utility',
17
}
27
['Fabrice Bellard'], 1),
18
28
+ ('qemu-storage-daemon', 'qemu-storage-daemon', u'QEMU storage daemon',
19
-static int bdrv_check_update_perm(BlockDriverState *bs, BlockReopenQueue *q,
29
+ [], 1),
20
- uint64_t new_used_perm,
30
('qemu-nbd', 'qemu-nbd', u'QEMU Disk Network Block Device Server',
21
- uint64_t new_shared_perm,
31
['Anthony Liguori <anthony@codemonkey.ws>'], 8),
22
- Error **errp);
32
('qemu-pr-helper', 'qemu-pr-helper', 'QEMU persistent reservation helper',
23
-
33
diff --git a/docs/tools/index.rst b/docs/tools/index.rst
24
typedef struct BlockReopenQueueEntry {
34
index XXXXXXX..XXXXXXX 100644
25
bool prepared;
35
--- a/docs/tools/index.rst
26
bool perms_checked;
36
+++ b/docs/tools/index.rst
27
@@ -XXX,XX +XXX,XX @@ static int bdrv_check_perm_common(GSList *list, BlockReopenQueue *q,
37
@@ -XXX,XX +XXX,XX @@ Contents:
28
return 0;
38
:maxdepth: 2
29
}
39
30
40
qemu-img
31
-static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q,
41
+ qemu-storage-daemon
32
- uint64_t cumulative_perms,
42
qemu-nbd
33
- uint64_t cumulative_shared_perms, Error **errp)
43
qemu-pr-helper
34
-{
44
qemu-trace-stap
35
- g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, bs);
45
diff --git a/docs/tools/qemu-storage-daemon.rst b/docs/tools/qemu-storage-daemon.rst
36
- return bdrv_check_perm_common(list, q, true, cumulative_perms,
46
new file mode 100644
37
- cumulative_shared_perms, NULL, errp);
47
index XXXXXXX..XXXXXXX
38
-}
48
--- /dev/null
39
-
49
+++ b/docs/tools/qemu-storage-daemon.rst
40
static int bdrv_list_refresh_perms(GSList *list, BlockReopenQueue *q,
50
@@ -XXX,XX +XXX,XX @@
41
Transaction *tran, Error **errp)
51
+QEMU Storage Daemon
42
{
52
+===================
43
return bdrv_check_perm_common(list, q, false, 0, 0, tran, errp);
53
+
44
}
54
+Synopsis
45
55
+--------
46
-/*
56
+
47
- * Notifies drivers that after a previous bdrv_check_perm() call, the
57
+**qemu-storage-daemon** [options]
48
- * permission update is not performed and any preparations made for it (e.g.
58
+
49
- * taken file locks) need to be undone.
59
+Description
50
- */
60
+-----------
51
-static void bdrv_node_abort_perm_update(BlockDriverState *bs)
61
+
52
-{
62
+qemu-storage-daemon provides disk image functionality from QEMU, qemu-img, and
53
- BlockDriver *drv = bs->drv;
63
+qemu-nbd in a long-running process controlled via QMP commands without running
54
- BdrvChild *c;
64
+a virtual machine. It can export disk images, run block job operations, and
55
-
65
+perform other disk-related operations. The daemon is controlled via a QMP
56
- if (!drv) {
66
+monitor and initial configuration from the command-line.
57
- return;
67
+
58
- }
68
+The daemon offers the following subset of QEMU features:
59
-
69
+
60
- bdrv_drv_set_perm_abort(bs);
70
+* Block nodes
61
-
71
+* Block jobs
62
- QLIST_FOREACH(c, &bs->children, next) {
72
+* Block exports
63
- bdrv_child_set_perm_abort(c);
73
+* Throttle groups
64
- }
74
+* Character devices
65
-}
75
+* Crypto and secrets
66
-
76
+* QMP
67
-static void bdrv_list_abort_perm_update(GSList *list)
77
+* IOThreads
68
-{
78
+
69
- for ( ; list; list = list->next) {
79
+Commands can be sent over a QEMU Monitor Protocol (QMP) connection. See the
70
- bdrv_node_abort_perm_update((BlockDriverState *)list->data);
80
+:manpage:`qemu-storage-daemon-qmp-ref(7)` manual page for a description of the
71
- }
81
+commands.
72
-}
82
+
73
-
83
+The daemon runs until it is stopped using the ``quit`` QMP command or
74
-__attribute__((unused))
84
+SIGINT/SIGHUP/SIGTERM.
75
-static void bdrv_abort_perm_update(BlockDriverState *bs)
85
+
76
-{
86
+**Warning:** Never modify images in use by a running virtual machine or any
77
- g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, bs);
87
+other process; this may destroy the image. Also, be aware that querying an
78
- return bdrv_list_abort_perm_update(list);
88
+image that is being modified by another process may encounter inconsistent
79
-}
89
+state.
80
-
90
+
81
static void bdrv_node_set_perm(BlockDriverState *bs)
91
+Options
82
{
92
+-------
83
BlockDriver *drv = bs->drv;
93
+
84
@@ -XXX,XX +XXX,XX @@ char *bdrv_perm_names(uint64_t perm)
94
+.. program:: qemu-storage-daemon
85
return g_string_free(result, FALSE);
95
+
86
}
96
+Standard options:
87
97
+
88
-/*
98
+.. option:: -h, --help
89
- * Checks whether a new reference to @bs can be added if the new user requires
99
+
90
- * @new_used_perm/@new_shared_perm as its permissions. If @ignore_children is
100
+ Display help and exit
91
- * set, the BdrvChild objects in this list are ignored in the calculations;
101
+
92
- * this allows checking permission updates for an existing reference.
102
+.. option:: -V, --version
93
- *
103
+
94
- * Needs to be followed by a call to either bdrv_set_perm() or
104
+ Display version information and exit
95
- * bdrv_abort_perm_update(). */
105
+
96
-__attribute__((unused))
106
+.. option:: -T, --trace [[enable=]PATTERN][,events=FILE][,file=FILE]
97
-static int bdrv_check_update_perm(BlockDriverState *bs, BlockReopenQueue *q,
107
+
98
- uint64_t new_used_perm,
108
+ .. include:: ../qemu-option-trace.rst.inc
99
- uint64_t new_shared_perm,
109
+
100
- Error **errp)
110
+.. option:: --blockdev BLOCKDEVDEF
101
-{
111
+
102
- BdrvChild *c;
112
+ is a block node definition. See the :manpage:`qemu(1)` manual page for a
103
- uint64_t cumulative_perms = new_used_perm;
113
+ description of block node properties and the :manpage:`qemu-block-drivers(7)`
104
- uint64_t cumulative_shared_perms = new_shared_perm;
114
+ manual page for a description of driver-specific parameters.
105
-
115
+
106
-
116
+.. option:: --chardev CHARDEVDEF
107
- /* There is no reason why anyone couldn't tolerate write_unchanged */
117
+
108
- assert(new_shared_perm & BLK_PERM_WRITE_UNCHANGED);
118
+ is a character device definition. See the :manpage:`qemu(1)` manual page for
109
-
119
+ a description of character device properties. A common character device
110
- QLIST_FOREACH(c, &bs->parents, next_parent) {
120
+ definition configures a UNIX domain socket::
111
- if ((new_used_perm & c->shared_perm) != new_used_perm) {
121
+
112
- char *user = bdrv_child_user_desc(c);
122
+ --chardev socket,id=char1,path=/tmp/qmp.sock,server,nowait
113
- char *perm_names = bdrv_perm_names(new_used_perm & ~c->shared_perm);
123
+
114
-
124
+.. option:: --export [type=]nbd,id=<id>,node-name=<node-name>[,name=<export-name>][,writable=on|off][,bitmap=<name>]
115
- error_setg(errp, "Conflicts with use by %s as '%s', which does not "
125
+ --export [type=]vhost-user-blk,id=<id>,node-name=<node-name>,addr.type=unix,addr.path=<socket-path>[,writable=on|off][,logical-block-size=<block-size>][,num-queues=<num-queues>]
116
- "allow '%s' on %s",
126
+ --export [type=]vhost-user-blk,id=<id>,node-name=<node-name>,addr.type=fd,addr.str=<fd>[,writable=on|off][,logical-block-size=<block-size>][,num-queues=<num-queues>]
117
- user, c->name, perm_names, bdrv_get_node_name(c->bs));
127
+
118
- g_free(user);
128
+ is a block export definition. ``node-name`` is the block node that should be
119
- g_free(perm_names);
129
+ exported. ``writable`` determines whether or not the export allows write
120
- return -EPERM;
130
+ requests for modifying data (the default is off).
121
- }
131
+
122
-
132
+ The ``nbd`` export type requires ``--nbd-server`` (see below). ``name`` is
123
- if ((c->perm & new_shared_perm) != c->perm) {
133
+ the NBD export name. ``bitmap`` is the name of a dirty bitmap reachable from
124
- char *user = bdrv_child_user_desc(c);
134
+ the block node, so the NBD client can use NBD_OPT_SET_META_CONTEXT with the
125
- char *perm_names = bdrv_perm_names(c->perm & ~new_shared_perm);
135
+ metadata context name "qemu:dirty-bitmap:BITMAP" to inspect the bitmap.
126
-
136
+
127
- error_setg(errp, "Conflicts with use by %s as '%s', which uses "
137
+ The ``vhost-user-blk`` export type takes a vhost-user socket address on which
128
- "'%s' on %s",
138
+ it accept incoming connections. Both
129
- user, c->name, perm_names, bdrv_get_node_name(c->bs));
139
+ ``addr.type=unix,addr.path=<socket-path>`` for UNIX domain sockets and
130
- g_free(user);
140
+ ``addr.type=fd,addr.str=<fd>`` for file descriptor passing are supported.
131
- g_free(perm_names);
141
+ ``logical-block-size`` sets the logical block size in bytes (the default is
132
- return -EPERM;
142
+ 512). ``num-queues`` sets the number of virtqueues (the default is 1).
133
- }
143
+
134
-
144
+.. option:: --monitor MONITORDEF
135
- cumulative_perms |= c->perm;
145
+
136
- cumulative_shared_perms &= c->shared_perm;
146
+ is a QMP monitor definition. See the :manpage:`qemu(1)` manual page for
137
- }
147
+ a description of QMP monitor properties. A common QMP monitor definition
138
-
148
+ configures a monitor on character device ``char1``::
139
- return bdrv_check_perm(bs, q, cumulative_perms, cumulative_shared_perms,
149
+
140
- errp);
150
+ --monitor chardev=char1
141
-}
151
+
142
152
+.. option:: --nbd-server addr.type=inet,addr.host=<host>,addr.port=<port>[,tls-creds=<id>][,tls-authz=<id>][,max-connections=<n>]
143
static int bdrv_refresh_perms(BlockDriverState *bs, Error **errp)
153
+ --nbd-server addr.type=unix,addr.path=<path>[,tls-creds=<id>][,tls-authz=<id>][,max-connections=<n>]
144
{
154
+
155
+ is a server for NBD exports. Both TCP and UNIX domain sockets are supported.
156
+ TLS encryption can be configured using ``--object`` tls-creds-* and authz-*
157
+ secrets (see below).
158
+
159
+ To configure an NBD server on UNIX domain socket path ``/tmp/nbd.sock``::
160
+
161
+ --nbd-server addr.type=unix,addr.path=/tmp/nbd.sock
162
+
163
+.. option:: --object help
164
+ --object <type>,help
165
+ --object <type>[,<property>=<value>...]
166
+
167
+ is a QEMU user creatable object definition. List object types with ``help``.
168
+ List object properties with ``<type>,help``. See the :manpage:`qemu(1)`
169
+ manual page for a description of the object properties.
170
+
171
+Examples
172
+--------
173
+Launch the daemon with QMP monitor socket ``qmp.sock`` so clients can execute
174
+QMP commands::
175
+
176
+ $ qemu-storage-daemon \
177
+ --chardev socket,path=qmp.sock,server,nowait,id=char1 \
178
+ --monitor chardev=char1
179
+
180
+Export raw image file ``disk.img`` over NBD UNIX domain socket ``nbd.sock``::
181
+
182
+ $ qemu-storage-daemon \
183
+ --blockdev driver=file,node-name=disk,filename=disk.img \
184
+ --nbd-server addr.type=unix,addr.path=nbd.sock \
185
+ --export type=nbd,id=export,node-name=disk,writable=on
186
+
187
+Export a qcow2 image file ``disk.qcow2`` as a vhosts-user-blk device over UNIX
188
+domain socket ``vhost-user-blk.sock``::
189
+
190
+ $ qemu-storage-daemon \
191
+ --blockdev driver=file,node-name=file,filename=disk.qcow2 \
192
+ --blockdev driver=qcow2,node-name=qcow2,file=file \
193
+ --export type=vhost-user-blk,id=export,addr.type=unix,addr.path=vhost-user-blk.sock,node-name=qcow2
194
+
195
+See also
196
+--------
197
+
198
+:manpage:`qemu(1)`, :manpage:`qemu-block-drivers(7)`, :manpage:`qemu-storage-daemon-qmp-ref(7)`
199
--
145
--
200
2.29.2
146
2.30.2
201
147
202
148
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
device[NUMBER] thing in QOM path is not stable and tracking it during
3
bdrv_check_perm_common() has only one caller, so no more sense in
4
code modifications is not fun. Let's filter it like it's already done
4
"common".
5
in iotest 186.
6
5
7
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Message-Id: <20201216095205.526235-3-vsementsov@virtuozzo.com>
7
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
8
Message-Id: <20210428151804.439460-33-vsementsov@virtuozzo.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
10
---
11
tests/qemu-iotests/172 | 2 +-
11
block.c | 32 +++-----------------------------
12
tests/qemu-iotests/172.out | 152 ++++++++++++++++++-------------------
12
1 file changed, 3 insertions(+), 29 deletions(-)
13
2 files changed, 77 insertions(+), 77 deletions(-)
14
13
15
diff --git a/tests/qemu-iotests/172 b/tests/qemu-iotests/172
14
diff --git a/block.c b/block.c
16
index XXXXXXX..XXXXXXX 100755
15
index XXXXXXX..XXXXXXX 100644
17
--- a/tests/qemu-iotests/172
16
--- a/block.c
18
+++ b/tests/qemu-iotests/172
17
+++ b/block.c
19
@@ -XXX,XX +XXX,XX @@ check_floppy_qtree()
18
@@ -XXX,XX +XXX,XX @@ static int bdrv_node_check_perm(BlockDriverState *bs, BlockReopenQueue *q,
20
(QEMU_OPTIONS="" do_run_qemu "$@" |
19
return 0;
21
    _filter_testdir |_filter_generated_node_ids | _filter_hmp |
22
sed -ne '/^ dev: isa-fdc/,/^ dev:/{x;p};/^[a-z][^ ]* (NODE_NAME):* /,/^(qemu)$/{p}') 2>&1 |
23
- _filter_win32 | _filter_qemu
24
+ _filter_win32 | _filter_qemu | _filter_qom_path
25
}
20
}
26
21
27
check_cache_mode()
22
-/*
28
diff --git a/tests/qemu-iotests/172.out b/tests/qemu-iotests/172.out
23
- * If use_cumulative_perms is true, use cumulative_perms and
29
index XXXXXXX..XXXXXXX 100644
24
- * cumulative_shared_perms for first element of the list. Otherwise just refresh
30
--- a/tests/qemu-iotests/172.out
25
- * all permissions.
31
+++ b/tests/qemu-iotests/172.out
26
- */
32
@@ -XXX,XX +XXX,XX @@ Testing: -fda TEST_DIR/t.qcow2
27
-static int bdrv_check_perm_common(GSList *list, BlockReopenQueue *q,
33
share-rw = false
28
- bool use_cumulative_perms,
34
drive-type = "144"
29
- uint64_t cumulative_perms,
35
floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
30
- uint64_t cumulative_shared_perms,
36
- Attached to: /machine/unattached/device[15]
31
- Transaction *tran, Error **errp)
37
+ Attached to: /machine/unattached/device[N]
32
+static int bdrv_list_refresh_perms(GSList *list, BlockReopenQueue *q,
38
Removable device: not locked, tray closed
33
+ Transaction *tran, Error **errp)
39
Cache mode: writeback
34
{
40
35
int ret;
41
ide1-cd0: [not inserted]
36
+ uint64_t cumulative_perms, cumulative_shared_perms;
42
- Attached to: /machine/unattached/device[22]
37
BlockDriverState *bs;
43
+ Attached to: /machine/unattached/device[N]
38
44
Removable device: not locked, tray closed
39
- if (use_cumulative_perms) {
45
40
- bs = list->data;
46
sd0: [not inserted]
41
-
47
@@ -XXX,XX +XXX,XX @@ Testing: -fdb TEST_DIR/t.qcow2
42
- ret = bdrv_node_check_perm(bs, q, cumulative_perms,
48
share-rw = false
43
- cumulative_shared_perms,
49
drive-type = "288"
44
- tran, errp);
50
floppy1 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
45
- if (ret < 0) {
51
- Attached to: /machine/unattached/device[16]
46
- return ret;
52
+ Attached to: /machine/unattached/device[N]
47
- }
53
Removable device: not locked, tray closed
48
-
54
Cache mode: writeback
49
- list = list->next;
55
50
- }
56
ide1-cd0: [not inserted]
51
-
57
- Attached to: /machine/unattached/device[23]
52
for ( ; list; list = list->next) {
58
+ Attached to: /machine/unattached/device[N]
53
bs = list->data;
59
Removable device: not locked, tray closed
54
60
55
@@ -XXX,XX +XXX,XX @@ static int bdrv_check_perm_common(GSList *list, BlockReopenQueue *q,
61
floppy0: [not inserted]
56
return 0;
62
- Attached to: /machine/unattached/device[15]
57
}
63
+ Attached to: /machine/unattached/device[N]
58
64
Removable device: not locked, tray closed
59
-static int bdrv_list_refresh_perms(GSList *list, BlockReopenQueue *q,
65
60
- Transaction *tran, Error **errp)
66
sd0: [not inserted]
61
-{
67
@@ -XXX,XX +XXX,XX @@ Testing: -fda TEST_DIR/t.qcow2 -fdb TEST_DIR/t.qcow2.2
62
- return bdrv_check_perm_common(list, q, false, 0, 0, tran, errp);
68
share-rw = false
63
-}
69
drive-type = "144"
64
-
70
floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
65
static void bdrv_node_set_perm(BlockDriverState *bs)
71
- Attached to: /machine/unattached/device[15]
66
{
72
+ Attached to: /machine/unattached/device[N]
67
BlockDriver *drv = bs->drv;
73
Removable device: not locked, tray closed
74
Cache mode: writeback
75
76
floppy1 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2)
77
- Attached to: /machine/unattached/device[16]
78
+ Attached to: /machine/unattached/device[N]
79
Removable device: not locked, tray closed
80
Cache mode: writeback
81
82
ide1-cd0: [not inserted]
83
- Attached to: /machine/unattached/device[23]
84
+ Attached to: /machine/unattached/device[N]
85
Removable device: not locked, tray closed
86
87
sd0: [not inserted]
88
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2
89
share-rw = false
90
drive-type = "144"
91
floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
92
- Attached to: /machine/unattached/device[15]
93
+ Attached to: /machine/unattached/device[N]
94
Removable device: not locked, tray closed
95
Cache mode: writeback
96
97
ide1-cd0: [not inserted]
98
- Attached to: /machine/unattached/device[22]
99
+ Attached to: /machine/unattached/device[N]
100
Removable device: not locked, tray closed
101
102
sd0: [not inserted]
103
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2,index=1
104
share-rw = false
105
drive-type = "288"
106
floppy1 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
107
- Attached to: /machine/unattached/device[16]
108
+ Attached to: /machine/unattached/device[N]
109
Removable device: not locked, tray closed
110
Cache mode: writeback
111
112
ide1-cd0: [not inserted]
113
- Attached to: /machine/unattached/device[23]
114
+ Attached to: /machine/unattached/device[N]
115
Removable device: not locked, tray closed
116
117
floppy0: [not inserted]
118
- Attached to: /machine/unattached/device[15]
119
+ Attached to: /machine/unattached/device[N]
120
Removable device: not locked, tray closed
121
122
sd0: [not inserted]
123
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=floppy,file=TEST_DIR/t
124
share-rw = false
125
drive-type = "144"
126
floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
127
- Attached to: /machine/unattached/device[15]
128
+ Attached to: /machine/unattached/device[N]
129
Removable device: not locked, tray closed
130
Cache mode: writeback
131
132
floppy1 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2)
133
- Attached to: /machine/unattached/device[16]
134
+ Attached to: /machine/unattached/device[N]
135
Removable device: not locked, tray closed
136
Cache mode: writeback
137
138
ide1-cd0: [not inserted]
139
- Attached to: /machine/unattached/device[23]
140
+ Attached to: /machine/unattached/device[N]
141
Removable device: not locked, tray closed
142
143
sd0: [not inserted]
144
@@ -XXX,XX +XXX,XX @@ Use -device floppy,unit=0,drive=... instead.
145
share-rw = false
146
drive-type = "144"
147
none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
148
- Attached to: /machine/unattached/device[15]
149
+ Attached to: /machine/unattached/device[N]
150
Removable device: not locked, tray closed
151
Cache mode: writeback
152
153
ide1-cd0: [not inserted]
154
- Attached to: /machine/unattached/device[22]
155
+ Attached to: /machine/unattached/device[N]
156
Removable device: not locked, tray closed
157
158
sd0: [not inserted]
159
@@ -XXX,XX +XXX,XX @@ Use -device floppy,unit=1,drive=... instead.
160
share-rw = false
161
drive-type = "144"
162
none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
163
- Attached to: /machine/unattached/device[15]
164
+ Attached to: /machine/unattached/device[N]
165
Removable device: not locked, tray closed
166
Cache mode: writeback
167
168
ide1-cd0: [not inserted]
169
- Attached to: /machine/unattached/device[22]
170
+ Attached to: /machine/unattached/device[N]
171
Removable device: not locked, tray closed
172
173
sd0: [not inserted]
174
@@ -XXX,XX +XXX,XX @@ Use -device floppy,unit=1,drive=... instead.
175
share-rw = false
176
drive-type = "144"
177
none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
178
- Attached to: /machine/unattached/device[15]
179
+ Attached to: /machine/unattached/device[N]
180
Removable device: not locked, tray closed
181
Cache mode: writeback
182
183
none1 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2)
184
- Attached to: /machine/unattached/device[16]
185
+ Attached to: /machine/unattached/device[N]
186
Removable device: not locked, tray closed
187
Cache mode: writeback
188
189
ide1-cd0: [not inserted]
190
- Attached to: /machine/unattached/device[23]
191
+ Attached to: /machine/unattached/device[N]
192
Removable device: not locked, tray closed
193
194
sd0: [not inserted]
195
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0
196
share-rw = false
197
drive-type = "144"
198
none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
199
- Attached to: /machine/peripheral-anon/device[0]
200
+ Attached to: /machine/peripheral-anon/device[N]
201
Removable device: not locked, tray closed
202
Cache mode: writeback
203
204
ide1-cd0: [not inserted]
205
- Attached to: /machine/unattached/device[21]
206
+ Attached to: /machine/unattached/device[N]
207
Removable device: not locked, tray closed
208
209
sd0: [not inserted]
210
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,unit=1
211
share-rw = false
212
drive-type = "144"
213
none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
214
- Attached to: /machine/peripheral-anon/device[0]
215
+ Attached to: /machine/peripheral-anon/device[N]
216
Removable device: not locked, tray closed
217
Cache mode: writeback
218
219
ide1-cd0: [not inserted]
220
- Attached to: /machine/unattached/device[21]
221
+ Attached to: /machine/unattached/device[N]
222
Removable device: not locked, tray closed
223
224
sd0: [not inserted]
225
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qco
226
share-rw = false
227
drive-type = "144"
228
none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
229
- Attached to: /machine/peripheral-anon/device[0]
230
+ Attached to: /machine/peripheral-anon/device[N]
231
Removable device: not locked, tray closed
232
Cache mode: writeback
233
234
none1 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2)
235
- Attached to: /machine/peripheral-anon/device[1]
236
+ Attached to: /machine/peripheral-anon/device[N]
237
Removable device: not locked, tray closed
238
Cache mode: writeback
239
240
ide1-cd0: [not inserted]
241
- Attached to: /machine/unattached/device[21]
242
+ Attached to: /machine/unattached/device[N]
243
Removable device: not locked, tray closed
244
245
sd0: [not inserted]
246
@@ -XXX,XX +XXX,XX @@ Use -device floppy,unit=1,drive=... instead.
247
share-rw = false
248
drive-type = "144"
249
floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
250
- Attached to: /machine/unattached/device[16]
251
+ Attached to: /machine/unattached/device[N]
252
Removable device: not locked, tray closed
253
Cache mode: writeback
254
255
none0 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2)
256
- Attached to: /machine/unattached/device[15]
257
+ Attached to: /machine/unattached/device[N]
258
Removable device: not locked, tray closed
259
Cache mode: writeback
260
261
ide1-cd0: [not inserted]
262
- Attached to: /machine/unattached/device[23]
263
+ Attached to: /machine/unattached/device[N]
264
Removable device: not locked, tray closed
265
266
sd0: [not inserted]
267
@@ -XXX,XX +XXX,XX @@ Use -device floppy,unit=0,drive=... instead.
268
share-rw = false
269
drive-type = "144"
270
floppy1 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
271
- Attached to: /machine/unattached/device[16]
272
+ Attached to: /machine/unattached/device[N]
273
Removable device: not locked, tray closed
274
Cache mode: writeback
275
276
none0 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2)
277
- Attached to: /machine/unattached/device[15]
278
+ Attached to: /machine/unattached/device[N]
279
Removable device: not locked, tray closed
280
Cache mode: writeback
281
282
ide1-cd0: [not inserted]
283
- Attached to: /machine/unattached/device[23]
284
+ Attached to: /machine/unattached/device[N]
285
Removable device: not locked, tray closed
286
287
sd0: [not inserted]
288
@@ -XXX,XX +XXX,XX @@ Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device fl
289
share-rw = false
290
drive-type = "144"
291
floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
292
- Attached to: /machine/unattached/device[15]
293
+ Attached to: /machine/unattached/device[N]
294
Removable device: not locked, tray closed
295
Cache mode: writeback
296
297
none0 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2)
298
- Attached to: /machine/peripheral-anon/device[0]
299
+ Attached to: /machine/peripheral-anon/device[N]
300
Removable device: not locked, tray closed
301
Cache mode: writeback
302
303
ide1-cd0: [not inserted]
304
- Attached to: /machine/unattached/device[22]
305
+ Attached to: /machine/unattached/device[N]
306
Removable device: not locked, tray closed
307
308
sd0: [not inserted]
309
@@ -XXX,XX +XXX,XX @@ Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device fl
310
share-rw = false
311
drive-type = "144"
312
floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
313
- Attached to: /machine/unattached/device[15]
314
+ Attached to: /machine/unattached/device[N]
315
Removable device: not locked, tray closed
316
Cache mode: writeback
317
318
none0 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2)
319
- Attached to: /machine/peripheral-anon/device[0]
320
+ Attached to: /machine/peripheral-anon/device[N]
321
Removable device: not locked, tray closed
322
Cache mode: writeback
323
324
ide1-cd0: [not inserted]
325
- Attached to: /machine/unattached/device[22]
326
+ Attached to: /machine/unattached/device[N]
327
Removable device: not locked, tray closed
328
329
sd0: [not inserted]
330
@@ -XXX,XX +XXX,XX @@ Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device fl
331
share-rw = false
332
drive-type = "144"
333
floppy1 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
334
- Attached to: /machine/unattached/device[15]
335
+ Attached to: /machine/unattached/device[N]
336
Removable device: not locked, tray closed
337
Cache mode: writeback
338
339
none0 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2)
340
- Attached to: /machine/peripheral-anon/device[0]
341
+ Attached to: /machine/peripheral-anon/device[N]
342
Removable device: not locked, tray closed
343
Cache mode: writeback
344
345
ide1-cd0: [not inserted]
346
- Attached to: /machine/unattached/device[22]
347
+ Attached to: /machine/unattached/device[N]
348
Removable device: not locked, tray closed
349
350
sd0: [not inserted]
351
@@ -XXX,XX +XXX,XX @@ Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device fl
352
share-rw = false
353
drive-type = "144"
354
floppy1 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
355
- Attached to: /machine/unattached/device[15]
356
+ Attached to: /machine/unattached/device[N]
357
Removable device: not locked, tray closed
358
Cache mode: writeback
359
360
none0 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2)
361
- Attached to: /machine/peripheral-anon/device[0]
362
+ Attached to: /machine/peripheral-anon/device[N]
363
Removable device: not locked, tray closed
364
Cache mode: writeback
365
366
ide1-cd0: [not inserted]
367
- Attached to: /machine/unattached/device[22]
368
+ Attached to: /machine/unattached/device[N]
369
Removable device: not locked, tray closed
370
371
sd0: [not inserted]
372
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.q
373
share-rw = false
374
drive-type = "144"
375
floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
376
- Attached to: /machine/unattached/device[15]
377
+ Attached to: /machine/unattached/device[N]
378
Removable device: not locked, tray closed
379
Cache mode: writeback
380
381
none0 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2)
382
- Attached to: /machine/peripheral-anon/device[0]
383
+ Attached to: /machine/peripheral-anon/device[N]
384
Removable device: not locked, tray closed
385
Cache mode: writeback
386
387
ide1-cd0: [not inserted]
388
- Attached to: /machine/unattached/device[22]
389
+ Attached to: /machine/unattached/device[N]
390
Removable device: not locked, tray closed
391
392
sd0: [not inserted]
393
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.q
394
share-rw = false
395
drive-type = "144"
396
floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
397
- Attached to: /machine/unattached/device[15]
398
+ Attached to: /machine/unattached/device[N]
399
Removable device: not locked, tray closed
400
Cache mode: writeback
401
402
none0 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2)
403
- Attached to: /machine/peripheral-anon/device[0]
404
+ Attached to: /machine/peripheral-anon/device[N]
405
Removable device: not locked, tray closed
406
Cache mode: writeback
407
408
ide1-cd0: [not inserted]
409
- Attached to: /machine/unattached/device[22]
410
+ Attached to: /machine/unattached/device[N]
411
Removable device: not locked, tray closed
412
413
sd0: [not inserted]
414
@@ -XXX,XX +XXX,XX @@ Use -device floppy,unit=0,drive=... instead.
415
share-rw = false
416
drive-type = "144"
417
none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
418
- Attached to: /machine/unattached/device[15]
419
+ Attached to: /machine/unattached/device[N]
420
Removable device: not locked, tray closed
421
Cache mode: writeback
422
423
none1 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2)
424
- Attached to: /machine/peripheral-anon/device[0]
425
+ Attached to: /machine/peripheral-anon/device[N]
426
Removable device: not locked, tray closed
427
Cache mode: writeback
428
429
ide1-cd0: [not inserted]
430
- Attached to: /machine/unattached/device[22]
431
+ Attached to: /machine/unattached/device[N]
432
Removable device: not locked, tray closed
433
434
sd0: [not inserted]
435
@@ -XXX,XX +XXX,XX @@ Use -device floppy,unit=0,drive=... instead.
436
share-rw = false
437
drive-type = "144"
438
none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
439
- Attached to: /machine/unattached/device[15]
440
+ Attached to: /machine/unattached/device[N]
441
Removable device: not locked, tray closed
442
Cache mode: writeback
443
444
none1 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2)
445
- Attached to: /machine/peripheral-anon/device[0]
446
+ Attached to: /machine/peripheral-anon/device[N]
447
Removable device: not locked, tray closed
448
Cache mode: writeback
449
450
ide1-cd0: [not inserted]
451
- Attached to: /machine/unattached/device[22]
452
+ Attached to: /machine/unattached/device[N]
453
Removable device: not locked, tray closed
454
455
sd0: [not inserted]
456
@@ -XXX,XX +XXX,XX @@ Use -device floppy,unit=1,drive=... instead.
457
share-rw = false
458
drive-type = "144"
459
none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
460
- Attached to: /machine/unattached/device[15]
461
+ Attached to: /machine/unattached/device[N]
462
Removable device: not locked, tray closed
463
Cache mode: writeback
464
465
none1 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2)
466
- Attached to: /machine/peripheral-anon/device[0]
467
+ Attached to: /machine/peripheral-anon/device[N]
468
Removable device: not locked, tray closed
469
Cache mode: writeback
470
471
ide1-cd0: [not inserted]
472
- Attached to: /machine/unattached/device[22]
473
+ Attached to: /machine/unattached/device[N]
474
Removable device: not locked, tray closed
475
476
sd0: [not inserted]
477
@@ -XXX,XX +XXX,XX @@ Use -device floppy,unit=1,drive=... instead.
478
share-rw = false
479
drive-type = "144"
480
none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
481
- Attached to: /machine/unattached/device[15]
482
+ Attached to: /machine/unattached/device[N]
483
Removable device: not locked, tray closed
484
Cache mode: writeback
485
486
none1 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2)
487
- Attached to: /machine/peripheral-anon/device[0]
488
+ Attached to: /machine/peripheral-anon/device[N]
489
Removable device: not locked, tray closed
490
Cache mode: writeback
491
492
ide1-cd0: [not inserted]
493
- Attached to: /machine/unattached/device[22]
494
+ Attached to: /machine/unattached/device[N]
495
Removable device: not locked, tray closed
496
497
sd0: [not inserted]
498
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -global floppy.drive=none0 -device
499
share-rw = false
500
drive-type = "144"
501
none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
502
- Attached to: /machine/peripheral-anon/device[0]
503
+ Attached to: /machine/peripheral-anon/device[N]
504
Removable device: not locked, tray closed
505
Cache mode: writeback
506
507
ide1-cd0: [not inserted]
508
- Attached to: /machine/unattached/device[21]
509
+ Attached to: /machine/unattached/device[N]
510
Removable device: not locked, tray closed
511
512
sd0: [not inserted]
513
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,drive-t
514
share-rw = false
515
drive-type = "120"
516
none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
517
- Attached to: /machine/peripheral-anon/device[0]
518
+ Attached to: /machine/peripheral-anon/device[N]
519
Removable device: not locked, tray closed
520
Cache mode: writeback
521
522
ide1-cd0: [not inserted]
523
- Attached to: /machine/unattached/device[21]
524
+ Attached to: /machine/unattached/device[N]
525
Removable device: not locked, tray closed
526
527
sd0: [not inserted]
528
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,drive-t
529
share-rw = false
530
drive-type = "288"
531
none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
532
- Attached to: /machine/peripheral-anon/device[0]
533
+ Attached to: /machine/peripheral-anon/device[N]
534
Removable device: not locked, tray closed
535
Cache mode: writeback
536
537
ide1-cd0: [not inserted]
538
- Attached to: /machine/unattached/device[21]
539
+ Attached to: /machine/unattached/device[N]
540
Removable device: not locked, tray closed
541
542
sd0: [not inserted]
543
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,logical
544
share-rw = false
545
drive-type = "144"
546
none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
547
- Attached to: /machine/peripheral-anon/device[0]
548
+ Attached to: /machine/peripheral-anon/device[N]
549
Removable device: not locked, tray closed
550
Cache mode: writeback
551
552
ide1-cd0: [not inserted]
553
- Attached to: /machine/unattached/device[21]
554
+ Attached to: /machine/unattached/device[N]
555
Removable device: not locked, tray closed
556
557
sd0: [not inserted]
558
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,physica
559
share-rw = false
560
drive-type = "144"
561
none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
562
- Attached to: /machine/peripheral-anon/device[0]
563
+ Attached to: /machine/peripheral-anon/device[N]
564
Removable device: not locked, tray closed
565
Cache mode: writeback
566
567
ide1-cd0: [not inserted]
568
- Attached to: /machine/unattached/device[21]
569
+ Attached to: /machine/unattached/device[N]
570
Removable device: not locked, tray closed
571
572
sd0: [not inserted]
573
--
68
--
574
2.29.2
69
2.30.2
575
70
576
71
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
According to original commit, that added this filter (627f607e3dddb2),
3
bdrv_replace_child() has only one caller, the second argument is
4
the problematic thing in qom path is device[NUMBER], not the whole
4
unused. Inline it now. This triggers deletion of some more unused
5
path. Seems that tracking the other parts of the path in iotest output
5
interfaces.
6
is not bad. Let's make _filter_qom_path stricter.
7
6
8
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
Message-Id: <20201216095205.526235-2-vsementsov@virtuozzo.com>
8
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9
Message-Id: <20210428151804.439460-34-vsementsov@virtuozzo.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
11
---
12
tests/qemu-iotests/186.out | 56 ++++++++++++++++----------------
12
block.c | 101 ++++++++++----------------------------------------------
13
tests/qemu-iotests/common.filter | 2 +-
13
1 file changed, 18 insertions(+), 83 deletions(-)
14
2 files changed, 29 insertions(+), 29 deletions(-)
15
14
16
diff --git a/tests/qemu-iotests/186.out b/tests/qemu-iotests/186.out
15
diff --git a/block.c b/block.c
17
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
18
--- a/tests/qemu-iotests/186.out
17
--- a/block.c
19
+++ b/tests/qemu-iotests/186.out
18
+++ b/block.c
20
@@ -XXX,XX +XXX,XX @@ Testing: -device floppy
19
@@ -XXX,XX +XXX,XX @@ static int bdrv_list_refresh_perms(GSList *list, BlockReopenQueue *q,
21
QEMU X.Y.Z monitor - type 'help' for more information
20
return 0;
22
(qemu) info block
21
}
23
/machine/peripheral-anon/device[1]: [not inserted]
22
24
- Attached to: PATH
23
-static void bdrv_node_set_perm(BlockDriverState *bs)
25
+ Attached to: /machine/peripheral-anon/device[N]
24
-{
26
Removable device: not locked, tray closed
25
- BlockDriver *drv = bs->drv;
27
(qemu) quit
26
- BdrvChild *c;
28
27
-
29
@@ -XXX,XX +XXX,XX @@ Testing: -device ide-cd
28
- if (!drv) {
30
QEMU X.Y.Z monitor - type 'help' for more information
29
- return;
31
(qemu) info block
30
- }
32
/machine/peripheral-anon/device[1]: [not inserted]
31
-
33
- Attached to: PATH
32
- bdrv_drv_set_perm_commit(bs);
34
+ Attached to: /machine/peripheral-anon/device[N]
33
-
35
Removable device: not locked, tray closed
34
- /* Drivers that never have children can omit .bdrv_child_perm() */
36
(qemu) quit
35
- if (!drv->bdrv_child_perm) {
37
36
- assert(QLIST_EMPTY(&bs->children));
38
@@ -XXX,XX +XXX,XX @@ Testing: -device scsi-cd
37
- return;
39
QEMU X.Y.Z monitor - type 'help' for more information
38
- }
40
(qemu) info block
39
-
41
/machine/peripheral-anon/device[1]: [not inserted]
40
- /* Update all children */
42
- Attached to: PATH
41
- QLIST_FOREACH(c, &bs->children, next) {
43
+ Attached to: /machine/peripheral-anon/device[N]
42
- bdrv_child_set_perm_commit(c);
44
Removable device: not locked, tray closed
43
- }
45
(qemu) quit
44
-}
46
45
-
47
@@ -XXX,XX +XXX,XX @@ Testing: -blockdev driver=null-co,read-zeroes=on,node-name=null -device ide-hd,d
46
-static void bdrv_list_set_perm(GSList *list)
48
QEMU X.Y.Z monitor - type 'help' for more information
47
-{
49
(qemu) info block
48
- for ( ; list; list = list->next) {
50
null: json:{"read-zeroes": true, "driver": "null-co"} (null-co)
49
- bdrv_node_set_perm((BlockDriverState *)list->data);
51
- Attached to: PATH
50
- }
52
+ Attached to: /machine/peripheral-anon/device[N]
51
-}
53
Cache mode: writeback
52
-
54
(qemu) quit
53
-static void bdrv_set_perm(BlockDriverState *bs)
55
54
-{
56
@@ -XXX,XX +XXX,XX @@ Testing: -blockdev driver=null-co,read-zeroes=on,node-name=null -device scsi-hd,
55
- g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, bs);
57
QEMU X.Y.Z monitor - type 'help' for more information
56
- return bdrv_list_set_perm(list);
58
(qemu) info block
57
-}
59
null: json:{"read-zeroes": true, "driver": "null-co"} (null-co)
58
-
60
- Attached to: PATH
59
void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm,
61
+ Attached to: /machine/peripheral-anon/device[N]
60
uint64_t *shared_perm)
62
Cache mode: writeback
63
(qemu) quit
64
65
@@ -XXX,XX +XXX,XX @@ Testing: -blockdev driver=null-co,read-zeroes=on,node-name=null -device virtio-b
66
QEMU X.Y.Z monitor - type 'help' for more information
67
(qemu) info block
68
null: json:{"read-zeroes": true, "driver": "null-co"} (null-co)
69
- Attached to: PATH
70
+ Attached to: /machine/peripheral-anon/device[N]/virtio-backend
71
Cache mode: writeback
72
(qemu) quit
73
74
@@ -XXX,XX +XXX,XX @@ Testing: -blockdev driver=null-co,read-zeroes=on,node-name=null -device virtio-b
75
QEMU X.Y.Z monitor - type 'help' for more information
76
(qemu) info block
77
null: json:{"read-zeroes": true, "driver": "null-co"} (null-co)
78
- Attached to: PATH
79
+ Attached to: /machine/peripheral/qdev_id/virtio-backend
80
Cache mode: writeback
81
(qemu) quit
82
83
@@ -XXX,XX +XXX,XX @@ Testing: -blockdev driver=null-co,read-zeroes=on,node-name=null -device floppy,d
84
QEMU X.Y.Z monitor - type 'help' for more information
85
(qemu) info block
86
null: json:{"read-zeroes": true, "driver": "null-co"} (null-co)
87
- Attached to: PATH
88
+ Attached to: /machine/peripheral-anon/device[N]
89
Removable device: not locked, tray closed
90
Cache mode: writeback
91
(qemu) quit
92
@@ -XXX,XX +XXX,XX @@ Testing: -blockdev driver=null-co,read-zeroes=on,node-name=null -device ide-cd,d
93
QEMU X.Y.Z monitor - type 'help' for more information
94
(qemu) info block
95
null: json:{"read-zeroes": true, "driver": "null-co"} (null-co)
96
- Attached to: PATH
97
+ Attached to: /machine/peripheral-anon/device[N]
98
Removable device: not locked, tray closed
99
Cache mode: writeback
100
(qemu) quit
101
@@ -XXX,XX +XXX,XX @@ Testing: -blockdev driver=null-co,read-zeroes=on,node-name=null -device scsi-cd,
102
QEMU X.Y.Z monitor - type 'help' for more information
103
(qemu) info block
104
null: json:{"read-zeroes": true, "driver": "null-co"} (null-co)
105
- Attached to: PATH
106
+ Attached to: /machine/peripheral-anon/device[N]
107
Removable device: not locked, tray closed
108
Cache mode: writeback
109
(qemu) quit
110
@@ -XXX,XX +XXX,XX @@ none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co)
111
Cache mode: writeback
112
113
null: json:{"read-zeroes": "on", "driver": "null-co"} (null-co)
114
- Attached to: PATH
115
+ Attached to: /machine/peripheral/qdev_id/virtio-backend
116
Cache mode: writeback
117
(qemu) quit
118
119
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none,driver=null-co,read-zeroes=on,node-name=null -device ide
120
QEMU X.Y.Z monitor - type 'help' for more information
121
(qemu) info block
122
none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co)
123
- Attached to: PATH
124
+ Attached to: /machine/peripheral-anon/device[N]
125
Cache mode: writeback
126
(qemu) quit
127
128
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none,driver=null-co,read-zeroes=on,node-name=null -device scs
129
QEMU X.Y.Z monitor - type 'help' for more information
130
(qemu) info block
131
none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co)
132
- Attached to: PATH
133
+ Attached to: /machine/peripheral-anon/device[N]
134
Cache mode: writeback
135
(qemu) quit
136
137
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none,driver=null-co,read-zeroes=on,node-name=null -device vir
138
QEMU X.Y.Z monitor - type 'help' for more information
139
(qemu) info block
140
none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co)
141
- Attached to: PATH
142
+ Attached to: /machine/peripheral-anon/device[N]/virtio-backend
143
Cache mode: writeback
144
(qemu) quit
145
146
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none,driver=null-co,read-zeroes=on,node-name=null -device vir
147
QEMU X.Y.Z monitor - type 'help' for more information
148
(qemu) info block
149
none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co)
150
- Attached to: PATH
151
+ Attached to: /machine/peripheral/qdev_id/virtio-backend
152
Cache mode: writeback
153
(qemu) quit
154
155
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none,driver=null-co,read-zeroes=on,node-name=null -device flo
156
QEMU X.Y.Z monitor - type 'help' for more information
157
(qemu) info block
158
none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co)
159
- Attached to: PATH
160
+ Attached to: /machine/peripheral-anon/device[N]
161
Removable device: not locked, tray closed
162
Cache mode: writeback
163
(qemu) quit
164
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none,driver=null-co,read-zeroes=on,node-name=null -device ide
165
QEMU X.Y.Z monitor - type 'help' for more information
166
(qemu) info block
167
none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co)
168
- Attached to: PATH
169
+ Attached to: /machine/peripheral-anon/device[N]
170
Removable device: not locked, tray closed
171
Cache mode: writeback
172
(qemu) quit
173
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none,driver=null-co,read-zeroes=on,node-name=null -device scs
174
QEMU X.Y.Z monitor - type 'help' for more information
175
(qemu) info block
176
none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co)
177
- Attached to: PATH
178
+ Attached to: /machine/peripheral-anon/device[N]
179
Removable device: not locked, tray closed
180
Cache mode: writeback
181
(qemu) quit
182
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none -device floppy,drive=none0
183
QEMU X.Y.Z monitor - type 'help' for more information
184
(qemu) info block
185
none0: [not inserted]
186
- Attached to: PATH
187
+ Attached to: /machine/peripheral-anon/device[N]
188
Removable device: not locked, tray closed
189
(qemu) quit
190
191
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none -device ide-cd,drive=none0
192
QEMU X.Y.Z monitor - type 'help' for more information
193
(qemu) info block
194
none0: [not inserted]
195
- Attached to: PATH
196
+ Attached to: /machine/peripheral-anon/device[N]
197
Removable device: not locked, tray closed
198
(qemu) quit
199
200
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=none -device scsi-cd,drive=none0
201
QEMU X.Y.Z monitor - type 'help' for more information
202
(qemu) info block
203
none0: [not inserted]
204
- Attached to: PATH
205
+ Attached to: /machine/peripheral-anon/device[N]
206
Removable device: not locked, tray closed
207
(qemu) quit
208
209
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=floppy
210
QEMU X.Y.Z monitor - type 'help' for more information
211
(qemu) info block
212
floppy0: [not inserted]
213
- Attached to: PATH
214
+ Attached to: /machine/unattached/device[N]
215
Removable device: not locked, tray closed
216
(qemu) quit
217
218
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=floppy,driver=null-co,read-zeroes=on
219
QEMU X.Y.Z monitor - type 'help' for more information
220
(qemu) info block
221
floppy0 (NODE_NAME): json:{"read-zeroes": "on", "driver": "null-co"} (null-co)
222
- Attached to: PATH
223
+ Attached to: /machine/unattached/device[N]
224
Removable device: not locked, tray closed
225
Cache mode: writeback
226
(qemu) quit
227
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=ide,driver=null-co,read-zeroes=on
228
QEMU X.Y.Z monitor - type 'help' for more information
229
(qemu) info block
230
ide0-hd0 (NODE_NAME): json:{"read-zeroes": "on", "driver": "null-co"} (null-co)
231
- Attached to: PATH
232
+ Attached to: /machine/unattached/device[N]
233
Cache mode: writeback
234
(qemu) quit
235
236
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=ide,media=cdrom
237
QEMU X.Y.Z monitor - type 'help' for more information
238
(qemu) info block
239
ide0-cd0: [not inserted]
240
- Attached to: PATH
241
+ Attached to: /machine/unattached/device[N]
242
Removable device: not locked, tray closed
243
(qemu) quit
244
245
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=ide,driver=null-co,read-zeroes=on,media=cdrom
246
QEMU X.Y.Z monitor - type 'help' for more information
247
(qemu) info block
248
ide0-cd0 (NODE_NAME): json:{"read-zeroes": "on", "driver": "null-co"} (null-co, read-only)
249
- Attached to: PATH
250
+ Attached to: /machine/unattached/device[N]
251
Removable device: not locked, tray closed
252
Cache mode: writeback
253
(qemu) quit
254
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=virtio,driver=null-co,read-zeroes=on
255
QEMU X.Y.Z monitor - type 'help' for more information
256
(qemu) info block
257
virtio0 (NODE_NAME): json:{"read-zeroes": "on", "driver": "null-co"} (null-co)
258
- Attached to: PATH
259
+ Attached to: /machine/peripheral-anon/device[N]/virtio-backend
260
Cache mode: writeback
261
(qemu) quit
262
263
@@ -XXX,XX +XXX,XX @@ Testing: -drive if=pflash,driver=null-co,read-zeroes=on,size=1M
264
QEMU X.Y.Z monitor - type 'help' for more information
265
(qemu) info block
266
pflash0 (NODE_NAME): json:{"read-zeroes": "on", "driver": "null-co", "size": "1M"} (null-co)
267
- Attached to: PATH
268
+ Attached to: /machine/system.flash0
269
Cache mode: writeback
270
(qemu) quit
271
272
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
273
index XXXXXXX..XXXXXXX 100644
274
--- a/tests/qemu-iotests/common.filter
275
+++ b/tests/qemu-iotests/common.filter
276
@@ -XXX,XX +XXX,XX @@ _filter_generated_node_ids()
277
278
_filter_qom_path()
279
{
61
{
280
- $SED -e 's#\(Attached to: *\) /.*#\1 PATH#'
62
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child,
281
+ $SED -e '/Attached to:/s/\device[[0-9]\+\]/device[N]/g'
63
}
282
}
64
}
283
65
284
# replace occurrences of the actual TEST_DIR value with TEST_DIR
66
-/*
67
- * Updates @child to change its reference to point to @new_bs, including
68
- * checking and applying the necessary permission updates both to the old node
69
- * and to @new_bs.
70
- *
71
- * NULL is passed as @new_bs for removing the reference before freeing @child.
72
- *
73
- * If @new_bs is not NULL, bdrv_check_perm() must be called beforehand, as this
74
- * function uses bdrv_set_perm() to update the permissions according to the new
75
- * reference that @new_bs gets.
76
- *
77
- * Callers must ensure that child->frozen is false.
78
- */
79
-static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs)
80
-{
81
- BlockDriverState *old_bs = child->bs;
82
-
83
- /* Asserts that child->frozen == false */
84
- bdrv_replace_child_noperm(child, new_bs);
85
-
86
- /*
87
- * Start with the new node's permissions. If @new_bs is a (direct
88
- * or indirect) child of @old_bs, we must complete the permission
89
- * update on @new_bs before we loosen the restrictions on @old_bs.
90
- * Otherwise, bdrv_check_perm() on @old_bs would re-initiate
91
- * updating the permissions of @new_bs, and thus not purely loosen
92
- * restrictions.
93
- */
94
- if (new_bs) {
95
- bdrv_set_perm(new_bs);
96
- }
97
-
98
- if (old_bs) {
99
- /*
100
- * Update permissions for old node. We're just taking a parent away, so
101
- * we're loosening restrictions. Errors of permission update are not
102
- * fatal in this case, ignore them.
103
- */
104
- bdrv_refresh_perms(old_bs, NULL);
105
-
106
- /* When the parent requiring a non-default AioContext is removed, the
107
- * node moves back to the main AioContext */
108
- bdrv_try_set_aio_context(old_bs, qemu_get_aio_context(), NULL);
109
- }
110
-}
111
-
112
static void bdrv_child_free(void *opaque)
113
{
114
BdrvChild *c = opaque;
115
@@ -XXX,XX +XXX,XX @@ static int bdrv_attach_child_noperm(BlockDriverState *parent_bs,
116
117
static void bdrv_detach_child(BdrvChild *child)
118
{
119
- bdrv_replace_child(child, NULL);
120
+ BlockDriverState *old_bs = child->bs;
121
+
122
+ bdrv_replace_child_noperm(child, NULL);
123
bdrv_remove_empty_child(child);
124
+
125
+ if (old_bs) {
126
+ /*
127
+ * Update permissions for old node. We're just taking a parent away, so
128
+ * we're loosening restrictions. Errors of permission update are not
129
+ * fatal in this case, ignore them.
130
+ */
131
+ bdrv_refresh_perms(old_bs, NULL);
132
+
133
+ /*
134
+ * When the parent requiring a non-default AioContext is removed, the
135
+ * node moves back to the main AioContext
136
+ */
137
+ bdrv_try_set_aio_context(old_bs, qemu_get_aio_context(), NULL);
138
+ }
139
}
140
141
/*
285
--
142
--
286
2.29.2
143
2.30.2
287
144
288
145
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
Some of the next commits will checksum structs. Change vpc_checksum()
3
Old interfaces dropped, nobody directly calls
4
to take void * instead of uint8_t, to save us pointless casts to
4
bdrv_child_set_perm_abort() and bdrv_child_set_perm_commit(), so we can
5
uint8_t *.
5
use personal state structure for the action and stop exploiting
6
BdrvChild structure. Also, drop "_safe" suffix which is redundant now.
6
7
7
Signed-off-by: Markus Armbruster <armbru@redhat.com>
8
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Message-Id: <20201217162003.1102738-5-armbru@redhat.com>
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Message-Id: <20210428151804.439460-35-vsementsov@virtuozzo.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
12
---
12
block/vpc.c | 3 ++-
13
include/block/block_int.h | 5 ----
13
1 file changed, 2 insertions(+), 1 deletion(-)
14
block.c | 63 ++++++++++++++-------------------------
15
2 files changed, 22 insertions(+), 46 deletions(-)
14
16
15
diff --git a/block/vpc.c b/block/vpc.c
17
diff --git a/include/block/block_int.h b/include/block/block_int.h
16
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
17
--- a/block/vpc.c
19
--- a/include/block/block_int.h
18
+++ b/block/vpc.c
20
+++ b/include/block/block_int.h
19
@@ -XXX,XX +XXX,XX @@ static QemuOptsList vpc_runtime_opts = {
21
@@ -XXX,XX +XXX,XX @@ struct BdrvChild {
20
22
*/
21
static QemuOptsList vpc_create_opts;
23
uint64_t shared_perm;
22
24
23
-static uint32_t vpc_checksum(uint8_t *buf, size_t size)
25
- /* backup of permissions during permission update procedure */
24
+static uint32_t vpc_checksum(void *p, size_t size)
26
- bool has_backup_perm;
27
- uint64_t backup_perm;
28
- uint64_t backup_shared_perm;
29
-
30
/*
31
* This link is frozen: the child can neither be replaced nor
32
* detached from the parent.
33
diff --git a/block.c b/block.c
34
index XXXXXXX..XXXXXXX 100644
35
--- a/block.c
36
+++ b/block.c
37
@@ -XXX,XX +XXX,XX @@ static GSList *bdrv_topological_dfs(GSList *list, GHashTable *found,
38
return g_slist_prepend(list, bs);
39
}
40
41
-static void bdrv_child_set_perm_commit(void *opaque)
42
-{
43
- BdrvChild *c = opaque;
44
-
45
- c->has_backup_perm = false;
46
-}
47
+typedef struct BdrvChildSetPermState {
48
+ BdrvChild *child;
49
+ uint64_t old_perm;
50
+ uint64_t old_shared_perm;
51
+} BdrvChildSetPermState;
52
53
static void bdrv_child_set_perm_abort(void *opaque)
25
{
54
{
26
+ uint8_t *buf = p;
55
- BdrvChild *c = opaque;
27
uint32_t res = 0;
56
- /*
28
int i;
57
- * We may have child->has_backup_perm unset at this point, as in case of
58
- * _check_ stage of permission update failure we may _check_ not the whole
59
- * subtree. Still, _abort_ is called on the whole subtree anyway.
60
- */
61
- if (c->has_backup_perm) {
62
- c->perm = c->backup_perm;
63
- c->shared_perm = c->backup_shared_perm;
64
- c->has_backup_perm = false;
65
- }
66
+ BdrvChildSetPermState *s = opaque;
67
+
68
+ s->child->perm = s->old_perm;
69
+ s->child->shared_perm = s->old_shared_perm;
70
}
71
72
static TransactionActionDrv bdrv_child_set_pem_drv = {
73
.abort = bdrv_child_set_perm_abort,
74
- .commit = bdrv_child_set_perm_commit,
75
+ .clean = g_free,
76
};
77
78
-/*
79
- * With tran=NULL needs to be followed by direct call to either
80
- * bdrv_child_set_perm_commit() or bdrv_child_set_perm_abort().
81
- *
82
- * With non-NULL tran needs to be followed by tran_abort() or tran_commit()
83
- * instead.
84
- */
85
-static void bdrv_child_set_perm_safe(BdrvChild *c, uint64_t perm,
86
- uint64_t shared, Transaction *tran)
87
+static void bdrv_child_set_perm(BdrvChild *c, uint64_t perm,
88
+ uint64_t shared, Transaction *tran)
89
{
90
- if (!c->has_backup_perm) {
91
- c->has_backup_perm = true;
92
- c->backup_perm = c->perm;
93
- c->backup_shared_perm = c->shared_perm;
94
- }
95
- /*
96
- * Note: it's OK if c->has_backup_perm was already set, as we can find the
97
- * same c twice during check_perm procedure
98
- */
99
+ BdrvChildSetPermState *s = g_new(BdrvChildSetPermState, 1);
100
+
101
+ *s = (BdrvChildSetPermState) {
102
+ .child = c,
103
+ .old_perm = c->perm,
104
+ .old_shared_perm = c->shared_perm,
105
+ };
106
107
c->perm = perm;
108
c->shared_perm = shared;
109
110
- if (tran) {
111
- tran_add(tran, &bdrv_child_set_pem_drv, c);
112
- }
113
+ tran_add(tran, &bdrv_child_set_pem_drv, s);
114
}
115
116
static void bdrv_drv_set_perm_commit(void *opaque)
117
@@ -XXX,XX +XXX,XX @@ static int bdrv_node_check_perm(BlockDriverState *bs, BlockReopenQueue *q,
118
bdrv_child_perm(bs, c->bs, c, c->role, q,
119
cumulative_perms, cumulative_shared_perms,
120
&cur_perm, &cur_shared);
121
- bdrv_child_set_perm_safe(c, cur_perm, cur_shared, tran);
122
+ bdrv_child_set_perm(c, cur_perm, cur_shared, tran);
123
}
124
125
return 0;
126
@@ -XXX,XX +XXX,XX @@ int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared,
127
Transaction *tran = tran_new();
128
int ret;
129
130
- bdrv_child_set_perm_safe(c, perm, shared, tran);
131
+ bdrv_child_set_perm(c, perm, shared, tran);
132
133
ret = bdrv_refresh_perms(c->bs, &local_err);
29
134
30
--
135
--
31
2.29.2
136
2.30.2
32
137
33
138
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
Pad VHDFooter as specified in the "Virtual Hard Disk Image Format
3
We don't have bdrv_replace_child(), so it's time for
4
Specification" version 1.0[*]. Change footer buffers from
4
bdrv_replace_child_safe() to take its place.
5
uint8_t[HEADER_SIZE] to VHDFooter. Their size remains the same.
6
5
7
The VHDFooter * variables pointing to a VHDFooter variable right next
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
to it are now silly. Eliminate them, and shorten the remaining
7
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9
variables' names.
8
Message-Id: <20210428151804.439460-36-vsementsov@virtuozzo.com>
10
11
Most variables pointing to s->footer are now also silly. Eliminate
12
them, too.
13
14
[*] http://download.microsoft.com/download/f/f/e/ffef50a5-07dd-4cf8-aaa3-442c0673a029/Virtual%20Hard%20Disk%20Format%20Spec_10_18_06.doc
15
16
Signed-off-by: Markus Armbruster <armbru@redhat.com>
17
Message-Id: <20201217162003.1102738-8-armbru@redhat.com>
18
Reviewed-by: Max Reitz <mreitz@redhat.com>
19
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
20
---
10
---
21
block/vpc.c | 77 +++++++++++++++++++++++++----------------------------
11
block.c | 10 +++++-----
22
1 file changed, 37 insertions(+), 40 deletions(-)
12
1 file changed, 5 insertions(+), 5 deletions(-)
23
13
24
diff --git a/block/vpc.c b/block/vpc.c
14
diff --git a/block.c b/block.c
25
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
26
--- a/block/vpc.c
16
--- a/block.c
27
+++ b/block/vpc.c
17
+++ b/block.c
28
@@ -XXX,XX +XXX,XX @@ typedef struct vhd_footer {
18
@@ -XXX,XX +XXX,XX @@ static TransactionActionDrv bdrv_replace_child_drv = {
29
QemuUUID uuid;
19
};
30
20
31
uint8_t in_saved_state;
21
/*
32
+ uint8_t reserved[427];
22
- * bdrv_replace_child_safe
33
} QEMU_PACKED VHDFooter;
23
+ * bdrv_replace_child
34
24
*
35
+QEMU_BUILD_BUG_ON(sizeof(VHDFooter) != 512);
25
* Note: real unref of old_bs is done only on commit.
36
+
26
*/
37
typedef struct vhd_dyndisk_header {
27
-static void bdrv_replace_child_safe(BdrvChild *child, BlockDriverState *new_bs,
38
char magic[8]; /* "cxsparse" */
28
- Transaction *tran)
39
29
+static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs,
40
@@ -XXX,XX +XXX,XX @@ QEMU_BUILD_BUG_ON(sizeof(VHDDynDiskHeader) != 1024);
30
+ Transaction *tran)
41
31
{
42
typedef struct BDRVVPCState {
32
BdrvReplaceChildState *s = g_new(BdrvReplaceChildState, 1);
43
CoMutex lock;
33
*s = (BdrvReplaceChildState) {
44
- uint8_t footer_buf[HEADER_SIZE];
34
@@ -XXX,XX +XXX,XX @@ static void bdrv_remove_filter_or_cow_child(BlockDriverState *bs,
45
+ VHDFooter footer;
46
uint64_t free_data_block_offset;
47
int max_table_entries;
48
uint32_t *pagetable;
49
@@ -XXX,XX +XXX,XX @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
50
goto fail;
51
}
35
}
52
36
53
- ret = bdrv_pread(bs->file, 0, s->footer_buf, HEADER_SIZE);
37
if (child->bs) {
54
+ ret = bdrv_pread(bs->file, 0, &s->footer, HEADER_SIZE);
38
- bdrv_replace_child_safe(child, NULL, tran);
55
if (ret < 0) {
39
+ bdrv_replace_child(child, NULL, tran);
56
error_setg(errp, "Unable to read VHD header");
57
goto fail;
58
}
40
}
59
41
60
- footer = (VHDFooter *) s->footer_buf;
42
s = g_new(BdrvRemoveFilterOrCowChild, 1);
61
+ footer = &s->footer;
43
@@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_noperm(BlockDriverState *from,
62
if (strncmp(footer->creator, "conectix", 8)) {
44
c->name, from->node_name);
63
int64_t offset = bdrv_getlength(bs->file->bs);
45
return -EPERM;
64
if (offset < 0) {
65
@@ -XXX,XX +XXX,XX @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
66
}
46
}
67
47
- bdrv_replace_child_safe(c, to, tran);
68
/* If a fixed disk, the footer is found only at the end of the file */
48
+ bdrv_replace_child(c, to, tran);
69
- ret = bdrv_pread(bs->file, offset-HEADER_SIZE, s->footer_buf,
70
+ ret = bdrv_pread(bs->file, offset - HEADER_SIZE, footer,
71
HEADER_SIZE);
72
if (ret < 0) {
73
goto fail;
74
@@ -XXX,XX +XXX,XX @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
75
76
checksum = be32_to_cpu(footer->checksum);
77
footer->checksum = 0;
78
- if (vpc_checksum(s->footer_buf, HEADER_SIZE) != checksum) {
79
+ if (vpc_checksum(footer, HEADER_SIZE) != checksum) {
80
error_setg(errp, "Incorrect header checksum");
81
ret = -EINVAL;
82
goto fail;
83
@@ -XXX,XX +XXX,XX @@ static int rewrite_footer(BlockDriverState *bs)
84
BDRVVPCState *s = bs->opaque;
85
int64_t offset = s->free_data_block_offset;
86
87
- ret = bdrv_pwrite_sync(bs->file, offset, s->footer_buf, HEADER_SIZE);
88
+ ret = bdrv_pwrite_sync(bs->file, offset, &s->footer, HEADER_SIZE);
89
if (ret < 0)
90
return ret;
91
92
@@ -XXX,XX +XXX,XX @@ fail:
93
static int vpc_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
94
{
95
BDRVVPCState *s = (BDRVVPCState *)bs->opaque;
96
- VHDFooter *footer = (VHDFooter *) s->footer_buf;
97
98
- if (be32_to_cpu(footer->type) != VHD_FIXED) {
99
+ if (be32_to_cpu(s->footer.type) != VHD_FIXED) {
100
bdi->cluster_size = s->block_size;
101
}
49
}
102
50
103
@@ -XXX,XX +XXX,XX @@ vpc_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
51
return 0;
104
int64_t image_offset;
105
int64_t n_bytes;
106
int64_t bytes_done = 0;
107
- VHDFooter *footer = (VHDFooter *) s->footer_buf;
108
QEMUIOVector local_qiov;
109
110
- if (be32_to_cpu(footer->type) == VHD_FIXED) {
111
+ if (be32_to_cpu(s->footer.type) == VHD_FIXED) {
112
return bdrv_co_preadv(bs->file, offset, bytes, qiov, 0);
113
}
114
115
@@ -XXX,XX +XXX,XX @@ vpc_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
116
int64_t n_bytes;
117
int64_t bytes_done = 0;
118
int ret = 0;
119
- VHDFooter *footer = (VHDFooter *) s->footer_buf;
120
QEMUIOVector local_qiov;
121
122
- if (be32_to_cpu(footer->type) == VHD_FIXED) {
123
+ if (be32_to_cpu(s->footer.type) == VHD_FIXED) {
124
return bdrv_co_pwritev(bs->file, offset, bytes, qiov, 0);
125
}
126
127
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_block_status(BlockDriverState *bs,
128
BlockDriverState **file)
129
{
130
BDRVVPCState *s = bs->opaque;
131
- VHDFooter *footer = (VHDFooter*) s->footer_buf;
132
int64_t image_offset;
133
bool allocated;
134
int ret;
135
int64_t n;
136
137
- if (be32_to_cpu(footer->type) == VHD_FIXED) {
138
+ if (be32_to_cpu(s->footer.type) == VHD_FIXED) {
139
*pnum = bytes;
140
*map = offset;
141
*file = bs->file->bs;
142
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_create(BlockdevCreateOptions *opts,
143
BlockBackend *blk = NULL;
144
BlockDriverState *bs = NULL;
145
146
- uint8_t footer_buf[HEADER_SIZE];
147
- VHDFooter *footer = (VHDFooter *)footer_buf;
148
+ VHDFooter footer;
149
uint16_t cyls = 0;
150
uint8_t heads = 0;
151
uint8_t secs_per_cyl = 0;
152
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_create(BlockdevCreateOptions *opts,
153
}
154
155
/* Prepare the Hard Disk Footer */
156
- memset(footer_buf, 0, HEADER_SIZE);
157
+ memset(&footer, 0, HEADER_SIZE);
158
159
- memcpy(footer->creator, "conectix", 8);
160
+ memcpy(footer.creator, "conectix", 8);
161
if (vpc_opts->force_size) {
162
- memcpy(footer->creator_app, "qem2", 4);
163
+ memcpy(footer.creator_app, "qem2", 4);
164
} else {
165
- memcpy(footer->creator_app, "qemu", 4);
166
+ memcpy(footer.creator_app, "qemu", 4);
167
}
168
- memcpy(footer->creator_os, "Wi2k", 4);
169
+ memcpy(footer.creator_os, "Wi2k", 4);
170
171
- footer->features = cpu_to_be32(0x02);
172
- footer->version = cpu_to_be32(0x00010000);
173
+ footer.features = cpu_to_be32(0x02);
174
+ footer.version = cpu_to_be32(0x00010000);
175
if (disk_type == VHD_DYNAMIC) {
176
- footer->data_offset = cpu_to_be64(HEADER_SIZE);
177
+ footer.data_offset = cpu_to_be64(HEADER_SIZE);
178
} else {
179
- footer->data_offset = cpu_to_be64(0xFFFFFFFFFFFFFFFFULL);
180
+ footer.data_offset = cpu_to_be64(0xFFFFFFFFFFFFFFFFULL);
181
}
182
- footer->timestamp = cpu_to_be32(time(NULL) - VHD_TIMESTAMP_BASE);
183
+ footer.timestamp = cpu_to_be32(time(NULL) - VHD_TIMESTAMP_BASE);
184
185
/* Version of Virtual PC 2007 */
186
- footer->major = cpu_to_be16(0x0005);
187
- footer->minor = cpu_to_be16(0x0003);
188
- footer->orig_size = cpu_to_be64(total_size);
189
- footer->current_size = cpu_to_be64(total_size);
190
- footer->cyls = cpu_to_be16(cyls);
191
- footer->heads = heads;
192
- footer->secs_per_cyl = secs_per_cyl;
193
+ footer.major = cpu_to_be16(0x0005);
194
+ footer.minor = cpu_to_be16(0x0003);
195
+ footer.orig_size = cpu_to_be64(total_size);
196
+ footer.current_size = cpu_to_be64(total_size);
197
+ footer.cyls = cpu_to_be16(cyls);
198
+ footer.heads = heads;
199
+ footer.secs_per_cyl = secs_per_cyl;
200
201
- footer->type = cpu_to_be32(disk_type);
202
+ footer.type = cpu_to_be32(disk_type);
203
204
qemu_uuid_generate(&uuid);
205
- footer->uuid = uuid;
206
+ footer.uuid = uuid;
207
208
- footer->checksum = cpu_to_be32(vpc_checksum(footer_buf, HEADER_SIZE));
209
+ footer.checksum = cpu_to_be32(vpc_checksum(&footer, HEADER_SIZE));
210
211
if (disk_type == VHD_DYNAMIC) {
212
- ret = create_dynamic_disk(blk, footer_buf, total_sectors);
213
+ ret = create_dynamic_disk(blk, (uint8_t *)&footer, total_sectors);
214
if (ret < 0) {
215
error_setg(errp, "Unable to create or write VHD header");
216
}
217
} else {
218
- ret = create_fixed_disk(blk, footer_buf, total_size, errp);
219
+ ret = create_fixed_disk(blk, (uint8_t *)&footer, total_size, errp);
220
}
221
222
out:
223
@@ -XXX,XX +XXX,XX @@ fail:
224
static int vpc_has_zero_init(BlockDriverState *bs)
225
{
226
BDRVVPCState *s = bs->opaque;
227
- VHDFooter *footer = (VHDFooter *) s->footer_buf;
228
229
- if (be32_to_cpu(footer->type) == VHD_FIXED) {
230
+ if (be32_to_cpu(s->footer.type) == VHD_FIXED) {
231
return bdrv_has_zero_init(bs->file->bs);
232
} else {
233
return 1;
234
--
52
--
235
2.29.2
53
2.30.2
236
54
237
55
diff view generated by jsdifflib
1
From: Stefan Hajnoczi <stefanha@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
Although individual qemu-storage-daemon QMP commands are identical to
3
Now, bdrv_node_check_perm() is called only with fresh cumulative
4
QEMU QMP commands, qemu-storage-daemon only supports a subset of QEMU's
4
permissions, so its actually "refresh_perm".
5
QMP commands. Generate a manual page of just the commands supported by
6
qemu-storage-daemon so that users know exactly what is available in
7
qemu-storage-daemon.
8
5
9
Add an h1 heading in storage-daemon/qapi/qapi-schema.json so that
6
Move permission calculation to the function. Also, drop unreachable
10
block-core.json is at the h2 heading level.
7
error message and rewrite the remaining one to be more generic (as now
8
we don't know which node is added and which was already here).
11
9
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Add also Virtuozzo copyright, as big work is done at this point.
13
Message-Id: <20201209103802.350848-2-stefanha@redhat.com>
11
12
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
13
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
14
Message-Id: <20210428151804.439460-37-vsementsov@virtuozzo.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
16
---
16
docs/interop/conf.py | 2 ++
17
block.c | 38 +++++++++++---------------------------
17
docs/interop/index.rst | 1 +
18
tests/qemu-iotests/245 | 2 +-
18
docs/interop/qemu-storage-daemon-qmp-ref.rst | 13 +++++++++++++
19
2 files changed, 12 insertions(+), 28 deletions(-)
19
docs/meson.build | 1 +
20
storage-daemon/qapi/qapi-schema.json | 3 +++
21
5 files changed, 20 insertions(+)
22
create mode 100644 docs/interop/qemu-storage-daemon-qmp-ref.rst
23
20
24
diff --git a/docs/interop/conf.py b/docs/interop/conf.py
21
diff --git a/block.c b/block.c
25
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
26
--- a/docs/interop/conf.py
23
--- a/block.c
27
+++ b/docs/interop/conf.py
24
+++ b/block.c
28
@@ -XXX,XX +XXX,XX @@ man_pages = [
29
[], 7),
30
('qemu-qmp-ref', 'qemu-qmp-ref', 'QEMU QMP Reference Manual',
31
[], 7),
32
+ ('qemu-storage-daemon-qmp-ref', 'qemu-storage-daemon-qmp-ref',
33
+ 'QEMU Storage Daemon QMP Reference Manual', [], 7),
34
]
35
diff --git a/docs/interop/index.rst b/docs/interop/index.rst
36
index XXXXXXX..XXXXXXX 100644
37
--- a/docs/interop/index.rst
38
+++ b/docs/interop/index.rst
39
@@ -XXX,XX +XXX,XX @@ Contents:
40
qemu-ga
41
qemu-ga-ref
42
qemu-qmp-ref
43
+ qemu-storage-daemon-qmp-ref
44
vhost-user
45
vhost-user-gpu
46
vhost-vdpa
47
diff --git a/docs/interop/qemu-storage-daemon-qmp-ref.rst b/docs/interop/qemu-storage-daemon-qmp-ref.rst
48
new file mode 100644
49
index XXXXXXX..XXXXXXX
50
--- /dev/null
51
+++ b/docs/interop/qemu-storage-daemon-qmp-ref.rst
52
@@ -XXX,XX +XXX,XX @@
25
@@ -XXX,XX +XXX,XX @@
53
+QEMU Storage Daemon QMP Reference Manual
26
* QEMU System Emulator block driver
54
+========================================
27
*
28
* Copyright (c) 2003 Fabrice Bellard
29
+ * Copyright (c) 2020 Virtuozzo International GmbH.
30
*
31
* Permission is hereby granted, free of charge, to any person obtaining a copy
32
* of this software and associated documentation files (the "Software"), to deal
33
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs,
34
}
35
36
/*
37
- * Check whether permissions on this node can be changed in a way that
38
- * @cumulative_perms and @cumulative_shared_perms are the new cumulative
39
- * permissions of all its parents. This involves checking whether all necessary
40
- * permission changes to child nodes can be performed.
41
- *
42
- * A call to this function must always be followed by a call to bdrv_set_perm()
43
- * or bdrv_abort_perm_update().
44
+ * Refresh permissions in @bs subtree. The function is intended to be called
45
+ * after some graph modification that was done without permission update.
46
*/
47
-static int bdrv_node_check_perm(BlockDriverState *bs, BlockReopenQueue *q,
48
- uint64_t cumulative_perms,
49
- uint64_t cumulative_shared_perms,
50
- Transaction *tran, Error **errp)
51
+static int bdrv_node_refresh_perm(BlockDriverState *bs, BlockReopenQueue *q,
52
+ Transaction *tran, Error **errp)
53
{
54
BlockDriver *drv = bs->drv;
55
BdrvChild *c;
56
int ret;
57
+ uint64_t cumulative_perms, cumulative_shared_perms;
55
+
58
+
56
+..
59
+ bdrv_get_cumulative_perm(bs, &cumulative_perms, &cumulative_shared_perms);
57
+ TODO: the old Texinfo manual used to note that this manual
60
58
+ is GPL-v2-or-later. We should make that reader-visible
61
/* Write permissions never work with read-only images */
59
+ both here and in our Sphinx manuals more generally.
62
if ((cumulative_perms & (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED)) &&
60
+
63
@@ -XXX,XX +XXX,XX @@ static int bdrv_node_check_perm(BlockDriverState *bs, BlockReopenQueue *q,
61
+..
64
if (!bdrv_is_writable_after_reopen(bs, NULL)) {
62
+ TODO: display the QEMU version, both here and in our Sphinx manuals
65
error_setg(errp, "Block node is read-only");
63
+ more generally.
66
} else {
64
+
67
- uint64_t current_perms, current_shared;
65
+.. qapi-doc:: storage-daemon/qapi/qapi-schema.json
68
- bdrv_get_cumulative_perm(bs, &current_perms, &current_shared);
66
diff --git a/docs/meson.build b/docs/meson.build
69
- if (current_perms & (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED)) {
67
index XXXXXXX..XXXXXXX 100644
70
- error_setg(errp, "Cannot make block node read-only, there is "
68
--- a/docs/meson.build
71
- "a writer on it");
69
+++ b/docs/meson.build
72
- } else {
70
@@ -XXX,XX +XXX,XX @@ if build_docs
73
- error_setg(errp, "Cannot make block node read-only and create "
71
'qemu-ga.8': (have_tools ? 'man8' : ''),
74
- "a writer on it");
72
'qemu-ga-ref.7': 'man7',
75
- }
73
'qemu-qmp-ref.7': 'man7',
76
+ error_setg(errp, "Read-only block node '%s' cannot support "
74
+ 'qemu-storage-daemon-qmp-ref.7': (have_tools ? 'man7' : ''),
77
+ "read-write users", bdrv_get_node_name(bs));
75
},
78
}
76
'tools': {
79
77
'qemu-img.1': (have_tools ? 'man1' : ''),
80
return -EPERM;
78
diff --git a/storage-daemon/qapi/qapi-schema.json b/storage-daemon/qapi/qapi-schema.json
81
@@ -XXX,XX +XXX,XX @@ static int bdrv_list_refresh_perms(GSList *list, BlockReopenQueue *q,
79
index XXXXXXX..XXXXXXX 100644
82
Transaction *tran, Error **errp)
80
--- a/storage-daemon/qapi/qapi-schema.json
83
{
81
+++ b/storage-daemon/qapi/qapi-schema.json
84
int ret;
82
@@ -XXX,XX +XXX,XX @@
85
- uint64_t cumulative_perms, cumulative_shared_perms;
83
86
BlockDriverState *bs;
84
{ 'include': '../../qapi/pragma.json' }
87
85
88
for ( ; list; list = list->next) {
86
+##
89
@@ -XXX,XX +XXX,XX @@ static int bdrv_list_refresh_perms(GSList *list, BlockReopenQueue *q,
87
+# = Block devices
90
return -EINVAL;
88
+##
91
}
89
{ 'include': '../../qapi/block-core.json' }
92
90
{ 'include': '../../qapi/block-export.json' }
93
- bdrv_get_cumulative_perm(bs, &cumulative_perms,
91
{ 'include': '../../qapi/char.json' }
94
- &cumulative_shared_perms);
95
-
96
- ret = bdrv_node_check_perm(bs, q, cumulative_perms,
97
- cumulative_shared_perms,
98
- tran, errp);
99
+ ret = bdrv_node_refresh_perm(bs, q, tran, errp);
100
if (ret < 0) {
101
return ret;
102
}
103
diff --git a/tests/qemu-iotests/245 b/tests/qemu-iotests/245
104
index XXXXXXX..XXXXXXX 100755
105
--- a/tests/qemu-iotests/245
106
+++ b/tests/qemu-iotests/245
107
@@ -XXX,XX +XXX,XX @@ class TestBlockdevReopen(iotests.QMPTestCase):
108
# We can't reopen hd1 to read-only, as block-stream requires it to be
109
# read-write
110
self.reopen(opts['backing'], {'read-only': True},
111
- "Cannot make block node read-only, there is a writer on it")
112
+ "Read-only block node 'hd1' cannot support read-write users")
113
114
# We can't remove hd2 while the stream job is ongoing
115
opts['backing']['backing'] = None
92
--
116
--
93
2.29.2
117
2.30.2
94
118
95
119
diff view generated by jsdifflib
1
From: Peter Lieven <pl@kamp.de>
1
Normally, blk_new_open() just shares all permissions. This was fine
2
originally when permissions only protected against uses in the same
3
process because no other part of the code would actually get to access
4
the block nodes opened with blk_new_open(). However, since we use it for
5
file locking now, unsharing permissions becomes desirable.
2
6
3
nfs_client_open returns the file size in sectors. This effectively
7
Add a new BDRV_O_NO_SHARE flag that is used in blk_new_open() to unshare
4
makes it impossible to open files larger than 1TB.
8
any permissions that can be unshared.
5
9
6
Fixes: c22a03454544c2a08f1107c5cc8481a5574533d5
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Cc: qemu-stable@nongnu.org
11
Message-Id: <20210422164344.283389-2-kwolf@redhat.com>
8
Signed-off-by: Peter Lieven <pl@kamp.de>
12
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Message-Id: <20201209121735.16437-1-pl@kamp.de>
13
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
15
---
13
block/nfs.c | 2 +-
16
include/block/block.h | 1 +
14
1 file changed, 1 insertion(+), 1 deletion(-)
17
block/block-backend.c | 19 +++++++++++++------
18
2 files changed, 14 insertions(+), 6 deletions(-)
15
19
16
diff --git a/block/nfs.c b/block/nfs.c
20
diff --git a/include/block/block.h b/include/block/block.h
17
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
18
--- a/block/nfs.c
22
--- a/include/block/block.h
19
+++ b/block/nfs.c
23
+++ b/include/block/block.h
20
@@ -XXX,XX +XXX,XX @@ static int64_t nfs_client_open_qdict(NFSClient *client, QDict *options,
24
@@ -XXX,XX +XXX,XX @@ typedef struct HDGeometry {
21
int flags, int open_flags, Error **errp)
25
uint32_t cylinders;
22
{
26
} HDGeometry;
23
BlockdevOptionsNfs *opts;
27
24
- int ret;
28
+#define BDRV_O_NO_SHARE 0x0001 /* don't share permissions */
25
+ int64_t ret;
29
#define BDRV_O_RDWR 0x0002
26
30
#define BDRV_O_RESIZE 0x0004 /* request permission for resizing the node */
27
opts = nfs_options_qdict_to_qapi(options, errp);
31
#define BDRV_O_SNAPSHOT 0x0008 /* open the file read only and save writes in a snapshot */
28
if (opts == NULL) {
32
diff --git a/block/block-backend.c b/block/block-backend.c
33
index XXXXXXX..XXXXXXX 100644
34
--- a/block/block-backend.c
35
+++ b/block/block-backend.c
36
@@ -XXX,XX +XXX,XX @@ BlockBackend *blk_new_open(const char *filename, const char *reference,
37
BlockBackend *blk;
38
BlockDriverState *bs;
39
uint64_t perm = 0;
40
+ uint64_t shared = BLK_PERM_ALL;
41
42
- /* blk_new_open() is mainly used in .bdrv_create implementations and the
43
- * tools where sharing isn't a concern because the BDS stays private, so we
44
- * just request permission according to the flags.
45
+ /*
46
+ * blk_new_open() is mainly used in .bdrv_create implementations and the
47
+ * tools where sharing isn't a major concern because the BDS stays private
48
+ * and the file is generally not supposed to be used by a second process,
49
+ * so we just request permission according to the flags.
50
*
51
* The exceptions are xen_disk and blockdev_init(); in these cases, the
52
* caller of blk_new_open() doesn't make use of the permissions, but they
53
* shouldn't hurt either. We can still share everything here because the
54
- * guest devices will add their own blockers if they can't share. */
55
+ * guest devices will add their own blockers if they can't share.
56
+ */
57
if ((flags & BDRV_O_NO_IO) == 0) {
58
perm |= BLK_PERM_CONSISTENT_READ;
59
if (flags & BDRV_O_RDWR) {
60
@@ -XXX,XX +XXX,XX @@ BlockBackend *blk_new_open(const char *filename, const char *reference,
61
if (flags & BDRV_O_RESIZE) {
62
perm |= BLK_PERM_RESIZE;
63
}
64
+ if (flags & BDRV_O_NO_SHARE) {
65
+ shared = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED;
66
+ }
67
68
- blk = blk_new(qemu_get_aio_context(), perm, BLK_PERM_ALL);
69
+ blk = blk_new(qemu_get_aio_context(), perm, shared);
70
bs = bdrv_open(filename, reference, options, flags, errp);
71
if (!bs) {
72
blk_unref(blk);
73
@@ -XXX,XX +XXX,XX @@ BlockBackend *blk_new_open(const char *filename, const char *reference,
74
75
blk->root = bdrv_root_attach_child(bs, "root", &child_root,
76
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
77
- perm, BLK_PERM_ALL, blk, errp);
78
+ perm, shared, blk, errp);
79
if (!blk->root) {
80
blk_unref(blk);
81
return NULL;
29
--
82
--
30
2.29.2
83
2.30.2
31
84
32
85
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
For a successful conversion of an image, we must make sure that its
2
content doesn't change during the conversion.
2
3
3
Commit 8b1170012b1 has added a global maximum disk length for the block
4
A special case of this is using the same image file both as the source
4
layer, so the error message when creating an overly large disk has
5
and as the destination. If both input and output format are raw, the
5
changed.
6
operation would just be useless work, with other formats it is a sure
7
way to destroy the image. This will now fail because the image file
8
can't be opened a second time for the output when opening it for the
9
input has already acquired file locks to unshare BLK_PERM_WRITE.
6
10
7
Fixes: 8b1170012b1de6649c66ac1887f4df7e312abf3b
11
Nevertheless, if there is some reason in a special case why it is
8
("block: introduce BDRV_MAX_LENGTH")
12
actually okay to allow writes to the image while it is being converted,
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
-U can still be used to force sharing all permissions.
10
Message-Id: <20201214175158.299919-1-mreitz@redhat.com>
14
15
Note that for most image formats, BLK_PERM_WRITE would already be
16
unshared by the format driver, so this only really makes a difference
17
for raw source images (but any output format).
18
19
Reported-by: Xueqiang Wei <xuwei@redhat.com>
20
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
21
Reviewed-by: Eric Blake <eblake@redhat.com>
22
Message-Id: <20210422164344.283389-3-kwolf@redhat.com>
11
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
23
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
24
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
25
---
14
tests/qemu-iotests/210.out | 2 +-
26
qemu-img.c | 2 +-
15
1 file changed, 1 insertion(+), 1 deletion(-)
27
1 file changed, 1 insertion(+), 1 deletion(-)
16
28
17
diff --git a/tests/qemu-iotests/210.out b/tests/qemu-iotests/210.out
29
diff --git a/qemu-img.c b/qemu-img.c
18
index XXXXXXX..XXXXXXX 100644
30
index XXXXXXX..XXXXXXX 100644
19
--- a/tests/qemu-iotests/210.out
31
--- a/qemu-img.c
20
+++ b/tests/qemu-iotests/210.out
32
+++ b/qemu-img.c
21
@@ -XXX,XX +XXX,XX @@ Job failed: The requested file size is too large
33
@@ -XXX,XX +XXX,XX @@ static void set_rate_limit(BlockBackend *blk, int64_t rate_limit)
22
=== Resize image with invalid sizes ===
34
23
35
static int img_convert(int argc, char **argv)
24
{"execute": "block_resize", "arguments": {"node-name": "node1", "size": 9223372036854775296}}
36
{
25
-{"error": {"class": "GenericError", "desc": "The requested file size is too large"}}
37
- int c, bs_i, flags, src_flags = 0;
26
+{"error": {"class": "GenericError", "desc": "Required too big image size, it must be not greater than 9223372035781033984"}}
38
+ int c, bs_i, flags, src_flags = BDRV_O_NO_SHARE;
27
{"execute": "block_resize", "arguments": {"node-name": "node1", "size": 9223372036854775808}}
39
const char *fmt = NULL, *out_fmt = NULL, *cache = "unsafe",
28
{"error": {"class": "GenericError", "desc": "Invalid parameter type for 'size', expected: integer"}}
40
*src_cache = BDRV_DEFAULT_CACHE, *out_baseimg = NULL,
29
{"execute": "block_resize", "arguments": {"node-name": "node1", "size": 18446744073709551104}}
41
*out_filename, *out_baseimg_param, *snapshot_name = NULL;
30
--
42
--
31
2.29.2
43
2.30.2
32
44
33
45
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
1
virtio_add_queue() aborts when queue_size > VIRTQUEUE_MAX_SIZE, so
2
vhost_user_blk_device_realize() should check this before calling it.
2
3
3
This is the QEMU equivalent of this Linux commit (but 7 years later):
4
Simple reproducer:
4
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=f7025a43a9da2
5
5
6
The MTD subsystem has its own small museum of ancient NANDs
6
qemu-system-x86_64 \
7
in a form of the CONFIG_MTD_NAND_MUSEUM_IDS configuration option.
7
-chardev null,id=foo \
8
The museum contains stone age NANDs with 256 bytes pages, as well
8
-device vhost-user-blk-pci,queue-size=4096,chardev=foo
9
as iron age NANDs with 512 bytes per page and up to 8MiB page size.
10
9
11
It is with great sorrow that I inform you that the museum is being
10
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1935014
12
decommissioned. The MTD subsystem is out of budget for Kconfig
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
options and already has too many of them, and there is a general
12
Message-Id: <20210413165654.50810-1-kwolf@redhat.com>
14
kernel trend to simplify the configuration menu.
13
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
15
14
Reviewed-by: Raphael Norwitz <raphael.norwitz@nutanix.com>
16
We remove the stone age exhibits along with closing the museum,
15
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
17
but some of the iron age ones are transferred to the regular NAND
16
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
18
depot. Namely, only those which have unique device IDs are
19
transferred, and the ones which have conflicting device IDs are
20
removed.
21
22
The machine using this device are:
23
- axis-dev88
24
- tosa (via tc6393xb_init)
25
- spitz based (akita, borzoi, terrier)
26
27
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
28
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
29
Message-Id: <20201214002620.342384-1-f4bug@amsat.org>
30
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
31
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
32
---
18
---
33
hw/block/nand.c | 12 +-----------
19
hw/block/vhost-user-blk.c | 5 +++++
34
1 file changed, 1 insertion(+), 11 deletions(-)
20
1 file changed, 5 insertions(+)
35
21
36
diff --git a/hw/block/nand.c b/hw/block/nand.c
22
diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c
37
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
38
--- a/hw/block/nand.c
24
--- a/hw/block/vhost-user-blk.c
39
+++ b/hw/block/nand.c
25
+++ b/hw/block/vhost-user-blk.c
40
@@ -XXX,XX +XXX,XX @@ static void mem_and(uint8_t *dest, const uint8_t *src, size_t n)
26
@@ -XXX,XX +XXX,XX @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp)
41
# define ADDR_SHIFT        16
27
error_setg(errp, "vhost-user-blk: queue size must be non-zero");
42
# include "nand.c"
28
return;
43
29
}
44
-/* Information based on Linux drivers/mtd/nand/nand_ids.c */
30
+ if (s->queue_size > VIRTQUEUE_MAX_SIZE) {
45
+/* Information based on Linux drivers/mtd/nand/raw/nand_ids.c */
31
+ error_setg(errp, "vhost-user-blk: queue size must not exceed %d",
46
static const struct {
32
+ VIRTQUEUE_MAX_SIZE);
47
int size;
33
+ return;
48
int width;
34
+ }
49
@@ -XXX,XX +XXX,XX @@ static const struct {
35
50
} nand_flash_ids[0x100] = {
36
if (!vhost_user_init(&s->vhost_user, &s->chardev, errp)) {
51
[0 ... 0xff] = { 0 },
37
return;
52
53
- [0x6e] = { 1,    8,    8, 4, 0 },
54
- [0x64] = { 2,    8,    8, 4, 0 },
55
[0x6b] = { 4,    8,    9, 4, 0 },
56
- [0xe8] = { 1,    8,    8, 4, 0 },
57
- [0xec] = { 1,    8,    8, 4, 0 },
58
- [0xea] = { 2,    8,    8, 4, 0 },
59
- [0xd5] = { 4,    8,    9, 4, 0 },
60
[0xe3] = { 4,    8,    9, 4, 0 },
61
[0xe5] = { 4,    8,    9, 4, 0 },
62
[0xd6] = { 8,    8,    9, 4, 0 },
63
-
64
- [0x39] = { 8,    8,    9, 4, 0 },
65
[0xe6] = { 8,    8,    9, 4, 0 },
66
- [0x49] = { 8,    16,    9, 4, NAND_BUSWIDTH_16 },
67
- [0x59] = { 8,    16,    9, 4, NAND_BUSWIDTH_16 },
68
69
[0x33] = { 16,    8,    9, 5, 0 },
70
[0x73] = { 16,    8,    9, 5, 0 },
71
--
38
--
72
2.29.2
39
2.30.2
73
40
74
41
diff view generated by jsdifflib