1 | The following changes since commit 1e3ee834083227f552179f6e43902cba5a866e6b: | 1 | The following changes since commit 143c2e0432859826c9e8d5b2baa307355f1a5332: |
---|---|---|---|
2 | 2 | ||
3 | Merge remote-tracking branch 'remotes/thibault/tags/samuel-thibault' into staging (2017-09-25 20:31:24 +0100) | 3 | Merge remote-tracking branch 'remotes/maxreitz/tags/pull-block-2021-07-19' into staging (2021-07-19 19:06:05 +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 b156d51b62e6970753e1f9f36f7c4d5fdbf4c619: | 9 | for you to fetch changes up to d21471696b07f30cb00453709d055a25c1afde85: |
10 | 10 | ||
11 | Merge remote-tracking branch 'mreitz/tags/pull-block-2017-09-26' into queue-block (2017-09-26 15:03:02 +0200) | 11 | iotests/307: Test iothread conflict for exports (2021-07-20 16:49:50 +0200) |
12 | 12 | ||
13 | ---------------------------------------------------------------- | 13 | ---------------------------------------------------------------- |
14 | Block layer patches | 14 | Block layer patches |
15 | 15 | ||
16 | - mirror: Fix active mirror deadlock | ||
17 | - replication: Fix crashes due to operations on wrong BdrvChild | ||
18 | - configure: Add option to use driver whitelist even in tools | ||
19 | - vvfat: Fix crash when opening image read-write | ||
20 | - export: Fix crash in error path with fixed-iothread=false | ||
21 | |||
16 | ---------------------------------------------------------------- | 22 | ---------------------------------------------------------------- |
17 | Alberto Garcia (1): | 23 | Kevin Wolf (1): |
18 | throttle: Assert that bkt->max is valid in throttle_compute_wait() | 24 | block: Add option to use driver whitelist even in tools |
19 | 25 | ||
20 | Cornelia Huck (3): | 26 | Lukas Straub (4): |
21 | iotests: use -ccw on s390x for 040, 139, and 182 | 27 | replication: Remove s->active_disk |
22 | iotests: use -ccw on s390x for 051 | 28 | replication: Reduce usage of s->hidden_disk and s->secondary_disk |
23 | iotests: use virtio aliases for 067 | 29 | replication: Properly attach children |
30 | replication: Remove workaround | ||
24 | 31 | ||
25 | Fam Zheng (3): | 32 | Max Reitz (2): |
26 | qemu-img: Clarify about relative backing file options | 33 | block/export: Conditionally ignore set-context error |
27 | file-posix: Clear out first sector in hdev_create | 34 | iotests/307: Test iothread conflict for exports |
28 | iotests: Print full path of bad output if mismatch | ||
29 | 35 | ||
30 | Kevin Wolf (9): | 36 | Vladimir Sementsov-Ogievskiy (4): |
31 | qemu-iotests: Add missing -machine accel=qtest | 37 | block/mirror: set .co for active-write MirrorOp objects |
32 | qemu-io: Drop write permissions before read-only reopen | 38 | iotest 151: add test-case that shows active mirror dead-lock |
33 | block: Add reopen_queue to bdrv_child_perm() | 39 | block/mirror: fix active mirror dead-lock in mirror_wait_on_conflicts |
34 | block: Add reopen queue to bdrv_check_perm() | 40 | block/vvfat: fix: drop backing |
35 | block: Base permissions on rw state after reopen | ||
36 | block: reopen: Queue children after their parents | ||
37 | block: Fix permissions after bdrv_reopen() | ||
38 | qemu-iotests: Test change-backing-file command | ||
39 | Merge remote-tracking branch 'mreitz/tags/pull-block-2017-09-26' into queue-block | ||
40 | 41 | ||
41 | Manos Pitsidianakis (1): | 42 | configure | 14 +++++- |
42 | block/throttle-groups.c: allocate RestartData on the heap | 43 | block.c | 3 ++ |
44 | block/export/export.c | 5 +- | ||
45 | block/mirror.c | 13 ++++++ | ||
46 | block/replication.c | 111 +++++++++++++++++++++++++++------------------ | ||
47 | block/vvfat.c | 43 ++---------------- | ||
48 | meson.build | 1 + | ||
49 | tests/qemu-iotests/151 | 54 +++++++++++++++++++++- | ||
50 | tests/qemu-iotests/151.out | 4 +- | ||
51 | tests/qemu-iotests/307 | 15 ++++++ | ||
52 | tests/qemu-iotests/307.out | 8 ++++ | ||
53 | 11 files changed, 182 insertions(+), 89 deletions(-) | ||
43 | 54 | ||
44 | Pavel Butsykin (4): | ||
45 | qemu-img: add --shrink flag for resize | ||
46 | qcow2: add qcow2_cache_discard | ||
47 | qcow2: add shrink image support | ||
48 | qemu-iotests: add shrinking image test | ||
49 | 55 | ||
50 | Stefan Hajnoczi (1): | ||
51 | docs: add qemu-block-drivers(7) man page | ||
52 | |||
53 | Thomas Huth (1): | ||
54 | block: Clean up some bad code in the vvfat driver | ||
55 | |||
56 | Vladimir Sementsov-Ogievskiy (2): | ||
57 | iotests: fix 181: enable postcopy-ram capability on target | ||
58 | block/qcow2-bitmap: fix use of uninitialized pointer | ||
59 | |||
60 | qapi/block-core.json | 8 +- | ||
61 | block/qcow2.h | 17 + | ||
62 | include/block/block.h | 2 +- | ||
63 | include/block/block_int.h | 7 + | ||
64 | block.c | 191 +++++++--- | ||
65 | block/commit.c | 1 + | ||
66 | block/file-posix.c | 10 + | ||
67 | block/mirror.c | 1 + | ||
68 | block/qcow2-bitmap.c | 2 +- | ||
69 | block/qcow2-cache.c | 26 ++ | ||
70 | block/qcow2-cluster.c | 50 +++ | ||
71 | block/qcow2-refcount.c | 140 +++++++- | ||
72 | block/qcow2.c | 43 ++- | ||
73 | block/replication.c | 1 + | ||
74 | block/throttle-groups.c | 12 +- | ||
75 | block/vvfat.c | 27 +- | ||
76 | qemu-img.c | 23 ++ | ||
77 | qemu-io-cmds.c | 12 + | ||
78 | util/throttle.c | 1 + | ||
79 | Makefile | 6 +- | ||
80 | docs/qemu-block-drivers.texi | 804 ++++++++++++++++++++++++++++++++++++++++++ | ||
81 | qemu-doc.texi | 781 +--------------------------------------- | ||
82 | qemu-img-cmds.hx | 4 +- | ||
83 | qemu-img.texi | 15 +- | ||
84 | tests/qemu-iotests/040 | 6 +- | ||
85 | tests/qemu-iotests/051 | 12 +- | ||
86 | tests/qemu-iotests/051.out | 2 +- | ||
87 | tests/qemu-iotests/051.pc.out | 2 +- | ||
88 | tests/qemu-iotests/067 | 2 +- | ||
89 | tests/qemu-iotests/067.out | 2 +- | ||
90 | tests/qemu-iotests/102 | 4 +- | ||
91 | tests/qemu-iotests/106 | 2 +- | ||
92 | tests/qemu-iotests/139 | 12 +- | ||
93 | tests/qemu-iotests/163 | 170 +++++++++ | ||
94 | tests/qemu-iotests/163.out | 5 + | ||
95 | tests/qemu-iotests/172 | 2 +- | ||
96 | tests/qemu-iotests/181 | 2 + | ||
97 | tests/qemu-iotests/181.out | 1 - | ||
98 | tests/qemu-iotests/182 | 13 +- | ||
99 | tests/qemu-iotests/186 | 6 +- | ||
100 | tests/qemu-iotests/187.out | 2 +- | ||
101 | tests/qemu-iotests/195 | 92 +++++ | ||
102 | tests/qemu-iotests/195.out | 78 ++++ | ||
103 | tests/qemu-iotests/check | 2 +- | ||
104 | tests/qemu-iotests/group | 2 + | ||
105 | 45 files changed, 1708 insertions(+), 895 deletions(-) | ||
106 | create mode 100644 docs/qemu-block-drivers.texi | ||
107 | create mode 100644 tests/qemu-iotests/163 | ||
108 | create mode 100644 tests/qemu-iotests/163.out | ||
109 | create mode 100755 tests/qemu-iotests/195 | ||
110 | create mode 100644 tests/qemu-iotests/195.out | ||
111 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | A basic set of qemu options is initialised in ./common: | ||
2 | 1 | ||
3 | export QEMU_OPTIONS="-nodefaults -machine accel=qtest" | ||
4 | |||
5 | However, two test cases (172 and 186) overwrite QEMU_OPTIONS and neglect | ||
6 | to manually set '-machine accel=qtest'. Add the missing option for 172. | ||
7 | 186 probably only copied the code from 172, it doesn't actually need to | ||
8 | overwrite QEMU_OPTIONS, so remove that in 186. | ||
9 | |||
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
11 | Tested-by: Cornelia Huck <cohuck@redhat.com> | ||
12 | Reviewed-by: Cornelia Huck <cohuck@redhat.com> | ||
13 | --- | ||
14 | tests/qemu-iotests/172 | 2 +- | ||
15 | tests/qemu-iotests/186 | 6 +++--- | ||
16 | 2 files changed, 4 insertions(+), 4 deletions(-) | ||
17 | |||
18 | diff --git a/tests/qemu-iotests/172 b/tests/qemu-iotests/172 | ||
19 | index XXXXXXX..XXXXXXX 100755 | ||
20 | --- a/tests/qemu-iotests/172 | ||
21 | +++ b/tests/qemu-iotests/172 | ||
22 | @@ -XXX,XX +XXX,XX @@ function do_run_qemu() | ||
23 | done | ||
24 | fi | ||
25 | echo quit | ||
26 | - ) | $QEMU -nographic -monitor stdio -serial none "$@" | ||
27 | + ) | $QEMU -machine accel=qtest -nographic -monitor stdio -serial none "$@" | ||
28 | echo | ||
29 | } | ||
30 | |||
31 | diff --git a/tests/qemu-iotests/186 b/tests/qemu-iotests/186 | ||
32 | index XXXXXXX..XXXXXXX 100755 | ||
33 | --- a/tests/qemu-iotests/186 | ||
34 | +++ b/tests/qemu-iotests/186 | ||
35 | @@ -XXX,XX +XXX,XX @@ function do_run_qemu() | ||
36 | done | ||
37 | fi | ||
38 | echo quit | ||
39 | - ) | $QEMU -S -nodefaults -display none -device virtio-scsi-pci -monitor stdio "$@" 2>&1 | ||
40 | + ) | $QEMU -S -display none -device virtio-scsi-pci -monitor stdio "$@" 2>&1 | ||
41 | echo | ||
42 | } | ||
43 | |||
44 | function check_info_block() | ||
45 | { | ||
46 | echo "info block" | | ||
47 | - QEMU_OPTIONS="" do_run_qemu "$@" | _filter_win32 | _filter_hmp | | ||
48 | - _filter_qemu | _filter_generated_node_ids | ||
49 | + do_run_qemu "$@" | _filter_win32 | _filter_hmp | _filter_qemu | | ||
50 | + _filter_generated_node_ids | ||
51 | } | ||
52 | |||
53 | |||
54 | -- | ||
55 | 2.13.5 | ||
56 | |||
57 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Fam Zheng <famz@redhat.com> | ||
2 | 1 | ||
3 | It's not too surprising when a user specifies the backing file relative | ||
4 | to the current working directory instead of the top layer image. This | ||
5 | causes error when they differ. Though the error message has enough | ||
6 | information to infer the fact about the misunderstanding, it is better | ||
7 | if we document this explicitly, so that users don't have to learn from | ||
8 | mistakes. | ||
9 | |||
10 | Signed-off-by: Fam Zheng <famz@redhat.com> | ||
11 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
12 | Reviewed-by: Jeff Cody <jcody@redhat.com> | ||
13 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
15 | --- | ||
16 | qemu-img.texi | 9 +++++++++ | ||
17 | 1 file changed, 9 insertions(+) | ||
18 | |||
19 | diff --git a/qemu-img.texi b/qemu-img.texi | ||
20 | index XXXXXXX..XXXXXXX 100644 | ||
21 | --- a/qemu-img.texi | ||
22 | +++ b/qemu-img.texi | ||
23 | @@ -XXX,XX +XXX,XX @@ only the differences from @var{backing_file}. No size needs to be specified in | ||
24 | this case. @var{backing_file} will never be modified unless you use the | ||
25 | @code{commit} monitor command (or qemu-img commit). | ||
26 | |||
27 | +If a relative path name is given, the backing file is looked up relative to | ||
28 | +the directory containing @var{filename}. | ||
29 | + | ||
30 | Note that a given backing file will be opened to check that it is valid. Use | ||
31 | the @code{-u} option to enable unsafe backing file mode, which means that the | ||
32 | image will be created even if the associated backing file cannot be opened. A | ||
33 | @@ -XXX,XX +XXX,XX @@ created as a copy on write image of the specified base image; the | ||
34 | @var{backing_file} should have the same content as the input's base image, | ||
35 | however the path, image format, etc may differ. | ||
36 | |||
37 | +If a relative path name is given, the backing file is looked up relative to | ||
38 | +the directory containing @var{output_filename}. | ||
39 | + | ||
40 | If the @code{-n} option is specified, the target volume creation will be | ||
41 | skipped. This is useful for formats such as @code{rbd} if the target | ||
42 | volume has already been created with site specific options that cannot | ||
43 | @@ -XXX,XX +XXX,XX @@ The backing file is changed to @var{backing_file} and (if the image format of | ||
44 | string), then the image is rebased onto no backing file (i.e. it will exist | ||
45 | independently of any backing file). | ||
46 | |||
47 | +If a relative path name is given, the backing file is looked up relative to | ||
48 | +the directory containing @var{filename}. | ||
49 | + | ||
50 | @var{cache} specifies the cache mode to be used for @var{filename}, whereas | ||
51 | @var{src_cache} specifies the cache mode for reading backing files. | ||
52 | |||
53 | -- | ||
54 | 2.13.5 | ||
55 | |||
56 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> |
---|---|---|---|
2 | 2 | ||
3 | Without initialization to zero dirty_bitmap field may be not zero | 3 | This field is unused, but it very helpful for debugging. |
4 | for a bitmap which should not be stored and | ||
5 | qcow2_store_persistent_dirty_bitmaps will erroneously call | ||
6 | store_bitmap for it which leads to SIGSEGV on bdrv_dirty_bitmap_name. | ||
7 | 4 | ||
8 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 5 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> |
9 | Message-id: 20170922144353.4220-1-vsementsov@virtuozzo.com | 6 | Message-Id: <20210702211636.228981-2-vsementsov@virtuozzo.com> |
10 | Cc: qemu-stable@nongnu.org | 7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
11 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
12 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
13 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
14 | --- | 8 | --- |
15 | block/qcow2-bitmap.c | 2 +- | 9 | block/mirror.c | 1 + |
16 | 1 file changed, 1 insertion(+), 1 deletion(-) | 10 | 1 file changed, 1 insertion(+) |
17 | 11 | ||
18 | diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c | 12 | diff --git a/block/mirror.c b/block/mirror.c |
19 | index XXXXXXX..XXXXXXX 100644 | 13 | index XXXXXXX..XXXXXXX 100644 |
20 | --- a/block/qcow2-bitmap.c | 14 | --- a/block/mirror.c |
21 | +++ b/block/qcow2-bitmap.c | 15 | +++ b/block/mirror.c |
22 | @@ -XXX,XX +XXX,XX @@ static Qcow2BitmapList *bitmap_list_load(BlockDriverState *bs, uint64_t offset, | 16 | @@ -XXX,XX +XXX,XX @@ static MirrorOp *coroutine_fn active_write_prepare(MirrorBlockJob *s, |
23 | goto fail; | 17 | .bytes = bytes, |
24 | } | 18 | .is_active_write = true, |
25 | 19 | .is_in_flight = true, | |
26 | - bm = g_new(Qcow2Bitmap, 1); | 20 | + .co = qemu_coroutine_self(), |
27 | + bm = g_new0(Qcow2Bitmap, 1); | 21 | }; |
28 | bm->table.offset = e->bitmap_table_offset; | 22 | qemu_co_queue_init(&op->waiting_requests); |
29 | bm->table.size = e->bitmap_table_size; | 23 | QTAILQ_INSERT_TAIL(&s->ops_in_flight, op, next); |
30 | bm->flags = e->flags; | ||
31 | -- | 24 | -- |
32 | 2.13.5 | 25 | 2.31.1 |
33 | 26 | ||
34 | 27 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> |
---|---|---|---|
2 | 2 | ||
3 | Migration capabilities should be enabled on both source and | 3 | There is a dead-lock in active mirror: when we have parallel |
4 | destination qemu processes. | 4 | intersecting requests (note that non intersecting requests may be |
5 | considered intersecting after aligning to mirror granularity), it may | ||
6 | happen that request A waits request B in mirror_wait_on_conflicts() and | ||
7 | request B waits for A. | ||
8 | |||
9 | Look at the test for details. Test now dead-locks, that's why it's | ||
10 | disabled. Next commit will fix mirror and enable the test. | ||
5 | 11 | ||
6 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 12 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> |
13 | Message-Id: <20210702211636.228981-3-vsementsov@virtuozzo.com> | ||
7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
8 | --- | 15 | --- |
9 | tests/qemu-iotests/181 | 2 ++ | 16 | tests/qemu-iotests/151 | 62 ++++++++++++++++++++++++++++++++++++-- |
10 | tests/qemu-iotests/181.out | 1 - | 17 | tests/qemu-iotests/151.out | 4 +-- |
11 | 2 files changed, 2 insertions(+), 1 deletion(-) | 18 | 2 files changed, 62 insertions(+), 4 deletions(-) |
12 | 19 | ||
13 | diff --git a/tests/qemu-iotests/181 b/tests/qemu-iotests/181 | 20 | diff --git a/tests/qemu-iotests/151 b/tests/qemu-iotests/151 |
14 | index XXXXXXX..XXXXXXX 100755 | 21 | index XXXXXXX..XXXXXXX 100755 |
15 | --- a/tests/qemu-iotests/181 | 22 | --- a/tests/qemu-iotests/151 |
16 | +++ b/tests/qemu-iotests/181 | 23 | +++ b/tests/qemu-iotests/151 |
17 | @@ -XXX,XX +XXX,XX @@ echo | 24 | @@ -XXX,XX +XXX,XX @@ class TestActiveMirror(iotests.QMPTestCase): |
18 | 25 | 'if': 'none', | |
19 | # Slow down migration so much that it definitely won't finish before we can | 26 | 'node-name': 'source-node', |
20 | # switch to postcopy | 27 | 'driver': iotests.imgfmt, |
21 | +# Enable postcopy-ram capability both on source and destination | 28 | - 'file': {'driver': 'file', |
22 | silent=yes | 29 | - 'filename': source_img}} |
23 | +_send_qemu_cmd $dest 'migrate_set_capability postcopy-ram on' "(qemu)" | 30 | + 'file': {'driver': 'blkdebug', |
24 | _send_qemu_cmd $src 'migrate_set_speed 4k' "(qemu)" | 31 | + 'image': {'driver': 'file', |
25 | _send_qemu_cmd $src 'migrate_set_capability postcopy-ram on' "(qemu)" | 32 | + 'filename': source_img}}} |
26 | _send_qemu_cmd $src "migrate -d unix:${MIG_SOCKET}" "(qemu)" | 33 | |
27 | diff --git a/tests/qemu-iotests/181.out b/tests/qemu-iotests/181.out | 34 | blk_target = {'node-name': 'target-node', |
35 | 'driver': iotests.imgfmt, | ||
36 | @@ -XXX,XX +XXX,XX @@ class TestActiveMirror(iotests.QMPTestCase): | ||
37 | |||
38 | self.potential_writes_in_flight = False | ||
39 | |||
40 | + def testIntersectingActiveIO(self): | ||
41 | + # FIXME: test-case is dead-locking. To reproduce dead-lock just drop | ||
42 | + # this return statement | ||
43 | + return | ||
44 | + | ||
45 | + # Fill the source image | ||
46 | + result = self.vm.hmp_qemu_io('source', 'write -P 1 0 2M') | ||
47 | + | ||
48 | + # Start the block job (very slowly) | ||
49 | + result = self.vm.qmp('blockdev-mirror', | ||
50 | + job_id='mirror', | ||
51 | + filter_node_name='mirror-node', | ||
52 | + device='source-node', | ||
53 | + target='target-node', | ||
54 | + sync='full', | ||
55 | + copy_mode='write-blocking', | ||
56 | + speed=1) | ||
57 | + | ||
58 | + self.vm.hmp_qemu_io('source', 'break write_aio A') | ||
59 | + self.vm.hmp_qemu_io('source', 'aio_write 0 1M') # 1 | ||
60 | + self.vm.hmp_qemu_io('source', 'wait_break A') | ||
61 | + self.vm.hmp_qemu_io('source', 'aio_write 0 2M') # 2 | ||
62 | + self.vm.hmp_qemu_io('source', 'aio_write 0 2M') # 3 | ||
63 | + | ||
64 | + # Now 2 and 3 are in mirror_wait_on_conflicts, waiting for 1 | ||
65 | + | ||
66 | + self.vm.hmp_qemu_io('source', 'break write_aio B') | ||
67 | + self.vm.hmp_qemu_io('source', 'aio_write 1M 2M') # 4 | ||
68 | + self.vm.hmp_qemu_io('source', 'wait_break B') | ||
69 | + | ||
70 | + # 4 doesn't wait for 2 and 3, because they didn't yet set | ||
71 | + # in_flight_bitmap. So, nothing prevents 4 to go except for our | ||
72 | + # break-point B. | ||
73 | + | ||
74 | + self.vm.hmp_qemu_io('source', 'resume A') | ||
75 | + | ||
76 | + # Now we resumed 1, so 2 and 3 goes to the next iteration of while loop | ||
77 | + # in mirror_wait_on_conflicts(). They don't exit, as bitmap is dirty | ||
78 | + # due to request 4. And they start to wait: 2 wait for 3, 3 wait for 2 | ||
79 | + # - DEAD LOCK. | ||
80 | + # Note that it's important that we add request 4 at last: requests are | ||
81 | + # appended to the list, so we are sure that 4 is last in the list, so 2 | ||
82 | + # and 3 now waits for each other, not for 4. | ||
83 | + | ||
84 | + self.vm.hmp_qemu_io('source', 'resume B') | ||
85 | + | ||
86 | + # Resuming 4 doesn't help, 2 and 3 already dead-locked | ||
87 | + # To check the dead-lock run: | ||
88 | + # gdb -p $(pidof qemu-system-x86_64) -ex 'set $job=(MirrorBlockJob *)jobs.lh_first' -ex 'p *$job->ops_in_flight.tqh_first' -ex 'p *$job->ops_in_flight.tqh_first->next.tqe_next' | ||
89 | + # You'll see two MirrorOp objects waiting on each other | ||
90 | + | ||
91 | + result = self.vm.qmp('block-job-set-speed', device='mirror', speed=0) | ||
92 | + self.assert_qmp(result, 'return', {}) | ||
93 | + self.complete_and_wait(drive='mirror') | ||
94 | + | ||
95 | + self.potential_writes_in_flight = False | ||
96 | + | ||
97 | |||
98 | if __name__ == '__main__': | ||
99 | iotests.main(supported_fmts=['qcow2', 'raw'], | ||
100 | diff --git a/tests/qemu-iotests/151.out b/tests/qemu-iotests/151.out | ||
28 | index XXXXXXX..XXXXXXX 100644 | 101 | index XXXXXXX..XXXXXXX 100644 |
29 | --- a/tests/qemu-iotests/181.out | 102 | --- a/tests/qemu-iotests/151.out |
30 | +++ b/tests/qemu-iotests/181.out | 103 | +++ b/tests/qemu-iotests/151.out |
31 | @@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 0 | 104 | @@ -XXX,XX +XXX,XX @@ |
32 | 105 | -... | |
33 | === Do some I/O on the destination === | 106 | +.... |
34 | 107 | ---------------------------------------------------------------------- | |
35 | -QEMU X.Y.Z monitor - type 'help' for more information | 108 | -Ran 3 tests |
36 | (qemu) qemu-io disk "read -P 0x55 0 64k" | 109 | +Ran 4 tests |
37 | read 65536/65536 bytes at offset 0 | 110 | |
38 | 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | 111 | OK |
39 | -- | 112 | -- |
40 | 2.13.5 | 113 | 2.31.1 |
41 | 114 | ||
42 | 115 | diff view generated by jsdifflib |
1 | From: Stefan Hajnoczi <stefanha@redhat.com> | 1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> |
---|---|---|---|
2 | 2 | ||
3 | Block driver documentation is available in qemu-doc.html. It would be | 3 | It's possible that requests start to wait each other in |
4 | convenient to have documentation for formats, protocols, and filter | 4 | mirror_wait_on_conflicts(). To avoid it let's use same technique as in |
5 | drivers in a man page. | 5 | block/io.c in bdrv_wait_serialising_requests_locked() / |
6 | bdrv_find_conflicting_request(): don't wait on intersecting request if | ||
7 | it is already waiting for some other request. | ||
6 | 8 | ||
7 | Extract the relevant part of qemu-doc.html into a new file called | 9 | For details of the dead-lock look at testIntersectingActiveIO() |
8 | docs/qemu-block-drivers.texi. This file can also be built as a | 10 | test-case which we actually fixing now. |
9 | stand-alone document (man, html, etc). | ||
10 | 11 | ||
11 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | 12 | Fixes: d06107ade0ce74dc39739bac80de84b51ec18546 |
13 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
14 | Message-Id: <20210702211636.228981-4-vsementsov@virtuozzo.com> | ||
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 15 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
13 | --- | 16 | --- |
14 | Makefile | 6 +- | 17 | block/mirror.c | 12 ++++++++++++ |
15 | docs/qemu-block-drivers.texi | 804 +++++++++++++++++++++++++++++++++++++++++++ | 18 | tests/qemu-iotests/151 | 18 +++++------------- |
16 | qemu-doc.texi | 781 +---------------------------------------- | 19 | 2 files changed, 17 insertions(+), 13 deletions(-) |
17 | 3 files changed, 810 insertions(+), 781 deletions(-) | ||
18 | create mode 100644 docs/qemu-block-drivers.texi | ||
19 | 20 | ||
20 | diff --git a/Makefile b/Makefile | 21 | diff --git a/block/mirror.c b/block/mirror.c |
21 | index XXXXXXX..XXXXXXX 100644 | 22 | index XXXXXXX..XXXXXXX 100644 |
22 | --- a/Makefile | 23 | --- a/block/mirror.c |
23 | +++ b/Makefile | 24 | +++ b/block/mirror.c |
24 | @@ -XXX,XX +XXX,XX @@ ifdef BUILD_DOCS | 25 | @@ -XXX,XX +XXX,XX @@ struct MirrorOp { |
25 | DOCS=qemu-doc.html qemu-doc.txt qemu.1 qemu-img.1 qemu-nbd.8 qemu-ga.8 | 26 | bool is_in_flight; |
26 | DOCS+=docs/interop/qemu-qmp-ref.html docs/interop/qemu-qmp-ref.txt docs/interop/qemu-qmp-ref.7 | 27 | CoQueue waiting_requests; |
27 | DOCS+=docs/interop/qemu-ga-ref.html docs/interop/qemu-ga-ref.txt docs/interop/qemu-ga-ref.7 | 28 | Coroutine *co; |
28 | +DOCS+=docs/qemu-block-drivers.7 | 29 | + MirrorOp *waiting_for_op; |
29 | ifdef CONFIG_VIRTFS | 30 | |
30 | DOCS+=fsdev/virtfs-proxy-helper.1 | 31 | QTAILQ_ENTRY(MirrorOp) next; |
31 | endif | 32 | }; |
32 | @@ -XXX,XX +XXX,XX @@ distclean: clean | 33 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn mirror_wait_on_conflicts(MirrorOp *self, |
33 | rm -f docs/interop/qemu-qmp-ref.txt docs/interop/qemu-ga-ref.txt | 34 | if (ranges_overlap(self_start_chunk, self_nb_chunks, |
34 | rm -f docs/interop/qemu-qmp-ref.pdf docs/interop/qemu-ga-ref.pdf | 35 | op_start_chunk, op_nb_chunks)) |
35 | rm -f docs/interop/qemu-qmp-ref.html docs/interop/qemu-ga-ref.html | 36 | { |
36 | + rm -f docs/qemu-block-drivers.7 | 37 | + /* |
37 | for d in $(TARGET_DIRS); do \ | 38 | + * If the operation is already (indirectly) waiting for us, or |
38 | rm -rf $$d || exit 1 ; \ | 39 | + * will wait for us as soon as it wakes up, then just go on |
39 | done | 40 | + * (instead of producing a deadlock in the former case). |
40 | @@ -XXX,XX +XXX,XX @@ ifdef CONFIG_POSIX | 41 | + */ |
41 | $(INSTALL_DATA) qemu.1 "$(DESTDIR)$(mandir)/man1" | 42 | + if (op->waiting_for_op) { |
42 | $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man7" | 43 | + continue; |
43 | $(INSTALL_DATA) docs/interop/qemu-qmp-ref.7 "$(DESTDIR)$(mandir)/man7" | 44 | + } |
44 | + $(INSTALL_DATA) docs/qemu-block-drivers.7 "$(DESTDIR)$(mandir)/man7" | ||
45 | ifneq ($(TOOLS),) | ||
46 | $(INSTALL_DATA) qemu-img.1 "$(DESTDIR)$(mandir)/man1" | ||
47 | $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man8" | ||
48 | @@ -XXX,XX +XXX,XX @@ qemu-img.1: qemu-img.texi qemu-option-trace.texi qemu-img-cmds.texi | ||
49 | fsdev/virtfs-proxy-helper.1: fsdev/virtfs-proxy-helper.texi | ||
50 | qemu-nbd.8: qemu-nbd.texi qemu-option-trace.texi | ||
51 | qemu-ga.8: qemu-ga.texi | ||
52 | +docs/qemu-block-drivers.7: docs/qemu-block-drivers.texi | ||
53 | |||
54 | html: qemu-doc.html docs/interop/qemu-qmp-ref.html docs/interop/qemu-ga-ref.html | ||
55 | info: qemu-doc.info docs/interop/qemu-qmp-ref.info docs/interop/qemu-ga-ref.info | ||
56 | @@ -XXX,XX +XXX,XX @@ txt: qemu-doc.txt docs/interop/qemu-qmp-ref.txt docs/interop/qemu-ga-ref.txt | ||
57 | qemu-doc.html qemu-doc.info qemu-doc.pdf qemu-doc.txt: \ | ||
58 | qemu-img.texi qemu-nbd.texi qemu-options.texi qemu-option-trace.texi \ | ||
59 | qemu-monitor.texi qemu-img-cmds.texi qemu-ga.texi \ | ||
60 | - qemu-monitor-info.texi | ||
61 | + qemu-monitor-info.texi docs/qemu-block-drivers.texi | ||
62 | |||
63 | docs/interop/qemu-ga-ref.dvi docs/interop/qemu-ga-ref.html \ | ||
64 | docs/interop/qemu-ga-ref.info docs/interop/qemu-ga-ref.pdf \ | ||
65 | diff --git a/docs/qemu-block-drivers.texi b/docs/qemu-block-drivers.texi | ||
66 | new file mode 100644 | ||
67 | index XXXXXXX..XXXXXXX | ||
68 | --- /dev/null | ||
69 | +++ b/docs/qemu-block-drivers.texi | ||
70 | @@ -XXX,XX +XXX,XX @@ | ||
71 | +@c man begin SYNOPSIS | ||
72 | +QEMU block driver reference manual | ||
73 | +@c man end | ||
74 | + | 45 | + |
75 | +@c man begin DESCRIPTION | 46 | + self->waiting_for_op = op; |
76 | + | 47 | qemu_co_queue_wait(&op->waiting_requests, NULL); |
77 | +@node disk_images_formats | 48 | + self->waiting_for_op = NULL; |
78 | +@subsection Disk image file formats | 49 | break; |
79 | + | 50 | } |
80 | +QEMU supports many image file formats that can be used with VMs as well as with | 51 | } |
81 | +any of the tools (like @code{qemu-img}). This includes the preferred formats | 52 | diff --git a/tests/qemu-iotests/151 b/tests/qemu-iotests/151 |
82 | +raw and qcow2 as well as formats that are supported for compatibility with | 53 | index XXXXXXX..XXXXXXX 100755 |
83 | +older QEMU versions or other hypervisors. | 54 | --- a/tests/qemu-iotests/151 |
84 | + | 55 | +++ b/tests/qemu-iotests/151 |
85 | +Depending on the image format, different options can be passed to | 56 | @@ -XXX,XX +XXX,XX @@ class TestActiveMirror(iotests.QMPTestCase): |
86 | +@code{qemu-img create} and @code{qemu-img convert} using the @code{-o} option. | 57 | self.potential_writes_in_flight = False |
87 | +This section describes each format and the options that are supported for it. | 58 | |
88 | + | 59 | def testIntersectingActiveIO(self): |
89 | +@table @option | 60 | - # FIXME: test-case is dead-locking. To reproduce dead-lock just drop |
90 | +@item raw | 61 | - # this return statement |
91 | + | 62 | - return |
92 | +Raw disk image format. This format has the advantage of | ||
93 | +being simple and easily exportable to all other emulators. If your | ||
94 | +file system supports @emph{holes} (for example in ext2 or ext3 on | ||
95 | +Linux or NTFS on Windows), then only the written sectors will reserve | ||
96 | +space. Use @code{qemu-img info} to know the real size used by the | ||
97 | +image or @code{ls -ls} on Unix/Linux. | ||
98 | + | ||
99 | +Supported options: | ||
100 | +@table @code | ||
101 | +@item preallocation | ||
102 | +Preallocation mode (allowed values: @code{off}, @code{falloc}, @code{full}). | ||
103 | +@code{falloc} mode preallocates space for image by calling posix_fallocate(). | ||
104 | +@code{full} mode preallocates space for image by writing zeros to underlying | ||
105 | +storage. | ||
106 | +@end table | ||
107 | + | ||
108 | +@item qcow2 | ||
109 | +QEMU image format, the most versatile format. Use it to have smaller | ||
110 | +images (useful if your filesystem does not supports holes, for example | ||
111 | +on Windows), zlib based compression and support of multiple VM | ||
112 | +snapshots. | ||
113 | + | ||
114 | +Supported options: | ||
115 | +@table @code | ||
116 | +@item compat | ||
117 | +Determines the qcow2 version to use. @code{compat=0.10} uses the | ||
118 | +traditional image format that can be read by any QEMU since 0.10. | ||
119 | +@code{compat=1.1} enables image format extensions that only QEMU 1.1 and | ||
120 | +newer understand (this is the default). Amongst others, this includes | ||
121 | +zero clusters, which allow efficient copy-on-read for sparse images. | ||
122 | + | ||
123 | +@item backing_file | ||
124 | +File name of a base image (see @option{create} subcommand) | ||
125 | +@item backing_fmt | ||
126 | +Image format of the base image | ||
127 | +@item encryption | ||
128 | +This option is deprecated and equivalent to @code{encrypt.format=aes} | ||
129 | + | ||
130 | +@item encrypt.format | ||
131 | + | ||
132 | +If this is set to @code{luks}, it requests that the qcow2 payload (not | ||
133 | +qcow2 header) be encrypted using the LUKS format. The passphrase to | ||
134 | +use to unlock the LUKS key slot is given by the @code{encrypt.key-secret} | ||
135 | +parameter. LUKS encryption parameters can be tuned with the other | ||
136 | +@code{encrypt.*} parameters. | ||
137 | + | ||
138 | +If this is set to @code{aes}, the image is encrypted with 128-bit AES-CBC. | ||
139 | +The encryption key is given by the @code{encrypt.key-secret} parameter. | ||
140 | +This encryption format is considered to be flawed by modern cryptography | ||
141 | +standards, suffering from a number of design problems: | ||
142 | + | ||
143 | +@itemize @minus | ||
144 | +@item The AES-CBC cipher is used with predictable initialization vectors based | ||
145 | +on the sector number. This makes it vulnerable to chosen plaintext attacks | ||
146 | +which can reveal the existence of encrypted data. | ||
147 | +@item The user passphrase is directly used as the encryption key. A poorly | ||
148 | +chosen or short passphrase will compromise the security of the encryption. | ||
149 | +@item In the event of the passphrase being compromised there is no way to | ||
150 | +change the passphrase to protect data in any qcow images. The files must | ||
151 | +be cloned, using a different encryption passphrase in the new file. The | ||
152 | +original file must then be securely erased using a program like shred, | ||
153 | +though even this is ineffective with many modern storage technologies. | ||
154 | +@end itemize | ||
155 | + | ||
156 | +The use of this is no longer supported in system emulators. Support only | ||
157 | +remains in the command line utilities, for the purposes of data liberation | ||
158 | +and interoperability with old versions of QEMU. The @code{luks} format | ||
159 | +should be used instead. | ||
160 | + | ||
161 | +@item encrypt.key-secret | ||
162 | + | ||
163 | +Provides the ID of a @code{secret} object that contains the passphrase | ||
164 | +(@code{encrypt.format=luks}) or encryption key (@code{encrypt.format=aes}). | ||
165 | + | ||
166 | +@item encrypt.cipher-alg | ||
167 | + | ||
168 | +Name of the cipher algorithm and key length. Currently defaults | ||
169 | +to @code{aes-256}. Only used when @code{encrypt.format=luks}. | ||
170 | + | ||
171 | +@item encrypt.cipher-mode | ||
172 | + | ||
173 | +Name of the encryption mode to use. Currently defaults to @code{xts}. | ||
174 | +Only used when @code{encrypt.format=luks}. | ||
175 | + | ||
176 | +@item encrypt.ivgen-alg | ||
177 | + | ||
178 | +Name of the initialization vector generator algorithm. Currently defaults | ||
179 | +to @code{plain64}. Only used when @code{encrypt.format=luks}. | ||
180 | + | ||
181 | +@item encrypt.ivgen-hash-alg | ||
182 | + | ||
183 | +Name of the hash algorithm to use with the initialization vector generator | ||
184 | +(if required). Defaults to @code{sha256}. Only used when @code{encrypt.format=luks}. | ||
185 | + | ||
186 | +@item encrypt.hash-alg | ||
187 | + | ||
188 | +Name of the hash algorithm to use for PBKDF algorithm | ||
189 | +Defaults to @code{sha256}. Only used when @code{encrypt.format=luks}. | ||
190 | + | ||
191 | +@item encrypt.iter-time | ||
192 | + | ||
193 | +Amount of time, in milliseconds, to use for PBKDF algorithm per key slot. | ||
194 | +Defaults to @code{2000}. Only used when @code{encrypt.format=luks}. | ||
195 | + | ||
196 | +@item cluster_size | ||
197 | +Changes the qcow2 cluster size (must be between 512 and 2M). Smaller cluster | ||
198 | +sizes can improve the image file size whereas larger cluster sizes generally | ||
199 | +provide better performance. | ||
200 | + | ||
201 | +@item preallocation | ||
202 | +Preallocation mode (allowed values: @code{off}, @code{metadata}, @code{falloc}, | ||
203 | +@code{full}). An image with preallocated metadata is initially larger but can | ||
204 | +improve performance when the image needs to grow. @code{falloc} and @code{full} | ||
205 | +preallocations are like the same options of @code{raw} format, but sets up | ||
206 | +metadata also. | ||
207 | + | ||
208 | +@item lazy_refcounts | ||
209 | +If this option is set to @code{on}, reference count updates are postponed with | ||
210 | +the goal of avoiding metadata I/O and improving performance. This is | ||
211 | +particularly interesting with @option{cache=writethrough} which doesn't batch | ||
212 | +metadata updates. The tradeoff is that after a host crash, the reference count | ||
213 | +tables must be rebuilt, i.e. on the next open an (automatic) @code{qemu-img | ||
214 | +check -r all} is required, which may take some time. | ||
215 | + | ||
216 | +This option can only be enabled if @code{compat=1.1} is specified. | ||
217 | + | ||
218 | +@item nocow | ||
219 | +If this option is set to @code{on}, it will turn off COW of the file. It's only | ||
220 | +valid on btrfs, no effect on other file systems. | ||
221 | + | ||
222 | +Btrfs has low performance when hosting a VM image file, even more when the guest | ||
223 | +on the VM also using btrfs as file system. Turning off COW is a way to mitigate | ||
224 | +this bad performance. Generally there are two ways to turn off COW on btrfs: | ||
225 | +a) Disable it by mounting with nodatacow, then all newly created files will be | ||
226 | +NOCOW. b) For an empty file, add the NOCOW file attribute. That's what this option | ||
227 | +does. | ||
228 | + | ||
229 | +Note: this option is only valid to new or empty files. If there is an existing | ||
230 | +file which is COW and has data blocks already, it couldn't be changed to NOCOW | ||
231 | +by setting @code{nocow=on}. One can issue @code{lsattr filename} to check if | ||
232 | +the NOCOW flag is set or not (Capital 'C' is NOCOW flag). | ||
233 | + | ||
234 | +@end table | ||
235 | + | ||
236 | +@item qed | ||
237 | +Old QEMU image format with support for backing files and compact image files | ||
238 | +(when your filesystem or transport medium does not support holes). | ||
239 | + | ||
240 | +When converting QED images to qcow2, you might want to consider using the | ||
241 | +@code{lazy_refcounts=on} option to get a more QED-like behaviour. | ||
242 | + | ||
243 | +Supported options: | ||
244 | +@table @code | ||
245 | +@item backing_file | ||
246 | +File name of a base image (see @option{create} subcommand). | ||
247 | +@item backing_fmt | ||
248 | +Image file format of backing file (optional). Useful if the format cannot be | ||
249 | +autodetected because it has no header, like some vhd/vpc files. | ||
250 | +@item cluster_size | ||
251 | +Changes the cluster size (must be power-of-2 between 4K and 64K). Smaller | ||
252 | +cluster sizes can improve the image file size whereas larger cluster sizes | ||
253 | +generally provide better performance. | ||
254 | +@item table_size | ||
255 | +Changes the number of clusters per L1/L2 table (must be power-of-2 between 1 | ||
256 | +and 16). There is normally no need to change this value but this option can be | ||
257 | +used for performance benchmarking. | ||
258 | +@end table | ||
259 | + | ||
260 | +@item qcow | ||
261 | +Old QEMU image format with support for backing files, compact image files, | ||
262 | +encryption and compression. | ||
263 | + | ||
264 | +Supported options: | ||
265 | +@table @code | ||
266 | +@item backing_file | ||
267 | +File name of a base image (see @option{create} subcommand) | ||
268 | +@item encryption | ||
269 | +This option is deprecated and equivalent to @code{encrypt.format=aes} | ||
270 | + | ||
271 | +@item encrypt.format | ||
272 | +If this is set to @code{aes}, the image is encrypted with 128-bit AES-CBC. | ||
273 | +The encryption key is given by the @code{encrypt.key-secret} parameter. | ||
274 | +This encryption format is considered to be flawed by modern cryptography | ||
275 | +standards, suffering from a number of design problems enumerated previously | ||
276 | +against the @code{qcow2} image format. | ||
277 | + | ||
278 | +The use of this is no longer supported in system emulators. Support only | ||
279 | +remains in the command line utilities, for the purposes of data liberation | ||
280 | +and interoperability with old versions of QEMU. | ||
281 | + | ||
282 | +Users requiring native encryption should use the @code{qcow2} format | ||
283 | +instead with @code{encrypt.format=luks}. | ||
284 | + | ||
285 | +@item encrypt.key-secret | ||
286 | + | ||
287 | +Provides the ID of a @code{secret} object that contains the encryption | ||
288 | +key (@code{encrypt.format=aes}). | ||
289 | + | ||
290 | +@end table | ||
291 | + | ||
292 | +@item luks | ||
293 | + | ||
294 | +LUKS v1 encryption format, compatible with Linux dm-crypt/cryptsetup | ||
295 | + | ||
296 | +Supported options: | ||
297 | +@table @code | ||
298 | + | ||
299 | +@item key-secret | ||
300 | + | ||
301 | +Provides the ID of a @code{secret} object that contains the passphrase. | ||
302 | + | ||
303 | +@item cipher-alg | ||
304 | + | ||
305 | +Name of the cipher algorithm and key length. Currently defaults | ||
306 | +to @code{aes-256}. | ||
307 | + | ||
308 | +@item cipher-mode | ||
309 | + | ||
310 | +Name of the encryption mode to use. Currently defaults to @code{xts}. | ||
311 | + | ||
312 | +@item ivgen-alg | ||
313 | + | ||
314 | +Name of the initialization vector generator algorithm. Currently defaults | ||
315 | +to @code{plain64}. | ||
316 | + | ||
317 | +@item ivgen-hash-alg | ||
318 | + | ||
319 | +Name of the hash algorithm to use with the initialization vector generator | ||
320 | +(if required). Defaults to @code{sha256}. | ||
321 | + | ||
322 | +@item hash-alg | ||
323 | + | ||
324 | +Name of the hash algorithm to use for PBKDF algorithm | ||
325 | +Defaults to @code{sha256}. | ||
326 | + | ||
327 | +@item iter-time | ||
328 | + | ||
329 | +Amount of time, in milliseconds, to use for PBKDF algorithm per key slot. | ||
330 | +Defaults to @code{2000}. | ||
331 | + | ||
332 | +@end table | ||
333 | + | ||
334 | +@item vdi | ||
335 | +VirtualBox 1.1 compatible image format. | ||
336 | +Supported options: | ||
337 | +@table @code | ||
338 | +@item static | ||
339 | +If this option is set to @code{on}, the image is created with metadata | ||
340 | +preallocation. | ||
341 | +@end table | ||
342 | + | ||
343 | +@item vmdk | ||
344 | +VMware 3 and 4 compatible image format. | ||
345 | + | ||
346 | +Supported options: | ||
347 | +@table @code | ||
348 | +@item backing_file | ||
349 | +File name of a base image (see @option{create} subcommand). | ||
350 | +@item compat6 | ||
351 | +Create a VMDK version 6 image (instead of version 4) | ||
352 | +@item hwversion | ||
353 | +Specify vmdk virtual hardware version. Compat6 flag cannot be enabled | ||
354 | +if hwversion is specified. | ||
355 | +@item subformat | ||
356 | +Specifies which VMDK subformat to use. Valid options are | ||
357 | +@code{monolithicSparse} (default), | ||
358 | +@code{monolithicFlat}, | ||
359 | +@code{twoGbMaxExtentSparse}, | ||
360 | +@code{twoGbMaxExtentFlat} and | ||
361 | +@code{streamOptimized}. | ||
362 | +@end table | ||
363 | + | ||
364 | +@item vpc | ||
365 | +VirtualPC compatible image format (VHD). | ||
366 | +Supported options: | ||
367 | +@table @code | ||
368 | +@item subformat | ||
369 | +Specifies which VHD subformat to use. Valid options are | ||
370 | +@code{dynamic} (default) and @code{fixed}. | ||
371 | +@end table | ||
372 | + | ||
373 | +@item VHDX | ||
374 | +Hyper-V compatible image format (VHDX). | ||
375 | +Supported options: | ||
376 | +@table @code | ||
377 | +@item subformat | ||
378 | +Specifies which VHDX subformat to use. Valid options are | ||
379 | +@code{dynamic} (default) and @code{fixed}. | ||
380 | +@item block_state_zero | ||
381 | +Force use of payload blocks of type 'ZERO'. Can be set to @code{on} (default) | ||
382 | +or @code{off}. When set to @code{off}, new blocks will be created as | ||
383 | +@code{PAYLOAD_BLOCK_NOT_PRESENT}, which means parsers are free to return | ||
384 | +arbitrary data for those blocks. Do not set to @code{off} when using | ||
385 | +@code{qemu-img convert} with @code{subformat=dynamic}. | ||
386 | +@item block_size | ||
387 | +Block size; min 1 MB, max 256 MB. 0 means auto-calculate based on image size. | ||
388 | +@item log_size | ||
389 | +Log size; min 1 MB. | ||
390 | +@end table | ||
391 | +@end table | ||
392 | + | ||
393 | +@subsubsection Read-only formats | ||
394 | +More disk image file formats are supported in a read-only mode. | ||
395 | +@table @option | ||
396 | +@item bochs | ||
397 | +Bochs images of @code{growing} type. | ||
398 | +@item cloop | ||
399 | +Linux Compressed Loop image, useful only to reuse directly compressed | ||
400 | +CD-ROM images present for example in the Knoppix CD-ROMs. | ||
401 | +@item dmg | ||
402 | +Apple disk image. | ||
403 | +@item parallels | ||
404 | +Parallels disk image format. | ||
405 | +@end table | ||
406 | + | ||
407 | + | ||
408 | +@node host_drives | ||
409 | +@subsection Using host drives | ||
410 | + | ||
411 | +In addition to disk image files, QEMU can directly access host | ||
412 | +devices. We describe here the usage for QEMU version >= 0.8.3. | ||
413 | + | ||
414 | +@subsubsection Linux | ||
415 | + | ||
416 | +On Linux, you can directly use the host device filename instead of a | ||
417 | +disk image filename provided you have enough privileges to access | ||
418 | +it. For example, use @file{/dev/cdrom} to access to the CDROM. | ||
419 | + | ||
420 | +@table @code | ||
421 | +@item CD | ||
422 | +You can specify a CDROM device even if no CDROM is loaded. QEMU has | ||
423 | +specific code to detect CDROM insertion or removal. CDROM ejection by | ||
424 | +the guest OS is supported. Currently only data CDs are supported. | ||
425 | +@item Floppy | ||
426 | +You can specify a floppy device even if no floppy is loaded. Floppy | ||
427 | +removal is currently not detected accurately (if you change floppy | ||
428 | +without doing floppy access while the floppy is not loaded, the guest | ||
429 | +OS will think that the same floppy is loaded). | ||
430 | +Use of the host's floppy device is deprecated, and support for it will | ||
431 | +be removed in a future release. | ||
432 | +@item Hard disks | ||
433 | +Hard disks can be used. Normally you must specify the whole disk | ||
434 | +(@file{/dev/hdb} instead of @file{/dev/hdb1}) so that the guest OS can | ||
435 | +see it as a partitioned disk. WARNING: unless you know what you do, it | ||
436 | +is better to only make READ-ONLY accesses to the hard disk otherwise | ||
437 | +you may corrupt your host data (use the @option{-snapshot} command | ||
438 | +line option or modify the device permissions accordingly). | ||
439 | +@end table | ||
440 | + | ||
441 | +@subsubsection Windows | ||
442 | + | ||
443 | +@table @code | ||
444 | +@item CD | ||
445 | +The preferred syntax is the drive letter (e.g. @file{d:}). The | ||
446 | +alternate syntax @file{\\.\d:} is supported. @file{/dev/cdrom} is | ||
447 | +supported as an alias to the first CDROM drive. | ||
448 | + | ||
449 | +Currently there is no specific code to handle removable media, so it | ||
450 | +is better to use the @code{change} or @code{eject} monitor commands to | ||
451 | +change or eject media. | ||
452 | +@item Hard disks | ||
453 | +Hard disks can be used with the syntax: @file{\\.\PhysicalDrive@var{N}} | ||
454 | +where @var{N} is the drive number (0 is the first hard disk). | ||
455 | + | ||
456 | +WARNING: unless you know what you do, it is better to only make | ||
457 | +READ-ONLY accesses to the hard disk otherwise you may corrupt your | ||
458 | +host data (use the @option{-snapshot} command line so that the | ||
459 | +modifications are written in a temporary file). | ||
460 | +@end table | ||
461 | + | ||
462 | + | ||
463 | +@subsubsection Mac OS X | ||
464 | + | ||
465 | +@file{/dev/cdrom} is an alias to the first CDROM. | ||
466 | + | ||
467 | +Currently there is no specific code to handle removable media, so it | ||
468 | +is better to use the @code{change} or @code{eject} monitor commands to | ||
469 | +change or eject media. | ||
470 | + | ||
471 | +@node disk_images_fat_images | ||
472 | +@subsection Virtual FAT disk images | ||
473 | + | ||
474 | +QEMU can automatically create a virtual FAT disk image from a | ||
475 | +directory tree. In order to use it, just type: | ||
476 | + | ||
477 | +@example | ||
478 | +qemu-system-i386 linux.img -hdb fat:/my_directory | ||
479 | +@end example | ||
480 | + | ||
481 | +Then you access access to all the files in the @file{/my_directory} | ||
482 | +directory without having to copy them in a disk image or to export | ||
483 | +them via SAMBA or NFS. The default access is @emph{read-only}. | ||
484 | + | ||
485 | +Floppies can be emulated with the @code{:floppy:} option: | ||
486 | + | ||
487 | +@example | ||
488 | +qemu-system-i386 linux.img -fda fat:floppy:/my_directory | ||
489 | +@end example | ||
490 | + | ||
491 | +A read/write support is available for testing (beta stage) with the | ||
492 | +@code{:rw:} option: | ||
493 | + | ||
494 | +@example | ||
495 | +qemu-system-i386 linux.img -fda fat:floppy:rw:/my_directory | ||
496 | +@end example | ||
497 | + | ||
498 | +What you should @emph{never} do: | ||
499 | +@itemize | ||
500 | +@item use non-ASCII filenames ; | ||
501 | +@item use "-snapshot" together with ":rw:" ; | ||
502 | +@item expect it to work when loadvm'ing ; | ||
503 | +@item write to the FAT directory on the host system while accessing it with the guest system. | ||
504 | +@end itemize | ||
505 | + | ||
506 | +@node disk_images_nbd | ||
507 | +@subsection NBD access | ||
508 | + | ||
509 | +QEMU can access directly to block device exported using the Network Block Device | ||
510 | +protocol. | ||
511 | + | ||
512 | +@example | ||
513 | +qemu-system-i386 linux.img -hdb nbd://my_nbd_server.mydomain.org:1024/ | ||
514 | +@end example | ||
515 | + | ||
516 | +If the NBD server is located on the same host, you can use an unix socket instead | ||
517 | +of an inet socket: | ||
518 | + | ||
519 | +@example | ||
520 | +qemu-system-i386 linux.img -hdb nbd+unix://?socket=/tmp/my_socket | ||
521 | +@end example | ||
522 | + | ||
523 | +In this case, the block device must be exported using qemu-nbd: | ||
524 | + | ||
525 | +@example | ||
526 | +qemu-nbd --socket=/tmp/my_socket my_disk.qcow2 | ||
527 | +@end example | ||
528 | + | ||
529 | +The use of qemu-nbd allows sharing of a disk between several guests: | ||
530 | +@example | ||
531 | +qemu-nbd --socket=/tmp/my_socket --share=2 my_disk.qcow2 | ||
532 | +@end example | ||
533 | + | ||
534 | +@noindent | ||
535 | +and then you can use it with two guests: | ||
536 | +@example | ||
537 | +qemu-system-i386 linux1.img -hdb nbd+unix://?socket=/tmp/my_socket | ||
538 | +qemu-system-i386 linux2.img -hdb nbd+unix://?socket=/tmp/my_socket | ||
539 | +@end example | ||
540 | + | ||
541 | +If the nbd-server uses named exports (supported since NBD 2.9.18, or with QEMU's | ||
542 | +own embedded NBD server), you must specify an export name in the URI: | ||
543 | +@example | ||
544 | +qemu-system-i386 -cdrom nbd://localhost/debian-500-ppc-netinst | ||
545 | +qemu-system-i386 -cdrom nbd://localhost/openSUSE-11.1-ppc-netinst | ||
546 | +@end example | ||
547 | + | ||
548 | +The URI syntax for NBD is supported since QEMU 1.3. An alternative syntax is | ||
549 | +also available. Here are some example of the older syntax: | ||
550 | +@example | ||
551 | +qemu-system-i386 linux.img -hdb nbd:my_nbd_server.mydomain.org:1024 | ||
552 | +qemu-system-i386 linux2.img -hdb nbd:unix:/tmp/my_socket | ||
553 | +qemu-system-i386 -cdrom nbd:localhost:10809:exportname=debian-500-ppc-netinst | ||
554 | +@end example | ||
555 | + | ||
556 | +@node disk_images_sheepdog | ||
557 | +@subsection Sheepdog disk images | ||
558 | + | ||
559 | +Sheepdog is a distributed storage system for QEMU. It provides highly | ||
560 | +available block level storage volumes that can be attached to | ||
561 | +QEMU-based virtual machines. | ||
562 | + | ||
563 | +You can create a Sheepdog disk image with the command: | ||
564 | +@example | ||
565 | +qemu-img create sheepdog:///@var{image} @var{size} | ||
566 | +@end example | ||
567 | +where @var{image} is the Sheepdog image name and @var{size} is its | ||
568 | +size. | ||
569 | + | ||
570 | +To import the existing @var{filename} to Sheepdog, you can use a | ||
571 | +convert command. | ||
572 | +@example | ||
573 | +qemu-img convert @var{filename} sheepdog:///@var{image} | ||
574 | +@end example | ||
575 | + | ||
576 | +You can boot from the Sheepdog disk image with the command: | ||
577 | +@example | ||
578 | +qemu-system-i386 sheepdog:///@var{image} | ||
579 | +@end example | ||
580 | + | ||
581 | +You can also create a snapshot of the Sheepdog image like qcow2. | ||
582 | +@example | ||
583 | +qemu-img snapshot -c @var{tag} sheepdog:///@var{image} | ||
584 | +@end example | ||
585 | +where @var{tag} is a tag name of the newly created snapshot. | ||
586 | + | ||
587 | +To boot from the Sheepdog snapshot, specify the tag name of the | ||
588 | +snapshot. | ||
589 | +@example | ||
590 | +qemu-system-i386 sheepdog:///@var{image}#@var{tag} | ||
591 | +@end example | ||
592 | + | ||
593 | +You can create a cloned image from the existing snapshot. | ||
594 | +@example | ||
595 | +qemu-img create -b sheepdog:///@var{base}#@var{tag} sheepdog:///@var{image} | ||
596 | +@end example | ||
597 | +where @var{base} is a image name of the source snapshot and @var{tag} | ||
598 | +is its tag name. | ||
599 | + | ||
600 | +You can use an unix socket instead of an inet socket: | ||
601 | + | ||
602 | +@example | ||
603 | +qemu-system-i386 sheepdog+unix:///@var{image}?socket=@var{path} | ||
604 | +@end example | ||
605 | + | ||
606 | +If the Sheepdog daemon doesn't run on the local host, you need to | ||
607 | +specify one of the Sheepdog servers to connect to. | ||
608 | +@example | ||
609 | +qemu-img create sheepdog://@var{hostname}:@var{port}/@var{image} @var{size} | ||
610 | +qemu-system-i386 sheepdog://@var{hostname}:@var{port}/@var{image} | ||
611 | +@end example | ||
612 | + | ||
613 | +@node disk_images_iscsi | ||
614 | +@subsection iSCSI LUNs | ||
615 | + | ||
616 | +iSCSI is a popular protocol used to access SCSI devices across a computer | ||
617 | +network. | ||
618 | + | ||
619 | +There are two different ways iSCSI devices can be used by QEMU. | ||
620 | + | ||
621 | +The first method is to mount the iSCSI LUN on the host, and make it appear as | ||
622 | +any other ordinary SCSI device on the host and then to access this device as a | ||
623 | +/dev/sd device from QEMU. How to do this differs between host OSes. | ||
624 | + | ||
625 | +The second method involves using the iSCSI initiator that is built into | ||
626 | +QEMU. This provides a mechanism that works the same way regardless of which | ||
627 | +host OS you are running QEMU on. This section will describe this second method | ||
628 | +of using iSCSI together with QEMU. | ||
629 | + | ||
630 | +In QEMU, iSCSI devices are described using special iSCSI URLs | ||
631 | + | ||
632 | +@example | ||
633 | +URL syntax: | ||
634 | +iscsi://[<username>[%<password>]@@]<host>[:<port>]/<target-iqn-name>/<lun> | ||
635 | +@end example | ||
636 | + | ||
637 | +Username and password are optional and only used if your target is set up | ||
638 | +using CHAP authentication for access control. | ||
639 | +Alternatively the username and password can also be set via environment | ||
640 | +variables to have these not show up in the process list | ||
641 | + | ||
642 | +@example | ||
643 | +export LIBISCSI_CHAP_USERNAME=<username> | ||
644 | +export LIBISCSI_CHAP_PASSWORD=<password> | ||
645 | +iscsi://<host>/<target-iqn-name>/<lun> | ||
646 | +@end example | ||
647 | + | ||
648 | +Various session related parameters can be set via special options, either | ||
649 | +in a configuration file provided via '-readconfig' or directly on the | ||
650 | +command line. | ||
651 | + | ||
652 | +If the initiator-name is not specified qemu will use a default name | ||
653 | +of 'iqn.2008-11.org.linux-kvm[:<uuid>'] where <uuid> is the UUID of the | ||
654 | +virtual machine. If the UUID is not specified qemu will use | ||
655 | +'iqn.2008-11.org.linux-kvm[:<name>'] where <name> is the name of the | ||
656 | +virtual machine. | ||
657 | + | ||
658 | +@example | ||
659 | +Setting a specific initiator name to use when logging in to the target | ||
660 | +-iscsi initiator-name=iqn.qemu.test:my-initiator | ||
661 | +@end example | ||
662 | + | ||
663 | +@example | ||
664 | +Controlling which type of header digest to negotiate with the target | ||
665 | +-iscsi header-digest=CRC32C|CRC32C-NONE|NONE-CRC32C|NONE | ||
666 | +@end example | ||
667 | + | ||
668 | +These can also be set via a configuration file | ||
669 | +@example | ||
670 | +[iscsi] | ||
671 | + user = "CHAP username" | ||
672 | + password = "CHAP password" | ||
673 | + initiator-name = "iqn.qemu.test:my-initiator" | ||
674 | + # header digest is one of CRC32C|CRC32C-NONE|NONE-CRC32C|NONE | ||
675 | + header-digest = "CRC32C" | ||
676 | +@end example | ||
677 | + | ||
678 | + | ||
679 | +Setting the target name allows different options for different targets | ||
680 | +@example | ||
681 | +[iscsi "iqn.target.name"] | ||
682 | + user = "CHAP username" | ||
683 | + password = "CHAP password" | ||
684 | + initiator-name = "iqn.qemu.test:my-initiator" | ||
685 | + # header digest is one of CRC32C|CRC32C-NONE|NONE-CRC32C|NONE | ||
686 | + header-digest = "CRC32C" | ||
687 | +@end example | ||
688 | + | ||
689 | + | ||
690 | +Howto use a configuration file to set iSCSI configuration options: | ||
691 | +@example | ||
692 | +cat >iscsi.conf <<EOF | ||
693 | +[iscsi] | ||
694 | + user = "me" | ||
695 | + password = "my password" | ||
696 | + initiator-name = "iqn.qemu.test:my-initiator" | ||
697 | + header-digest = "CRC32C" | ||
698 | +EOF | ||
699 | + | ||
700 | +qemu-system-i386 -drive file=iscsi://127.0.0.1/iqn.qemu.test/1 \ | ||
701 | + -readconfig iscsi.conf | ||
702 | +@end example | ||
703 | + | ||
704 | + | ||
705 | +Howto set up a simple iSCSI target on loopback and accessing it via QEMU: | ||
706 | +@example | ||
707 | +This example shows how to set up an iSCSI target with one CDROM and one DISK | ||
708 | +using the Linux STGT software target. This target is available on Red Hat based | ||
709 | +systems as the package 'scsi-target-utils'. | ||
710 | + | ||
711 | +tgtd --iscsi portal=127.0.0.1:3260 | ||
712 | +tgtadm --lld iscsi --op new --mode target --tid 1 -T iqn.qemu.test | ||
713 | +tgtadm --lld iscsi --mode logicalunit --op new --tid 1 --lun 1 \ | ||
714 | + -b /IMAGES/disk.img --device-type=disk | ||
715 | +tgtadm --lld iscsi --mode logicalunit --op new --tid 1 --lun 2 \ | ||
716 | + -b /IMAGES/cd.iso --device-type=cd | ||
717 | +tgtadm --lld iscsi --op bind --mode target --tid 1 -I ALL | ||
718 | + | ||
719 | +qemu-system-i386 -iscsi initiator-name=iqn.qemu.test:my-initiator \ | ||
720 | + -boot d -drive file=iscsi://127.0.0.1/iqn.qemu.test/1 \ | ||
721 | + -cdrom iscsi://127.0.0.1/iqn.qemu.test/2 | ||
722 | +@end example | ||
723 | + | ||
724 | +@node disk_images_gluster | ||
725 | +@subsection GlusterFS disk images | ||
726 | + | ||
727 | +GlusterFS is a user space distributed file system. | ||
728 | + | ||
729 | +You can boot from the GlusterFS disk image with the command: | ||
730 | +@example | ||
731 | +URI: | ||
732 | +qemu-system-x86_64 -drive file=gluster[+@var{type}]://[@var{host}[:@var{port}]]/@var{volume}/@var{path} | ||
733 | + [?socket=...][,file.debug=9][,file.logfile=...] | ||
734 | + | ||
735 | +JSON: | ||
736 | +qemu-system-x86_64 'json:@{"driver":"qcow2", | ||
737 | + "file":@{"driver":"gluster", | ||
738 | + "volume":"testvol","path":"a.img","debug":9,"logfile":"...", | ||
739 | + "server":[@{"type":"tcp","host":"...","port":"..."@}, | ||
740 | + @{"type":"unix","socket":"..."@}]@}@}' | ||
741 | +@end example | ||
742 | + | ||
743 | +@var{gluster} is the protocol. | ||
744 | + | ||
745 | +@var{type} specifies the transport type used to connect to gluster | ||
746 | +management daemon (glusterd). Valid transport types are | ||
747 | +tcp and unix. In the URI form, if a transport type isn't specified, | ||
748 | +then tcp type is assumed. | ||
749 | + | ||
750 | +@var{host} specifies the server where the volume file specification for | ||
751 | +the given volume resides. This can be either a hostname or an ipv4 address. | ||
752 | +If transport type is unix, then @var{host} field should not be specified. | ||
753 | +Instead @var{socket} field needs to be populated with the path to unix domain | ||
754 | +socket. | ||
755 | + | ||
756 | +@var{port} is the port number on which glusterd is listening. This is optional | ||
757 | +and if not specified, it defaults to port 24007. If the transport type is unix, | ||
758 | +then @var{port} should not be specified. | ||
759 | + | ||
760 | +@var{volume} is the name of the gluster volume which contains the disk image. | ||
761 | + | ||
762 | +@var{path} is the path to the actual disk image that resides on gluster volume. | ||
763 | + | ||
764 | +@var{debug} is the logging level of the gluster protocol driver. Debug levels | ||
765 | +are 0-9, with 9 being the most verbose, and 0 representing no debugging output. | ||
766 | +The default level is 4. The current logging levels defined in the gluster source | ||
767 | +are 0 - None, 1 - Emergency, 2 - Alert, 3 - Critical, 4 - Error, 5 - Warning, | ||
768 | +6 - Notice, 7 - Info, 8 - Debug, 9 - Trace | ||
769 | + | ||
770 | +@var{logfile} is a commandline option to mention log file path which helps in | ||
771 | +logging to the specified file and also help in persisting the gfapi logs. The | ||
772 | +default is stderr. | ||
773 | + | ||
774 | + | ||
775 | + | ||
776 | + | ||
777 | +You can create a GlusterFS disk image with the command: | ||
778 | +@example | ||
779 | +qemu-img create gluster://@var{host}/@var{volume}/@var{path} @var{size} | ||
780 | +@end example | ||
781 | + | ||
782 | +Examples | ||
783 | +@example | ||
784 | +qemu-system-x86_64 -drive file=gluster://1.2.3.4/testvol/a.img | ||
785 | +qemu-system-x86_64 -drive file=gluster+tcp://1.2.3.4/testvol/a.img | ||
786 | +qemu-system-x86_64 -drive file=gluster+tcp://1.2.3.4:24007/testvol/dir/a.img | ||
787 | +qemu-system-x86_64 -drive file=gluster+tcp://[1:2:3:4:5:6:7:8]/testvol/dir/a.img | ||
788 | +qemu-system-x86_64 -drive file=gluster+tcp://[1:2:3:4:5:6:7:8]:24007/testvol/dir/a.img | ||
789 | +qemu-system-x86_64 -drive file=gluster+tcp://server.domain.com:24007/testvol/dir/a.img | ||
790 | +qemu-system-x86_64 -drive file=gluster+unix:///testvol/dir/a.img?socket=/tmp/glusterd.socket | ||
791 | +qemu-system-x86_64 -drive file=gluster+rdma://1.2.3.4:24007/testvol/a.img | ||
792 | +qemu-system-x86_64 -drive file=gluster://1.2.3.4/testvol/a.img,file.debug=9,file.logfile=/var/log/qemu-gluster.log | ||
793 | +qemu-system-x86_64 'json:@{"driver":"qcow2", | ||
794 | + "file":@{"driver":"gluster", | ||
795 | + "volume":"testvol","path":"a.img", | ||
796 | + "debug":9,"logfile":"/var/log/qemu-gluster.log", | ||
797 | + "server":[@{"type":"tcp","host":"1.2.3.4","port":24007@}, | ||
798 | + @{"type":"unix","socket":"/var/run/glusterd.socket"@}]@}@}' | ||
799 | +qemu-system-x86_64 -drive driver=qcow2,file.driver=gluster,file.volume=testvol,file.path=/path/a.img, | ||
800 | + file.debug=9,file.logfile=/var/log/qemu-gluster.log, | ||
801 | + file.server.0.type=tcp,file.server.0.host=1.2.3.4,file.server.0.port=24007, | ||
802 | + file.server.1.type=unix,file.server.1.socket=/var/run/glusterd.socket | ||
803 | +@end example | ||
804 | + | ||
805 | +@node disk_images_ssh | ||
806 | +@subsection Secure Shell (ssh) disk images | ||
807 | + | ||
808 | +You can access disk images located on a remote ssh server | ||
809 | +by using the ssh protocol: | ||
810 | + | ||
811 | +@example | ||
812 | +qemu-system-x86_64 -drive file=ssh://[@var{user}@@]@var{server}[:@var{port}]/@var{path}[?host_key_check=@var{host_key_check}] | ||
813 | +@end example | ||
814 | + | ||
815 | +Alternative syntax using properties: | ||
816 | + | ||
817 | +@example | ||
818 | +qemu-system-x86_64 -drive file.driver=ssh[,file.user=@var{user}],file.host=@var{server}[,file.port=@var{port}],file.path=@var{path}[,file.host_key_check=@var{host_key_check}] | ||
819 | +@end example | ||
820 | + | ||
821 | +@var{ssh} is the protocol. | ||
822 | + | ||
823 | +@var{user} is the remote user. If not specified, then the local | ||
824 | +username is tried. | ||
825 | + | ||
826 | +@var{server} specifies the remote ssh server. Any ssh server can be | ||
827 | +used, but it must implement the sftp-server protocol. Most Unix/Linux | ||
828 | +systems should work without requiring any extra configuration. | ||
829 | + | ||
830 | +@var{port} is the port number on which sshd is listening. By default | ||
831 | +the standard ssh port (22) is used. | ||
832 | + | ||
833 | +@var{path} is the path to the disk image. | ||
834 | + | ||
835 | +The optional @var{host_key_check} parameter controls how the remote | ||
836 | +host's key is checked. The default is @code{yes} which means to use | ||
837 | +the local @file{.ssh/known_hosts} file. Setting this to @code{no} | ||
838 | +turns off known-hosts checking. Or you can check that the host key | ||
839 | +matches a specific fingerprint: | ||
840 | +@code{host_key_check=md5:78:45:8e:14:57:4f:d5:45:83:0a:0e:f3:49:82:c9:c8} | ||
841 | +(@code{sha1:} can also be used as a prefix, but note that OpenSSH | ||
842 | +tools only use MD5 to print fingerprints). | ||
843 | + | ||
844 | +Currently authentication must be done using ssh-agent. Other | ||
845 | +authentication methods may be supported in future. | ||
846 | + | ||
847 | +Note: Many ssh servers do not support an @code{fsync}-style operation. | ||
848 | +The ssh driver cannot guarantee that disk flush requests are | ||
849 | +obeyed, and this causes a risk of disk corruption if the remote | ||
850 | +server or network goes down during writes. The driver will | ||
851 | +print a warning when @code{fsync} is not supported: | ||
852 | + | ||
853 | +warning: ssh server @code{ssh.example.com:22} does not support fsync | ||
854 | + | ||
855 | +With sufficiently new versions of libssh2 and OpenSSH, @code{fsync} is | ||
856 | +supported. | ||
857 | + | ||
858 | +@c man end | ||
859 | + | ||
860 | +@ignore | ||
861 | + | ||
862 | +@setfilename qemu-block-drivers | ||
863 | +@settitle QEMU block drivers reference | ||
864 | + | ||
865 | +@c man begin SEEALSO | ||
866 | +The HTML documentation of QEMU for more precise information and Linux | ||
867 | +user mode emulator invocation. | ||
868 | +@c man end | ||
869 | + | ||
870 | +@c man begin AUTHOR | ||
871 | +Fabrice Bellard and the QEMU Project developers | ||
872 | +@c man end | ||
873 | + | ||
874 | +@end ignore | ||
875 | diff --git a/qemu-doc.texi b/qemu-doc.texi | ||
876 | index XXXXXXX..XXXXXXX 100644 | ||
877 | --- a/qemu-doc.texi | ||
878 | +++ b/qemu-doc.texi | ||
879 | @@ -XXX,XX +XXX,XX @@ state is not saved or restored properly (in particular USB). | ||
880 | |||
881 | @include qemu-nbd.texi | ||
882 | |||
883 | -@node disk_images_formats | ||
884 | -@subsection Disk image file formats | ||
885 | - | 63 | - |
886 | -QEMU supports many image file formats that can be used with VMs as well as with | 64 | # Fill the source image |
887 | -any of the tools (like @code{qemu-img}). This includes the preferred formats | 65 | result = self.vm.hmp_qemu_io('source', 'write -P 1 0 2M') |
888 | -raw and qcow2 as well as formats that are supported for compatibility with | 66 | |
889 | -older QEMU versions or other hypervisors. | 67 | @@ -XXX,XX +XXX,XX @@ class TestActiveMirror(iotests.QMPTestCase): |
890 | - | 68 | |
891 | -Depending on the image format, different options can be passed to | 69 | # Now we resumed 1, so 2 and 3 goes to the next iteration of while loop |
892 | -@code{qemu-img create} and @code{qemu-img convert} using the @code{-o} option. | 70 | # in mirror_wait_on_conflicts(). They don't exit, as bitmap is dirty |
893 | -This section describes each format and the options that are supported for it. | 71 | - # due to request 4. And they start to wait: 2 wait for 3, 3 wait for 2 |
894 | - | 72 | - # - DEAD LOCK. |
895 | -@table @option | 73 | - # Note that it's important that we add request 4 at last: requests are |
896 | -@item raw | 74 | - # appended to the list, so we are sure that 4 is last in the list, so 2 |
897 | - | 75 | - # and 3 now waits for each other, not for 4. |
898 | -Raw disk image format. This format has the advantage of | 76 | + # due to request 4. |
899 | -being simple and easily exportable to all other emulators. If your | 77 | + # In the past at that point 2 and 3 would wait for each other producing |
900 | -file system supports @emph{holes} (for example in ext2 or ext3 on | 78 | + # a dead-lock. Now this is fixed and they will wait for request 4. |
901 | -Linux or NTFS on Windows), then only the written sectors will reserve | 79 | |
902 | -space. Use @code{qemu-img info} to know the real size used by the | 80 | self.vm.hmp_qemu_io('source', 'resume B') |
903 | -image or @code{ls -ls} on Unix/Linux. | 81 | |
904 | - | 82 | - # Resuming 4 doesn't help, 2 and 3 already dead-locked |
905 | -Supported options: | 83 | - # To check the dead-lock run: |
906 | -@table @code | 84 | - # gdb -p $(pidof qemu-system-x86_64) -ex 'set $job=(MirrorBlockJob *)jobs.lh_first' -ex 'p *$job->ops_in_flight.tqh_first' -ex 'p *$job->ops_in_flight.tqh_first->next.tqe_next' |
907 | -@item preallocation | 85 | - # You'll see two MirrorOp objects waiting on each other |
908 | -Preallocation mode (allowed values: @code{off}, @code{falloc}, @code{full}). | 86 | + # After resuming 4, one of 2 and 3 goes first and set in_flight_bitmap, |
909 | -@code{falloc} mode preallocates space for image by calling posix_fallocate(). | 87 | + # so the other will wait for it. |
910 | -@code{full} mode preallocates space for image by writing zeros to underlying | 88 | |
911 | -storage. | 89 | result = self.vm.qmp('block-job-set-speed', device='mirror', speed=0) |
912 | -@end table | 90 | self.assert_qmp(result, 'return', {}) |
913 | - | ||
914 | -@item qcow2 | ||
915 | -QEMU image format, the most versatile format. Use it to have smaller | ||
916 | -images (useful if your filesystem does not supports holes, for example | ||
917 | -on Windows), zlib based compression and support of multiple VM | ||
918 | -snapshots. | ||
919 | - | ||
920 | -Supported options: | ||
921 | -@table @code | ||
922 | -@item compat | ||
923 | -Determines the qcow2 version to use. @code{compat=0.10} uses the | ||
924 | -traditional image format that can be read by any QEMU since 0.10. | ||
925 | -@code{compat=1.1} enables image format extensions that only QEMU 1.1 and | ||
926 | -newer understand (this is the default). Amongst others, this includes | ||
927 | -zero clusters, which allow efficient copy-on-read for sparse images. | ||
928 | - | ||
929 | -@item backing_file | ||
930 | -File name of a base image (see @option{create} subcommand) | ||
931 | -@item backing_fmt | ||
932 | -Image format of the base image | ||
933 | -@item encryption | ||
934 | -This option is deprecated and equivalent to @code{encrypt.format=aes} | ||
935 | - | ||
936 | -@item encrypt.format | ||
937 | - | ||
938 | -If this is set to @code{luks}, it requests that the qcow2 payload (not | ||
939 | -qcow2 header) be encrypted using the LUKS format. The passphrase to | ||
940 | -use to unlock the LUKS key slot is given by the @code{encrypt.key-secret} | ||
941 | -parameter. LUKS encryption parameters can be tuned with the other | ||
942 | -@code{encrypt.*} parameters. | ||
943 | - | ||
944 | -If this is set to @code{aes}, the image is encrypted with 128-bit AES-CBC. | ||
945 | -The encryption key is given by the @code{encrypt.key-secret} parameter. | ||
946 | -This encryption format is considered to be flawed by modern cryptography | ||
947 | -standards, suffering from a number of design problems: | ||
948 | - | ||
949 | -@itemize @minus | ||
950 | -@item The AES-CBC cipher is used with predictable initialization vectors based | ||
951 | -on the sector number. This makes it vulnerable to chosen plaintext attacks | ||
952 | -which can reveal the existence of encrypted data. | ||
953 | -@item The user passphrase is directly used as the encryption key. A poorly | ||
954 | -chosen or short passphrase will compromise the security of the encryption. | ||
955 | -@item In the event of the passphrase being compromised there is no way to | ||
956 | -change the passphrase to protect data in any qcow images. The files must | ||
957 | -be cloned, using a different encryption passphrase in the new file. The | ||
958 | -original file must then be securely erased using a program like shred, | ||
959 | -though even this is ineffective with many modern storage technologies. | ||
960 | -@end itemize | ||
961 | - | ||
962 | -The use of this is no longer supported in system emulators. Support only | ||
963 | -remains in the command line utilities, for the purposes of data liberation | ||
964 | -and interoperability with old versions of QEMU. The @code{luks} format | ||
965 | -should be used instead. | ||
966 | - | ||
967 | -@item encrypt.key-secret | ||
968 | - | ||
969 | -Provides the ID of a @code{secret} object that contains the passphrase | ||
970 | -(@code{encrypt.format=luks}) or encryption key (@code{encrypt.format=aes}). | ||
971 | - | ||
972 | -@item encrypt.cipher-alg | ||
973 | - | ||
974 | -Name of the cipher algorithm and key length. Currently defaults | ||
975 | -to @code{aes-256}. Only used when @code{encrypt.format=luks}. | ||
976 | - | ||
977 | -@item encrypt.cipher-mode | ||
978 | - | ||
979 | -Name of the encryption mode to use. Currently defaults to @code{xts}. | ||
980 | -Only used when @code{encrypt.format=luks}. | ||
981 | - | ||
982 | -@item encrypt.ivgen-alg | ||
983 | - | ||
984 | -Name of the initialization vector generator algorithm. Currently defaults | ||
985 | -to @code{plain64}. Only used when @code{encrypt.format=luks}. | ||
986 | - | ||
987 | -@item encrypt.ivgen-hash-alg | ||
988 | - | ||
989 | -Name of the hash algorithm to use with the initialization vector generator | ||
990 | -(if required). Defaults to @code{sha256}. Only used when @code{encrypt.format=luks}. | ||
991 | - | ||
992 | -@item encrypt.hash-alg | ||
993 | - | ||
994 | -Name of the hash algorithm to use for PBKDF algorithm | ||
995 | -Defaults to @code{sha256}. Only used when @code{encrypt.format=luks}. | ||
996 | - | ||
997 | -@item encrypt.iter-time | ||
998 | - | ||
999 | -Amount of time, in milliseconds, to use for PBKDF algorithm per key slot. | ||
1000 | -Defaults to @code{2000}. Only used when @code{encrypt.format=luks}. | ||
1001 | - | ||
1002 | -@item cluster_size | ||
1003 | -Changes the qcow2 cluster size (must be between 512 and 2M). Smaller cluster | ||
1004 | -sizes can improve the image file size whereas larger cluster sizes generally | ||
1005 | -provide better performance. | ||
1006 | - | ||
1007 | -@item preallocation | ||
1008 | -Preallocation mode (allowed values: @code{off}, @code{metadata}, @code{falloc}, | ||
1009 | -@code{full}). An image with preallocated metadata is initially larger but can | ||
1010 | -improve performance when the image needs to grow. @code{falloc} and @code{full} | ||
1011 | -preallocations are like the same options of @code{raw} format, but sets up | ||
1012 | -metadata also. | ||
1013 | - | ||
1014 | -@item lazy_refcounts | ||
1015 | -If this option is set to @code{on}, reference count updates are postponed with | ||
1016 | -the goal of avoiding metadata I/O and improving performance. This is | ||
1017 | -particularly interesting with @option{cache=writethrough} which doesn't batch | ||
1018 | -metadata updates. The tradeoff is that after a host crash, the reference count | ||
1019 | -tables must be rebuilt, i.e. on the next open an (automatic) @code{qemu-img | ||
1020 | -check -r all} is required, which may take some time. | ||
1021 | - | ||
1022 | -This option can only be enabled if @code{compat=1.1} is specified. | ||
1023 | - | ||
1024 | -@item nocow | ||
1025 | -If this option is set to @code{on}, it will turn off COW of the file. It's only | ||
1026 | -valid on btrfs, no effect on other file systems. | ||
1027 | - | ||
1028 | -Btrfs has low performance when hosting a VM image file, even more when the guest | ||
1029 | -on the VM also using btrfs as file system. Turning off COW is a way to mitigate | ||
1030 | -this bad performance. Generally there are two ways to turn off COW on btrfs: | ||
1031 | -a) Disable it by mounting with nodatacow, then all newly created files will be | ||
1032 | -NOCOW. b) For an empty file, add the NOCOW file attribute. That's what this option | ||
1033 | -does. | ||
1034 | - | ||
1035 | -Note: this option is only valid to new or empty files. If there is an existing | ||
1036 | -file which is COW and has data blocks already, it couldn't be changed to NOCOW | ||
1037 | -by setting @code{nocow=on}. One can issue @code{lsattr filename} to check if | ||
1038 | -the NOCOW flag is set or not (Capital 'C' is NOCOW flag). | ||
1039 | - | ||
1040 | -@end table | ||
1041 | - | ||
1042 | -@item qed | ||
1043 | -Old QEMU image format with support for backing files and compact image files | ||
1044 | -(when your filesystem or transport medium does not support holes). | ||
1045 | - | ||
1046 | -When converting QED images to qcow2, you might want to consider using the | ||
1047 | -@code{lazy_refcounts=on} option to get a more QED-like behaviour. | ||
1048 | - | ||
1049 | -Supported options: | ||
1050 | -@table @code | ||
1051 | -@item backing_file | ||
1052 | -File name of a base image (see @option{create} subcommand). | ||
1053 | -@item backing_fmt | ||
1054 | -Image file format of backing file (optional). Useful if the format cannot be | ||
1055 | -autodetected because it has no header, like some vhd/vpc files. | ||
1056 | -@item cluster_size | ||
1057 | -Changes the cluster size (must be power-of-2 between 4K and 64K). Smaller | ||
1058 | -cluster sizes can improve the image file size whereas larger cluster sizes | ||
1059 | -generally provide better performance. | ||
1060 | -@item table_size | ||
1061 | -Changes the number of clusters per L1/L2 table (must be power-of-2 between 1 | ||
1062 | -and 16). There is normally no need to change this value but this option can be | ||
1063 | -used for performance benchmarking. | ||
1064 | -@end table | ||
1065 | - | ||
1066 | -@item qcow | ||
1067 | -Old QEMU image format with support for backing files, compact image files, | ||
1068 | -encryption and compression. | ||
1069 | - | ||
1070 | -Supported options: | ||
1071 | -@table @code | ||
1072 | -@item backing_file | ||
1073 | -File name of a base image (see @option{create} subcommand) | ||
1074 | -@item encryption | ||
1075 | -This option is deprecated and equivalent to @code{encrypt.format=aes} | ||
1076 | - | ||
1077 | -@item encrypt.format | ||
1078 | -If this is set to @code{aes}, the image is encrypted with 128-bit AES-CBC. | ||
1079 | -The encryption key is given by the @code{encrypt.key-secret} parameter. | ||
1080 | -This encryption format is considered to be flawed by modern cryptography | ||
1081 | -standards, suffering from a number of design problems enumerated previously | ||
1082 | -against the @code{qcow2} image format. | ||
1083 | - | ||
1084 | -The use of this is no longer supported in system emulators. Support only | ||
1085 | -remains in the command line utilities, for the purposes of data liberation | ||
1086 | -and interoperability with old versions of QEMU. | ||
1087 | - | ||
1088 | -Users requiring native encryption should use the @code{qcow2} format | ||
1089 | -instead with @code{encrypt.format=luks}. | ||
1090 | - | ||
1091 | -@item encrypt.key-secret | ||
1092 | - | ||
1093 | -Provides the ID of a @code{secret} object that contains the encryption | ||
1094 | -key (@code{encrypt.format=aes}). | ||
1095 | - | ||
1096 | -@end table | ||
1097 | - | ||
1098 | -@item luks | ||
1099 | - | ||
1100 | -LUKS v1 encryption format, compatible with Linux dm-crypt/cryptsetup | ||
1101 | - | ||
1102 | -Supported options: | ||
1103 | -@table @code | ||
1104 | - | ||
1105 | -@item key-secret | ||
1106 | - | ||
1107 | -Provides the ID of a @code{secret} object that contains the passphrase. | ||
1108 | - | ||
1109 | -@item cipher-alg | ||
1110 | - | ||
1111 | -Name of the cipher algorithm and key length. Currently defaults | ||
1112 | -to @code{aes-256}. | ||
1113 | - | ||
1114 | -@item cipher-mode | ||
1115 | - | ||
1116 | -Name of the encryption mode to use. Currently defaults to @code{xts}. | ||
1117 | - | ||
1118 | -@item ivgen-alg | ||
1119 | - | ||
1120 | -Name of the initialization vector generator algorithm. Currently defaults | ||
1121 | -to @code{plain64}. | ||
1122 | - | ||
1123 | -@item ivgen-hash-alg | ||
1124 | - | ||
1125 | -Name of the hash algorithm to use with the initialization vector generator | ||
1126 | -(if required). Defaults to @code{sha256}. | ||
1127 | - | ||
1128 | -@item hash-alg | ||
1129 | - | ||
1130 | -Name of the hash algorithm to use for PBKDF algorithm | ||
1131 | -Defaults to @code{sha256}. | ||
1132 | - | ||
1133 | -@item iter-time | ||
1134 | - | ||
1135 | -Amount of time, in milliseconds, to use for PBKDF algorithm per key slot. | ||
1136 | -Defaults to @code{2000}. | ||
1137 | - | ||
1138 | -@end table | ||
1139 | - | ||
1140 | -@item vdi | ||
1141 | -VirtualBox 1.1 compatible image format. | ||
1142 | -Supported options: | ||
1143 | -@table @code | ||
1144 | -@item static | ||
1145 | -If this option is set to @code{on}, the image is created with metadata | ||
1146 | -preallocation. | ||
1147 | -@end table | ||
1148 | - | ||
1149 | -@item vmdk | ||
1150 | -VMware 3 and 4 compatible image format. | ||
1151 | - | ||
1152 | -Supported options: | ||
1153 | -@table @code | ||
1154 | -@item backing_file | ||
1155 | -File name of a base image (see @option{create} subcommand). | ||
1156 | -@item compat6 | ||
1157 | -Create a VMDK version 6 image (instead of version 4) | ||
1158 | -@item hwversion | ||
1159 | -Specify vmdk virtual hardware version. Compat6 flag cannot be enabled | ||
1160 | -if hwversion is specified. | ||
1161 | -@item subformat | ||
1162 | -Specifies which VMDK subformat to use. Valid options are | ||
1163 | -@code{monolithicSparse} (default), | ||
1164 | -@code{monolithicFlat}, | ||
1165 | -@code{twoGbMaxExtentSparse}, | ||
1166 | -@code{twoGbMaxExtentFlat} and | ||
1167 | -@code{streamOptimized}. | ||
1168 | -@end table | ||
1169 | - | ||
1170 | -@item vpc | ||
1171 | -VirtualPC compatible image format (VHD). | ||
1172 | -Supported options: | ||
1173 | -@table @code | ||
1174 | -@item subformat | ||
1175 | -Specifies which VHD subformat to use. Valid options are | ||
1176 | -@code{dynamic} (default) and @code{fixed}. | ||
1177 | -@end table | ||
1178 | - | ||
1179 | -@item VHDX | ||
1180 | -Hyper-V compatible image format (VHDX). | ||
1181 | -Supported options: | ||
1182 | -@table @code | ||
1183 | -@item subformat | ||
1184 | -Specifies which VHDX subformat to use. Valid options are | ||
1185 | -@code{dynamic} (default) and @code{fixed}. | ||
1186 | -@item block_state_zero | ||
1187 | -Force use of payload blocks of type 'ZERO'. Can be set to @code{on} (default) | ||
1188 | -or @code{off}. When set to @code{off}, new blocks will be created as | ||
1189 | -@code{PAYLOAD_BLOCK_NOT_PRESENT}, which means parsers are free to return | ||
1190 | -arbitrary data for those blocks. Do not set to @code{off} when using | ||
1191 | -@code{qemu-img convert} with @code{subformat=dynamic}. | ||
1192 | -@item block_size | ||
1193 | -Block size; min 1 MB, max 256 MB. 0 means auto-calculate based on image size. | ||
1194 | -@item log_size | ||
1195 | -Log size; min 1 MB. | ||
1196 | -@end table | ||
1197 | -@end table | ||
1198 | - | ||
1199 | -@subsubsection Read-only formats | ||
1200 | -More disk image file formats are supported in a read-only mode. | ||
1201 | -@table @option | ||
1202 | -@item bochs | ||
1203 | -Bochs images of @code{growing} type. | ||
1204 | -@item cloop | ||
1205 | -Linux Compressed Loop image, useful only to reuse directly compressed | ||
1206 | -CD-ROM images present for example in the Knoppix CD-ROMs. | ||
1207 | -@item dmg | ||
1208 | -Apple disk image. | ||
1209 | -@item parallels | ||
1210 | -Parallels disk image format. | ||
1211 | -@end table | ||
1212 | - | ||
1213 | - | ||
1214 | -@node host_drives | ||
1215 | -@subsection Using host drives | ||
1216 | - | ||
1217 | -In addition to disk image files, QEMU can directly access host | ||
1218 | -devices. We describe here the usage for QEMU version >= 0.8.3. | ||
1219 | - | ||
1220 | -@subsubsection Linux | ||
1221 | - | ||
1222 | -On Linux, you can directly use the host device filename instead of a | ||
1223 | -disk image filename provided you have enough privileges to access | ||
1224 | -it. For example, use @file{/dev/cdrom} to access to the CDROM. | ||
1225 | - | ||
1226 | -@table @code | ||
1227 | -@item CD | ||
1228 | -You can specify a CDROM device even if no CDROM is loaded. QEMU has | ||
1229 | -specific code to detect CDROM insertion or removal. CDROM ejection by | ||
1230 | -the guest OS is supported. Currently only data CDs are supported. | ||
1231 | -@item Floppy | ||
1232 | -You can specify a floppy device even if no floppy is loaded. Floppy | ||
1233 | -removal is currently not detected accurately (if you change floppy | ||
1234 | -without doing floppy access while the floppy is not loaded, the guest | ||
1235 | -OS will think that the same floppy is loaded). | ||
1236 | -Use of the host's floppy device is deprecated, and support for it will | ||
1237 | -be removed in a future release. | ||
1238 | -@item Hard disks | ||
1239 | -Hard disks can be used. Normally you must specify the whole disk | ||
1240 | -(@file{/dev/hdb} instead of @file{/dev/hdb1}) so that the guest OS can | ||
1241 | -see it as a partitioned disk. WARNING: unless you know what you do, it | ||
1242 | -is better to only make READ-ONLY accesses to the hard disk otherwise | ||
1243 | -you may corrupt your host data (use the @option{-snapshot} command | ||
1244 | -line option or modify the device permissions accordingly). | ||
1245 | -@end table | ||
1246 | - | ||
1247 | -@subsubsection Windows | ||
1248 | - | ||
1249 | -@table @code | ||
1250 | -@item CD | ||
1251 | -The preferred syntax is the drive letter (e.g. @file{d:}). The | ||
1252 | -alternate syntax @file{\\.\d:} is supported. @file{/dev/cdrom} is | ||
1253 | -supported as an alias to the first CDROM drive. | ||
1254 | - | ||
1255 | -Currently there is no specific code to handle removable media, so it | ||
1256 | -is better to use the @code{change} or @code{eject} monitor commands to | ||
1257 | -change or eject media. | ||
1258 | -@item Hard disks | ||
1259 | -Hard disks can be used with the syntax: @file{\\.\PhysicalDrive@var{N}} | ||
1260 | -where @var{N} is the drive number (0 is the first hard disk). | ||
1261 | - | ||
1262 | -WARNING: unless you know what you do, it is better to only make | ||
1263 | -READ-ONLY accesses to the hard disk otherwise you may corrupt your | ||
1264 | -host data (use the @option{-snapshot} command line so that the | ||
1265 | -modifications are written in a temporary file). | ||
1266 | -@end table | ||
1267 | - | ||
1268 | - | ||
1269 | -@subsubsection Mac OS X | ||
1270 | - | ||
1271 | -@file{/dev/cdrom} is an alias to the first CDROM. | ||
1272 | - | ||
1273 | -Currently there is no specific code to handle removable media, so it | ||
1274 | -is better to use the @code{change} or @code{eject} monitor commands to | ||
1275 | -change or eject media. | ||
1276 | - | ||
1277 | -@node disk_images_fat_images | ||
1278 | -@subsection Virtual FAT disk images | ||
1279 | - | ||
1280 | -QEMU can automatically create a virtual FAT disk image from a | ||
1281 | -directory tree. In order to use it, just type: | ||
1282 | - | ||
1283 | -@example | ||
1284 | -qemu-system-i386 linux.img -hdb fat:/my_directory | ||
1285 | -@end example | ||
1286 | - | ||
1287 | -Then you access access to all the files in the @file{/my_directory} | ||
1288 | -directory without having to copy them in a disk image or to export | ||
1289 | -them via SAMBA or NFS. The default access is @emph{read-only}. | ||
1290 | - | ||
1291 | -Floppies can be emulated with the @code{:floppy:} option: | ||
1292 | - | ||
1293 | -@example | ||
1294 | -qemu-system-i386 linux.img -fda fat:floppy:/my_directory | ||
1295 | -@end example | ||
1296 | - | ||
1297 | -A read/write support is available for testing (beta stage) with the | ||
1298 | -@code{:rw:} option: | ||
1299 | - | ||
1300 | -@example | ||
1301 | -qemu-system-i386 linux.img -fda fat:floppy:rw:/my_directory | ||
1302 | -@end example | ||
1303 | - | ||
1304 | -What you should @emph{never} do: | ||
1305 | -@itemize | ||
1306 | -@item use non-ASCII filenames ; | ||
1307 | -@item use "-snapshot" together with ":rw:" ; | ||
1308 | -@item expect it to work when loadvm'ing ; | ||
1309 | -@item write to the FAT directory on the host system while accessing it with the guest system. | ||
1310 | -@end itemize | ||
1311 | - | ||
1312 | -@node disk_images_nbd | ||
1313 | -@subsection NBD access | ||
1314 | - | ||
1315 | -QEMU can access directly to block device exported using the Network Block Device | ||
1316 | -protocol. | ||
1317 | - | ||
1318 | -@example | ||
1319 | -qemu-system-i386 linux.img -hdb nbd://my_nbd_server.mydomain.org:1024/ | ||
1320 | -@end example | ||
1321 | - | ||
1322 | -If the NBD server is located on the same host, you can use an unix socket instead | ||
1323 | -of an inet socket: | ||
1324 | - | ||
1325 | -@example | ||
1326 | -qemu-system-i386 linux.img -hdb nbd+unix://?socket=/tmp/my_socket | ||
1327 | -@end example | ||
1328 | - | ||
1329 | -In this case, the block device must be exported using qemu-nbd: | ||
1330 | - | ||
1331 | -@example | ||
1332 | -qemu-nbd --socket=/tmp/my_socket my_disk.qcow2 | ||
1333 | -@end example | ||
1334 | - | ||
1335 | -The use of qemu-nbd allows sharing of a disk between several guests: | ||
1336 | -@example | ||
1337 | -qemu-nbd --socket=/tmp/my_socket --share=2 my_disk.qcow2 | ||
1338 | -@end example | ||
1339 | - | ||
1340 | -@noindent | ||
1341 | -and then you can use it with two guests: | ||
1342 | -@example | ||
1343 | -qemu-system-i386 linux1.img -hdb nbd+unix://?socket=/tmp/my_socket | ||
1344 | -qemu-system-i386 linux2.img -hdb nbd+unix://?socket=/tmp/my_socket | ||
1345 | -@end example | ||
1346 | - | ||
1347 | -If the nbd-server uses named exports (supported since NBD 2.9.18, or with QEMU's | ||
1348 | -own embedded NBD server), you must specify an export name in the URI: | ||
1349 | -@example | ||
1350 | -qemu-system-i386 -cdrom nbd://localhost/debian-500-ppc-netinst | ||
1351 | -qemu-system-i386 -cdrom nbd://localhost/openSUSE-11.1-ppc-netinst | ||
1352 | -@end example | ||
1353 | - | ||
1354 | -The URI syntax for NBD is supported since QEMU 1.3. An alternative syntax is | ||
1355 | -also available. Here are some example of the older syntax: | ||
1356 | -@example | ||
1357 | -qemu-system-i386 linux.img -hdb nbd:my_nbd_server.mydomain.org:1024 | ||
1358 | -qemu-system-i386 linux2.img -hdb nbd:unix:/tmp/my_socket | ||
1359 | -qemu-system-i386 -cdrom nbd:localhost:10809:exportname=debian-500-ppc-netinst | ||
1360 | -@end example | ||
1361 | - | ||
1362 | -@node disk_images_sheepdog | ||
1363 | -@subsection Sheepdog disk images | ||
1364 | - | ||
1365 | -Sheepdog is a distributed storage system for QEMU. It provides highly | ||
1366 | -available block level storage volumes that can be attached to | ||
1367 | -QEMU-based virtual machines. | ||
1368 | - | ||
1369 | -You can create a Sheepdog disk image with the command: | ||
1370 | -@example | ||
1371 | -qemu-img create sheepdog:///@var{image} @var{size} | ||
1372 | -@end example | ||
1373 | -where @var{image} is the Sheepdog image name and @var{size} is its | ||
1374 | -size. | ||
1375 | - | ||
1376 | -To import the existing @var{filename} to Sheepdog, you can use a | ||
1377 | -convert command. | ||
1378 | -@example | ||
1379 | -qemu-img convert @var{filename} sheepdog:///@var{image} | ||
1380 | -@end example | ||
1381 | - | ||
1382 | -You can boot from the Sheepdog disk image with the command: | ||
1383 | -@example | ||
1384 | -qemu-system-i386 sheepdog:///@var{image} | ||
1385 | -@end example | ||
1386 | - | ||
1387 | -You can also create a snapshot of the Sheepdog image like qcow2. | ||
1388 | -@example | ||
1389 | -qemu-img snapshot -c @var{tag} sheepdog:///@var{image} | ||
1390 | -@end example | ||
1391 | -where @var{tag} is a tag name of the newly created snapshot. | ||
1392 | - | ||
1393 | -To boot from the Sheepdog snapshot, specify the tag name of the | ||
1394 | -snapshot. | ||
1395 | -@example | ||
1396 | -qemu-system-i386 sheepdog:///@var{image}#@var{tag} | ||
1397 | -@end example | ||
1398 | - | ||
1399 | -You can create a cloned image from the existing snapshot. | ||
1400 | -@example | ||
1401 | -qemu-img create -b sheepdog:///@var{base}#@var{tag} sheepdog:///@var{image} | ||
1402 | -@end example | ||
1403 | -where @var{base} is a image name of the source snapshot and @var{tag} | ||
1404 | -is its tag name. | ||
1405 | - | ||
1406 | -You can use an unix socket instead of an inet socket: | ||
1407 | - | ||
1408 | -@example | ||
1409 | -qemu-system-i386 sheepdog+unix:///@var{image}?socket=@var{path} | ||
1410 | -@end example | ||
1411 | - | ||
1412 | -If the Sheepdog daemon doesn't run on the local host, you need to | ||
1413 | -specify one of the Sheepdog servers to connect to. | ||
1414 | -@example | ||
1415 | -qemu-img create sheepdog://@var{hostname}:@var{port}/@var{image} @var{size} | ||
1416 | -qemu-system-i386 sheepdog://@var{hostname}:@var{port}/@var{image} | ||
1417 | -@end example | ||
1418 | - | ||
1419 | -@node disk_images_iscsi | ||
1420 | -@subsection iSCSI LUNs | ||
1421 | - | ||
1422 | -iSCSI is a popular protocol used to access SCSI devices across a computer | ||
1423 | -network. | ||
1424 | - | ||
1425 | -There are two different ways iSCSI devices can be used by QEMU. | ||
1426 | - | ||
1427 | -The first method is to mount the iSCSI LUN on the host, and make it appear as | ||
1428 | -any other ordinary SCSI device on the host and then to access this device as a | ||
1429 | -/dev/sd device from QEMU. How to do this differs between host OSes. | ||
1430 | - | ||
1431 | -The second method involves using the iSCSI initiator that is built into | ||
1432 | -QEMU. This provides a mechanism that works the same way regardless of which | ||
1433 | -host OS you are running QEMU on. This section will describe this second method | ||
1434 | -of using iSCSI together with QEMU. | ||
1435 | - | ||
1436 | -In QEMU, iSCSI devices are described using special iSCSI URLs | ||
1437 | - | ||
1438 | -@example | ||
1439 | -URL syntax: | ||
1440 | -iscsi://[<username>[%<password>]@@]<host>[:<port>]/<target-iqn-name>/<lun> | ||
1441 | -@end example | ||
1442 | - | ||
1443 | -Username and password are optional and only used if your target is set up | ||
1444 | -using CHAP authentication for access control. | ||
1445 | -Alternatively the username and password can also be set via environment | ||
1446 | -variables to have these not show up in the process list | ||
1447 | - | ||
1448 | -@example | ||
1449 | -export LIBISCSI_CHAP_USERNAME=<username> | ||
1450 | -export LIBISCSI_CHAP_PASSWORD=<password> | ||
1451 | -iscsi://<host>/<target-iqn-name>/<lun> | ||
1452 | -@end example | ||
1453 | - | ||
1454 | -Various session related parameters can be set via special options, either | ||
1455 | -in a configuration file provided via '-readconfig' or directly on the | ||
1456 | -command line. | ||
1457 | - | ||
1458 | -If the initiator-name is not specified qemu will use a default name | ||
1459 | -of 'iqn.2008-11.org.linux-kvm[:<uuid>'] where <uuid> is the UUID of the | ||
1460 | -virtual machine. If the UUID is not specified qemu will use | ||
1461 | -'iqn.2008-11.org.linux-kvm[:<name>'] where <name> is the name of the | ||
1462 | -virtual machine. | ||
1463 | - | ||
1464 | -@example | ||
1465 | -Setting a specific initiator name to use when logging in to the target | ||
1466 | --iscsi initiator-name=iqn.qemu.test:my-initiator | ||
1467 | -@end example | ||
1468 | - | ||
1469 | -@example | ||
1470 | -Controlling which type of header digest to negotiate with the target | ||
1471 | --iscsi header-digest=CRC32C|CRC32C-NONE|NONE-CRC32C|NONE | ||
1472 | -@end example | ||
1473 | - | ||
1474 | -These can also be set via a configuration file | ||
1475 | -@example | ||
1476 | -[iscsi] | ||
1477 | - user = "CHAP username" | ||
1478 | - password = "CHAP password" | ||
1479 | - initiator-name = "iqn.qemu.test:my-initiator" | ||
1480 | - # header digest is one of CRC32C|CRC32C-NONE|NONE-CRC32C|NONE | ||
1481 | - header-digest = "CRC32C" | ||
1482 | -@end example | ||
1483 | - | ||
1484 | - | ||
1485 | -Setting the target name allows different options for different targets | ||
1486 | -@example | ||
1487 | -[iscsi "iqn.target.name"] | ||
1488 | - user = "CHAP username" | ||
1489 | - password = "CHAP password" | ||
1490 | - initiator-name = "iqn.qemu.test:my-initiator" | ||
1491 | - # header digest is one of CRC32C|CRC32C-NONE|NONE-CRC32C|NONE | ||
1492 | - header-digest = "CRC32C" | ||
1493 | -@end example | ||
1494 | - | ||
1495 | - | ||
1496 | -Howto use a configuration file to set iSCSI configuration options: | ||
1497 | -@example | ||
1498 | -cat >iscsi.conf <<EOF | ||
1499 | -[iscsi] | ||
1500 | - user = "me" | ||
1501 | - password = "my password" | ||
1502 | - initiator-name = "iqn.qemu.test:my-initiator" | ||
1503 | - header-digest = "CRC32C" | ||
1504 | -EOF | ||
1505 | - | ||
1506 | -qemu-system-i386 -drive file=iscsi://127.0.0.1/iqn.qemu.test/1 \ | ||
1507 | - -readconfig iscsi.conf | ||
1508 | -@end example | ||
1509 | - | ||
1510 | - | ||
1511 | -Howto set up a simple iSCSI target on loopback and accessing it via QEMU: | ||
1512 | -@example | ||
1513 | -This example shows how to set up an iSCSI target with one CDROM and one DISK | ||
1514 | -using the Linux STGT software target. This target is available on Red Hat based | ||
1515 | -systems as the package 'scsi-target-utils'. | ||
1516 | - | ||
1517 | -tgtd --iscsi portal=127.0.0.1:3260 | ||
1518 | -tgtadm --lld iscsi --op new --mode target --tid 1 -T iqn.qemu.test | ||
1519 | -tgtadm --lld iscsi --mode logicalunit --op new --tid 1 --lun 1 \ | ||
1520 | - -b /IMAGES/disk.img --device-type=disk | ||
1521 | -tgtadm --lld iscsi --mode logicalunit --op new --tid 1 --lun 2 \ | ||
1522 | - -b /IMAGES/cd.iso --device-type=cd | ||
1523 | -tgtadm --lld iscsi --op bind --mode target --tid 1 -I ALL | ||
1524 | - | ||
1525 | -qemu-system-i386 -iscsi initiator-name=iqn.qemu.test:my-initiator \ | ||
1526 | - -boot d -drive file=iscsi://127.0.0.1/iqn.qemu.test/1 \ | ||
1527 | - -cdrom iscsi://127.0.0.1/iqn.qemu.test/2 | ||
1528 | -@end example | ||
1529 | - | ||
1530 | -@node disk_images_gluster | ||
1531 | -@subsection GlusterFS disk images | ||
1532 | - | ||
1533 | -GlusterFS is a user space distributed file system. | ||
1534 | - | ||
1535 | -You can boot from the GlusterFS disk image with the command: | ||
1536 | -@example | ||
1537 | -URI: | ||
1538 | -qemu-system-x86_64 -drive file=gluster[+@var{type}]://[@var{host}[:@var{port}]]/@var{volume}/@var{path} | ||
1539 | - [?socket=...][,file.debug=9][,file.logfile=...] | ||
1540 | - | ||
1541 | -JSON: | ||
1542 | -qemu-system-x86_64 'json:@{"driver":"qcow2", | ||
1543 | - "file":@{"driver":"gluster", | ||
1544 | - "volume":"testvol","path":"a.img","debug":9,"logfile":"...", | ||
1545 | - "server":[@{"type":"tcp","host":"...","port":"..."@}, | ||
1546 | - @{"type":"unix","socket":"..."@}]@}@}' | ||
1547 | -@end example | ||
1548 | - | ||
1549 | -@var{gluster} is the protocol. | ||
1550 | - | ||
1551 | -@var{type} specifies the transport type used to connect to gluster | ||
1552 | -management daemon (glusterd). Valid transport types are | ||
1553 | -tcp and unix. In the URI form, if a transport type isn't specified, | ||
1554 | -then tcp type is assumed. | ||
1555 | - | ||
1556 | -@var{host} specifies the server where the volume file specification for | ||
1557 | -the given volume resides. This can be either a hostname or an ipv4 address. | ||
1558 | -If transport type is unix, then @var{host} field should not be specified. | ||
1559 | -Instead @var{socket} field needs to be populated with the path to unix domain | ||
1560 | -socket. | ||
1561 | - | ||
1562 | -@var{port} is the port number on which glusterd is listening. This is optional | ||
1563 | -and if not specified, it defaults to port 24007. If the transport type is unix, | ||
1564 | -then @var{port} should not be specified. | ||
1565 | - | ||
1566 | -@var{volume} is the name of the gluster volume which contains the disk image. | ||
1567 | - | ||
1568 | -@var{path} is the path to the actual disk image that resides on gluster volume. | ||
1569 | - | ||
1570 | -@var{debug} is the logging level of the gluster protocol driver. Debug levels | ||
1571 | -are 0-9, with 9 being the most verbose, and 0 representing no debugging output. | ||
1572 | -The default level is 4. The current logging levels defined in the gluster source | ||
1573 | -are 0 - None, 1 - Emergency, 2 - Alert, 3 - Critical, 4 - Error, 5 - Warning, | ||
1574 | -6 - Notice, 7 - Info, 8 - Debug, 9 - Trace | ||
1575 | - | ||
1576 | -@var{logfile} is a commandline option to mention log file path which helps in | ||
1577 | -logging to the specified file and also help in persisting the gfapi logs. The | ||
1578 | -default is stderr. | ||
1579 | - | ||
1580 | - | ||
1581 | - | ||
1582 | - | ||
1583 | -You can create a GlusterFS disk image with the command: | ||
1584 | -@example | ||
1585 | -qemu-img create gluster://@var{host}/@var{volume}/@var{path} @var{size} | ||
1586 | -@end example | ||
1587 | - | ||
1588 | -Examples | ||
1589 | -@example | ||
1590 | -qemu-system-x86_64 -drive file=gluster://1.2.3.4/testvol/a.img | ||
1591 | -qemu-system-x86_64 -drive file=gluster+tcp://1.2.3.4/testvol/a.img | ||
1592 | -qemu-system-x86_64 -drive file=gluster+tcp://1.2.3.4:24007/testvol/dir/a.img | ||
1593 | -qemu-system-x86_64 -drive file=gluster+tcp://[1:2:3:4:5:6:7:8]/testvol/dir/a.img | ||
1594 | -qemu-system-x86_64 -drive file=gluster+tcp://[1:2:3:4:5:6:7:8]:24007/testvol/dir/a.img | ||
1595 | -qemu-system-x86_64 -drive file=gluster+tcp://server.domain.com:24007/testvol/dir/a.img | ||
1596 | -qemu-system-x86_64 -drive file=gluster+unix:///testvol/dir/a.img?socket=/tmp/glusterd.socket | ||
1597 | -qemu-system-x86_64 -drive file=gluster+rdma://1.2.3.4:24007/testvol/a.img | ||
1598 | -qemu-system-x86_64 -drive file=gluster://1.2.3.4/testvol/a.img,file.debug=9,file.logfile=/var/log/qemu-gluster.log | ||
1599 | -qemu-system-x86_64 'json:@{"driver":"qcow2", | ||
1600 | - "file":@{"driver":"gluster", | ||
1601 | - "volume":"testvol","path":"a.img", | ||
1602 | - "debug":9,"logfile":"/var/log/qemu-gluster.log", | ||
1603 | - "server":[@{"type":"tcp","host":"1.2.3.4","port":24007@}, | ||
1604 | - @{"type":"unix","socket":"/var/run/glusterd.socket"@}]@}@}' | ||
1605 | -qemu-system-x86_64 -drive driver=qcow2,file.driver=gluster,file.volume=testvol,file.path=/path/a.img, | ||
1606 | - file.debug=9,file.logfile=/var/log/qemu-gluster.log, | ||
1607 | - file.server.0.type=tcp,file.server.0.host=1.2.3.4,file.server.0.port=24007, | ||
1608 | - file.server.1.type=unix,file.server.1.socket=/var/run/glusterd.socket | ||
1609 | -@end example | ||
1610 | - | ||
1611 | -@node disk_images_ssh | ||
1612 | -@subsection Secure Shell (ssh) disk images | ||
1613 | - | ||
1614 | -You can access disk images located on a remote ssh server | ||
1615 | -by using the ssh protocol: | ||
1616 | - | ||
1617 | -@example | ||
1618 | -qemu-system-x86_64 -drive file=ssh://[@var{user}@@]@var{server}[:@var{port}]/@var{path}[?host_key_check=@var{host_key_check}] | ||
1619 | -@end example | ||
1620 | - | ||
1621 | -Alternative syntax using properties: | ||
1622 | - | ||
1623 | -@example | ||
1624 | -qemu-system-x86_64 -drive file.driver=ssh[,file.user=@var{user}],file.host=@var{server}[,file.port=@var{port}],file.path=@var{path}[,file.host_key_check=@var{host_key_check}] | ||
1625 | -@end example | ||
1626 | - | ||
1627 | -@var{ssh} is the protocol. | ||
1628 | - | ||
1629 | -@var{user} is the remote user. If not specified, then the local | ||
1630 | -username is tried. | ||
1631 | - | ||
1632 | -@var{server} specifies the remote ssh server. Any ssh server can be | ||
1633 | -used, but it must implement the sftp-server protocol. Most Unix/Linux | ||
1634 | -systems should work without requiring any extra configuration. | ||
1635 | - | ||
1636 | -@var{port} is the port number on which sshd is listening. By default | ||
1637 | -the standard ssh port (22) is used. | ||
1638 | - | ||
1639 | -@var{path} is the path to the disk image. | ||
1640 | - | ||
1641 | -The optional @var{host_key_check} parameter controls how the remote | ||
1642 | -host's key is checked. The default is @code{yes} which means to use | ||
1643 | -the local @file{.ssh/known_hosts} file. Setting this to @code{no} | ||
1644 | -turns off known-hosts checking. Or you can check that the host key | ||
1645 | -matches a specific fingerprint: | ||
1646 | -@code{host_key_check=md5:78:45:8e:14:57:4f:d5:45:83:0a:0e:f3:49:82:c9:c8} | ||
1647 | -(@code{sha1:} can also be used as a prefix, but note that OpenSSH | ||
1648 | -tools only use MD5 to print fingerprints). | ||
1649 | - | ||
1650 | -Currently authentication must be done using ssh-agent. Other | ||
1651 | -authentication methods may be supported in future. | ||
1652 | - | ||
1653 | -Note: Many ssh servers do not support an @code{fsync}-style operation. | ||
1654 | -The ssh driver cannot guarantee that disk flush requests are | ||
1655 | -obeyed, and this causes a risk of disk corruption if the remote | ||
1656 | -server or network goes down during writes. The driver will | ||
1657 | -print a warning when @code{fsync} is not supported: | ||
1658 | - | ||
1659 | -warning: ssh server @code{ssh.example.com:22} does not support fsync | ||
1660 | - | ||
1661 | -With sufficiently new versions of libssh2 and OpenSSH, @code{fsync} is | ||
1662 | -supported. | ||
1663 | +@include docs/qemu-block-drivers.texi | ||
1664 | |||
1665 | @node pcsys_network | ||
1666 | @section Network emulation | ||
1667 | -- | 91 | -- |
1668 | 2.13.5 | 92 | 2.31.1 |
1669 | 93 | ||
1670 | 94 | diff view generated by jsdifflib |
1 | When new permissions are calculated during bdrv_reopen(), they need to | 1 | Currently, the block driver whitelists are only applied for the system |
---|---|---|---|
2 | be based on the state of the graph as it will be after the reopen has | 2 | emulator. All other binaries still give unrestricted access to all block |
3 | completed, not on the current state of the involved nodes. | 3 | drivers. There are use cases where this made sense because the main |
4 | concern was avoiding customers running VMs on less optimised block | ||
5 | drivers and getting bad performance. Allowing the same image format e.g. | ||
6 | as a target for 'qemu-img convert' is not a problem then. | ||
4 | 7 | ||
5 | This patch makes bdrv_is_writable() optionally accept a BlockReopenQueue | 8 | However, if the concern is the supportability of the driver in general, |
6 | from which the new flags are taken. This is then used for determining | 9 | either in full or when used read-write, not applying the list driver |
7 | the new bs->file permissions of format drivers as soon as we add the | 10 | whitelist in tools doesn't help - especially since qemu-nbd and |
8 | code to actually pass a non-NULL reopen queue to the .bdrv_child_perm | 11 | qemu-storage-daemon now give access to more or less the same operations |
9 | callbacks. | 12 | in block drivers as running a system emulator. |
10 | 13 | ||
11 | While moving bdrv_is_writable(), make it static. It isn't used outside | 14 | In order to address this, introduce a new configure option that enforces |
12 | block.c. | 15 | the driver whitelist in all binaries. |
13 | 16 | ||
14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 17 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
18 | Message-Id: <20210709164141.254097-1-kwolf@redhat.com> | ||
15 | Reviewed-by: Eric Blake <eblake@redhat.com> | 19 | Reviewed-by: Eric Blake <eblake@redhat.com> |
20 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
16 | --- | 21 | --- |
17 | include/block/block.h | 1 - | 22 | configure | 14 ++++++++++++-- |
18 | block.c | 52 ++++++++++++++++++++++++++++++++++++--------------- | 23 | block.c | 3 +++ |
19 | 2 files changed, 37 insertions(+), 16 deletions(-) | 24 | meson.build | 1 + |
25 | 3 files changed, 16 insertions(+), 2 deletions(-) | ||
20 | 26 | ||
21 | diff --git a/include/block/block.h b/include/block/block.h | 27 | diff --git a/configure b/configure |
22 | index XXXXXXX..XXXXXXX 100644 | 28 | index XXXXXXX..XXXXXXX 100755 |
23 | --- a/include/block/block.h | 29 | --- a/configure |
24 | +++ b/include/block/block.h | 30 | +++ b/configure |
25 | @@ -XXX,XX +XXX,XX @@ int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base, | 31 | @@ -XXX,XX +XXX,XX @@ cross_prefix="" |
26 | int64_t offset, int64_t bytes, int64_t *pnum); | 32 | audio_drv_list="" |
27 | 33 | block_drv_rw_whitelist="" | |
28 | bool bdrv_is_read_only(BlockDriverState *bs); | 34 | block_drv_ro_whitelist="" |
29 | -bool bdrv_is_writable(BlockDriverState *bs); | 35 | +block_drv_whitelist_tools="no" |
30 | int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only, | 36 | host_cc="cc" |
31 | bool ignore_allow_rdw, Error **errp); | 37 | audio_win_int="" |
32 | int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp); | 38 | libs_qga="" |
39 | @@ -XXX,XX +XXX,XX @@ for opt do | ||
40 | ;; | ||
41 | --block-drv-ro-whitelist=*) block_drv_ro_whitelist=$(echo "$optarg" | sed -e 's/,/ /g') | ||
42 | ;; | ||
43 | + --enable-block-drv-whitelist-in-tools) block_drv_whitelist_tools="yes" | ||
44 | + ;; | ||
45 | + --disable-block-drv-whitelist-in-tools) block_drv_whitelist_tools="no" | ||
46 | + ;; | ||
47 | --enable-debug-tcg) debug_tcg="yes" | ||
48 | ;; | ||
49 | --disable-debug-tcg) debug_tcg="no" | ||
50 | @@ -XXX,XX +XXX,XX @@ Advanced options (experts only): | ||
51 | --block-drv-whitelist=L Same as --block-drv-rw-whitelist=L | ||
52 | --block-drv-rw-whitelist=L | ||
53 | set block driver read-write whitelist | ||
54 | - (affects only QEMU, not qemu-img) | ||
55 | + (by default affects only QEMU, not tools like qemu-img) | ||
56 | --block-drv-ro-whitelist=L | ||
57 | set block driver read-only whitelist | ||
58 | - (affects only QEMU, not qemu-img) | ||
59 | + (by default affects only QEMU, not tools like qemu-img) | ||
60 | + --enable-block-drv-whitelist-in-tools | ||
61 | + use block whitelist also in tools instead of only QEMU | ||
62 | --enable-trace-backends=B Set trace backend | ||
63 | Available backends: $trace_backend_list | ||
64 | --with-trace-file=NAME Full PATH,NAME of file to store traces | ||
65 | @@ -XXX,XX +XXX,XX @@ if test "$audio_win_int" = "yes" ; then | ||
66 | fi | ||
67 | echo "CONFIG_BDRV_RW_WHITELIST=$block_drv_rw_whitelist" >> $config_host_mak | ||
68 | echo "CONFIG_BDRV_RO_WHITELIST=$block_drv_ro_whitelist" >> $config_host_mak | ||
69 | +if test "$block_drv_whitelist_tools" = "yes" ; then | ||
70 | + echo "CONFIG_BDRV_WHITELIST_TOOLS=y" >> $config_host_mak | ||
71 | +fi | ||
72 | if test "$xfs" = "yes" ; then | ||
73 | echo "CONFIG_XFS=y" >> $config_host_mak | ||
74 | fi | ||
33 | diff --git a/block.c b/block.c | 75 | diff --git a/block.c b/block.c |
34 | index XXXXXXX..XXXXXXX 100644 | 76 | index XXXXXXX..XXXXXXX 100644 |
35 | --- a/block.c | 77 | --- a/block.c |
36 | +++ b/block.c | 78 | +++ b/block.c |
37 | @@ -XXX,XX +XXX,XX @@ bool bdrv_is_read_only(BlockDriverState *bs) | 79 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs, |
38 | return bs->read_only; | 80 | |
81 | void bdrv_init(void) | ||
82 | { | ||
83 | +#ifdef CONFIG_BDRV_WHITELIST_TOOLS | ||
84 | + use_bdrv_whitelist = 1; | ||
85 | +#endif | ||
86 | module_call_init(MODULE_INIT_BLOCK); | ||
39 | } | 87 | } |
40 | 88 | ||
41 | -/* Returns whether the image file can be written to right now */ | 89 | diff --git a/meson.build b/meson.build |
42 | -bool bdrv_is_writable(BlockDriverState *bs) | 90 | index XXXXXXX..XXXXXXX 100644 |
43 | -{ | 91 | --- a/meson.build |
44 | - return !bdrv_is_read_only(bs) && !(bs->open_flags & BDRV_O_INACTIVE); | 92 | +++ b/meson.build |
45 | -} | 93 | @@ -XXX,XX +XXX,XX @@ summary_info += {'coroutine pool': config_host['CONFIG_COROUTINE_POOL'] == '1 |
46 | - | 94 | if have_block |
47 | int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only, | 95 | summary_info += {'Block whitelist (rw)': config_host['CONFIG_BDRV_RW_WHITELIST']} |
48 | bool ignore_allow_rdw, Error **errp) | 96 | summary_info += {'Block whitelist (ro)': config_host['CONFIG_BDRV_RO_WHITELIST']} |
49 | { | 97 | + summary_info += {'Use block whitelist in tools': config_host.has_key('CONFIG_BDRV_WHITELIST_TOOLS')} |
50 | @@ -XXX,XX +XXX,XX @@ static int bdrv_child_check_perm(BdrvChild *c, BlockReopenQueue *q, | 98 | summary_info += {'VirtFS support': have_virtfs} |
51 | static void bdrv_child_abort_perm_update(BdrvChild *c); | 99 | summary_info += {'build virtiofs daemon': have_virtiofsd} |
52 | static void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared); | 100 | summary_info += {'Live block migration': config_host.has_key('CONFIG_LIVE_BLOCK_MIGRATION')} |
53 | |||
54 | +typedef struct BlockReopenQueueEntry { | ||
55 | + bool prepared; | ||
56 | + BDRVReopenState state; | ||
57 | + QSIMPLEQ_ENTRY(BlockReopenQueueEntry) entry; | ||
58 | +} BlockReopenQueueEntry; | ||
59 | + | ||
60 | +/* | ||
61 | + * Return the flags that @bs will have after the reopens in @q have | ||
62 | + * successfully completed. If @q is NULL (or @bs is not contained in @q), | ||
63 | + * return the current flags. | ||
64 | + */ | ||
65 | +static int bdrv_reopen_get_flags(BlockReopenQueue *q, BlockDriverState *bs) | ||
66 | +{ | ||
67 | + BlockReopenQueueEntry *entry; | ||
68 | + | ||
69 | + if (q != NULL) { | ||
70 | + QSIMPLEQ_FOREACH(entry, q, entry) { | ||
71 | + if (entry->state.bs == bs) { | ||
72 | + return entry->state.flags; | ||
73 | + } | ||
74 | + } | ||
75 | + } | ||
76 | + | ||
77 | + return bs->open_flags; | ||
78 | +} | ||
79 | + | ||
80 | +/* Returns whether the image file can be written to after the reopen queue @q | ||
81 | + * has been successfully applied, or right now if @q is NULL. */ | ||
82 | +static bool bdrv_is_writable(BlockDriverState *bs, BlockReopenQueue *q) | ||
83 | +{ | ||
84 | + int flags = bdrv_reopen_get_flags(q, bs); | ||
85 | + | ||
86 | + return (flags & (BDRV_O_RDWR | BDRV_O_INACTIVE)) == BDRV_O_RDWR; | ||
87 | +} | ||
88 | + | ||
89 | static void bdrv_child_perm(BlockDriverState *bs, BlockDriverState *child_bs, | ||
90 | BdrvChild *c, const BdrvChildRole *role, | ||
91 | BlockReopenQueue *reopen_queue, | ||
92 | @@ -XXX,XX +XXX,XX @@ static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q, | ||
93 | |||
94 | /* Write permissions never work with read-only images */ | ||
95 | if ((cumulative_perms & (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED)) && | ||
96 | - !bdrv_is_writable(bs)) | ||
97 | + !bdrv_is_writable(bs, q)) | ||
98 | { | ||
99 | error_setg(errp, "Block node is read-only"); | ||
100 | return -EPERM; | ||
101 | @@ -XXX,XX +XXX,XX @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
102 | &perm, &shared); | ||
103 | |||
104 | /* Format drivers may touch metadata even if the guest doesn't write */ | ||
105 | - /* TODO Take flags from reopen_queue */ | ||
106 | - if (bdrv_is_writable(bs)) { | ||
107 | + if (bdrv_is_writable(bs, reopen_queue)) { | ||
108 | perm |= BLK_PERM_WRITE | BLK_PERM_RESIZE; | ||
109 | } | ||
110 | |||
111 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_open(const char *filename, const char *reference, | ||
112 | NULL, errp); | ||
113 | } | ||
114 | |||
115 | -typedef struct BlockReopenQueueEntry { | ||
116 | - bool prepared; | ||
117 | - BDRVReopenState state; | ||
118 | - QSIMPLEQ_ENTRY(BlockReopenQueueEntry) entry; | ||
119 | -} BlockReopenQueueEntry; | ||
120 | - | ||
121 | /* | ||
122 | * Adds a BlockDriverState to a simple queue for an atomic, transactional | ||
123 | * reopen of multiple devices. | ||
124 | -- | 101 | -- |
125 | 2.13.5 | 102 | 2.31.1 |
126 | 103 | ||
127 | 104 | diff view generated by jsdifflib |
1 | If we switch between read-only and read-write, the permissions that | 1 | From: Lukas Straub <lukasstraub2@web.de> |
---|---|---|---|
2 | image format drivers need on bs->file change, too. Make sure to update | ||
3 | the permissions during bdrv_reopen(). | ||
4 | 2 | ||
3 | s->active_disk is bs->file. Remove it and use local variables instead. | ||
4 | |||
5 | Signed-off-by: Lukas Straub <lukasstraub2@web.de> | ||
6 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
7 | Message-Id: <2534f867ea9be5b666dfce19744b7d4e2b96c976.1626619393.git.lukasstraub2@web.de> | ||
8 | Reviewed-by: Zhang Chen <chen.zhang@intel.com> | ||
5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
6 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
7 | --- | 10 | --- |
8 | include/block/block.h | 1 + | 11 | block/replication.c | 34 +++++++++++++++++----------------- |
9 | block.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++ | 12 | 1 file changed, 17 insertions(+), 17 deletions(-) |
10 | 2 files changed, 65 insertions(+) | ||
11 | 13 | ||
12 | diff --git a/include/block/block.h b/include/block/block.h | 14 | diff --git a/block/replication.c b/block/replication.c |
13 | index XXXXXXX..XXXXXXX 100644 | 15 | index XXXXXXX..XXXXXXX 100644 |
14 | --- a/include/block/block.h | 16 | --- a/block/replication.c |
15 | +++ b/include/block/block.h | 17 | +++ b/block/replication.c |
16 | @@ -XXX,XX +XXX,XX @@ typedef QSIMPLEQ_HEAD(BlockReopenQueue, BlockReopenQueueEntry) BlockReopenQueue; | 18 | @@ -XXX,XX +XXX,XX @@ typedef enum { |
17 | typedef struct BDRVReopenState { | 19 | typedef struct BDRVReplicationState { |
18 | BlockDriverState *bs; | 20 | ReplicationMode mode; |
19 | int flags; | 21 | ReplicationStage stage; |
20 | + uint64_t perm, shared_perm; | 22 | - BdrvChild *active_disk; |
21 | QDict *options; | 23 | BlockJob *commit_job; |
22 | QDict *explicit_options; | 24 | BdrvChild *hidden_disk; |
23 | void *opaque; | 25 | BdrvChild *secondary_disk; |
24 | diff --git a/block.c b/block.c | 26 | @@ -XXX,XX +XXX,XX @@ out: |
25 | index XXXXXXX..XXXXXXX 100644 | ||
26 | --- a/block.c | ||
27 | +++ b/block.c | ||
28 | @@ -XXX,XX +XXX,XX @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, | ||
29 | bs_entry->state.explicit_options = explicit_options; | ||
30 | bs_entry->state.flags = flags; | ||
31 | |||
32 | + /* This needs to be overwritten in bdrv_reopen_prepare() */ | ||
33 | + bs_entry->state.perm = UINT64_MAX; | ||
34 | + bs_entry->state.shared_perm = 0; | ||
35 | + | ||
36 | QLIST_FOREACH(child, &bs->children, next) { | ||
37 | QDict *new_child_options; | ||
38 | char *child_key_dot; | ||
39 | @@ -XXX,XX +XXX,XX @@ int bdrv_reopen(BlockDriverState *bs, int bdrv_flags, Error **errp) | ||
40 | return ret; | 27 | return ret; |
41 | } | 28 | } |
42 | 29 | ||
43 | +static BlockReopenQueueEntry *find_parent_in_reopen_queue(BlockReopenQueue *q, | 30 | -static void secondary_do_checkpoint(BDRVReplicationState *s, Error **errp) |
44 | + BdrvChild *c) | 31 | +static void secondary_do_checkpoint(BlockDriverState *bs, Error **errp) |
45 | +{ | 32 | { |
46 | + BlockReopenQueueEntry *entry; | 33 | + BDRVReplicationState *s = bs->opaque; |
47 | + | 34 | + BdrvChild *active_disk = bs->file; |
48 | + QSIMPLEQ_FOREACH(entry, q, entry) { | 35 | Error *local_err = NULL; |
49 | + BlockDriverState *bs = entry->state.bs; | 36 | int ret; |
50 | + BdrvChild *child; | 37 | |
51 | + | 38 | @@ -XXX,XX +XXX,XX @@ static void secondary_do_checkpoint(BDRVReplicationState *s, Error **errp) |
52 | + QLIST_FOREACH(child, &bs->children, next) { | 39 | return; |
53 | + if (child == c) { | ||
54 | + return entry; | ||
55 | + } | ||
56 | + } | ||
57 | + } | ||
58 | + | ||
59 | + return NULL; | ||
60 | +} | ||
61 | + | ||
62 | +static void bdrv_reopen_perm(BlockReopenQueue *q, BlockDriverState *bs, | ||
63 | + uint64_t *perm, uint64_t *shared) | ||
64 | +{ | ||
65 | + BdrvChild *c; | ||
66 | + BlockReopenQueueEntry *parent; | ||
67 | + uint64_t cumulative_perms = 0; | ||
68 | + uint64_t cumulative_shared_perms = BLK_PERM_ALL; | ||
69 | + | ||
70 | + QLIST_FOREACH(c, &bs->parents, next_parent) { | ||
71 | + parent = find_parent_in_reopen_queue(q, c); | ||
72 | + if (!parent) { | ||
73 | + cumulative_perms |= c->perm; | ||
74 | + cumulative_shared_perms &= c->shared_perm; | ||
75 | + } else { | ||
76 | + uint64_t nperm, nshared; | ||
77 | + | ||
78 | + bdrv_child_perm(parent->state.bs, bs, c, c->role, q, | ||
79 | + parent->state.perm, parent->state.shared_perm, | ||
80 | + &nperm, &nshared); | ||
81 | + | ||
82 | + cumulative_perms |= nperm; | ||
83 | + cumulative_shared_perms &= nshared; | ||
84 | + } | ||
85 | + } | ||
86 | + *perm = cumulative_perms; | ||
87 | + *shared = cumulative_shared_perms; | ||
88 | +} | ||
89 | |||
90 | /* | ||
91 | * Prepares a BlockDriverState for reopen. All changes are staged in the | ||
92 | @@ -XXX,XX +XXX,XX @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue, | ||
93 | goto error; | ||
94 | } | 40 | } |
95 | 41 | ||
96 | + /* Calculate required permissions after reopening */ | 42 | - if (!s->active_disk->bs->drv) { |
97 | + bdrv_reopen_perm(queue, reopen_state->bs, | 43 | + if (!active_disk->bs->drv) { |
98 | + &reopen_state->perm, &reopen_state->shared_perm); | 44 | error_setg(errp, "Active disk %s is ejected", |
99 | 45 | - s->active_disk->bs->node_name); | |
100 | ret = bdrv_flush(reopen_state->bs); | 46 | + active_disk->bs->node_name); |
101 | if (ret) { | 47 | return; |
102 | @@ -XXX,XX +XXX,XX @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue, | ||
103 | } while ((entry = qdict_next(reopen_state->options, entry))); | ||
104 | } | 48 | } |
105 | 49 | ||
106 | + ret = bdrv_check_perm(reopen_state->bs, queue, reopen_state->perm, | 50 | - ret = bdrv_make_empty(s->active_disk, errp); |
107 | + reopen_state->shared_perm, NULL, errp); | 51 | + ret = bdrv_make_empty(active_disk, errp); |
108 | + if (ret < 0) { | 52 | if (ret < 0) { |
109 | + goto error; | 53 | return; |
110 | + } | ||
111 | + | ||
112 | ret = 0; | ||
113 | |||
114 | error: | ||
115 | @@ -XXX,XX +XXX,XX @@ void bdrv_reopen_commit(BDRVReopenState *reopen_state) | ||
116 | |||
117 | bdrv_refresh_limits(bs, NULL); | ||
118 | |||
119 | + bdrv_set_perm(reopen_state->bs, reopen_state->perm, | ||
120 | + reopen_state->shared_perm); | ||
121 | + | ||
122 | new_can_write = | ||
123 | !bdrv_is_read_only(bs) && !(bdrv_get_flags(bs) & BDRV_O_INACTIVE); | ||
124 | if (!old_can_write && new_can_write && drv->bdrv_reopen_bitmaps_rw) { | ||
125 | @@ -XXX,XX +XXX,XX @@ void bdrv_reopen_abort(BDRVReopenState *reopen_state) | ||
126 | } | 54 | } |
127 | 55 | @@ -XXX,XX +XXX,XX @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, | |
128 | QDECREF(reopen_state->explicit_options); | 56 | BlockDriverState *bs = rs->opaque; |
129 | + | 57 | BDRVReplicationState *s; |
130 | + bdrv_abort_perm_update(reopen_state->bs); | 58 | BlockDriverState *top_bs; |
59 | + BdrvChild *active_disk; | ||
60 | int64_t active_length, hidden_length, disk_length; | ||
61 | AioContext *aio_context; | ||
62 | Error *local_err = NULL; | ||
63 | @@ -XXX,XX +XXX,XX @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, | ||
64 | case REPLICATION_MODE_PRIMARY: | ||
65 | break; | ||
66 | case REPLICATION_MODE_SECONDARY: | ||
67 | - s->active_disk = bs->file; | ||
68 | - if (!s->active_disk || !s->active_disk->bs || | ||
69 | - !s->active_disk->bs->backing) { | ||
70 | + active_disk = bs->file; | ||
71 | + if (!active_disk || !active_disk->bs || !active_disk->bs->backing) { | ||
72 | error_setg(errp, "Active disk doesn't have backing file"); | ||
73 | aio_context_release(aio_context); | ||
74 | return; | ||
75 | } | ||
76 | |||
77 | - s->hidden_disk = s->active_disk->bs->backing; | ||
78 | + s->hidden_disk = active_disk->bs->backing; | ||
79 | if (!s->hidden_disk->bs || !s->hidden_disk->bs->backing) { | ||
80 | error_setg(errp, "Hidden disk doesn't have backing file"); | ||
81 | aio_context_release(aio_context); | ||
82 | @@ -XXX,XX +XXX,XX @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, | ||
83 | } | ||
84 | |||
85 | /* verify the length */ | ||
86 | - active_length = bdrv_getlength(s->active_disk->bs); | ||
87 | + active_length = bdrv_getlength(active_disk->bs); | ||
88 | hidden_length = bdrv_getlength(s->hidden_disk->bs); | ||
89 | disk_length = bdrv_getlength(s->secondary_disk->bs); | ||
90 | if (active_length < 0 || hidden_length < 0 || disk_length < 0 || | ||
91 | @@ -XXX,XX +XXX,XX @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, | ||
92 | } | ||
93 | |||
94 | /* Must be true, or the bdrv_getlength() calls would have failed */ | ||
95 | - assert(s->active_disk->bs->drv && s->hidden_disk->bs->drv); | ||
96 | + assert(active_disk->bs->drv && s->hidden_disk->bs->drv); | ||
97 | |||
98 | - if (!s->active_disk->bs->drv->bdrv_make_empty || | ||
99 | + if (!active_disk->bs->drv->bdrv_make_empty || | ||
100 | !s->hidden_disk->bs->drv->bdrv_make_empty) { | ||
101 | error_setg(errp, | ||
102 | "Active disk or hidden disk doesn't support make_empty"); | ||
103 | @@ -XXX,XX +XXX,XX @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, | ||
104 | s->stage = BLOCK_REPLICATION_RUNNING; | ||
105 | |||
106 | if (s->mode == REPLICATION_MODE_SECONDARY) { | ||
107 | - secondary_do_checkpoint(s, errp); | ||
108 | + secondary_do_checkpoint(bs, errp); | ||
109 | } | ||
110 | |||
111 | s->error = 0; | ||
112 | @@ -XXX,XX +XXX,XX @@ static void replication_do_checkpoint(ReplicationState *rs, Error **errp) | ||
113 | } | ||
114 | |||
115 | if (s->mode == REPLICATION_MODE_SECONDARY) { | ||
116 | - secondary_do_checkpoint(s, errp); | ||
117 | + secondary_do_checkpoint(bs, errp); | ||
118 | } | ||
119 | aio_context_release(aio_context); | ||
131 | } | 120 | } |
132 | 121 | @@ -XXX,XX +XXX,XX @@ static void replication_done(void *opaque, int ret) | |
133 | 122 | if (ret == 0) { | |
123 | s->stage = BLOCK_REPLICATION_DONE; | ||
124 | |||
125 | - s->active_disk = NULL; | ||
126 | s->secondary_disk = NULL; | ||
127 | s->hidden_disk = NULL; | ||
128 | s->error = 0; | ||
129 | @@ -XXX,XX +XXX,XX @@ static void replication_stop(ReplicationState *rs, bool failover, Error **errp) | ||
130 | } | ||
131 | |||
132 | if (!failover) { | ||
133 | - secondary_do_checkpoint(s, errp); | ||
134 | + secondary_do_checkpoint(bs, errp); | ||
135 | s->stage = BLOCK_REPLICATION_DONE; | ||
136 | aio_context_release(aio_context); | ||
137 | return; | ||
138 | @@ -XXX,XX +XXX,XX @@ static void replication_stop(ReplicationState *rs, bool failover, Error **errp) | ||
139 | |||
140 | s->stage = BLOCK_REPLICATION_FAILOVER; | ||
141 | s->commit_job = commit_active_start( | ||
142 | - NULL, s->active_disk->bs, s->secondary_disk->bs, | ||
143 | + NULL, bs->file->bs, s->secondary_disk->bs, | ||
144 | JOB_INTERNAL, 0, BLOCKDEV_ON_ERROR_REPORT, | ||
145 | NULL, replication_done, bs, true, errp); | ||
146 | break; | ||
134 | -- | 147 | -- |
135 | 2.13.5 | 148 | 2.31.1 |
136 | 149 | ||
137 | 150 | diff view generated by jsdifflib |
1 | From: Pavel Butsykin <pbutsykin@virtuozzo.com> | 1 | From: Lukas Straub <lukasstraub2@web.de> |
---|---|---|---|
2 | 2 | ||
3 | Whenever l2/refcount table clusters are discarded from the file we can | 3 | In preparation for the next patch, initialize s->hidden_disk and |
4 | automatically drop unnecessary content of the cache tables. This reduces | 4 | s->secondary_disk later and replace access to them with local variables |
5 | the chance of eviction useful cache data and eliminates inconsistent data | 5 | in the places where they aren't initialized yet. |
6 | in the cache with the data in the file. | ||
7 | 6 | ||
8 | Signed-off-by: Pavel Butsykin <pbutsykin@virtuozzo.com> | 7 | Signed-off-by: Lukas Straub <lukasstraub2@web.de> |
9 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 8 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> |
10 | Reviewed-by: John Snow <jsnow@redhat.com> | 9 | Message-Id: <1eb9dc179267207d9c7eccaeb30761758e32e9ab.1626619393.git.lukasstraub2@web.de> |
11 | Message-id: 20170918124230.8152-3-pbutsykin@virtuozzo.com | 10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
12 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
13 | --- | 11 | --- |
14 | block/qcow2.h | 3 +++ | 12 | block/replication.c | 45 ++++++++++++++++++++++++++++----------------- |
15 | block/qcow2-cache.c | 26 ++++++++++++++++++++++++++ | 13 | 1 file changed, 28 insertions(+), 17 deletions(-) |
16 | block/qcow2-refcount.c | 20 ++++++++++++++++++-- | ||
17 | 3 files changed, 47 insertions(+), 2 deletions(-) | ||
18 | 14 | ||
19 | diff --git a/block/qcow2.h b/block/qcow2.h | 15 | diff --git a/block/replication.c b/block/replication.c |
20 | index XXXXXXX..XXXXXXX 100644 | 16 | index XXXXXXX..XXXXXXX 100644 |
21 | --- a/block/qcow2.h | 17 | --- a/block/replication.c |
22 | +++ b/block/qcow2.h | 18 | +++ b/block/replication.c |
23 | @@ -XXX,XX +XXX,XX @@ int qcow2_cache_get(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset, | 19 | @@ -XXX,XX +XXX,XX @@ static void reopen_backing_file(BlockDriverState *bs, bool writable, |
24 | int qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset, | 20 | Error **errp) |
25 | void **table); | 21 | { |
26 | void qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table); | 22 | BDRVReplicationState *s = bs->opaque; |
27 | +void *qcow2_cache_is_table_offset(BlockDriverState *bs, Qcow2Cache *c, | 23 | + BdrvChild *hidden_disk, *secondary_disk; |
28 | + uint64_t offset); | 24 | BlockReopenQueue *reopen_queue = NULL; |
29 | +void qcow2_cache_discard(BlockDriverState *bs, Qcow2Cache *c, void *table); | 25 | |
30 | 26 | + /* | |
31 | /* qcow2-bitmap.c functions */ | 27 | + * s->hidden_disk and s->secondary_disk may not be set yet, as they will |
32 | int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res, | 28 | + * only be set after the children are writable. |
33 | diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c | 29 | + */ |
34 | index XXXXXXX..XXXXXXX 100644 | 30 | + hidden_disk = bs->file->bs->backing; |
35 | --- a/block/qcow2-cache.c | 31 | + secondary_disk = hidden_disk->bs->backing; |
36 | +++ b/block/qcow2-cache.c | ||
37 | @@ -XXX,XX +XXX,XX @@ void qcow2_cache_entry_mark_dirty(BlockDriverState *bs, Qcow2Cache *c, | ||
38 | assert(c->entries[i].offset != 0); | ||
39 | c->entries[i].dirty = true; | ||
40 | } | ||
41 | + | 32 | + |
42 | +void *qcow2_cache_is_table_offset(BlockDriverState *bs, Qcow2Cache *c, | 33 | if (writable) { |
43 | + uint64_t offset) | 34 | - s->orig_hidden_read_only = bdrv_is_read_only(s->hidden_disk->bs); |
44 | +{ | 35 | - s->orig_secondary_read_only = bdrv_is_read_only(s->secondary_disk->bs); |
45 | + int i; | 36 | + s->orig_hidden_read_only = bdrv_is_read_only(hidden_disk->bs); |
46 | + | 37 | + s->orig_secondary_read_only = bdrv_is_read_only(secondary_disk->bs); |
47 | + for (i = 0; i < c->size; i++) { | 38 | } |
48 | + if (c->entries[i].offset == offset) { | 39 | |
49 | + return qcow2_cache_get_table_addr(bs, c, i); | 40 | - bdrv_subtree_drained_begin(s->hidden_disk->bs); |
50 | + } | 41 | - bdrv_subtree_drained_begin(s->secondary_disk->bs); |
51 | + } | 42 | + bdrv_subtree_drained_begin(hidden_disk->bs); |
52 | + return NULL; | 43 | + bdrv_subtree_drained_begin(secondary_disk->bs); |
53 | +} | 44 | |
54 | + | 45 | if (s->orig_hidden_read_only) { |
55 | +void qcow2_cache_discard(BlockDriverState *bs, Qcow2Cache *c, void *table) | 46 | QDict *opts = qdict_new(); |
56 | +{ | 47 | qdict_put_bool(opts, BDRV_OPT_READ_ONLY, !writable); |
57 | + int i = qcow2_cache_get_table_idx(bs, c, table); | 48 | - reopen_queue = bdrv_reopen_queue(reopen_queue, s->hidden_disk->bs, |
58 | + | 49 | + reopen_queue = bdrv_reopen_queue(reopen_queue, hidden_disk->bs, |
59 | + assert(c->entries[i].ref == 0); | 50 | opts, true); |
60 | + | 51 | } |
61 | + c->entries[i].offset = 0; | 52 | |
62 | + c->entries[i].lru_counter = 0; | 53 | if (s->orig_secondary_read_only) { |
63 | + c->entries[i].dirty = false; | 54 | QDict *opts = qdict_new(); |
64 | + | 55 | qdict_put_bool(opts, BDRV_OPT_READ_ONLY, !writable); |
65 | + qcow2_cache_table_release(bs, c, i, 1); | 56 | - reopen_queue = bdrv_reopen_queue(reopen_queue, s->secondary_disk->bs, |
66 | +} | 57 | + reopen_queue = bdrv_reopen_queue(reopen_queue, secondary_disk->bs, |
67 | diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c | 58 | opts, true); |
68 | index XXXXXXX..XXXXXXX 100644 | 59 | } |
69 | --- a/block/qcow2-refcount.c | 60 | |
70 | +++ b/block/qcow2-refcount.c | 61 | @@ -XXX,XX +XXX,XX @@ static void reopen_backing_file(BlockDriverState *bs, bool writable, |
71 | @@ -XXX,XX +XXX,XX @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs, | ||
72 | } | ||
73 | s->set_refcount(refcount_block, block_index, refcount); | ||
74 | |||
75 | - if (refcount == 0 && s->discard_passthrough[type]) { | ||
76 | - update_refcount_discard(bs, cluster_offset, s->cluster_size); | ||
77 | + if (refcount == 0) { | ||
78 | + void *table; | ||
79 | + | ||
80 | + table = qcow2_cache_is_table_offset(bs, s->refcount_block_cache, | ||
81 | + offset); | ||
82 | + if (table != NULL) { | ||
83 | + qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block); | ||
84 | + qcow2_cache_discard(bs, s->refcount_block_cache, table); | ||
85 | + } | ||
86 | + | ||
87 | + table = qcow2_cache_is_table_offset(bs, s->l2_table_cache, offset); | ||
88 | + if (table != NULL) { | ||
89 | + qcow2_cache_discard(bs, s->l2_table_cache, table); | ||
90 | + } | ||
91 | + | ||
92 | + if (s->discard_passthrough[type]) { | ||
93 | + update_refcount_discard(bs, cluster_offset, s->cluster_size); | ||
94 | + } | ||
95 | } | 62 | } |
96 | } | 63 | } |
97 | 64 | ||
65 | - bdrv_subtree_drained_end(s->hidden_disk->bs); | ||
66 | - bdrv_subtree_drained_end(s->secondary_disk->bs); | ||
67 | + bdrv_subtree_drained_end(hidden_disk->bs); | ||
68 | + bdrv_subtree_drained_end(secondary_disk->bs); | ||
69 | } | ||
70 | |||
71 | static void backup_job_cleanup(BlockDriverState *bs) | ||
72 | @@ -XXX,XX +XXX,XX @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, | ||
73 | BlockDriverState *bs = rs->opaque; | ||
74 | BDRVReplicationState *s; | ||
75 | BlockDriverState *top_bs; | ||
76 | - BdrvChild *active_disk; | ||
77 | + BdrvChild *active_disk, *hidden_disk, *secondary_disk; | ||
78 | int64_t active_length, hidden_length, disk_length; | ||
79 | AioContext *aio_context; | ||
80 | Error *local_err = NULL; | ||
81 | @@ -XXX,XX +XXX,XX @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, | ||
82 | return; | ||
83 | } | ||
84 | |||
85 | - s->hidden_disk = active_disk->bs->backing; | ||
86 | - if (!s->hidden_disk->bs || !s->hidden_disk->bs->backing) { | ||
87 | + hidden_disk = active_disk->bs->backing; | ||
88 | + if (!hidden_disk->bs || !hidden_disk->bs->backing) { | ||
89 | error_setg(errp, "Hidden disk doesn't have backing file"); | ||
90 | aio_context_release(aio_context); | ||
91 | return; | ||
92 | } | ||
93 | |||
94 | - s->secondary_disk = s->hidden_disk->bs->backing; | ||
95 | - if (!s->secondary_disk->bs || !bdrv_has_blk(s->secondary_disk->bs)) { | ||
96 | + secondary_disk = hidden_disk->bs->backing; | ||
97 | + if (!secondary_disk->bs || !bdrv_has_blk(secondary_disk->bs)) { | ||
98 | error_setg(errp, "The secondary disk doesn't have block backend"); | ||
99 | aio_context_release(aio_context); | ||
100 | return; | ||
101 | @@ -XXX,XX +XXX,XX @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, | ||
102 | |||
103 | /* verify the length */ | ||
104 | active_length = bdrv_getlength(active_disk->bs); | ||
105 | - hidden_length = bdrv_getlength(s->hidden_disk->bs); | ||
106 | - disk_length = bdrv_getlength(s->secondary_disk->bs); | ||
107 | + hidden_length = bdrv_getlength(hidden_disk->bs); | ||
108 | + disk_length = bdrv_getlength(secondary_disk->bs); | ||
109 | if (active_length < 0 || hidden_length < 0 || disk_length < 0 || | ||
110 | active_length != hidden_length || hidden_length != disk_length) { | ||
111 | error_setg(errp, "Active disk, hidden disk, secondary disk's length" | ||
112 | @@ -XXX,XX +XXX,XX @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, | ||
113 | } | ||
114 | |||
115 | /* Must be true, or the bdrv_getlength() calls would have failed */ | ||
116 | - assert(active_disk->bs->drv && s->hidden_disk->bs->drv); | ||
117 | + assert(active_disk->bs->drv && hidden_disk->bs->drv); | ||
118 | |||
119 | if (!active_disk->bs->drv->bdrv_make_empty || | ||
120 | - !s->hidden_disk->bs->drv->bdrv_make_empty) { | ||
121 | + !hidden_disk->bs->drv->bdrv_make_empty) { | ||
122 | error_setg(errp, | ||
123 | "Active disk or hidden disk doesn't support make_empty"); | ||
124 | aio_context_release(aio_context); | ||
125 | @@ -XXX,XX +XXX,XX @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, | ||
126 | return; | ||
127 | } | ||
128 | |||
129 | + s->hidden_disk = hidden_disk; | ||
130 | + s->secondary_disk = secondary_disk; | ||
131 | + | ||
132 | /* start backup job now */ | ||
133 | error_setg(&s->blocker, | ||
134 | "Block device is in use by internal backup job"); | ||
98 | -- | 135 | -- |
99 | 2.13.5 | 136 | 2.31.1 |
100 | 137 | ||
101 | 138 | diff view generated by jsdifflib |
1 | In the context of bdrv_reopen(), we'll have to look at the state of the | 1 | From: Lukas Straub <lukasstraub2@web.de> |
---|---|---|---|
2 | graph as it will be after the reopen. This interface addition is in | ||
3 | preparation for the change. | ||
4 | 2 | ||
3 | The replication driver needs access to the children block-nodes of | ||
4 | it's child so it can issue bdrv_make_empty() and bdrv_co_pwritev() | ||
5 | to manage the replication. However, it does this by directly copying | ||
6 | the BdrvChilds, which is wrong. | ||
7 | |||
8 | Fix this by properly attaching the block-nodes with | ||
9 | bdrv_attach_child() and requesting the required permissions. | ||
10 | |||
11 | This ultimatively fixes a potential crash in replication_co_writev(), | ||
12 | because it may write to s->secondary_disk if it is in state | ||
13 | BLOCK_REPLICATION_FAILOVER_FAILED, without requesting write | ||
14 | permissions first. And now the workaround in | ||
15 | secondary_do_checkpoint() can be removed. | ||
16 | |||
17 | Signed-off-by: Lukas Straub <lukasstraub2@web.de> | ||
18 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
19 | Message-Id: <5d0539d729afb8072d0d7cde977c5066285591b4.1626619393.git.lukasstraub2@web.de> | ||
5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 20 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
6 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
7 | --- | 21 | --- |
8 | include/block/block_int.h | 7 +++++++ | 22 | block/replication.c | 30 +++++++++++++++++++++++++++--- |
9 | block.c | 19 ++++++++++++------- | 23 | 1 file changed, 27 insertions(+), 3 deletions(-) |
10 | block/commit.c | 1 + | ||
11 | block/mirror.c | 1 + | ||
12 | block/replication.c | 1 + | ||
13 | block/vvfat.c | 1 + | ||
14 | 6 files changed, 23 insertions(+), 7 deletions(-) | ||
15 | 24 | ||
16 | diff --git a/include/block/block_int.h b/include/block/block_int.h | ||
17 | index XXXXXXX..XXXXXXX 100644 | ||
18 | --- a/include/block/block_int.h | ||
19 | +++ b/include/block/block_int.h | ||
20 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
21 | * | ||
22 | * If @c is NULL, return the permissions for attaching a new child for the | ||
23 | * given @role. | ||
24 | + * | ||
25 | + * If @reopen_queue is non-NULL, don't return the currently needed | ||
26 | + * permissions, but those that will be needed after applying the | ||
27 | + * @reopen_queue. | ||
28 | */ | ||
29 | void (*bdrv_child_perm)(BlockDriverState *bs, BdrvChild *c, | ||
30 | const BdrvChildRole *role, | ||
31 | + BlockReopenQueue *reopen_queue, | ||
32 | uint64_t parent_perm, uint64_t parent_shared, | ||
33 | uint64_t *nperm, uint64_t *nshared); | ||
34 | |||
35 | @@ -XXX,XX +XXX,XX @@ int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared, | ||
36 | * all children */ | ||
37 | void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
38 | const BdrvChildRole *role, | ||
39 | + BlockReopenQueue *reopen_queue, | ||
40 | uint64_t perm, uint64_t shared, | ||
41 | uint64_t *nperm, uint64_t *nshared); | ||
42 | |||
43 | @@ -XXX,XX +XXX,XX @@ void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
44 | * CONSISTENT_READ and doesn't share WRITE. */ | ||
45 | void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
46 | const BdrvChildRole *role, | ||
47 | + BlockReopenQueue *reopen_queue, | ||
48 | uint64_t perm, uint64_t shared, | ||
49 | uint64_t *nperm, uint64_t *nshared); | ||
50 | |||
51 | diff --git a/block.c b/block.c | ||
52 | index XXXXXXX..XXXXXXX 100644 | ||
53 | --- a/block.c | ||
54 | +++ b/block.c | ||
55 | @@ -XXX,XX +XXX,XX @@ static void bdrv_child_abort_perm_update(BdrvChild *c); | ||
56 | static void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared); | ||
57 | |||
58 | static void bdrv_child_perm(BlockDriverState *bs, BlockDriverState *child_bs, | ||
59 | - BdrvChild *c, | ||
60 | - const BdrvChildRole *role, | ||
61 | + BdrvChild *c, const BdrvChildRole *role, | ||
62 | + BlockReopenQueue *reopen_queue, | ||
63 | uint64_t parent_perm, uint64_t parent_shared, | ||
64 | uint64_t *nperm, uint64_t *nshared) | ||
65 | { | ||
66 | if (bs->drv && bs->drv->bdrv_child_perm) { | ||
67 | - bs->drv->bdrv_child_perm(bs, c, role, | ||
68 | + bs->drv->bdrv_child_perm(bs, c, role, reopen_queue, | ||
69 | parent_perm, parent_shared, | ||
70 | nperm, nshared); | ||
71 | } | ||
72 | + /* TODO Take force_share from reopen_queue */ | ||
73 | if (child_bs && child_bs->force_share) { | ||
74 | *nshared = BLK_PERM_ALL; | ||
75 | } | ||
76 | @@ -XXX,XX +XXX,XX @@ static int bdrv_check_perm(BlockDriverState *bs, uint64_t cumulative_perms, | ||
77 | /* Check all children */ | ||
78 | QLIST_FOREACH(c, &bs->children, next) { | ||
79 | uint64_t cur_perm, cur_shared; | ||
80 | - bdrv_child_perm(bs, c->bs, c, c->role, | ||
81 | + bdrv_child_perm(bs, c->bs, c, c->role, NULL, | ||
82 | cumulative_perms, cumulative_shared_perms, | ||
83 | &cur_perm, &cur_shared); | ||
84 | ret = bdrv_child_check_perm(c, cur_perm, cur_shared, ignore_children, | ||
85 | @@ -XXX,XX +XXX,XX @@ static void bdrv_set_perm(BlockDriverState *bs, uint64_t cumulative_perms, | ||
86 | /* Update all children */ | ||
87 | QLIST_FOREACH(c, &bs->children, next) { | ||
88 | uint64_t cur_perm, cur_shared; | ||
89 | - bdrv_child_perm(bs, c->bs, c, c->role, | ||
90 | + bdrv_child_perm(bs, c->bs, c, c->role, NULL, | ||
91 | cumulative_perms, cumulative_shared_perms, | ||
92 | &cur_perm, &cur_shared); | ||
93 | bdrv_child_set_perm(c, cur_perm, cur_shared); | ||
94 | @@ -XXX,XX +XXX,XX @@ int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared, | ||
95 | |||
96 | void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
97 | const BdrvChildRole *role, | ||
98 | + BlockReopenQueue *reopen_queue, | ||
99 | uint64_t perm, uint64_t shared, | ||
100 | uint64_t *nperm, uint64_t *nshared) | ||
101 | { | ||
102 | @@ -XXX,XX +XXX,XX @@ void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
103 | |||
104 | void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
105 | const BdrvChildRole *role, | ||
106 | + BlockReopenQueue *reopen_queue, | ||
107 | uint64_t perm, uint64_t shared, | ||
108 | uint64_t *nperm, uint64_t *nshared) | ||
109 | { | ||
110 | @@ -XXX,XX +XXX,XX @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, | ||
111 | if (!backing) { | ||
112 | /* Apart from the modifications below, the same permissions are | ||
113 | * forwarded and left alone as for filters */ | ||
114 | - bdrv_filter_default_perms(bs, c, role, perm, shared, &perm, &shared); | ||
115 | + bdrv_filter_default_perms(bs, c, role, reopen_queue, perm, shared, | ||
116 | + &perm, &shared); | ||
117 | |||
118 | /* Format drivers may touch metadata even if the guest doesn't write */ | ||
119 | + /* TODO Take flags from reopen_queue */ | ||
120 | if (bdrv_is_writable(bs)) { | ||
121 | perm |= BLK_PERM_WRITE | BLK_PERM_RESIZE; | ||
122 | } | ||
123 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, | ||
124 | |||
125 | assert(parent_bs->drv); | ||
126 | assert(bdrv_get_aio_context(parent_bs) == bdrv_get_aio_context(child_bs)); | ||
127 | - bdrv_child_perm(parent_bs, child_bs, NULL, child_role, | ||
128 | + bdrv_child_perm(parent_bs, child_bs, NULL, child_role, NULL, | ||
129 | perm, shared_perm, &perm, &shared_perm); | ||
130 | |||
131 | child = bdrv_root_attach_child(child_bs, child_name, child_role, | ||
132 | diff --git a/block/commit.c b/block/commit.c | ||
133 | index XXXXXXX..XXXXXXX 100644 | ||
134 | --- a/block/commit.c | ||
135 | +++ b/block/commit.c | ||
136 | @@ -XXX,XX +XXX,XX @@ static void bdrv_commit_top_close(BlockDriverState *bs) | ||
137 | |||
138 | static void bdrv_commit_top_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
139 | const BdrvChildRole *role, | ||
140 | + BlockReopenQueue *reopen_queue, | ||
141 | uint64_t perm, uint64_t shared, | ||
142 | uint64_t *nperm, uint64_t *nshared) | ||
143 | { | ||
144 | diff --git a/block/mirror.c b/block/mirror.c | ||
145 | index XXXXXXX..XXXXXXX 100644 | ||
146 | --- a/block/mirror.c | ||
147 | +++ b/block/mirror.c | ||
148 | @@ -XXX,XX +XXX,XX @@ static void bdrv_mirror_top_close(BlockDriverState *bs) | ||
149 | |||
150 | static void bdrv_mirror_top_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
151 | const BdrvChildRole *role, | ||
152 | + BlockReopenQueue *reopen_queue, | ||
153 | uint64_t perm, uint64_t shared, | ||
154 | uint64_t *nperm, uint64_t *nshared) | ||
155 | { | ||
156 | diff --git a/block/replication.c b/block/replication.c | 25 | diff --git a/block/replication.c b/block/replication.c |
157 | index XXXXXXX..XXXXXXX 100644 | 26 | index XXXXXXX..XXXXXXX 100644 |
158 | --- a/block/replication.c | 27 | --- a/block/replication.c |
159 | +++ b/block/replication.c | 28 | +++ b/block/replication.c |
160 | @@ -XXX,XX +XXX,XX @@ static void replication_close(BlockDriverState *bs) | 29 | @@ -XXX,XX +XXX,XX @@ static void replication_child_perm(BlockDriverState *bs, BdrvChild *c, |
161 | |||
162 | static void replication_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
163 | const BdrvChildRole *role, | ||
164 | + BlockReopenQueue *reopen_queue, | ||
165 | uint64_t perm, uint64_t shared, | 30 | uint64_t perm, uint64_t shared, |
166 | uint64_t *nperm, uint64_t *nshared) | 31 | uint64_t *nperm, uint64_t *nshared) |
167 | { | 32 | { |
168 | diff --git a/block/vvfat.c b/block/vvfat.c | 33 | - *nperm = BLK_PERM_CONSISTENT_READ; |
169 | index XXXXXXX..XXXXXXX 100644 | 34 | + if (role & BDRV_CHILD_PRIMARY) { |
170 | --- a/block/vvfat.c | 35 | + *nperm = BLK_PERM_CONSISTENT_READ; |
171 | +++ b/block/vvfat.c | 36 | + } else { |
172 | @@ -XXX,XX +XXX,XX @@ err: | 37 | + *nperm = 0; |
173 | 38 | + } | |
174 | static void vvfat_child_perm(BlockDriverState *bs, BdrvChild *c, | 39 | + |
175 | const BdrvChildRole *role, | 40 | if ((bs->open_flags & (BDRV_O_INACTIVE | BDRV_O_RDWR)) == BDRV_O_RDWR) { |
176 | + BlockReopenQueue *reopen_queue, | 41 | *nperm |= BLK_PERM_WRITE; |
177 | uint64_t perm, uint64_t shared, | 42 | } |
178 | uint64_t *nperm, uint64_t *nshared) | 43 | @@ -XXX,XX +XXX,XX @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, |
179 | { | 44 | return; |
45 | } | ||
46 | |||
47 | - s->hidden_disk = hidden_disk; | ||
48 | - s->secondary_disk = secondary_disk; | ||
49 | + bdrv_ref(hidden_disk->bs); | ||
50 | + s->hidden_disk = bdrv_attach_child(bs, hidden_disk->bs, "hidden disk", | ||
51 | + &child_of_bds, BDRV_CHILD_DATA, | ||
52 | + &local_err); | ||
53 | + if (local_err) { | ||
54 | + error_propagate(errp, local_err); | ||
55 | + aio_context_release(aio_context); | ||
56 | + return; | ||
57 | + } | ||
58 | + | ||
59 | + bdrv_ref(secondary_disk->bs); | ||
60 | + s->secondary_disk = bdrv_attach_child(bs, secondary_disk->bs, | ||
61 | + "secondary disk", &child_of_bds, | ||
62 | + BDRV_CHILD_DATA, &local_err); | ||
63 | + if (local_err) { | ||
64 | + error_propagate(errp, local_err); | ||
65 | + aio_context_release(aio_context); | ||
66 | + return; | ||
67 | + } | ||
68 | |||
69 | /* start backup job now */ | ||
70 | error_setg(&s->blocker, | ||
71 | @@ -XXX,XX +XXX,XX @@ static void replication_done(void *opaque, int ret) | ||
72 | if (ret == 0) { | ||
73 | s->stage = BLOCK_REPLICATION_DONE; | ||
74 | |||
75 | + bdrv_unref_child(bs, s->secondary_disk); | ||
76 | s->secondary_disk = NULL; | ||
77 | + bdrv_unref_child(bs, s->hidden_disk); | ||
78 | s->hidden_disk = NULL; | ||
79 | s->error = 0; | ||
80 | } else { | ||
180 | -- | 81 | -- |
181 | 2.13.5 | 82 | 2.31.1 |
182 | 83 | ||
183 | 84 | diff view generated by jsdifflib |
1 | We will calculate the required new permissions in the prepare stage of a | 1 | From: Lukas Straub <lukasstraub2@web.de> |
---|---|---|---|
2 | reopen. Required permissions of children can be influenced by the | ||
3 | changes made to their parents, but parents are independent from their | ||
4 | children. This means that permissions need to be calculated top-down. In | ||
5 | order to achieve this, queue parents before their children rather than | ||
6 | queuing the children first. | ||
7 | 2 | ||
3 | Remove the workaround introduced in commit | ||
4 | 6ecbc6c52672db5c13805735ca02784879ce8285 | ||
5 | "replication: Avoid blk_make_empty() on read-only child". | ||
6 | |||
7 | It is not needed anymore since s->hidden_disk is guaranteed to be | ||
8 | writable when secondary_do_checkpoint() runs. Because replication_start(), | ||
9 | _do_checkpoint() and _stop() are only called by COLO migration code | ||
10 | and COLO-migration activates all disks via bdrv_invalidate_cache_all() | ||
11 | before it calls these functions. | ||
12 | |||
13 | Signed-off-by: Lukas Straub <lukasstraub2@web.de> | ||
14 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
15 | Message-Id: <d3acfad43879e9f376bffa7dd797ae74d0a7c81a.1626619393.git.lukasstraub2@web.de> | ||
8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 16 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
9 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
10 | --- | 17 | --- |
11 | block.c | 26 +++++++++++++------------- | 18 | block/replication.c | 12 +----------- |
12 | 1 file changed, 13 insertions(+), 13 deletions(-) | 19 | 1 file changed, 1 insertion(+), 11 deletions(-) |
13 | 20 | ||
14 | diff --git a/block.c b/block.c | 21 | diff --git a/block/replication.c b/block/replication.c |
15 | index XXXXXXX..XXXXXXX 100644 | 22 | index XXXXXXX..XXXXXXX 100644 |
16 | --- a/block.c | 23 | --- a/block/replication.c |
17 | +++ b/block.c | 24 | +++ b/block/replication.c |
18 | @@ -XXX,XX +XXX,XX @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, | 25 | @@ -XXX,XX +XXX,XX @@ static void secondary_do_checkpoint(BlockDriverState *bs, Error **errp) |
19 | flags |= BDRV_O_ALLOW_RDWR; | 26 | return; |
20 | } | 27 | } |
21 | 28 | ||
22 | + if (!bs_entry) { | 29 | - BlockBackend *blk = blk_new(qemu_get_current_aio_context(), |
23 | + bs_entry = g_new0(BlockReopenQueueEntry, 1); | 30 | - BLK_PERM_WRITE, BLK_PERM_ALL); |
24 | + QSIMPLEQ_INSERT_TAIL(bs_queue, bs_entry, entry); | 31 | - blk_insert_bs(blk, s->hidden_disk->bs, &local_err); |
25 | + } else { | 32 | - if (local_err) { |
26 | + QDECREF(bs_entry->state.options); | 33 | - error_propagate(errp, local_err); |
27 | + QDECREF(bs_entry->state.explicit_options); | 34 | - blk_unref(blk); |
28 | + } | 35 | - return; |
29 | + | ||
30 | + bs_entry->state.bs = bs; | ||
31 | + bs_entry->state.options = options; | ||
32 | + bs_entry->state.explicit_options = explicit_options; | ||
33 | + bs_entry->state.flags = flags; | ||
34 | + | ||
35 | QLIST_FOREACH(child, &bs->children, next) { | ||
36 | QDict *new_child_options; | ||
37 | char *child_key_dot; | ||
38 | @@ -XXX,XX +XXX,XX @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, | ||
39 | child->role, options, flags); | ||
40 | } | ||
41 | |||
42 | - if (!bs_entry) { | ||
43 | - bs_entry = g_new0(BlockReopenQueueEntry, 1); | ||
44 | - QSIMPLEQ_INSERT_TAIL(bs_queue, bs_entry, entry); | ||
45 | - } else { | ||
46 | - QDECREF(bs_entry->state.options); | ||
47 | - QDECREF(bs_entry->state.explicit_options); | ||
48 | - } | 36 | - } |
49 | - | 37 | - |
50 | - bs_entry->state.bs = bs; | 38 | - ret = blk_make_empty(blk, errp); |
51 | - bs_entry->state.options = options; | 39 | - blk_unref(blk); |
52 | - bs_entry->state.explicit_options = explicit_options; | 40 | + ret = bdrv_make_empty(s->hidden_disk, errp); |
53 | - bs_entry->state.flags = flags; | 41 | if (ret < 0) { |
54 | - | 42 | return; |
55 | return bs_queue; | 43 | } |
56 | } | ||
57 | |||
58 | -- | 44 | -- |
59 | 2.13.5 | 45 | 2.31.1 |
60 | 46 | ||
61 | 47 | diff view generated by jsdifflib |
1 | From: Thomas Huth <thuth@redhat.com> | 1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> |
---|---|---|---|
2 | 2 | ||
3 | Remove the unnecessary home-grown redefinition of the assert() macro here, | 3 | Most probably this fake backing child doesn't work anyway (see notes |
4 | and remove the unusable debug code at the end of the checkpoint() function. | 4 | about it in a8a4d15c1c34d). |
5 | The code there uses assert() with side-effects (assignment to the "mapping" | ||
6 | variable), which should be avoided. Looking more closely, it seems as it is | ||
7 | apparently also only usable for one certain directory layout (with a file | ||
8 | named USB.H in it) and thus is of no use for the rest of the world. | ||
9 | 5 | ||
10 | Signed-off-by: Thomas Huth <thuth@redhat.com> | 6 | Still, since 25f78d9e2de528473d52 drivers are required to set |
11 | Reviewed-by: John Snow <jsnow@redhat.com> | 7 | .supports_backing if they want to call bdrv_set_backing_hd, so now |
12 | Reviewed-by: Eric Blake <eblake@redhat.com> | 8 | vvfat just doesn't work because of this check. |
9 | |||
10 | Let's finally drop this fake backing file. | ||
11 | |||
12 | Fixes: 25f78d9e2de528473d52acfcf7acdfb64e3453d4 | ||
13 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
14 | Message-Id: <20210715124853.13335-1-vsementsov@virtuozzo.com> | ||
15 | Tested-by: John Arbuckle <programmingkidx@gmail.com> | ||
13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 16 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
14 | --- | 17 | --- |
15 | block/vvfat.c | 26 ++------------------------ | 18 | block/vvfat.c | 43 ++++--------------------------------------- |
16 | 1 file changed, 2 insertions(+), 24 deletions(-) | 19 | 1 file changed, 4 insertions(+), 39 deletions(-) |
17 | 20 | ||
18 | diff --git a/block/vvfat.c b/block/vvfat.c | 21 | diff --git a/block/vvfat.c b/block/vvfat.c |
19 | index XXXXXXX..XXXXXXX 100644 | 22 | index XXXXXXX..XXXXXXX 100644 |
20 | --- a/block/vvfat.c | 23 | --- a/block/vvfat.c |
21 | +++ b/block/vvfat.c | 24 | +++ b/block/vvfat.c |
22 | @@ -XXX,XX +XXX,XX @@ | 25 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn vvfat_co_block_status(BlockDriverState *bs, |
23 | 26 | return BDRV_BLOCK_DATA; | |
24 | static void checkpoint(void); | 27 | } |
25 | 28 | ||
26 | -#ifdef __MINGW32__ | 29 | -static int coroutine_fn |
27 | -void nonono(const char* file, int line, const char* msg) { | 30 | -write_target_commit(BlockDriverState *bs, uint64_t offset, uint64_t bytes, |
28 | - fprintf(stderr, "Nonono! %s:%d %s\n", file, line, msg); | 31 | - QEMUIOVector *qiov, int flags) |
29 | - exit(-5); | 32 | -{ |
33 | - int ret; | ||
34 | - | ||
35 | - BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque); | ||
36 | - qemu_co_mutex_lock(&s->lock); | ||
37 | - ret = try_commit(s); | ||
38 | - qemu_co_mutex_unlock(&s->lock); | ||
39 | - | ||
40 | - return ret; | ||
30 | -} | 41 | -} |
31 | -#undef assert | ||
32 | -#define assert(a) do {if (!(a)) nonono(__FILE__, __LINE__, #a);}while(0) | ||
33 | -#endif | ||
34 | - | 42 | - |
35 | #else | 43 | -static BlockDriver vvfat_write_target = { |
36 | 44 | - .format_name = "vvfat_write_target", | |
37 | #define DLOG(a) | 45 | - .instance_size = sizeof(void*), |
38 | @@ -XXX,XX +XXX,XX @@ static void bdrv_vvfat_init(void) | 46 | - .bdrv_co_pwritev = write_target_commit, |
39 | block_init(bdrv_vvfat_init); | 47 | -}; |
40 | 48 | - | |
41 | #ifdef DEBUG | 49 | static void vvfat_qcow_options(BdrvChildRole role, bool parent_is_format, |
42 | -static void checkpoint(void) { | 50 | int *child_flags, QDict *child_options, |
43 | +static void checkpoint(void) | 51 | int parent_flags, QDict *parent_options) |
44 | +{ | 52 | @@ -XXX,XX +XXX,XX @@ static int enable_write_target(BlockDriverState *bs, Error **errp) |
45 | assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2); | 53 | { |
46 | check1(vvv); | 54 | BDRVVVFATState *s = bs->opaque; |
47 | check2(vvv); | 55 | BlockDriver *bdrv_qcow = NULL; |
48 | assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY)); | 56 | - BlockDriverState *backing; |
49 | -#if 0 | 57 | QemuOpts *opts = NULL; |
50 | - if (((direntry_t*)vvv->directory.pointer)[1].attributes != 0xf) | 58 | int ret; |
51 | - fprintf(stderr, "Nonono!\n"); | 59 | int size = sector2cluster(s, s->sector_count); |
52 | - mapping_t* mapping; | 60 | @@ -XXX,XX +XXX,XX @@ static int enable_write_target(BlockDriverState *bs, Error **errp) |
53 | - direntry_t* direntry; | 61 | unlink(s->qcow_filename); |
54 | - assert(vvv->mapping.size >= vvv->mapping.item_size * vvv->mapping.next); | 62 | #endif |
55 | - assert(vvv->directory.size >= vvv->directory.item_size * vvv->directory.next); | 63 | |
56 | - if (vvv->mapping.next<47) | 64 | - backing = bdrv_new_open_driver(&vvfat_write_target, NULL, BDRV_O_ALLOW_RDWR, |
57 | - return; | 65 | - &error_abort); |
58 | - assert((mapping = array_get(&(vvv->mapping), 47))); | 66 | - *(void**) backing->opaque = s; |
59 | - assert(mapping->dir_index < vvv->directory.next); | 67 | - |
60 | - direntry = array_get(&(vvv->directory), mapping->dir_index); | 68 | - bdrv_set_backing_hd(s->bs, backing, &error_abort); |
61 | - assert(!memcmp(direntry->name, "USB H ", 11) || direntry->name[0]==0); | 69 | - bdrv_unref(backing); |
62 | -#endif | 70 | - |
71 | return 0; | ||
72 | |||
73 | err: | ||
74 | @@ -XXX,XX +XXX,XX @@ static void vvfat_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
75 | uint64_t perm, uint64_t shared, | ||
76 | uint64_t *nperm, uint64_t *nshared) | ||
77 | { | ||
78 | - if (role & BDRV_CHILD_DATA) { | ||
79 | - /* This is a private node, nobody should try to attach to it */ | ||
80 | - *nperm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE; | ||
81 | - *nshared = BLK_PERM_WRITE_UNCHANGED; | ||
82 | - } else { | ||
83 | - assert(role & BDRV_CHILD_COW); | ||
84 | - /* The backing file is there so 'commit' can use it. vvfat doesn't | ||
85 | - * access it in any way. */ | ||
86 | - *nperm = 0; | ||
87 | - *nshared = BLK_PERM_ALL; | ||
88 | - } | ||
89 | + assert(role & BDRV_CHILD_DATA); | ||
90 | + /* This is a private node, nobody should try to attach to it */ | ||
91 | + *nperm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE; | ||
92 | + *nshared = BLK_PERM_WRITE_UNCHANGED; | ||
63 | } | 93 | } |
64 | #endif | 94 | |
95 | static void vvfat_close(BlockDriverState *bs) | ||
65 | -- | 96 | -- |
66 | 2.13.5 | 97 | 2.31.1 |
67 | 98 | ||
68 | 99 | diff view generated by jsdifflib |
1 | This involves a temporary read-write reopen if the backing file link in | 1 | From: Max Reitz <mreitz@redhat.com> |
---|---|---|---|
2 | the middle of a backing file chain should be changed and is therefore a | ||
3 | good test for the latest bdrv_reopen() vs. op blockers fixes. | ||
4 | 2 | ||
3 | When invoking block-export-add with some iothread and | ||
4 | fixed-iothread=false, and changing the node's iothread fails, the error | ||
5 | is supposed to be ignored. | ||
6 | |||
7 | However, it is still stored in *errp, which is wrong. If a second error | ||
8 | occurs, the "*errp must be NULL" assertion in error_setv() fails: | ||
9 | |||
10 | qemu-system-x86_64: ../util/error.c:59: error_setv: Assertion | ||
11 | `*errp == NULL' failed. | ||
12 | |||
13 | So if fixed-iothread=false, we should ignore the error by passing NULL | ||
14 | to bdrv_try_set_aio_context(). | ||
15 | |||
16 | Fixes: f51d23c80af73c95e0ce703ad06a300f1b3d63ef | ||
17 | ("block/export: add iothread and fixed-iothread options") | ||
18 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
19 | Message-Id: <20210624083825.29224-2-mreitz@redhat.com> | ||
20 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 21 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
6 | --- | 22 | --- |
7 | tests/qemu-iotests/195 | 92 ++++++++++++++++++++++++++++++++++++++++++++++ | 23 | block/export/export.c | 5 ++++- |
8 | tests/qemu-iotests/195.out | 78 +++++++++++++++++++++++++++++++++++++++ | 24 | 1 file changed, 4 insertions(+), 1 deletion(-) |
9 | tests/qemu-iotests/group | 1 + | ||
10 | 3 files changed, 171 insertions(+) | ||
11 | create mode 100755 tests/qemu-iotests/195 | ||
12 | create mode 100644 tests/qemu-iotests/195.out | ||
13 | 25 | ||
14 | diff --git a/tests/qemu-iotests/195 b/tests/qemu-iotests/195 | 26 | diff --git a/block/export/export.c b/block/export/export.c |
15 | new file mode 100755 | ||
16 | index XXXXXXX..XXXXXXX | ||
17 | --- /dev/null | ||
18 | +++ b/tests/qemu-iotests/195 | ||
19 | @@ -XXX,XX +XXX,XX @@ | ||
20 | +#!/bin/bash | ||
21 | +# | ||
22 | +# Test change-backing-file command | ||
23 | +# | ||
24 | +# Copyright (C) 2017 Red Hat, Inc. | ||
25 | +# | ||
26 | +# This program is free software; you can redistribute it and/or modify | ||
27 | +# it under the terms of the GNU General Public License as published by | ||
28 | +# the Free Software Foundation; either version 2 of the License, or | ||
29 | +# (at your option) any later version. | ||
30 | +# | ||
31 | +# This program is distributed in the hope that it will be useful, | ||
32 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
33 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
34 | +# GNU General Public License for more details. | ||
35 | +# | ||
36 | +# You should have received a copy of the GNU General Public License | ||
37 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
38 | +# | ||
39 | + | ||
40 | +# creator | ||
41 | +owner=kwolf@redhat.com | ||
42 | + | ||
43 | +seq=`basename $0` | ||
44 | +echo "QA output created by $seq" | ||
45 | + | ||
46 | +here=`pwd` | ||
47 | +status=1 # failure is the default! | ||
48 | + | ||
49 | +_cleanup() | ||
50 | +{ | ||
51 | + _cleanup_test_img | ||
52 | + rm -f "$TEST_IMG.mid" | ||
53 | +} | ||
54 | +trap "_cleanup; exit \$status" 0 1 2 3 15 | ||
55 | + | ||
56 | +# get standard environment, filters and checks | ||
57 | +. ./common.rc | ||
58 | +. ./common.filter | ||
59 | + | ||
60 | +_supported_fmt qcow2 | ||
61 | +_supported_proto file | ||
62 | +_supported_os Linux | ||
63 | + | ||
64 | +function do_run_qemu() | ||
65 | +{ | ||
66 | + echo Testing: "$@" | _filter_imgfmt | ||
67 | + $QEMU -nographic -qmp-pretty stdio -serial none "$@" | ||
68 | + echo | ||
69 | +} | ||
70 | + | ||
71 | +function run_qemu() | ||
72 | +{ | ||
73 | + do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp \ | ||
74 | + | _filter_qemu_io | _filter_generated_node_ids | ||
75 | +} | ||
76 | + | ||
77 | +size=64M | ||
78 | +TEST_IMG="$TEST_IMG.base" _make_test_img $size | ||
79 | +TEST_IMG="$TEST_IMG.mid" _make_test_img -b "$TEST_IMG.base" | ||
80 | +_make_test_img -b "$TEST_IMG.mid" | ||
81 | + | ||
82 | +echo | ||
83 | +echo "Change backing file of mid (opened read-only)" | ||
84 | +echo | ||
85 | + | ||
86 | +run_qemu -drive if=none,file="$TEST_IMG",backing.node-name=mid <<EOF | ||
87 | +{"execute":"qmp_capabilities"} | ||
88 | +{"execute":"change-backing-file", "arguments":{"device":"none0","image-node-name":"mid","backing-file":"/dev/null"}} | ||
89 | +{"execute":"quit"} | ||
90 | +EOF | ||
91 | + | ||
92 | +TEST_IMG="$TEST_IMG.mid" _img_info | ||
93 | + | ||
94 | +echo | ||
95 | +echo "Change backing file of top (opened writable)" | ||
96 | +echo | ||
97 | + | ||
98 | +TEST_IMG="$TEST_IMG.mid" _make_test_img -b "$TEST_IMG.base" | ||
99 | + | ||
100 | +run_qemu -drive if=none,file="$TEST_IMG",node-name=top <<EOF | ||
101 | +{"execute":"qmp_capabilities"} | ||
102 | +{"execute":"change-backing-file", "arguments":{"device":"none0","image-node-name":"top","backing-file":"/dev/null"}} | ||
103 | +{"execute":"quit"} | ||
104 | +EOF | ||
105 | + | ||
106 | +_img_info | ||
107 | + | ||
108 | +# success, all done | ||
109 | +echo "*** done" | ||
110 | +rm -f $seq.full | ||
111 | +status=0 | ||
112 | diff --git a/tests/qemu-iotests/195.out b/tests/qemu-iotests/195.out | ||
113 | new file mode 100644 | ||
114 | index XXXXXXX..XXXXXXX | ||
115 | --- /dev/null | ||
116 | +++ b/tests/qemu-iotests/195.out | ||
117 | @@ -XXX,XX +XXX,XX @@ | ||
118 | +QA output created by 195 | ||
119 | +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 | ||
120 | +Formatting 'TEST_DIR/t.IMGFMT.mid', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base | ||
121 | +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.mid | ||
122 | + | ||
123 | +Change backing file of mid (opened read-only) | ||
124 | + | ||
125 | +Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,backing.node-name=mid | ||
126 | +{ | ||
127 | + QMP_VERSION | ||
128 | +} | ||
129 | +{ | ||
130 | + "return": { | ||
131 | + } | ||
132 | +} | ||
133 | +{ | ||
134 | + "return": { | ||
135 | + } | ||
136 | +} | ||
137 | +{ | ||
138 | + "return": { | ||
139 | + } | ||
140 | +} | ||
141 | +{ | ||
142 | + "timestamp": { | ||
143 | + "seconds": TIMESTAMP, | ||
144 | + "microseconds": TIMESTAMP | ||
145 | + }, | ||
146 | + "event": "SHUTDOWN", | ||
147 | + "data": { | ||
148 | + "guest": false | ||
149 | + } | ||
150 | +} | ||
151 | + | ||
152 | +image: TEST_DIR/t.IMGFMT.mid | ||
153 | +file format: IMGFMT | ||
154 | +virtual size: 64M (67108864 bytes) | ||
155 | +cluster_size: 65536 | ||
156 | +backing file: /dev/null | ||
157 | +backing file format: IMGFMT | ||
158 | + | ||
159 | +Change backing file of top (opened writable) | ||
160 | + | ||
161 | +Formatting 'TEST_DIR/t.IMGFMT.mid', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base | ||
162 | +Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,node-name=top | ||
163 | +{ | ||
164 | + QMP_VERSION | ||
165 | +} | ||
166 | +{ | ||
167 | + "return": { | ||
168 | + } | ||
169 | +} | ||
170 | +{ | ||
171 | + "return": { | ||
172 | + } | ||
173 | +} | ||
174 | +{ | ||
175 | + "return": { | ||
176 | + } | ||
177 | +} | ||
178 | +{ | ||
179 | + "timestamp": { | ||
180 | + "seconds": TIMESTAMP, | ||
181 | + "microseconds": TIMESTAMP | ||
182 | + }, | ||
183 | + "event": "SHUTDOWN", | ||
184 | + "data": { | ||
185 | + "guest": false | ||
186 | + } | ||
187 | +} | ||
188 | + | ||
189 | +image: TEST_DIR/t.IMGFMT | ||
190 | +file format: IMGFMT | ||
191 | +virtual size: 64M (67108864 bytes) | ||
192 | +cluster_size: 65536 | ||
193 | +backing file: /dev/null | ||
194 | +backing file format: IMGFMT | ||
195 | +*** done | ||
196 | diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group | ||
197 | index XXXXXXX..XXXXXXX 100644 | 27 | index XXXXXXX..XXXXXXX 100644 |
198 | --- a/tests/qemu-iotests/group | 28 | --- a/block/export/export.c |
199 | +++ b/tests/qemu-iotests/group | 29 | +++ b/block/export/export.c |
200 | @@ -XXX,XX +XXX,XX @@ | 30 | @@ -XXX,XX +XXX,XX @@ BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp) |
201 | 190 rw auto quick | 31 | if (export->has_iothread) { |
202 | 192 rw auto quick | 32 | IOThread *iothread; |
203 | 194 rw auto migration quick | 33 | AioContext *new_ctx; |
204 | +195 rw auto quick | 34 | + Error **set_context_errp; |
35 | |||
36 | iothread = iothread_by_id(export->iothread); | ||
37 | if (!iothread) { | ||
38 | @@ -XXX,XX +XXX,XX @@ BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp) | ||
39 | |||
40 | new_ctx = iothread_get_aio_context(iothread); | ||
41 | |||
42 | - ret = bdrv_try_set_aio_context(bs, new_ctx, errp); | ||
43 | + /* Ignore errors with fixed-iothread=false */ | ||
44 | + set_context_errp = fixed_iothread ? errp : NULL; | ||
45 | + ret = bdrv_try_set_aio_context(bs, new_ctx, set_context_errp); | ||
46 | if (ret == 0) { | ||
47 | aio_context_release(ctx); | ||
48 | aio_context_acquire(new_ctx); | ||
205 | -- | 49 | -- |
206 | 2.13.5 | 50 | 2.31.1 |
207 | 51 | ||
208 | 52 | diff view generated by jsdifflib |
1 | From: Fam Zheng <famz@redhat.com> | 1 | From: Max Reitz <mreitz@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | People get surprised when, after "qemu-img create -f raw /dev/sdX", they | 3 | Passing fixed-iothread=true should make iothread conflicts fatal, |
4 | still see qcow2 with "qemu-img info", if previously the bdev had a qcow2 | 4 | whereas fixed-iothread=false should not. |
5 | header. While this is natural because raw doesn't need to write any | ||
6 | magic bytes during creation, hdev_create is free to clear out the first | ||
7 | sector to make sure the stale qcow2 header doesn't cause such confusion. | ||
8 | 5 | ||
9 | Signed-off-by: Fam Zheng <famz@redhat.com> | 6 | Combine the second case with an error condition that is checked after |
7 | the iothread is handled, to verify that qemu does not crash if there is | ||
8 | such an error after changing the iothread failed. | ||
9 | |||
10 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
11 | Message-Id: <20210624083825.29224-3-mreitz@redhat.com> | ||
12 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
13 | Tested-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
11 | --- | 15 | --- |
12 | block/file-posix.c | 10 ++++++++++ | 16 | tests/qemu-iotests/307 | 15 +++++++++++++++ |
13 | 1 file changed, 10 insertions(+) | 17 | tests/qemu-iotests/307.out | 8 ++++++++ |
18 | 2 files changed, 23 insertions(+) | ||
14 | 19 | ||
15 | diff --git a/block/file-posix.c b/block/file-posix.c | 20 | diff --git a/tests/qemu-iotests/307 b/tests/qemu-iotests/307 |
21 | index XXXXXXX..XXXXXXX 100755 | ||
22 | --- a/tests/qemu-iotests/307 | ||
23 | +++ b/tests/qemu-iotests/307 | ||
24 | @@ -XXX,XX +XXX,XX @@ with iotests.FilePath('image') as img, \ | ||
25 | iotests.log('=== Launch VM ===') | ||
26 | |||
27 | vm.add_object('iothread,id=iothread0') | ||
28 | + vm.add_object('iothread,id=iothread1') | ||
29 | vm.add_blockdev(f'file,filename={img},node-name=file') | ||
30 | vm.add_blockdev(f'{iotests.imgfmt},file=file,node-name=fmt') | ||
31 | vm.add_blockdev('raw,file=file,node-name=ro,read-only=on') | ||
32 | + vm.add_blockdev('null-co,node-name=null') | ||
33 | vm.add_device(f'id=scsi0,driver=virtio-scsi,iothread=iothread0') | ||
34 | vm.launch() | ||
35 | |||
36 | @@ -XXX,XX +XXX,XX @@ with iotests.FilePath('image') as img, \ | ||
37 | vm.qmp_log('query-block-exports') | ||
38 | iotests.qemu_nbd_list_log('-k', socket) | ||
39 | |||
40 | + iotests.log('\n=== Add export with conflicting iothread ===') | ||
41 | + | ||
42 | + vm.qmp_log('device_add', id='sdb', driver='scsi-hd', drive='null') | ||
43 | + | ||
44 | + # Should fail because of fixed-iothread | ||
45 | + vm.qmp_log('block-export-add', id='export1', type='nbd', node_name='null', | ||
46 | + iothread='iothread1', fixed_iothread=True, writable=True) | ||
47 | + | ||
48 | + # Should ignore the iothread conflict, but then fail because of the | ||
49 | + # permission conflict (and not crash) | ||
50 | + vm.qmp_log('block-export-add', id='export1', type='nbd', node_name='null', | ||
51 | + iothread='iothread1', fixed_iothread=False, writable=True) | ||
52 | + | ||
53 | iotests.log('\n=== Add a writable export ===') | ||
54 | |||
55 | # This fails because share-rw=off | ||
56 | diff --git a/tests/qemu-iotests/307.out b/tests/qemu-iotests/307.out | ||
16 | index XXXXXXX..XXXXXXX 100644 | 57 | index XXXXXXX..XXXXXXX 100644 |
17 | --- a/block/file-posix.c | 58 | --- a/tests/qemu-iotests/307.out |
18 | +++ b/block/file-posix.c | 59 | +++ b/tests/qemu-iotests/307.out |
19 | @@ -XXX,XX +XXX,XX @@ static int hdev_create(const char *filename, QemuOpts *opts, | 60 | @@ -XXX,XX +XXX,XX @@ exports available: 1 |
20 | ret = -ENOSPC; | 61 | base:allocation |
21 | } | 62 | |
22 | 63 | ||
23 | + if (!ret && total_size) { | 64 | +=== Add export with conflicting iothread === |
24 | + uint8_t buf[BDRV_SECTOR_SIZE] = { 0 }; | 65 | +{"execute": "device_add", "arguments": {"drive": "null", "driver": "scsi-hd", "id": "sdb"}} |
25 | + int64_t zero_size = MIN(BDRV_SECTOR_SIZE, total_size); | 66 | +{"return": {}} |
26 | + if (lseek(fd, 0, SEEK_SET) == -1) { | 67 | +{"execute": "block-export-add", "arguments": {"fixed-iothread": true, "id": "export1", "iothread": "iothread1", "node-name": "null", "type": "nbd", "writable": true}} |
27 | + ret = -errno; | 68 | +{"error": {"class": "GenericError", "desc": "Cannot change iothread of active block backend"}} |
28 | + } else { | 69 | +{"execute": "block-export-add", "arguments": {"fixed-iothread": false, "id": "export1", "iothread": "iothread1", "node-name": "null", "type": "nbd", "writable": true}} |
29 | + ret = qemu_write_full(fd, buf, zero_size); | 70 | +{"error": {"class": "GenericError", "desc": "Permission conflict on node 'null': permissions 'write' are both required by an unnamed block device (uses node 'null' as 'root' child) and unshared by block device 'sdb' (uses node 'null' as 'root' child)."}} |
30 | + ret = ret == zero_size ? 0 : -errno; | 71 | + |
31 | + } | 72 | === Add a writable export === |
32 | + } | 73 | {"execute": "block-export-add", "arguments": {"description": "This is the writable second export", "id": "export1", "name": "export1", "node-name": "fmt", "type": "nbd", "writable": true, "writethrough": true}} |
33 | qemu_close(fd); | 74 | {"error": {"class": "GenericError", "desc": "Permission conflict on node 'fmt': permissions 'write' are both required by an unnamed block device (uses node 'fmt' as 'root' child) and unshared by block device 'sda' (uses node 'fmt' as 'root' child)."}} |
34 | return ret; | ||
35 | } | ||
36 | -- | 75 | -- |
37 | 2.13.5 | 76 | 2.31.1 |
38 | 77 | ||
39 | 78 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Cornelia Huck <cohuck@redhat.com> | ||
2 | 1 | ||
3 | The default cpu model on s390x does not provide zPCI, which is | ||
4 | not yet wired up on tcg. Moreover, virtio-ccw is the standard | ||
5 | on s390x, so use the -ccw instead of the -pci versions of virtio | ||
6 | devices on s390x. | ||
7 | |||
8 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
9 | Signed-off-by: Cornelia Huck <cohuck@redhat.com> | ||
10 | Reviewed-by: QingFeng Hao <haoqf@linux.vnet.ibm.com> | ||
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
12 | --- | ||
13 | tests/qemu-iotests/040 | 6 +++++- | ||
14 | tests/qemu-iotests/139 | 12 ++++++++++-- | ||
15 | tests/qemu-iotests/182 | 13 +++++++++++-- | ||
16 | 3 files changed, 26 insertions(+), 5 deletions(-) | ||
17 | |||
18 | diff --git a/tests/qemu-iotests/040 b/tests/qemu-iotests/040 | ||
19 | index XXXXXXX..XXXXXXX 100755 | ||
20 | --- a/tests/qemu-iotests/040 | ||
21 | +++ b/tests/qemu-iotests/040 | ||
22 | @@ -XXX,XX +XXX,XX @@ class TestSingleDrive(ImageCommitTestCase): | ||
23 | qemu_io('-f', 'raw', '-c', 'write -P 0xab 0 524288', backing_img) | ||
24 | qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0xef 524288 524288', mid_img) | ||
25 | self.vm = iotests.VM().add_drive(test_img, "node-name=top,backing.node-name=mid,backing.backing.node-name=base", interface="none") | ||
26 | - self.vm.add_device("virtio-scsi-pci") | ||
27 | + if iotests.qemu_default_machine == 's390-ccw-virtio': | ||
28 | + self.vm.add_device("virtio-scsi-ccw") | ||
29 | + else: | ||
30 | + self.vm.add_device("virtio-scsi-pci") | ||
31 | + | ||
32 | self.vm.add_device("scsi-hd,id=scsi0,drive=drive0") | ||
33 | self.vm.launch() | ||
34 | |||
35 | diff --git a/tests/qemu-iotests/139 b/tests/qemu-iotests/139 | ||
36 | index XXXXXXX..XXXXXXX 100644 | ||
37 | --- a/tests/qemu-iotests/139 | ||
38 | +++ b/tests/qemu-iotests/139 | ||
39 | @@ -XXX,XX +XXX,XX @@ import time | ||
40 | |||
41 | base_img = os.path.join(iotests.test_dir, 'base.img') | ||
42 | new_img = os.path.join(iotests.test_dir, 'new.img') | ||
43 | +if iotests.qemu_default_machine == 's390-ccw-virtio': | ||
44 | + default_virtio_blk = 'virtio-blk-ccw' | ||
45 | +else: | ||
46 | + default_virtio_blk = 'virtio-blk-pci' | ||
47 | |||
48 | class TestBlockdevDel(iotests.QMPTestCase): | ||
49 | |||
50 | def setUp(self): | ||
51 | iotests.qemu_img('create', '-f', iotests.imgfmt, base_img, '1M') | ||
52 | self.vm = iotests.VM() | ||
53 | - self.vm.add_device("virtio-scsi-pci,id=virtio-scsi") | ||
54 | + if iotests.qemu_default_machine == 's390-ccw-virtio': | ||
55 | + self.vm.add_device("virtio-scsi-ccw,id=virtio-scsi") | ||
56 | + else: | ||
57 | + self.vm.add_device("virtio-scsi-pci,id=virtio-scsi") | ||
58 | + | ||
59 | self.vm.launch() | ||
60 | |||
61 | def tearDown(self): | ||
62 | @@ -XXX,XX +XXX,XX @@ class TestBlockdevDel(iotests.QMPTestCase): | ||
63 | self.checkBlockDriverState(node, expect_error) | ||
64 | |||
65 | # Add a device model | ||
66 | - def addDeviceModel(self, device, backend, driver = 'virtio-blk-pci'): | ||
67 | + def addDeviceModel(self, device, backend, driver = default_virtio_blk): | ||
68 | result = self.vm.qmp('device_add', id = device, | ||
69 | driver = driver, drive = backend) | ||
70 | self.assert_qmp(result, 'return', {}) | ||
71 | diff --git a/tests/qemu-iotests/182 b/tests/qemu-iotests/182 | ||
72 | index XXXXXXX..XXXXXXX 100755 | ||
73 | --- a/tests/qemu-iotests/182 | ||
74 | +++ b/tests/qemu-iotests/182 | ||
75 | @@ -XXX,XX +XXX,XX @@ _supported_os Linux | ||
76 | |||
77 | size=32M | ||
78 | |||
79 | +case "$QEMU_DEFAULT_MACHINE" in | ||
80 | + s390-ccw-virtio) | ||
81 | + virtioblk=virtio-blk-ccw | ||
82 | + ;; | ||
83 | + *) | ||
84 | + virtioblk=virtio-blk-pci | ||
85 | + ;; | ||
86 | +esac | ||
87 | + | ||
88 | _make_test_img $size | ||
89 | |||
90 | echo "Starting QEMU" | ||
91 | _launch_qemu -drive file=$TEST_IMG,if=none,id=drive0,file.locking=on \ | ||
92 | - -device virtio-blk-pci,drive=drive0 | ||
93 | + -device $virtioblk,drive=drive0 | ||
94 | |||
95 | echo | ||
96 | echo "Starting a second QEMU using the same image should fail" | ||
97 | echo 'quit' | $QEMU -monitor stdio \ | ||
98 | -drive file=$TEST_IMG,if=none,id=drive0,file.locking=on \ | ||
99 | - -device virtio-blk-pci,drive=drive0 2>&1 | _filter_testdir 2>&1 | | ||
100 | + -device $virtioblk,drive=drive0 2>&1 | _filter_testdir 2>&1 | | ||
101 | _filter_qemu | | ||
102 | sed -e '/falling back to POSIX file/d' \ | ||
103 | -e '/locks can be lost unexpectedly/d' | ||
104 | -- | ||
105 | 2.13.5 | ||
106 | |||
107 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Cornelia Huck <cohuck@redhat.com> | ||
2 | 1 | ||
3 | The default cpu model on s390x does not provide zPCI, which is | ||
4 | not yet wired up on tcg. Moreover, virtio-ccw is the standard | ||
5 | on s390x, so use the -ccw instead of the -pci versions of virtio | ||
6 | devices on s390x. | ||
7 | |||
8 | Signed-off-by: Cornelia Huck <cohuck@redhat.com> | ||
9 | Reviewed-by: QingFeng Hao <haoqf@linux.vnet.ibm.com> | ||
10 | Reviewed-by: David Hildenbrand <david@redhat.com> | ||
11 | Reviewed-by: Thomas Huth <thuth@redhat.com> | ||
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
13 | --- | ||
14 | tests/qemu-iotests/051 | 12 +++++++++++- | ||
15 | tests/qemu-iotests/051.out | 2 +- | ||
16 | tests/qemu-iotests/051.pc.out | 2 +- | ||
17 | 3 files changed, 13 insertions(+), 3 deletions(-) | ||
18 | |||
19 | diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051 | ||
20 | index XXXXXXX..XXXXXXX 100755 | ||
21 | --- a/tests/qemu-iotests/051 | ||
22 | +++ b/tests/qemu-iotests/051 | ||
23 | @@ -XXX,XX +XXX,XX @@ echo | ||
24 | echo === Device without drive === | ||
25 | echo | ||
26 | |||
27 | -run_qemu -device virtio-scsi-pci -device scsi-hd | ||
28 | +case "$QEMU_DEFAULT_MACHINE" in | ||
29 | + s390-ccw-virtio) | ||
30 | + virtio_scsi=virtio-scsi-ccw | ||
31 | + ;; | ||
32 | + *) | ||
33 | + virtio_scsi=virtio-scsi-pci | ||
34 | + ;; | ||
35 | +esac | ||
36 | + | ||
37 | +run_qemu -device $virtio_scsi -device scsi-hd | | ||
38 | + sed -e "s/$virtio_scsi/VIRTIO_SCSI/" | ||
39 | |||
40 | echo | ||
41 | echo === Overriding backing file === | ||
42 | diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out | ||
43 | index XXXXXXX..XXXXXXX 100644 | ||
44 | --- a/tests/qemu-iotests/051.out | ||
45 | +++ b/tests/qemu-iotests/051.out | ||
46 | @@ -XXX,XX +XXX,XX @@ QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=qcow2,format=qcow2: Cannot specif | ||
47 | |||
48 | === Device without drive === | ||
49 | |||
50 | -Testing: -device virtio-scsi-pci -device scsi-hd | ||
51 | +Testing: -device VIRTIO_SCSI -device scsi-hd | ||
52 | QEMU X.Y.Z monitor - type 'help' for more information | ||
53 | (qemu) QEMU_PROG: -device scsi-hd: drive property not set | ||
54 | |||
55 | diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out | ||
56 | index XXXXXXX..XXXXXXX 100644 | ||
57 | --- a/tests/qemu-iotests/051.pc.out | ||
58 | +++ b/tests/qemu-iotests/051.pc.out | ||
59 | @@ -XXX,XX +XXX,XX @@ QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=qcow2,format=qcow2: Cannot specif | ||
60 | |||
61 | === Device without drive === | ||
62 | |||
63 | -Testing: -device virtio-scsi-pci -device scsi-hd | ||
64 | +Testing: -device VIRTIO_SCSI -device scsi-hd | ||
65 | QEMU X.Y.Z monitor - type 'help' for more information | ||
66 | (qemu) QEMU_PROG: -device scsi-hd: drive property not set | ||
67 | |||
68 | -- | ||
69 | 2.13.5 | ||
70 | |||
71 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Cornelia Huck <cohuck@redhat.com> | ||
2 | 1 | ||
3 | The default cpu model on s390x does not provide zPCI, which is | ||
4 | not yet wired up on tcg. Moreover, virtio-ccw is the standard | ||
5 | on s390x. | ||
6 | |||
7 | Using virtio-scsi will implicitly pick the right device, so just | ||
8 | switch to that for simplicity. | ||
9 | |||
10 | Signed-off-by: Cornelia Huck <cohuck@redhat.com> | ||
11 | Reviewed-by: QingFeng Hao <haoqf@linux.vnet.ibm.com> | ||
12 | Reviewed-by: David Hildenbrand <david@redhat.com> | ||
13 | Reviewed-by: Thomas Huth <thuth@redhat.com> | ||
14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
15 | --- | ||
16 | tests/qemu-iotests/067 | 2 +- | ||
17 | tests/qemu-iotests/067.out | 2 +- | ||
18 | 2 files changed, 2 insertions(+), 2 deletions(-) | ||
19 | |||
20 | diff --git a/tests/qemu-iotests/067 b/tests/qemu-iotests/067 | ||
21 | index XXXXXXX..XXXXXXX 100755 | ||
22 | --- a/tests/qemu-iotests/067 | ||
23 | +++ b/tests/qemu-iotests/067 | ||
24 | @@ -XXX,XX +XXX,XX @@ echo | ||
25 | echo === Empty drive with -device and device_del === | ||
26 | echo | ||
27 | |||
28 | -run_qemu -device virtio-scsi-pci -device scsi-cd,id=cd0 <<EOF | ||
29 | +run_qemu -device virtio-scsi -device scsi-cd,id=cd0 <<EOF | ||
30 | { "execute": "qmp_capabilities" } | ||
31 | { "execute": "query-block" } | ||
32 | { "execute": "device_del", "arguments": { "id": "cd0" } } | ||
33 | diff --git a/tests/qemu-iotests/067.out b/tests/qemu-iotests/067.out | ||
34 | index XXXXXXX..XXXXXXX 100644 | ||
35 | --- a/tests/qemu-iotests/067.out | ||
36 | +++ b/tests/qemu-iotests/067.out | ||
37 | @@ -XXX,XX +XXX,XX @@ Testing: | ||
38 | |||
39 | === Empty drive with -device and device_del === | ||
40 | |||
41 | -Testing: -device virtio-scsi-pci -device scsi-cd,id=cd0 | ||
42 | +Testing: -device virtio-scsi -device scsi-cd,id=cd0 | ||
43 | { | ||
44 | QMP_VERSION | ||
45 | } | ||
46 | -- | ||
47 | 2.13.5 | ||
48 | |||
49 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Fam Zheng <famz@redhat.com> | ||
2 | 1 | ||
3 | So it is easier to copy paste the path. | ||
4 | |||
5 | Signed-off-by: Fam Zheng <famz@redhat.com> | ||
6 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
7 | --- | ||
8 | tests/qemu-iotests/check | 2 +- | ||
9 | 1 file changed, 1 insertion(+), 1 deletion(-) | ||
10 | |||
11 | diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check | ||
12 | index XXXXXXX..XXXXXXX 100755 | ||
13 | --- a/tests/qemu-iotests/check | ||
14 | +++ b/tests/qemu-iotests/check | ||
15 | @@ -XXX,XX +XXX,XX @@ do | ||
16 | else | ||
17 | echo " - output mismatch (see $seq.out.bad)" | ||
18 | mv $tmp.out $seq.out.bad | ||
19 | - $diff -w "$reference" $seq.out.bad | ||
20 | + $diff -w "$reference" $(realpath $seq.out.bad) | ||
21 | err=true | ||
22 | fi | ||
23 | fi | ||
24 | -- | ||
25 | 2.13.5 | ||
26 | |||
27 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Alberto Garcia <berto@igalia.com> | ||
2 | 1 | ||
3 | If bkt->max == 0 and bkt->burst_length > 1 then we could have a | ||
4 | division by 0 in throttle_do_compute_wait(). That configuration is | ||
5 | however not permitted and is already detected by throttle_is_valid(), | ||
6 | but let's assert it in throttle_compute_wait() to make it explicit. | ||
7 | |||
8 | Found by Coverity (CID: 1381016). | ||
9 | |||
10 | Signed-off-by: Alberto Garcia <berto@igalia.com> | ||
11 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
13 | --- | ||
14 | util/throttle.c | 1 + | ||
15 | 1 file changed, 1 insertion(+) | ||
16 | |||
17 | diff --git a/util/throttle.c b/util/throttle.c | ||
18 | index XXXXXXX..XXXXXXX 100644 | ||
19 | --- a/util/throttle.c | ||
20 | +++ b/util/throttle.c | ||
21 | @@ -XXX,XX +XXX,XX @@ int64_t throttle_compute_wait(LeakyBucket *bkt) | ||
22 | /* If the main bucket is not full yet we still have to check the | ||
23 | * burst bucket in order to enforce the burst limit */ | ||
24 | if (bkt->burst_length > 1) { | ||
25 | + assert(bkt->max > 0); /* see throttle_is_valid() */ | ||
26 | extra = bkt->burst_level - burst_bucket_size; | ||
27 | if (extra > 0) { | ||
28 | return throttle_do_compute_wait(bkt->max, extra); | ||
29 | -- | ||
30 | 2.13.5 | ||
31 | |||
32 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Manos Pitsidianakis <el13635@mail.ntua.gr> | ||
2 | 1 | ||
3 | RestartData is the opaque data of the throttle_group_restart_queue_entry | ||
4 | coroutine. By being stack allocated, it isn't available anymore if | ||
5 | aio_co_enter schedules the coroutine with a bottom half and runs after | ||
6 | throttle_group_restart_queue returns. | ||
7 | |||
8 | Cc: qemu-stable@nongnu.org | ||
9 | Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr> | ||
10 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
11 | Reviewed-by: Alberto Garcia <berto@igalia.com> | ||
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
13 | --- | ||
14 | block/throttle-groups.c | 12 +++++++----- | ||
15 | 1 file changed, 7 insertions(+), 5 deletions(-) | ||
16 | |||
17 | diff --git a/block/throttle-groups.c b/block/throttle-groups.c | ||
18 | index XXXXXXX..XXXXXXX 100644 | ||
19 | --- a/block/throttle-groups.c | ||
20 | +++ b/block/throttle-groups.c | ||
21 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn throttle_group_restart_queue_entry(void *opaque) | ||
22 | schedule_next_request(tgm, is_write); | ||
23 | qemu_mutex_unlock(&tg->lock); | ||
24 | } | ||
25 | + | ||
26 | + g_free(data); | ||
27 | } | ||
28 | |||
29 | static void throttle_group_restart_queue(ThrottleGroupMember *tgm, bool is_write) | ||
30 | { | ||
31 | Coroutine *co; | ||
32 | - RestartData rd = { | ||
33 | - .tgm = tgm, | ||
34 | - .is_write = is_write | ||
35 | - }; | ||
36 | + RestartData *rd = g_new0(RestartData, 1); | ||
37 | + | ||
38 | + rd->tgm = tgm; | ||
39 | + rd->is_write = is_write; | ||
40 | |||
41 | - co = qemu_coroutine_create(throttle_group_restart_queue_entry, &rd); | ||
42 | + co = qemu_coroutine_create(throttle_group_restart_queue_entry, rd); | ||
43 | aio_co_enter(tgm->aio_context, co); | ||
44 | } | ||
45 | |||
46 | -- | ||
47 | 2.13.5 | ||
48 | |||
49 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | qemu-io provides a 'reopen' command that allows switching from writable | ||
2 | to read-only access. We need to make sure that we don't try to keep | ||
3 | write permissions to a BlockBackend that becomes read-only, otherwise | ||
4 | things are going to fail. | ||
5 | 1 | ||
6 | This requires a bdrv_drain() call because otherwise in-flight AIO | ||
7 | write requests could issue new internal requests while the permission | ||
8 | has already gone away, which would cause assertion failures. Draining | ||
9 | the queue doesn't break AIO requests in any new way, bdrv_reopen() would | ||
10 | drain it anyway only a few lines later. | ||
11 | |||
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
13 | Reviewed-by: Fam Zheng <famz@redhat.com> | ||
14 | --- | ||
15 | qemu-io-cmds.c | 12 ++++++++++++ | ||
16 | tests/qemu-iotests/187.out | 2 +- | ||
17 | 2 files changed, 13 insertions(+), 1 deletion(-) | ||
18 | |||
19 | diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c | ||
20 | index XXXXXXX..XXXXXXX 100644 | ||
21 | --- a/qemu-io-cmds.c | ||
22 | +++ b/qemu-io-cmds.c | ||
23 | @@ -XXX,XX +XXX,XX @@ static int reopen_f(BlockBackend *blk, int argc, char **argv) | ||
24 | return 0; | ||
25 | } | ||
26 | |||
27 | + if (!(flags & BDRV_O_RDWR)) { | ||
28 | + uint64_t orig_perm, orig_shared_perm; | ||
29 | + | ||
30 | + bdrv_drain(bs); | ||
31 | + | ||
32 | + blk_get_perm(blk, &orig_perm, &orig_shared_perm); | ||
33 | + blk_set_perm(blk, | ||
34 | + orig_perm & ~(BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED), | ||
35 | + orig_shared_perm, | ||
36 | + &error_abort); | ||
37 | + } | ||
38 | + | ||
39 | qopts = qemu_opts_find(&reopen_opts, NULL); | ||
40 | opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : NULL; | ||
41 | qemu_opts_reset(&reopen_opts); | ||
42 | diff --git a/tests/qemu-iotests/187.out b/tests/qemu-iotests/187.out | ||
43 | index XXXXXXX..XXXXXXX 100644 | ||
44 | --- a/tests/qemu-iotests/187.out | ||
45 | +++ b/tests/qemu-iotests/187.out | ||
46 | @@ -XXX,XX +XXX,XX @@ Start from read-write | ||
47 | |||
48 | wrote 65536/65536 bytes at offset 0 | ||
49 | 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
50 | -write failed: Operation not permitted | ||
51 | +Block node is read-only | ||
52 | wrote 65536/65536 bytes at offset 0 | ||
53 | 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
54 | *** done | ||
55 | -- | ||
56 | 2.13.5 | ||
57 | |||
58 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | In the context of bdrv_reopen(), we'll have to look at the state of the | ||
2 | graph as it will be after the reopen. This interface addition is in | ||
3 | preparation for the change. | ||
4 | 1 | ||
5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
6 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
7 | --- | ||
8 | block.c | 34 +++++++++++++++++++--------------- | ||
9 | 1 file changed, 19 insertions(+), 15 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 int bdrv_fill_options(QDict **options, const char *filename, | ||
16 | return 0; | ||
17 | } | ||
18 | |||
19 | -static int bdrv_child_check_perm(BdrvChild *c, uint64_t perm, uint64_t shared, | ||
20 | +static int bdrv_child_check_perm(BdrvChild *c, BlockReopenQueue *q, | ||
21 | + uint64_t perm, uint64_t shared, | ||
22 | GSList *ignore_children, Error **errp); | ||
23 | static void bdrv_child_abort_perm_update(BdrvChild *c); | ||
24 | static void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared); | ||
25 | @@ -XXX,XX +XXX,XX @@ static void bdrv_child_perm(BlockDriverState *bs, BlockDriverState *child_bs, | ||
26 | * A call to this function must always be followed by a call to bdrv_set_perm() | ||
27 | * or bdrv_abort_perm_update(). | ||
28 | */ | ||
29 | -static int bdrv_check_perm(BlockDriverState *bs, uint64_t cumulative_perms, | ||
30 | +static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q, | ||
31 | + uint64_t cumulative_perms, | ||
32 | uint64_t cumulative_shared_perms, | ||
33 | GSList *ignore_children, Error **errp) | ||
34 | { | ||
35 | @@ -XXX,XX +XXX,XX @@ static int bdrv_check_perm(BlockDriverState *bs, uint64_t cumulative_perms, | ||
36 | /* Check all children */ | ||
37 | QLIST_FOREACH(c, &bs->children, next) { | ||
38 | uint64_t cur_perm, cur_shared; | ||
39 | - bdrv_child_perm(bs, c->bs, c, c->role, NULL, | ||
40 | + bdrv_child_perm(bs, c->bs, c, c->role, q, | ||
41 | cumulative_perms, cumulative_shared_perms, | ||
42 | &cur_perm, &cur_shared); | ||
43 | - ret = bdrv_child_check_perm(c, cur_perm, cur_shared, ignore_children, | ||
44 | - errp); | ||
45 | + ret = bdrv_child_check_perm(c, q, cur_perm, cur_shared, | ||
46 | + ignore_children, errp); | ||
47 | if (ret < 0) { | ||
48 | return ret; | ||
49 | } | ||
50 | @@ -XXX,XX +XXX,XX @@ char *bdrv_perm_names(uint64_t perm) | ||
51 | * | ||
52 | * Needs to be followed by a call to either bdrv_set_perm() or | ||
53 | * bdrv_abort_perm_update(). */ | ||
54 | -static int bdrv_check_update_perm(BlockDriverState *bs, uint64_t new_used_perm, | ||
55 | +static int bdrv_check_update_perm(BlockDriverState *bs, BlockReopenQueue *q, | ||
56 | + uint64_t new_used_perm, | ||
57 | uint64_t new_shared_perm, | ||
58 | GSList *ignore_children, Error **errp) | ||
59 | { | ||
60 | @@ -XXX,XX +XXX,XX @@ static int bdrv_check_update_perm(BlockDriverState *bs, uint64_t new_used_perm, | ||
61 | cumulative_shared_perms &= c->shared_perm; | ||
62 | } | ||
63 | |||
64 | - return bdrv_check_perm(bs, cumulative_perms, cumulative_shared_perms, | ||
65 | + return bdrv_check_perm(bs, q, cumulative_perms, cumulative_shared_perms, | ||
66 | ignore_children, errp); | ||
67 | } | ||
68 | |||
69 | /* Needs to be followed by a call to either bdrv_child_set_perm() or | ||
70 | * bdrv_child_abort_perm_update(). */ | ||
71 | -static int bdrv_child_check_perm(BdrvChild *c, uint64_t perm, uint64_t shared, | ||
72 | +static int bdrv_child_check_perm(BdrvChild *c, BlockReopenQueue *q, | ||
73 | + uint64_t perm, uint64_t shared, | ||
74 | GSList *ignore_children, Error **errp) | ||
75 | { | ||
76 | int ret; | ||
77 | |||
78 | ignore_children = g_slist_prepend(g_slist_copy(ignore_children), c); | ||
79 | - ret = bdrv_check_update_perm(c->bs, perm, shared, ignore_children, errp); | ||
80 | + ret = bdrv_check_update_perm(c->bs, q, perm, shared, ignore_children, errp); | ||
81 | g_slist_free(ignore_children); | ||
82 | |||
83 | return ret; | ||
84 | @@ -XXX,XX +XXX,XX @@ int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared, | ||
85 | { | ||
86 | int ret; | ||
87 | |||
88 | - ret = bdrv_child_check_perm(c, perm, shared, NULL, errp); | ||
89 | + ret = bdrv_child_check_perm(c, NULL, perm, shared, NULL, errp); | ||
90 | if (ret < 0) { | ||
91 | bdrv_child_abort_perm_update(c); | ||
92 | return ret; | ||
93 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs) | ||
94 | * because we're just taking a parent away, so we're loosening | ||
95 | * restrictions. */ | ||
96 | bdrv_get_cumulative_perm(old_bs, &perm, &shared_perm); | ||
97 | - bdrv_check_perm(old_bs, perm, shared_perm, NULL, &error_abort); | ||
98 | + bdrv_check_perm(old_bs, NULL, perm, shared_perm, NULL, &error_abort); | ||
99 | bdrv_set_perm(old_bs, perm, shared_perm); | ||
100 | } | ||
101 | |||
102 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, | ||
103 | BdrvChild *child; | ||
104 | int ret; | ||
105 | |||
106 | - ret = bdrv_check_update_perm(child_bs, perm, shared_perm, NULL, errp); | ||
107 | + ret = bdrv_check_update_perm(child_bs, NULL, perm, shared_perm, NULL, errp); | ||
108 | if (ret < 0) { | ||
109 | bdrv_abort_perm_update(child_bs); | ||
110 | return NULL; | ||
111 | @@ -XXX,XX +XXX,XX @@ void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to, | ||
112 | |||
113 | /* Check whether the required permissions can be granted on @to, ignoring | ||
114 | * all BdrvChild in @list so that they can't block themselves. */ | ||
115 | - ret = bdrv_check_update_perm(to, perm, shared, list, errp); | ||
116 | + ret = bdrv_check_update_perm(to, NULL, perm, shared, list, errp); | ||
117 | if (ret < 0) { | ||
118 | bdrv_abort_perm_update(to); | ||
119 | goto out; | ||
120 | @@ -XXX,XX +XXX,XX @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp) | ||
121 | |||
122 | /* Update permissions, they may differ for inactive nodes */ | ||
123 | bdrv_get_cumulative_perm(bs, &perm, &shared_perm); | ||
124 | - ret = bdrv_check_perm(bs, perm, shared_perm, NULL, &local_err); | ||
125 | + ret = bdrv_check_perm(bs, NULL, perm, shared_perm, NULL, &local_err); | ||
126 | if (ret < 0) { | ||
127 | bs->open_flags |= BDRV_O_INACTIVE; | ||
128 | error_propagate(errp, local_err); | ||
129 | @@ -XXX,XX +XXX,XX @@ static int bdrv_inactivate_recurse(BlockDriverState *bs, | ||
130 | |||
131 | /* Update permissions, they may differ for inactive nodes */ | ||
132 | bdrv_get_cumulative_perm(bs, &perm, &shared_perm); | ||
133 | - bdrv_check_perm(bs, perm, shared_perm, NULL, &error_abort); | ||
134 | + bdrv_check_perm(bs, NULL, perm, shared_perm, NULL, &error_abort); | ||
135 | bdrv_set_perm(bs, perm, shared_perm); | ||
136 | } | ||
137 | |||
138 | -- | ||
139 | 2.13.5 | ||
140 | |||
141 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Pavel Butsykin <pbutsykin@virtuozzo.com> | ||
2 | 1 | ||
3 | The flag is additional precaution against data loss. Perhaps in the future the | ||
4 | operation shrink without this flag will be blocked for all formats, but for now | ||
5 | we need to maintain compatibility with raw. | ||
6 | |||
7 | Signed-off-by: Pavel Butsykin <pbutsykin@virtuozzo.com> | ||
8 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
9 | Reviewed-by: John Snow <jsnow@redhat.com> | ||
10 | Message-id: 20170918124230.8152-2-pbutsykin@virtuozzo.com | ||
11 | [mreitz: Added a missing space to a warning] | ||
12 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
13 | --- | ||
14 | qemu-img.c | 23 +++++++++++++++++++++++ | ||
15 | qemu-img-cmds.hx | 4 ++-- | ||
16 | qemu-img.texi | 6 +++++- | ||
17 | tests/qemu-iotests/102 | 4 ++-- | ||
18 | tests/qemu-iotests/106 | 2 +- | ||
19 | 5 files changed, 33 insertions(+), 6 deletions(-) | ||
20 | |||
21 | diff --git a/qemu-img.c b/qemu-img.c | ||
22 | index XXXXXXX..XXXXXXX 100644 | ||
23 | --- a/qemu-img.c | ||
24 | +++ b/qemu-img.c | ||
25 | @@ -XXX,XX +XXX,XX @@ enum { | ||
26 | OPTION_TARGET_IMAGE_OPTS = 263, | ||
27 | OPTION_SIZE = 264, | ||
28 | OPTION_PREALLOCATION = 265, | ||
29 | + OPTION_SHRINK = 266, | ||
30 | }; | ||
31 | |||
32 | typedef enum OutputFormat { | ||
33 | @@ -XXX,XX +XXX,XX @@ static int img_resize(int argc, char **argv) | ||
34 | }, | ||
35 | }; | ||
36 | bool image_opts = false; | ||
37 | + bool shrink = false; | ||
38 | |||
39 | /* Remove size from argv manually so that negative numbers are not treated | ||
40 | * as options by getopt. */ | ||
41 | @@ -XXX,XX +XXX,XX @@ static int img_resize(int argc, char **argv) | ||
42 | {"object", required_argument, 0, OPTION_OBJECT}, | ||
43 | {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, | ||
44 | {"preallocation", required_argument, 0, OPTION_PREALLOCATION}, | ||
45 | + {"shrink", no_argument, 0, OPTION_SHRINK}, | ||
46 | {0, 0, 0, 0} | ||
47 | }; | ||
48 | c = getopt_long(argc, argv, ":f:hq", | ||
49 | @@ -XXX,XX +XXX,XX @@ static int img_resize(int argc, char **argv) | ||
50 | return 1; | ||
51 | } | ||
52 | break; | ||
53 | + case OPTION_SHRINK: | ||
54 | + shrink = true; | ||
55 | + break; | ||
56 | } | ||
57 | } | ||
58 | if (optind != argc - 1) { | ||
59 | @@ -XXX,XX +XXX,XX @@ static int img_resize(int argc, char **argv) | ||
60 | goto out; | ||
61 | } | ||
62 | |||
63 | + if (total_size < current_size && !shrink) { | ||
64 | + warn_report("Shrinking an image will delete all data beyond the " | ||
65 | + "shrunken image's end. Before performing such an " | ||
66 | + "operation, make sure there is no important data there."); | ||
67 | + | ||
68 | + if (g_strcmp0(bdrv_get_format_name(blk_bs(blk)), "raw") != 0) { | ||
69 | + error_report( | ||
70 | + "Use the --shrink option to perform a shrink operation."); | ||
71 | + ret = -1; | ||
72 | + goto out; | ||
73 | + } else { | ||
74 | + warn_report("Using the --shrink option will suppress this message. " | ||
75 | + "Note that future versions of qemu-img may refuse to " | ||
76 | + "shrink images without this option."); | ||
77 | + } | ||
78 | + } | ||
79 | + | ||
80 | ret = blk_truncate(blk, total_size, prealloc, &err); | ||
81 | if (!ret) { | ||
82 | qprintf(quiet, "Image resized.\n"); | ||
83 | diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx | ||
84 | index XXXXXXX..XXXXXXX 100644 | ||
85 | --- a/qemu-img-cmds.hx | ||
86 | +++ b/qemu-img-cmds.hx | ||
87 | @@ -XXX,XX +XXX,XX @@ STEXI | ||
88 | ETEXI | ||
89 | |||
90 | DEF("resize", img_resize, | ||
91 | - "resize [--object objectdef] [--image-opts] [-q] filename [+ | -]size") | ||
92 | + "resize [--object objectdef] [--image-opts] [-q] [--shrink] filename [+ | -]size") | ||
93 | STEXI | ||
94 | -@item resize [--object @var{objectdef}] [--image-opts] [-q] @var{filename} [+ | -]@var{size} | ||
95 | +@item resize [--object @var{objectdef}] [--image-opts] [-q] [--shrink] @var{filename} [+ | -]@var{size} | ||
96 | ETEXI | ||
97 | |||
98 | STEXI | ||
99 | diff --git a/qemu-img.texi b/qemu-img.texi | ||
100 | index XXXXXXX..XXXXXXX 100644 | ||
101 | --- a/qemu-img.texi | ||
102 | +++ b/qemu-img.texi | ||
103 | @@ -XXX,XX +XXX,XX @@ qemu-img rebase -b base.img diff.qcow2 | ||
104 | At this point, @code{modified.img} can be discarded, since | ||
105 | @code{base.img + diff.qcow2} contains the same information. | ||
106 | |||
107 | -@item resize [--preallocation=@var{prealloc}] @var{filename} [+ | -]@var{size} | ||
108 | +@item resize [--shrink] [--preallocation=@var{prealloc}] @var{filename} [+ | -]@var{size} | ||
109 | |||
110 | Change the disk image as if it had been created with @var{size}. | ||
111 | |||
112 | @@ -XXX,XX +XXX,XX @@ Before using this command to shrink a disk image, you MUST use file system and | ||
113 | partitioning tools inside the VM to reduce allocated file systems and partition | ||
114 | sizes accordingly. Failure to do so will result in data loss! | ||
115 | |||
116 | +When shrinking images, the @code{--shrink} option must be given. This informs | ||
117 | +qemu-img that the user acknowledges all loss of data beyond the truncated | ||
118 | +image's end. | ||
119 | + | ||
120 | After using this command to grow a disk image, you must use file system and | ||
121 | partitioning tools inside the VM to actually begin using the new space on the | ||
122 | device. | ||
123 | diff --git a/tests/qemu-iotests/102 b/tests/qemu-iotests/102 | ||
124 | index XXXXXXX..XXXXXXX 100755 | ||
125 | --- a/tests/qemu-iotests/102 | ||
126 | +++ b/tests/qemu-iotests/102 | ||
127 | @@ -XXX,XX +XXX,XX @@ _make_test_img $IMG_SIZE | ||
128 | $QEMU_IO -c 'write 0 64k' "$TEST_IMG" | _filter_qemu_io | ||
129 | # Remove data cluster from image (first cluster: image header, second: reftable, | ||
130 | # third: refblock, fourth: L1 table, fifth: L2 table) | ||
131 | -$QEMU_IMG resize -f raw "$TEST_IMG" $((5 * 64 * 1024)) | ||
132 | +$QEMU_IMG resize -f raw --shrink "$TEST_IMG" $((5 * 64 * 1024)) | ||
133 | |||
134 | $QEMU_IO -c map "$TEST_IMG" | ||
135 | $QEMU_IMG map "$TEST_IMG" | ||
136 | @@ -XXX,XX +XXX,XX @@ $QEMU_IO -c 'write 0 64k' "$TEST_IMG" | _filter_qemu_io | ||
137 | |||
138 | qemu_comm_method=monitor _launch_qemu -drive if=none,file="$TEST_IMG",id=drv0 | ||
139 | |||
140 | -$QEMU_IMG resize -f raw "$TEST_IMG" $((5 * 64 * 1024)) | ||
141 | +$QEMU_IMG resize -f raw --shrink "$TEST_IMG" $((5 * 64 * 1024)) | ||
142 | |||
143 | _send_qemu_cmd $QEMU_HANDLE 'qemu-io drv0 map' 'allocated' \ | ||
144 | | sed -e 's/^(qemu).*qemu-io drv0 map...$/(qemu) qemu-io drv0 map/' | ||
145 | diff --git a/tests/qemu-iotests/106 b/tests/qemu-iotests/106 | ||
146 | index XXXXXXX..XXXXXXX 100755 | ||
147 | --- a/tests/qemu-iotests/106 | ||
148 | +++ b/tests/qemu-iotests/106 | ||
149 | @@ -XXX,XX +XXX,XX @@ echo '=== Testing image shrinking ===' | ||
150 | for growth_mode in falloc full off; do | ||
151 | echo | ||
152 | echo "--- growth_mode=$growth_mode ---" | ||
153 | - $QEMU_IMG resize -f "$IMGFMT" --preallocation=$growth_mode "$TEST_IMG" -${GROWTH_SIZE}K | ||
154 | + $QEMU_IMG resize -f "$IMGFMT" --shrink --preallocation=$growth_mode "$TEST_IMG" -${GROWTH_SIZE}K | ||
155 | done | ||
156 | |||
157 | # success, all done | ||
158 | -- | ||
159 | 2.13.5 | ||
160 | |||
161 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Pavel Butsykin <pbutsykin@virtuozzo.com> | ||
2 | 1 | ||
3 | This patch add shrinking of the image file for qcow2. As a result, this allows | ||
4 | us to reduce the virtual image size and free up space on the disk without | ||
5 | copying the image. Image can be fragmented and shrink is done by punching holes | ||
6 | in the image file. | ||
7 | |||
8 | Signed-off-by: Pavel Butsykin <pbutsykin@virtuozzo.com> | ||
9 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
10 | Reviewed-by: John Snow <jsnow@redhat.com> | ||
11 | Message-id: 20170918124230.8152-4-pbutsykin@virtuozzo.com | ||
12 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
13 | --- | ||
14 | qapi/block-core.json | 8 +++- | ||
15 | block/qcow2.h | 14 ++++++ | ||
16 | block/qcow2-cluster.c | 50 +++++++++++++++++++++ | ||
17 | block/qcow2-refcount.c | 120 +++++++++++++++++++++++++++++++++++++++++++++++++ | ||
18 | block/qcow2.c | 43 ++++++++++++++---- | ||
19 | 5 files changed, 225 insertions(+), 10 deletions(-) | ||
20 | |||
21 | diff --git a/qapi/block-core.json b/qapi/block-core.json | ||
22 | index XXXXXXX..XXXXXXX 100644 | ||
23 | --- a/qapi/block-core.json | ||
24 | +++ b/qapi/block-core.json | ||
25 | @@ -XXX,XX +XXX,XX @@ | ||
26 | # | ||
27 | # Trigger events supported by blkdebug. | ||
28 | # | ||
29 | +# @l1_shrink_write_table: write zeros to the l1 table to shrink image. | ||
30 | +# (since 2.11) | ||
31 | +# | ||
32 | +# @l1_shrink_free_l2_clusters: discard the l2 tables. (since 2.11) | ||
33 | +# | ||
34 | # Since: 2.9 | ||
35 | ## | ||
36 | { 'enum': 'BlkdebugEvent', 'prefix': 'BLKDBG', | ||
37 | @@ -XXX,XX +XXX,XX @@ | ||
38 | 'cluster_alloc_bytes', 'cluster_free', 'flush_to_os', | ||
39 | 'flush_to_disk', 'pwritev_rmw_head', 'pwritev_rmw_after_head', | ||
40 | 'pwritev_rmw_tail', 'pwritev_rmw_after_tail', 'pwritev', | ||
41 | - 'pwritev_zero', 'pwritev_done', 'empty_image_prepare' ] } | ||
42 | + 'pwritev_zero', 'pwritev_done', 'empty_image_prepare', | ||
43 | + 'l1_shrink_write_table', 'l1_shrink_free_l2_clusters' ] } | ||
44 | |||
45 | ## | ||
46 | # @BlkdebugInjectErrorOptions: | ||
47 | diff --git a/block/qcow2.h b/block/qcow2.h | ||
48 | index XXXXXXX..XXXXXXX 100644 | ||
49 | --- a/block/qcow2.h | ||
50 | +++ b/block/qcow2.h | ||
51 | @@ -XXX,XX +XXX,XX @@ static inline uint64_t refcount_diff(uint64_t r1, uint64_t r2) | ||
52 | return r1 > r2 ? r1 - r2 : r2 - r1; | ||
53 | } | ||
54 | |||
55 | +static inline | ||
56 | +uint32_t offset_to_reftable_index(BDRVQcow2State *s, uint64_t offset) | ||
57 | +{ | ||
58 | + return offset >> (s->refcount_block_bits + s->cluster_bits); | ||
59 | +} | ||
60 | + | ||
61 | +static inline uint64_t get_refblock_offset(BDRVQcow2State *s, uint64_t offset) | ||
62 | +{ | ||
63 | + uint32_t index = offset_to_reftable_index(s, offset); | ||
64 | + return s->refcount_table[index] & REFT_OFFSET_MASK; | ||
65 | +} | ||
66 | + | ||
67 | /* qcow2.c functions */ | ||
68 | int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov, | ||
69 | int64_t sector_num, int nb_sectors); | ||
70 | @@ -XXX,XX +XXX,XX @@ int qcow2_inc_refcounts_imrt(BlockDriverState *bs, BdrvCheckResult *res, | ||
71 | int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order, | ||
72 | BlockDriverAmendStatusCB *status_cb, | ||
73 | void *cb_opaque, Error **errp); | ||
74 | +int qcow2_shrink_reftable(BlockDriverState *bs); | ||
75 | |||
76 | /* qcow2-cluster.c functions */ | ||
77 | int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, | ||
78 | bool exact_size); | ||
79 | +int qcow2_shrink_l1_table(BlockDriverState *bs, uint64_t max_size); | ||
80 | int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index); | ||
81 | int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset); | ||
82 | int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num, | ||
83 | diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c | ||
84 | index XXXXXXX..XXXXXXX 100644 | ||
85 | --- a/block/qcow2-cluster.c | ||
86 | +++ b/block/qcow2-cluster.c | ||
87 | @@ -XXX,XX +XXX,XX @@ | ||
88 | #include "qemu/bswap.h" | ||
89 | #include "trace.h" | ||
90 | |||
91 | +int qcow2_shrink_l1_table(BlockDriverState *bs, uint64_t exact_size) | ||
92 | +{ | ||
93 | + BDRVQcow2State *s = bs->opaque; | ||
94 | + int new_l1_size, i, ret; | ||
95 | + | ||
96 | + if (exact_size >= s->l1_size) { | ||
97 | + return 0; | ||
98 | + } | ||
99 | + | ||
100 | + new_l1_size = exact_size; | ||
101 | + | ||
102 | +#ifdef DEBUG_ALLOC2 | ||
103 | + fprintf(stderr, "shrink l1_table from %d to %d\n", s->l1_size, new_l1_size); | ||
104 | +#endif | ||
105 | + | ||
106 | + BLKDBG_EVENT(bs->file, BLKDBG_L1_SHRINK_WRITE_TABLE); | ||
107 | + ret = bdrv_pwrite_zeroes(bs->file, s->l1_table_offset + | ||
108 | + new_l1_size * sizeof(uint64_t), | ||
109 | + (s->l1_size - new_l1_size) * sizeof(uint64_t), 0); | ||
110 | + if (ret < 0) { | ||
111 | + goto fail; | ||
112 | + } | ||
113 | + | ||
114 | + ret = bdrv_flush(bs->file->bs); | ||
115 | + if (ret < 0) { | ||
116 | + goto fail; | ||
117 | + } | ||
118 | + | ||
119 | + BLKDBG_EVENT(bs->file, BLKDBG_L1_SHRINK_FREE_L2_CLUSTERS); | ||
120 | + for (i = s->l1_size - 1; i > new_l1_size - 1; i--) { | ||
121 | + if ((s->l1_table[i] & L1E_OFFSET_MASK) == 0) { | ||
122 | + continue; | ||
123 | + } | ||
124 | + qcow2_free_clusters(bs, s->l1_table[i] & L1E_OFFSET_MASK, | ||
125 | + s->cluster_size, QCOW2_DISCARD_ALWAYS); | ||
126 | + s->l1_table[i] = 0; | ||
127 | + } | ||
128 | + return 0; | ||
129 | + | ||
130 | +fail: | ||
131 | + /* | ||
132 | + * If the write in the l1_table failed the image may contain a partially | ||
133 | + * overwritten l1_table. In this case it would be better to clear the | ||
134 | + * l1_table in memory to avoid possible image corruption. | ||
135 | + */ | ||
136 | + memset(s->l1_table + new_l1_size, 0, | ||
137 | + (s->l1_size - new_l1_size) * sizeof(uint64_t)); | ||
138 | + return ret; | ||
139 | +} | ||
140 | + | ||
141 | int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, | ||
142 | bool exact_size) | ||
143 | { | ||
144 | diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c | ||
145 | index XXXXXXX..XXXXXXX 100644 | ||
146 | --- a/block/qcow2-refcount.c | ||
147 | +++ b/block/qcow2-refcount.c | ||
148 | @@ -XXX,XX +XXX,XX @@ | ||
149 | #include "block/qcow2.h" | ||
150 | #include "qemu/range.h" | ||
151 | #include "qemu/bswap.h" | ||
152 | +#include "qemu/cutils.h" | ||
153 | |||
154 | static int64_t alloc_clusters_noref(BlockDriverState *bs, uint64_t size); | ||
155 | static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs, | ||
156 | @@ -XXX,XX +XXX,XX @@ done: | ||
157 | qemu_vfree(new_refblock); | ||
158 | return ret; | ||
159 | } | ||
160 | + | ||
161 | +static int qcow2_discard_refcount_block(BlockDriverState *bs, | ||
162 | + uint64_t discard_block_offs) | ||
163 | +{ | ||
164 | + BDRVQcow2State *s = bs->opaque; | ||
165 | + uint64_t refblock_offs = get_refblock_offset(s, discard_block_offs); | ||
166 | + uint64_t cluster_index = discard_block_offs >> s->cluster_bits; | ||
167 | + uint32_t block_index = cluster_index & (s->refcount_block_size - 1); | ||
168 | + void *refblock; | ||
169 | + int ret; | ||
170 | + | ||
171 | + assert(discard_block_offs != 0); | ||
172 | + | ||
173 | + ret = qcow2_cache_get(bs, s->refcount_block_cache, refblock_offs, | ||
174 | + &refblock); | ||
175 | + if (ret < 0) { | ||
176 | + return ret; | ||
177 | + } | ||
178 | + | ||
179 | + if (s->get_refcount(refblock, block_index) != 1) { | ||
180 | + qcow2_signal_corruption(bs, true, -1, -1, "Invalid refcount:" | ||
181 | + " refblock offset %#" PRIx64 | ||
182 | + ", reftable index %u" | ||
183 | + ", block offset %#" PRIx64 | ||
184 | + ", refcount %#" PRIx64, | ||
185 | + refblock_offs, | ||
186 | + offset_to_reftable_index(s, discard_block_offs), | ||
187 | + discard_block_offs, | ||
188 | + s->get_refcount(refblock, block_index)); | ||
189 | + qcow2_cache_put(bs, s->refcount_block_cache, &refblock); | ||
190 | + return -EINVAL; | ||
191 | + } | ||
192 | + s->set_refcount(refblock, block_index, 0); | ||
193 | + | ||
194 | + qcow2_cache_entry_mark_dirty(bs, s->refcount_block_cache, refblock); | ||
195 | + | ||
196 | + qcow2_cache_put(bs, s->refcount_block_cache, &refblock); | ||
197 | + | ||
198 | + if (cluster_index < s->free_cluster_index) { | ||
199 | + s->free_cluster_index = cluster_index; | ||
200 | + } | ||
201 | + | ||
202 | + refblock = qcow2_cache_is_table_offset(bs, s->refcount_block_cache, | ||
203 | + discard_block_offs); | ||
204 | + if (refblock) { | ||
205 | + /* discard refblock from the cache if refblock is cached */ | ||
206 | + qcow2_cache_discard(bs, s->refcount_block_cache, refblock); | ||
207 | + } | ||
208 | + update_refcount_discard(bs, discard_block_offs, s->cluster_size); | ||
209 | + | ||
210 | + return 0; | ||
211 | +} | ||
212 | + | ||
213 | +int qcow2_shrink_reftable(BlockDriverState *bs) | ||
214 | +{ | ||
215 | + BDRVQcow2State *s = bs->opaque; | ||
216 | + uint64_t *reftable_tmp = | ||
217 | + g_malloc(s->refcount_table_size * sizeof(uint64_t)); | ||
218 | + int i, ret; | ||
219 | + | ||
220 | + for (i = 0; i < s->refcount_table_size; i++) { | ||
221 | + int64_t refblock_offs = s->refcount_table[i] & REFT_OFFSET_MASK; | ||
222 | + void *refblock; | ||
223 | + bool unused_block; | ||
224 | + | ||
225 | + if (refblock_offs == 0) { | ||
226 | + reftable_tmp[i] = 0; | ||
227 | + continue; | ||
228 | + } | ||
229 | + ret = qcow2_cache_get(bs, s->refcount_block_cache, refblock_offs, | ||
230 | + &refblock); | ||
231 | + if (ret < 0) { | ||
232 | + goto out; | ||
233 | + } | ||
234 | + | ||
235 | + /* the refblock has own reference */ | ||
236 | + if (i == offset_to_reftable_index(s, refblock_offs)) { | ||
237 | + uint64_t block_index = (refblock_offs >> s->cluster_bits) & | ||
238 | + (s->refcount_block_size - 1); | ||
239 | + uint64_t refcount = s->get_refcount(refblock, block_index); | ||
240 | + | ||
241 | + s->set_refcount(refblock, block_index, 0); | ||
242 | + | ||
243 | + unused_block = buffer_is_zero(refblock, s->cluster_size); | ||
244 | + | ||
245 | + s->set_refcount(refblock, block_index, refcount); | ||
246 | + } else { | ||
247 | + unused_block = buffer_is_zero(refblock, s->cluster_size); | ||
248 | + } | ||
249 | + qcow2_cache_put(bs, s->refcount_block_cache, &refblock); | ||
250 | + | ||
251 | + reftable_tmp[i] = unused_block ? 0 : cpu_to_be64(s->refcount_table[i]); | ||
252 | + } | ||
253 | + | ||
254 | + ret = bdrv_pwrite_sync(bs->file, s->refcount_table_offset, reftable_tmp, | ||
255 | + s->refcount_table_size * sizeof(uint64_t)); | ||
256 | + /* | ||
257 | + * If the write in the reftable failed the image may contain a partially | ||
258 | + * overwritten reftable. In this case it would be better to clear the | ||
259 | + * reftable in memory to avoid possible image corruption. | ||
260 | + */ | ||
261 | + for (i = 0; i < s->refcount_table_size; i++) { | ||
262 | + if (s->refcount_table[i] && !reftable_tmp[i]) { | ||
263 | + if (ret == 0) { | ||
264 | + ret = qcow2_discard_refcount_block(bs, s->refcount_table[i] & | ||
265 | + REFT_OFFSET_MASK); | ||
266 | + } | ||
267 | + s->refcount_table[i] = 0; | ||
268 | + } | ||
269 | + } | ||
270 | + | ||
271 | + if (!s->cache_discards) { | ||
272 | + qcow2_process_discards(bs, ret); | ||
273 | + } | ||
274 | + | ||
275 | +out: | ||
276 | + g_free(reftable_tmp); | ||
277 | + return ret; | ||
278 | +} | ||
279 | diff --git a/block/qcow2.c b/block/qcow2.c | ||
280 | index XXXXXXX..XXXXXXX 100644 | ||
281 | --- a/block/qcow2.c | ||
282 | +++ b/block/qcow2.c | ||
283 | @@ -XXX,XX +XXX,XX @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset, | ||
284 | } | ||
285 | |||
286 | old_length = bs->total_sectors * 512; | ||
287 | + new_l1_size = size_to_l1(s, offset); | ||
288 | |||
289 | - /* shrinking is currently not supported */ | ||
290 | if (offset < old_length) { | ||
291 | - error_setg(errp, "qcow2 doesn't support shrinking images yet"); | ||
292 | - return -ENOTSUP; | ||
293 | - } | ||
294 | + if (prealloc != PREALLOC_MODE_OFF) { | ||
295 | + error_setg(errp, | ||
296 | + "Preallocation can't be used for shrinking an image"); | ||
297 | + return -EINVAL; | ||
298 | + } | ||
299 | |||
300 | - new_l1_size = size_to_l1(s, offset); | ||
301 | - ret = qcow2_grow_l1_table(bs, new_l1_size, true); | ||
302 | - if (ret < 0) { | ||
303 | - error_setg_errno(errp, -ret, "Failed to grow the L1 table"); | ||
304 | - return ret; | ||
305 | + ret = qcow2_cluster_discard(bs, ROUND_UP(offset, s->cluster_size), | ||
306 | + old_length - ROUND_UP(offset, | ||
307 | + s->cluster_size), | ||
308 | + QCOW2_DISCARD_ALWAYS, true); | ||
309 | + if (ret < 0) { | ||
310 | + error_setg_errno(errp, -ret, "Failed to discard cropped clusters"); | ||
311 | + return ret; | ||
312 | + } | ||
313 | + | ||
314 | + ret = qcow2_shrink_l1_table(bs, new_l1_size); | ||
315 | + if (ret < 0) { | ||
316 | + error_setg_errno(errp, -ret, | ||
317 | + "Failed to reduce the number of L2 tables"); | ||
318 | + return ret; | ||
319 | + } | ||
320 | + | ||
321 | + ret = qcow2_shrink_reftable(bs); | ||
322 | + if (ret < 0) { | ||
323 | + error_setg_errno(errp, -ret, | ||
324 | + "Failed to discard unused refblocks"); | ||
325 | + return ret; | ||
326 | + } | ||
327 | + } else { | ||
328 | + ret = qcow2_grow_l1_table(bs, new_l1_size, true); | ||
329 | + if (ret < 0) { | ||
330 | + error_setg_errno(errp, -ret, "Failed to grow the L1 table"); | ||
331 | + return ret; | ||
332 | + } | ||
333 | } | ||
334 | |||
335 | switch (prealloc) { | ||
336 | -- | ||
337 | 2.13.5 | ||
338 | |||
339 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Pavel Butsykin <pbutsykin@virtuozzo.com> | ||
2 | 1 | ||
3 | Signed-off-by: Pavel Butsykin <pbutsykin@virtuozzo.com> | ||
4 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
5 | Reviewed-by: John Snow <jsnow@redhat.com> | ||
6 | Message-id: 20170918124230.8152-5-pbutsykin@virtuozzo.com | ||
7 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
8 | --- | ||
9 | tests/qemu-iotests/163 | 170 +++++++++++++++++++++++++++++++++++++++++++++ | ||
10 | tests/qemu-iotests/163.out | 5 ++ | ||
11 | tests/qemu-iotests/group | 1 + | ||
12 | 3 files changed, 176 insertions(+) | ||
13 | create mode 100644 tests/qemu-iotests/163 | ||
14 | create mode 100644 tests/qemu-iotests/163.out | ||
15 | |||
16 | diff --git a/tests/qemu-iotests/163 b/tests/qemu-iotests/163 | ||
17 | new file mode 100644 | ||
18 | index XXXXXXX..XXXXXXX | ||
19 | --- /dev/null | ||
20 | +++ b/tests/qemu-iotests/163 | ||
21 | @@ -XXX,XX +XXX,XX @@ | ||
22 | +#!/usr/bin/env python | ||
23 | +# | ||
24 | +# Tests for shrinking images | ||
25 | +# | ||
26 | +# Copyright (c) 2016-2017 Parallels International GmbH | ||
27 | +# | ||
28 | +# This program is free software; you can redistribute it and/or modify | ||
29 | +# it under the terms of the GNU General Public License as published by | ||
30 | +# the Free Software Foundation; either version 2 of the License, or | ||
31 | +# (at your option) any later version. | ||
32 | +# | ||
33 | +# This program is distributed in the hope that it will be useful, | ||
34 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
35 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
36 | +# GNU General Public License for more details. | ||
37 | +# | ||
38 | +# You should have received a copy of the GNU General Public License | ||
39 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
40 | +# | ||
41 | + | ||
42 | +import os, random, iotests, struct, qcow2 | ||
43 | +from iotests import qemu_img, qemu_io, image_size | ||
44 | + | ||
45 | +test_img = os.path.join(iotests.test_dir, 'test.img') | ||
46 | +check_img = os.path.join(iotests.test_dir, 'check.img') | ||
47 | + | ||
48 | +def size_to_int(str): | ||
49 | + suff = ['B', 'K', 'M', 'G', 'T'] | ||
50 | + return int(str[:-1]) * 1024**suff.index(str[-1:]) | ||
51 | + | ||
52 | +class ShrinkBaseClass(iotests.QMPTestCase): | ||
53 | + image_len = '128M' | ||
54 | + shrink_size = '10M' | ||
55 | + chunk_size = '16M' | ||
56 | + refcount_bits = '16' | ||
57 | + | ||
58 | + def __qcow2_check(self, filename): | ||
59 | + entry_bits = 3 | ||
60 | + entry_size = 1 << entry_bits | ||
61 | + l1_mask = 0x00fffffffffffe00 | ||
62 | + div_roundup = lambda n, d: (n + d - 1) / d | ||
63 | + | ||
64 | + def split_by_n(data, n): | ||
65 | + for x in xrange(0, len(data), n): | ||
66 | + yield struct.unpack('>Q', data[x:x + n])[0] & l1_mask | ||
67 | + | ||
68 | + def check_l1_table(h, l1_data): | ||
69 | + l1_list = list(split_by_n(l1_data, entry_size)) | ||
70 | + real_l1_size = div_roundup(h.size, | ||
71 | + 1 << (h.cluster_bits*2 - entry_size)) | ||
72 | + used, unused = l1_list[:real_l1_size], l1_list[real_l1_size:] | ||
73 | + | ||
74 | + self.assertTrue(len(used) != 0, "Verifying l1 table content") | ||
75 | + self.assertFalse(any(unused), "Verifying l1 table content") | ||
76 | + | ||
77 | + def check_reftable(fd, h, reftable): | ||
78 | + for offset in split_by_n(reftable, entry_size): | ||
79 | + if offset != 0: | ||
80 | + fd.seek(offset) | ||
81 | + cluster = fd.read(1 << h.cluster_bits) | ||
82 | + self.assertTrue(any(cluster), "Verifying reftable content") | ||
83 | + | ||
84 | + with open(filename, "rb") as fd: | ||
85 | + h = qcow2.QcowHeader(fd) | ||
86 | + | ||
87 | + fd.seek(h.l1_table_offset) | ||
88 | + l1_table = fd.read(h.l1_size << entry_bits) | ||
89 | + | ||
90 | + fd.seek(h.refcount_table_offset) | ||
91 | + reftable = fd.read(h.refcount_table_clusters << h.cluster_bits) | ||
92 | + | ||
93 | + check_l1_table(h, l1_table) | ||
94 | + check_reftable(fd, h, reftable) | ||
95 | + | ||
96 | + def __raw_check(self, filename): | ||
97 | + pass | ||
98 | + | ||
99 | + image_check = { | ||
100 | + 'qcow2' : __qcow2_check, | ||
101 | + 'raw' : __raw_check | ||
102 | + } | ||
103 | + | ||
104 | + def setUp(self): | ||
105 | + if iotests.imgfmt == 'raw': | ||
106 | + qemu_img('create', '-f', iotests.imgfmt, test_img, self.image_len) | ||
107 | + qemu_img('create', '-f', iotests.imgfmt, check_img, | ||
108 | + self.shrink_size) | ||
109 | + else: | ||
110 | + qemu_img('create', '-f', iotests.imgfmt, | ||
111 | + '-o', 'cluster_size=' + self.cluster_size + | ||
112 | + ',refcount_bits=' + self.refcount_bits, | ||
113 | + test_img, self.image_len) | ||
114 | + qemu_img('create', '-f', iotests.imgfmt, | ||
115 | + '-o', 'cluster_size=%s'% self.cluster_size, | ||
116 | + check_img, self.shrink_size) | ||
117 | + qemu_io('-c', 'write -P 0xff 0 ' + self.shrink_size, check_img) | ||
118 | + | ||
119 | + def tearDown(self): | ||
120 | + os.remove(test_img) | ||
121 | + os.remove(check_img) | ||
122 | + | ||
123 | + def image_verify(self): | ||
124 | + self.assertEqual(image_size(test_img), image_size(check_img), | ||
125 | + "Verifying image size") | ||
126 | + self.image_check[iotests.imgfmt](self, test_img) | ||
127 | + | ||
128 | + if iotests.imgfmt == 'raw': | ||
129 | + return | ||
130 | + self.assertEqual(qemu_img('check', test_img), 0, | ||
131 | + "Verifying image corruption") | ||
132 | + | ||
133 | + def test_empty_image(self): | ||
134 | + qemu_img('resize', '-f', iotests.imgfmt, '--shrink', test_img, | ||
135 | + self.shrink_size) | ||
136 | + | ||
137 | + self.assertEqual( | ||
138 | + qemu_io('-c', 'read -P 0x00 %s'%self.shrink_size, test_img), | ||
139 | + qemu_io('-c', 'read -P 0x00 %s'%self.shrink_size, check_img), | ||
140 | + "Verifying image content") | ||
141 | + | ||
142 | + self.image_verify() | ||
143 | + | ||
144 | + def test_sequential_write(self): | ||
145 | + for offs in range(0, size_to_int(self.image_len), | ||
146 | + size_to_int(self.chunk_size)): | ||
147 | + qemu_io('-c', 'write -P 0xff %d %s' % (offs, self.chunk_size), | ||
148 | + test_img) | ||
149 | + | ||
150 | + qemu_img('resize', '-f', iotests.imgfmt, '--shrink', test_img, | ||
151 | + self.shrink_size) | ||
152 | + | ||
153 | + self.assertEqual(qemu_img("compare", test_img, check_img), 0, | ||
154 | + "Verifying image content") | ||
155 | + | ||
156 | + self.image_verify() | ||
157 | + | ||
158 | + def test_random_write(self): | ||
159 | + offs_list = range(0, size_to_int(self.image_len), | ||
160 | + size_to_int(self.chunk_size)) | ||
161 | + random.shuffle(offs_list) | ||
162 | + for offs in offs_list: | ||
163 | + qemu_io('-c', 'write -P 0xff %d %s' % (offs, self.chunk_size), | ||
164 | + test_img) | ||
165 | + | ||
166 | + qemu_img('resize', '-f', iotests.imgfmt, '--shrink', test_img, | ||
167 | + self.shrink_size) | ||
168 | + | ||
169 | + self.assertEqual(qemu_img("compare", test_img, check_img), 0, | ||
170 | + "Verifying image content") | ||
171 | + | ||
172 | + self.image_verify() | ||
173 | + | ||
174 | +class TestShrink512(ShrinkBaseClass): | ||
175 | + image_len = '3M' | ||
176 | + shrink_size = '1M' | ||
177 | + chunk_size = '256K' | ||
178 | + cluster_size = '512' | ||
179 | + refcount_bits = '64' | ||
180 | + | ||
181 | +class TestShrink64K(ShrinkBaseClass): | ||
182 | + cluster_size = '64K' | ||
183 | + | ||
184 | +class TestShrink1M(ShrinkBaseClass): | ||
185 | + cluster_size = '1M' | ||
186 | + refcount_bits = '1' | ||
187 | + | ||
188 | +ShrinkBaseClass = None | ||
189 | + | ||
190 | +if __name__ == '__main__': | ||
191 | + iotests.main(supported_fmts=['raw', 'qcow2']) | ||
192 | diff --git a/tests/qemu-iotests/163.out b/tests/qemu-iotests/163.out | ||
193 | new file mode 100644 | ||
194 | index XXXXXXX..XXXXXXX | ||
195 | --- /dev/null | ||
196 | +++ b/tests/qemu-iotests/163.out | ||
197 | @@ -XXX,XX +XXX,XX @@ | ||
198 | +......... | ||
199 | +---------------------------------------------------------------------- | ||
200 | +Ran 9 tests | ||
201 | + | ||
202 | +OK | ||
203 | diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group | ||
204 | index XXXXXXX..XXXXXXX 100644 | ||
205 | --- a/tests/qemu-iotests/group | ||
206 | +++ b/tests/qemu-iotests/group | ||
207 | @@ -XXX,XX +XXX,XX @@ | ||
208 | 159 rw auto quick | ||
209 | 160 rw auto quick | ||
210 | 162 auto quick | ||
211 | +163 rw auto quick | ||
212 | 165 rw auto quick | ||
213 | 170 rw auto quick | ||
214 | 171 rw auto quick | ||
215 | -- | ||
216 | 2.13.5 | ||
217 | |||
218 | diff view generated by jsdifflib |