1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#include "qemu/osdep.h"
22#include "qapi/error.h"
23#include "qemu/main-loop.h"
24#include "block/block_int.h"
25#include "sysemu/block-backend.h"
26
27static BlockDriver bdrv_pass_through = {
28 .format_name = "pass-through",
29 .bdrv_child_perm = bdrv_default_perms,
30};
31
32static void no_perm_default_perms(BlockDriverState *bs, BdrvChild *c,
33 BdrvChildRole role,
34 BlockReopenQueue *reopen_queue,
35 uint64_t perm, uint64_t shared,
36 uint64_t *nperm, uint64_t *nshared)
37{
38 *nperm = 0;
39 *nshared = BLK_PERM_ALL;
40}
41
42static BlockDriver bdrv_no_perm = {
43 .format_name = "no-perm",
44 .supports_backing = true,
45 .bdrv_child_perm = no_perm_default_perms,
46};
47
48static void exclusive_write_perms(BlockDriverState *bs, BdrvChild *c,
49 BdrvChildRole role,
50 BlockReopenQueue *reopen_queue,
51 uint64_t perm, uint64_t shared,
52 uint64_t *nperm, uint64_t *nshared)
53{
54 *nperm = BLK_PERM_WRITE;
55 *nshared = BLK_PERM_ALL & ~BLK_PERM_WRITE;
56}
57
58static BlockDriver bdrv_exclusive_writer = {
59 .format_name = "exclusive-writer",
60 .bdrv_child_perm = exclusive_write_perms,
61};
62
63static BlockDriverState *no_perm_node(const char *name)
64{
65 return bdrv_new_open_driver(&bdrv_no_perm, name, BDRV_O_RDWR, &error_abort);
66}
67
68static BlockDriverState *pass_through_node(const char *name)
69{
70 return bdrv_new_open_driver(&bdrv_pass_through, name,
71 BDRV_O_RDWR, &error_abort);
72}
73
74static BlockDriverState *exclusive_writer_node(const char *name)
75{
76 return bdrv_new_open_driver(&bdrv_exclusive_writer, name,
77 BDRV_O_RDWR, &error_abort);
78}
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124static void test_update_perm_tree(void)
125{
126 int ret;
127
128 BlockBackend *root = blk_new(qemu_get_aio_context(),
129 BLK_PERM_WRITE | BLK_PERM_CONSISTENT_READ,
130 BLK_PERM_ALL & ~BLK_PERM_WRITE);
131 BlockDriverState *bs = no_perm_node("node");
132 BlockDriverState *filter = pass_through_node("filter");
133
134 blk_insert_bs(root, bs, &error_abort);
135
136 bdrv_attach_child(filter, bs, "child", &child_of_bds,
137 BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, &error_abort);
138
139 ret = bdrv_append(filter, bs, NULL);
140 g_assert_cmpint(ret, <, 0);
141
142 bdrv_unref(filter);
143 blk_unref(root);
144}
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190static void test_should_update_child(void)
191{
192 BlockBackend *root = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
193 BlockDriverState *bs = no_perm_node("node");
194 BlockDriverState *filter = no_perm_node("filter");
195 BlockDriverState *target = no_perm_node("target");
196
197 blk_insert_bs(root, bs, &error_abort);
198
199 bdrv_set_backing_hd(target, bs, &error_abort);
200
201 g_assert(target->backing->bs == bs);
202 bdrv_attach_child(filter, target, "target", &child_of_bds,
203 BDRV_CHILD_DATA, &error_abort);
204 bdrv_append(filter, bs, &error_abort);
205 g_assert(target->backing->bs == bs);
206
207 bdrv_unref(filter);
208 bdrv_unref(bs);
209 blk_unref(root);
210}
211
212
213
214
215
216
217
218static void test_parallel_exclusive_write(void)
219{
220 BlockDriverState *top = exclusive_writer_node("top");
221 BlockDriverState *base = no_perm_node("base");
222 BlockDriverState *fl1 = pass_through_node("fl1");
223 BlockDriverState *fl2 = pass_through_node("fl2");
224
225
226
227
228
229 bdrv_ref(base);
230
231 bdrv_attach_child(top, fl1, "backing", &child_of_bds, BDRV_CHILD_DATA,
232 &error_abort);
233 bdrv_attach_child(fl1, base, "backing", &child_of_bds, BDRV_CHILD_FILTERED,
234 &error_abort);
235 bdrv_attach_child(fl2, base, "backing", &child_of_bds, BDRV_CHILD_FILTERED,
236 &error_abort);
237
238 bdrv_replace_node(fl1, fl2, &error_abort);
239
240 bdrv_unref(fl2);
241 bdrv_unref(top);
242}
243
244static void write_to_file_perms(BlockDriverState *bs, BdrvChild *c,
245 BdrvChildRole role,
246 BlockReopenQueue *reopen_queue,
247 uint64_t perm, uint64_t shared,
248 uint64_t *nperm, uint64_t *nshared)
249{
250 if (bs->file && c == bs->file) {
251 *nperm = BLK_PERM_WRITE;
252 *nshared = BLK_PERM_ALL & ~BLK_PERM_WRITE;
253 } else {
254 *nperm = 0;
255 *nshared = BLK_PERM_ALL;
256 }
257}
258
259static BlockDriver bdrv_write_to_file = {
260 .format_name = "tricky-perm",
261 .bdrv_child_perm = write_to_file_perms,
262};
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306static void test_parallel_perm_update(void)
307{
308 BlockDriverState *top = no_perm_node("top");
309 BlockDriverState *tricky =
310 bdrv_new_open_driver(&bdrv_write_to_file, "tricky", BDRV_O_RDWR,
311 &error_abort);
312 BlockDriverState *base = no_perm_node("base");
313 BlockDriverState *fl1 = pass_through_node("fl1");
314 BlockDriverState *fl2 = pass_through_node("fl2");
315 BdrvChild *c_fl1, *c_fl2;
316
317
318
319
320
321 bdrv_ref(base);
322
323 bdrv_attach_child(top, tricky, "file", &child_of_bds, BDRV_CHILD_DATA,
324 &error_abort);
325 c_fl1 = bdrv_attach_child(tricky, fl1, "first", &child_of_bds,
326 BDRV_CHILD_FILTERED, &error_abort);
327 c_fl2 = bdrv_attach_child(tricky, fl2, "second", &child_of_bds,
328 BDRV_CHILD_FILTERED, &error_abort);
329 bdrv_attach_child(fl1, base, "backing", &child_of_bds, BDRV_CHILD_FILTERED,
330 &error_abort);
331 bdrv_attach_child(fl2, base, "backing", &child_of_bds, BDRV_CHILD_FILTERED,
332 &error_abort);
333
334
335 tricky->file = c_fl1;
336 bdrv_child_refresh_perms(top, top->children.lh_first, &error_abort);
337
338 assert(c_fl1->perm & BLK_PERM_WRITE);
339 assert(!(c_fl2->perm & BLK_PERM_WRITE));
340
341
342 tricky->file = c_fl2;
343 bdrv_child_refresh_perms(top, top->children.lh_first, &error_abort);
344
345 assert(c_fl2->perm & BLK_PERM_WRITE);
346 assert(!(c_fl1->perm & BLK_PERM_WRITE));
347
348
349 tricky->file = c_fl1;
350 bdrv_child_refresh_perms(top, top->children.lh_first, &error_abort);
351
352 assert(c_fl1->perm & BLK_PERM_WRITE);
353 assert(!(c_fl2->perm & BLK_PERM_WRITE));
354
355 bdrv_unref(top);
356}
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376static void test_append_greedy_filter(void)
377{
378 BlockDriverState *top = exclusive_writer_node("top");
379 BlockDriverState *base = no_perm_node("base");
380 BlockDriverState *fl = exclusive_writer_node("fl1");
381
382 bdrv_attach_child(top, base, "backing", &child_of_bds, BDRV_CHILD_COW,
383 &error_abort);
384
385 bdrv_append(fl, base, &error_abort);
386 bdrv_unref(fl);
387 bdrv_unref(top);
388}
389
390int main(int argc, char *argv[])
391{
392 bdrv_init();
393 qemu_init_main_loop(&error_abort);
394
395 g_test_init(&argc, &argv, NULL);
396
397 g_test_add_func("/bdrv-graph-mod/update-perm-tree", test_update_perm_tree);
398 g_test_add_func("/bdrv-graph-mod/should-update-child",
399 test_should_update_child);
400 g_test_add_func("/bdrv-graph-mod/parallel-perm-update",
401 test_parallel_perm_update);
402 g_test_add_func("/bdrv-graph-mod/parallel-exclusive-write",
403 test_parallel_exclusive_write);
404 g_test_add_func("/bdrv-graph-mod/append-greedy-filter",
405 test_append_greedy_filter);
406
407 return g_test_run();
408}
409